1 package org.bouncycastle.cms; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.OutputStream; 6 import java.util.ArrayList; 7 import java.util.Collection; 8 import java.util.HashSet; 9 import java.util.Iterator; 10 import java.util.List; 11 import java.util.Set; 12 13 import org.bouncycastle.asn1.ASN1Encodable; 14 import org.bouncycastle.asn1.ASN1EncodableVector; 15 import org.bouncycastle.asn1.ASN1InputStream; 16 import org.bouncycastle.asn1.ASN1ObjectIdentifier; 17 import org.bouncycastle.asn1.ASN1Set; 18 import org.bouncycastle.asn1.ASN1TaggedObject; 19 import org.bouncycastle.asn1.BEROctetStringGenerator; 20 import org.bouncycastle.asn1.BERSet; 21 import org.bouncycastle.asn1.DERNull; 22 import org.bouncycastle.asn1.DERSet; 23 import org.bouncycastle.asn1.DERTaggedObject; 24 import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; 25 import org.bouncycastle.asn1.cms.ContentInfo; 26 // Android-removed: Unsupported algorithms 27 // import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat; 28 // import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; 29 // import org.bouncycastle.asn1.ocsp.OCSPResponse; 30 // import org.bouncycastle.asn1.ocsp.OCSPResponseStatus; 31 // import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; 32 // import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 33 // import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers; 34 // import org.bouncycastle.asn1.sec.SECObjectIdentifiers; 35 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 36 // import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; 37 import org.bouncycastle.cert.X509AttributeCertificateHolder; 38 import org.bouncycastle.cert.X509CRLHolder; 39 import org.bouncycastle.cert.X509CertificateHolder; 40 import org.bouncycastle.operator.DigestCalculator; 41 import org.bouncycastle.util.Store; 42 import org.bouncycastle.util.Strings; 43 import org.bouncycastle.util.io.Streams; 44 import org.bouncycastle.util.io.TeeInputStream; 45 import org.bouncycastle.util.io.TeeOutputStream; 46 47 class CMSUtils 48 { 49 private static final Set<String> des = new HashSet<String>(); 50 private static final Set mqvAlgs = new HashSet(); 51 private static final Set ecAlgs = new HashSet(); 52 private static final Set gostAlgs = new HashSet(); 53 54 static 55 { 56 des.add("DES"); 57 des.add("DESEDE"); 58 // BEGIN Android-removed: Unsupported algorithms 59 /* 60 des.add(OIWObjectIdentifiers.desCBC.getId()); 61 des.add(PKCSObjectIdentifiers.des_EDE3_CBC.getId()); 62 des.add(PKCSObjectIdentifiers.des_EDE3_CBC.getId()); 63 des.add(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId()); 64 65 mqvAlgs.add(X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme); 66 mqvAlgs.add(SECObjectIdentifiers.mqvSinglePass_sha224kdf_scheme); 67 mqvAlgs.add(SECObjectIdentifiers.mqvSinglePass_sha256kdf_scheme); 68 mqvAlgs.add(SECObjectIdentifiers.mqvSinglePass_sha384kdf_scheme); 69 mqvAlgs.add(SECObjectIdentifiers.mqvSinglePass_sha512kdf_scheme); 70 71 ecAlgs.add(X9ObjectIdentifiers.dhSinglePass_cofactorDH_sha1kdf_scheme); 72 ecAlgs.add(X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme); 73 ecAlgs.add(SECObjectIdentifiers.dhSinglePass_cofactorDH_sha224kdf_scheme); 74 ecAlgs.add(SECObjectIdentifiers.dhSinglePass_stdDH_sha224kdf_scheme); 75 ecAlgs.add(SECObjectIdentifiers.dhSinglePass_cofactorDH_sha256kdf_scheme); 76 ecAlgs.add(SECObjectIdentifiers.dhSinglePass_stdDH_sha256kdf_scheme); 77 ecAlgs.add(SECObjectIdentifiers.dhSinglePass_cofactorDH_sha384kdf_scheme); 78 ecAlgs.add(SECObjectIdentifiers.dhSinglePass_stdDH_sha384kdf_scheme); 79 ecAlgs.add(SECObjectIdentifiers.dhSinglePass_cofactorDH_sha512kdf_scheme); 80 ecAlgs.add(SECObjectIdentifiers.dhSinglePass_stdDH_sha512kdf_scheme); 81 82 gostAlgs.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_ESDH); 83 gostAlgs.add(RosstandartObjectIdentifiers.id_tc26_agreement_gost_3410_12_256); 84 gostAlgs.add(RosstandartObjectIdentifiers.id_tc26_agreement_gost_3410_12_512); 85 */ 86 // END Android-removed: Unsupported algorithms 87 } 88 isMQV(ASN1ObjectIdentifier algorithm)89 static boolean isMQV(ASN1ObjectIdentifier algorithm) 90 { 91 return mqvAlgs.contains(algorithm); 92 } 93 isEC(ASN1ObjectIdentifier algorithm)94 static boolean isEC(ASN1ObjectIdentifier algorithm) 95 { 96 return ecAlgs.contains(algorithm); 97 } 98 isGOST(ASN1ObjectIdentifier algorithm)99 static boolean isGOST(ASN1ObjectIdentifier algorithm) 100 { 101 return gostAlgs.contains(algorithm); 102 } 103 104 // BEGIN Android-removed: Unsupported algorithms 105 /* 106 static boolean isRFC2631(ASN1ObjectIdentifier algorithm) 107 { 108 return algorithm.equals(PKCSObjectIdentifiers.id_alg_ESDH) || algorithm.equals(PKCSObjectIdentifiers.id_alg_SSDH); 109 } 110 */ 111 // END Android-removed: Unsupported algorithms 112 isDES(String algorithmID)113 static boolean isDES(String algorithmID) 114 { 115 String name = Strings.toUpperCase(algorithmID); 116 117 return des.contains(name); 118 } 119 isEquivalent(AlgorithmIdentifier algId1, AlgorithmIdentifier algId2)120 static boolean isEquivalent(AlgorithmIdentifier algId1, AlgorithmIdentifier algId2) 121 { 122 if (algId1 == null || algId2 == null) 123 { 124 return false; 125 } 126 127 if (!algId1.getAlgorithm().equals(algId2.getAlgorithm())) 128 { 129 return false; 130 } 131 132 ASN1Encodable params1 = algId1.getParameters(); 133 ASN1Encodable params2 = algId2.getParameters(); 134 if (params1 != null) 135 { 136 return params1.equals(params2) || (params1.equals(DERNull.INSTANCE) && params2 == null); 137 } 138 139 return params2 == null || params2.equals(DERNull.INSTANCE); 140 } 141 readContentInfo( byte[] input)142 static ContentInfo readContentInfo( 143 byte[] input) 144 throws CMSException 145 { 146 // enforce limit checking as from a byte array 147 return readContentInfo(new ASN1InputStream(input)); 148 } 149 readContentInfo( InputStream input)150 static ContentInfo readContentInfo( 151 InputStream input) 152 throws CMSException 153 { 154 // enforce some limit checking 155 return readContentInfo(new ASN1InputStream(input)); 156 } 157 getCertificatesFromStore(Store certStore)158 static List getCertificatesFromStore(Store certStore) 159 throws CMSException 160 { 161 List certs = new ArrayList(); 162 163 try 164 { 165 for (Iterator it = certStore.getMatches(null).iterator(); it.hasNext(); ) 166 { 167 X509CertificateHolder c = (X509CertificateHolder)it.next(); 168 169 certs.add(c.toASN1Structure()); 170 } 171 172 return certs; 173 } 174 catch (ClassCastException e) 175 { 176 throw new CMSException("error processing certs", e); 177 } 178 } 179 getAttributeCertificatesFromStore(Store attrStore)180 static List getAttributeCertificatesFromStore(Store attrStore) 181 throws CMSException 182 { 183 List certs = new ArrayList(); 184 185 try 186 { 187 for (Iterator it = attrStore.getMatches(null).iterator(); it.hasNext(); ) 188 { 189 X509AttributeCertificateHolder attrCert = (X509AttributeCertificateHolder)it.next(); 190 191 certs.add(new DERTaggedObject(false, 2, attrCert.toASN1Structure())); 192 } 193 194 return certs; 195 } 196 catch (ClassCastException e) 197 { 198 throw new CMSException("error processing certs", e); 199 } 200 } 201 202 getCRLsFromStore(Store crlStore)203 static List getCRLsFromStore(Store crlStore) 204 throws CMSException 205 { 206 List crls = new ArrayList(); 207 208 try 209 { 210 for (Iterator it = crlStore.getMatches(null).iterator(); it.hasNext(); ) 211 { 212 Object rev = it.next(); 213 214 if (rev instanceof X509CRLHolder) 215 { 216 X509CRLHolder c = (X509CRLHolder)rev; 217 218 crls.add(c.toASN1Structure()); 219 } 220 // BEGIN Android-removed: OtherRevocationInfoFormat isn't supported 221 // else if (rev instanceof OtherRevocationInfoFormat) 222 // { 223 // OtherRevocationInfoFormat infoFormat = OtherRevocationInfoFormat.getInstance(rev); 224 // 225 // validateInfoFormat(infoFormat); 226 // 227 // crls.add(new DERTaggedObject(false, 1, infoFormat)); 228 // } 229 // END Android-removed: OtherRevocationInfoFormat isn't supported 230 else if (rev instanceof ASN1TaggedObject) 231 { 232 crls.add(rev); 233 } 234 } 235 236 return crls; 237 } 238 catch (ClassCastException e) 239 { 240 throw new CMSException("error processing certs", e); 241 } 242 } 243 244 // BEGIN Android-removed: OtherRevocationInfoFormat isn't supported 245 /* 246 private static void validateInfoFormat(OtherRevocationInfoFormat infoFormat) 247 { 248 if (CMSObjectIdentifiers.id_ri_ocsp_response.equals(infoFormat.getInfoFormat())) 249 { 250 OCSPResponse resp = OCSPResponse.getInstance(infoFormat.getInfo()); 251 252 if (OCSPResponseStatus.SUCCESSFUL != resp.getResponseStatus().getIntValue()) 253 { 254 throw new IllegalArgumentException("cannot add unsuccessful OCSP response to CMS SignedData"); 255 } 256 } 257 } 258 259 static Collection getOthersFromStore(ASN1ObjectIdentifier otherRevocationInfoFormat, Store otherRevocationInfos) 260 { 261 List others = new ArrayList(); 262 263 for (Iterator it = otherRevocationInfos.getMatches(null).iterator(); it.hasNext(); ) 264 { 265 ASN1Encodable info = (ASN1Encodable)it.next(); 266 OtherRevocationInfoFormat infoFormat = new OtherRevocationInfoFormat(otherRevocationInfoFormat, info); 267 268 validateInfoFormat(infoFormat); 269 270 others.add(new DERTaggedObject(false, 1, infoFormat)); 271 } 272 273 return others; 274 } 275 */ 276 // END Android-removed: OtherRevocationInfoFormat isn't supported 277 createBerSetFromList(List derObjects)278 static ASN1Set createBerSetFromList(List derObjects) 279 { 280 ASN1EncodableVector v = new ASN1EncodableVector(); 281 282 for (Iterator it = derObjects.iterator(); it.hasNext(); ) 283 { 284 v.add((ASN1Encodable)it.next()); 285 } 286 287 return new BERSet(v); 288 } 289 createDerSetFromList(List derObjects)290 static ASN1Set createDerSetFromList(List derObjects) 291 { 292 ASN1EncodableVector v = new ASN1EncodableVector(); 293 294 for (Iterator it = derObjects.iterator(); it.hasNext(); ) 295 { 296 v.add((ASN1Encodable)it.next()); 297 } 298 299 return new DERSet(v); 300 } 301 createBEROctetOutputStream(OutputStream s, int tagNo, boolean isExplicit, int bufferSize)302 static OutputStream createBEROctetOutputStream(OutputStream s, 303 int tagNo, boolean isExplicit, int bufferSize) 304 throws IOException 305 { 306 BEROctetStringGenerator octGen = new BEROctetStringGenerator(s, tagNo, isExplicit); 307 308 if (bufferSize != 0) 309 { 310 return octGen.getOctetOutputStream(new byte[bufferSize]); 311 } 312 313 return octGen.getOctetOutputStream(); 314 } 315 readContentInfo( ASN1InputStream in)316 private static ContentInfo readContentInfo( 317 ASN1InputStream in) 318 throws CMSException 319 { 320 try 321 { 322 ContentInfo info = ContentInfo.getInstance(in.readObject()); 323 if (info == null) 324 { 325 throw new CMSException("No content found."); 326 } 327 328 return info; 329 } 330 catch (IOException e) 331 { 332 throw new CMSException("IOException reading content.", e); 333 } 334 catch (ClassCastException e) 335 { 336 throw new CMSException("Malformed content.", e); 337 } 338 catch (IllegalArgumentException e) 339 { 340 throw new CMSException("Malformed content.", e); 341 } 342 } 343 streamToByteArray( InputStream in)344 public static byte[] streamToByteArray( 345 InputStream in) 346 throws IOException 347 { 348 return Streams.readAll(in); 349 } 350 streamToByteArray( InputStream in, int limit)351 public static byte[] streamToByteArray( 352 InputStream in, 353 int limit) 354 throws IOException 355 { 356 return Streams.readAllLimited(in, limit); 357 } 358 attachDigestsToInputStream(Collection digests, InputStream s)359 static InputStream attachDigestsToInputStream(Collection digests, InputStream s) 360 { 361 InputStream result = s; 362 Iterator it = digests.iterator(); 363 while (it.hasNext()) 364 { 365 DigestCalculator digest = (DigestCalculator)it.next(); 366 result = new TeeInputStream(result, digest.getOutputStream()); 367 } 368 return result; 369 } 370 attachSignersToOutputStream(Collection signers, OutputStream s)371 static OutputStream attachSignersToOutputStream(Collection signers, OutputStream s) 372 { 373 OutputStream result = s; 374 Iterator it = signers.iterator(); 375 while (it.hasNext()) 376 { 377 SignerInfoGenerator signerGen = (SignerInfoGenerator)it.next(); 378 result = getSafeTeeOutputStream(result, signerGen.getCalculatingOutputStream()); 379 } 380 return result; 381 } 382 getSafeOutputStream(OutputStream s)383 static OutputStream getSafeOutputStream(OutputStream s) 384 { 385 return s == null ? new NullOutputStream() : s; 386 } 387 getSafeTeeOutputStream(OutputStream s1, OutputStream s2)388 static OutputStream getSafeTeeOutputStream(OutputStream s1, 389 OutputStream s2) 390 { 391 return s1 == null ? getSafeOutputStream(s2) 392 : s2 == null ? getSafeOutputStream(s1) : new TeeOutputStream( 393 s1, s2); 394 } 395 } 396