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