001package org.apache.commons.ssl.org.bouncycastle.asn1.cms; 002 003import java.util.Enumeration; 004 005import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1EncodableVector; 006import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Integer; 007import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Object; 008import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1ObjectIdentifier; 009import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Primitive; 010import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Sequence; 011import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Set; 012import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1TaggedObject; 013import org.apache.commons.ssl.org.bouncycastle.asn1.BERSequence; 014import org.apache.commons.ssl.org.bouncycastle.asn1.BERSet; 015import org.apache.commons.ssl.org.bouncycastle.asn1.BERTaggedObject; 016import org.apache.commons.ssl.org.bouncycastle.asn1.DERTaggedObject; 017 018/** 019 * <a href="http://tools.ietf.org/html/rfc5652#section-5.1">RFC 5652</a>: 020 * <p> 021 * A signed data object containing multitude of {@link SignerInfo}s. 022 * <pre> 023 * SignedData ::= SEQUENCE { 024 * version CMSVersion, 025 * digestAlgorithms DigestAlgorithmIdentifiers, 026 * encapContentInfo EncapsulatedContentInfo, 027 * certificates [0] IMPLICIT CertificateSet OPTIONAL, 028 * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, 029 * signerInfos SignerInfos 030 * } 031 * 032 * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier 033 * 034 * SignerInfos ::= SET OF SignerInfo 035 * </pre> 036 * <p> 037 * The version calculation uses following ruleset from RFC 3852 section 5.1: 038 * <pre> 039 * IF ((certificates is present) AND 040 * (any certificates with a type of other are present)) OR 041 * ((crls is present) AND 042 * (any crls with a type of other are present)) 043 * THEN version MUST be 5 044 * ELSE 045 * IF (certificates is present) AND 046 * (any version 2 attribute certificates are present) 047 * THEN version MUST be 4 048 * ELSE 049 * IF ((certificates is present) AND 050 * (any version 1 attribute certificates are present)) OR 051 * (any SignerInfo structures are version 3) OR 052 * (encapContentInfo eContentType is other than id-data) 053 * THEN version MUST be 3 054 * ELSE version MUST be 1 055 * </pre> 056 * <p> 057 * @todo Check possible update for this to RFC 5652 level 058 */ 059public class SignedData 060 extends ASN1Object 061{ 062 private static final ASN1Integer VERSION_1 = new ASN1Integer(1); 063 private static final ASN1Integer VERSION_3 = new ASN1Integer(3); 064 private static final ASN1Integer VERSION_4 = new ASN1Integer(4); 065 private static final ASN1Integer VERSION_5 = new ASN1Integer(5); 066 067 private ASN1Integer version; 068 private ASN1Set digestAlgorithms; 069 private ContentInfo contentInfo; 070 private ASN1Set certificates; 071 private ASN1Set crls; 072 private ASN1Set signerInfos; 073 private boolean certsBer; 074 private boolean crlsBer; 075 076 /** 077 * Return a SignedData object from the given object. 078 * <p> 079 * Accepted inputs: 080 * <ul> 081 * <li> null → null 082 * <li> {@link SignedData} object 083 * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with SignedData structure inside 084 * </ul> 085 * 086 * @param o the object we want converted. 087 * @exception IllegalArgumentException if the object cannot be converted. 088 */ 089 public static SignedData getInstance( 090 Object o) 091 { 092 if (o instanceof SignedData) 093 { 094 return (SignedData)o; 095 } 096 else if (o != null) 097 { 098 return new SignedData(ASN1Sequence.getInstance(o)); 099 } 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}