SignedData.java revision 5db505e1f6a68c8d5dfdb0fed0b8607dea7bed96
1package org.bouncycastle.asn1.cms; 2 3import java.util.Enumeration; 4 5import org.bouncycastle.asn1.ASN1EncodableVector; 6import org.bouncycastle.asn1.ASN1Integer; 7import org.bouncycastle.asn1.ASN1Object; 8import org.bouncycastle.asn1.ASN1ObjectIdentifier; 9import org.bouncycastle.asn1.ASN1Primitive; 10import org.bouncycastle.asn1.ASN1Sequence; 11import org.bouncycastle.asn1.ASN1Set; 12import org.bouncycastle.asn1.ASN1TaggedObject; 13import org.bouncycastle.asn1.BERSequence; 14import org.bouncycastle.asn1.BERSet; 15import org.bouncycastle.asn1.BERTaggedObject; 16import org.bouncycastle.asn1.DERTaggedObject; 17 18/** 19 * <a href="http://tools.ietf.org/html/rfc5652#section-5.1">RFC 5652</a>: 20 * <p> 21 * A signed data object containing multitude of {@link SignerInfo}s. 22 * <pre> 23 * SignedData ::= SEQUENCE { 24 * version CMSVersion, 25 * digestAlgorithms DigestAlgorithmIdentifiers, 26 * encapContentInfo EncapsulatedContentInfo, 27 * certificates [0] IMPLICIT CertificateSet OPTIONAL, 28 * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, 29 * signerInfos SignerInfos 30 * } 31 * 32 * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier 33 * 34 * SignerInfos ::= SET OF SignerInfo 35 * </pre> 36 * <p> 37 * The version calculation uses following ruleset from RFC 3852 section 5.1: 38 * <pre> 39 * IF ((certificates is present) AND 40 * (any certificates with a type of other are present)) OR 41 * ((crls is present) AND 42 * (any crls with a type of other are present)) 43 * THEN version MUST be 5 44 * ELSE 45 * IF (certificates is present) AND 46 * (any version 2 attribute certificates are present) 47 * THEN version MUST be 4 48 * ELSE 49 * IF ((certificates is present) AND 50 * (any version 1 attribute certificates are present)) OR 51 * (any SignerInfo structures are version 3) OR 52 * (encapContentInfo eContentType is other than id-data) 53 * THEN version MUST be 3 54 * ELSE version MUST be 1 55 * </pre> 56 * <p> 57 * @todo Check possible update for this to RFC 5652 level 58 */ 59public class SignedData 60 extends ASN1Object 61{ 62 private static final ASN1Integer VERSION_1 = new ASN1Integer(1); 63 private static final ASN1Integer VERSION_3 = new ASN1Integer(3); 64 private static final ASN1Integer VERSION_4 = new ASN1Integer(4); 65 private static final ASN1Integer VERSION_5 = new ASN1Integer(5); 66 67 private ASN1Integer version; 68 private ASN1Set digestAlgorithms; 69 private ContentInfo contentInfo; 70 private ASN1Set certificates; 71 private ASN1Set crls; 72 private ASN1Set signerInfos; 73 private boolean certsBer; 74 private boolean crlsBer; 75 76 /** 77 * Return a SignedData object from the given object. 78 * <p> 79 * Accepted inputs: 80 * <ul> 81 * <li> null → null 82 * <li> {@link SignedData} object 83 * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with SignedData structure inside 84 * </ul> 85 * 86 * @param o the object we want converted. 87 * @exception IllegalArgumentException if the object cannot be converted. 88 */ 89 public static SignedData getInstance( 90 Object o) 91 { 92 if (o instanceof SignedData) 93 { 94 return (SignedData)o; 95 } 96 else if (o != null) 97 { 98 return new SignedData(ASN1Sequence.getInstance(o)); 99 } 100 101 return null; 102 } 103 104 public SignedData( 105 ASN1Set digestAlgorithms, 106 ContentInfo contentInfo, 107 ASN1Set certificates, 108 ASN1Set crls, 109 ASN1Set signerInfos) 110 { 111 this.version = calculateVersion(contentInfo.getContentType(), certificates, crls, signerInfos); 112 this.digestAlgorithms = digestAlgorithms; 113 this.contentInfo = contentInfo; 114 this.certificates = certificates; 115 this.crls = crls; 116 this.signerInfos = signerInfos; 117 this.crlsBer = crls instanceof BERSet; 118 this.certsBer = certificates instanceof BERSet; 119 } 120 121 122 private ASN1Integer calculateVersion( 123 ASN1ObjectIdentifier contentOid, 124 ASN1Set certs, 125 ASN1Set crls, 126 ASN1Set signerInfs) 127 { 128 boolean otherCert = false; 129 boolean otherCrl = false; 130 boolean attrCertV1Found = false; 131 boolean attrCertV2Found = false; 132 133 if (certs != null) 134 { 135 for (Enumeration en = certs.getObjects(); en.hasMoreElements();) 136 { 137 Object obj = en.nextElement(); 138 if (obj instanceof ASN1TaggedObject) 139 { 140 ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(obj); 141 142 if (tagged.getTagNo() == 1) 143 { 144 attrCertV1Found = true; 145 } 146 else if (tagged.getTagNo() == 2) 147 { 148 attrCertV2Found = true; 149 } 150 else if (tagged.getTagNo() == 3) 151 { 152 otherCert = true; 153 } 154 } 155 } 156 } 157 158 if (otherCert) 159 { 160 return new ASN1Integer(5); 161 } 162 163 if (crls != null) // no need to check if otherCert is true 164 { 165 for (Enumeration en = crls.getObjects(); en.hasMoreElements();) 166 { 167 Object obj = en.nextElement(); 168 if (obj instanceof ASN1TaggedObject) 169 { 170 otherCrl = true; 171 } 172 } 173 } 174 175 if (otherCrl) 176 { 177 return VERSION_5; 178 } 179 180 if (attrCertV2Found) 181 { 182 return VERSION_4; 183 } 184 185 if (attrCertV1Found) 186 { 187 return VERSION_3; 188 } 189 190 if (checkForVersion3(signerInfs)) 191 { 192 return VERSION_3; 193 } 194 195 if (!CMSObjectIdentifiers.data.equals(contentOid)) 196 { 197 return VERSION_3; 198 } 199 200 return VERSION_1; 201 } 202 203 private boolean checkForVersion3(ASN1Set signerInfs) 204 { 205 for (Enumeration e = signerInfs.getObjects(); e.hasMoreElements();) 206 { 207 SignerInfo s = SignerInfo.getInstance(e.nextElement()); 208 209 if (s.getVersion().getValue().intValue() == 3) 210 { 211 return true; 212 } 213 } 214 215 return false; 216 } 217 218 private SignedData( 219 ASN1Sequence seq) 220 { 221 Enumeration e = seq.getObjects(); 222 223 version = ASN1Integer.getInstance(e.nextElement()); 224 digestAlgorithms = ((ASN1Set)e.nextElement()); 225 contentInfo = ContentInfo.getInstance(e.nextElement()); 226 227 while (e.hasMoreElements()) 228 { 229 ASN1Primitive o = (ASN1Primitive)e.nextElement(); 230 231 // 232 // an interesting feature of SignedData is that there appear 233 // to be varying implementations... 234 // for the moment we ignore anything which doesn't fit. 235 // 236 if (o instanceof ASN1TaggedObject) 237 { 238 ASN1TaggedObject tagged = (ASN1TaggedObject)o; 239 240 switch (tagged.getTagNo()) 241 { 242 case 0: 243 certsBer = tagged instanceof BERTaggedObject; 244 certificates = ASN1Set.getInstance(tagged, false); 245 break; 246 case 1: 247 crlsBer = tagged instanceof BERTaggedObject; 248 crls = ASN1Set.getInstance(tagged, false); 249 break; 250 default: 251 throw new IllegalArgumentException("unknown tag value " + tagged.getTagNo()); 252 } 253 } 254 else 255 { 256 signerInfos = (ASN1Set)o; 257 } 258 } 259 } 260 261 public ASN1Integer getVersion() 262 { 263 return version; 264 } 265 266 public ASN1Set getDigestAlgorithms() 267 { 268 return digestAlgorithms; 269 } 270 271 public ContentInfo getEncapContentInfo() 272 { 273 return contentInfo; 274 } 275 276 public ASN1Set getCertificates() 277 { 278 return certificates; 279 } 280 281 public ASN1Set getCRLs() 282 { 283 return crls; 284 } 285 286 public ASN1Set getSignerInfos() 287 { 288 return signerInfos; 289 } 290 291 /** 292 * Produce an object suitable for an ASN1OutputStream. 293 */ 294 public ASN1Primitive toASN1Primitive() 295 { 296 ASN1EncodableVector v = new ASN1EncodableVector(); 297 298 v.add(version); 299 v.add(digestAlgorithms); 300 v.add(contentInfo); 301 302 if (certificates != null) 303 { 304 if (certsBer) 305 { 306 v.add(new BERTaggedObject(false, 0, certificates)); 307 } 308 else 309 { 310 v.add(new DERTaggedObject(false, 0, certificates)); 311 } 312 } 313 314 if (crls != null) 315 { 316 if (crlsBer) 317 { 318 v.add(new BERTaggedObject(false, 1, crls)); 319 } 320 else 321 { 322 v.add(new DERTaggedObject(false, 1, crls)); 323 } 324 } 325 326 v.add(signerInfos); 327 328 return new BERSequence(v); 329 } 330} 331