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