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.Iterator; 9 import java.util.List; 10 11 import org.bouncycastle.asn1.ASN1Encodable; 12 import org.bouncycastle.asn1.ASN1EncodableVector; 13 import org.bouncycastle.asn1.ASN1InputStream; 14 import org.bouncycastle.asn1.ASN1ObjectIdentifier; 15 import org.bouncycastle.asn1.ASN1Set; 16 import org.bouncycastle.asn1.ASN1TaggedObject; 17 import org.bouncycastle.asn1.BEROctetStringGenerator; 18 import org.bouncycastle.asn1.BERSet; 19 import org.bouncycastle.asn1.DERSet; 20 import org.bouncycastle.asn1.DERTaggedObject; 21 import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; 22 import org.bouncycastle.asn1.cms.ContentInfo; 23 // BEGIN android-removed 24 // import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat; 25 // import org.bouncycastle.asn1.ocsp.OCSPResponse; 26 // import org.bouncycastle.asn1.ocsp.OCSPResponseStatus; 27 // END android-removed 28 import org.bouncycastle.cert.X509AttributeCertificateHolder; 29 import org.bouncycastle.cert.X509CRLHolder; 30 import org.bouncycastle.cert.X509CertificateHolder; 31 import org.bouncycastle.operator.DigestCalculator; 32 import org.bouncycastle.util.Store; 33 import org.bouncycastle.util.Strings; 34 import org.bouncycastle.util.io.Streams; 35 import org.bouncycastle.util.io.TeeInputStream; 36 import org.bouncycastle.util.io.TeeOutputStream; 37 38 class CMSUtils 39 { 40 static ContentInfo readContentInfo( 41 byte[] input) 42 throws CMSException 43 { 44 // enforce limit checking as from a byte array 45 return readContentInfo(new ASN1InputStream(input)); 46 } 47 48 static ContentInfo readContentInfo( 49 InputStream input) 50 throws CMSException 51 { 52 // enforce some limit checking 53 return readContentInfo(new ASN1InputStream(input)); 54 } 55 56 static List getCertificatesFromStore(Store certStore) 57 throws CMSException 58 { 59 List certs = new ArrayList(); 60 61 try 62 { 63 for (Iterator it = certStore.getMatches(null).iterator(); it.hasNext();) 64 { 65 X509CertificateHolder c = (X509CertificateHolder)it.next(); 66 67 certs.add(c.toASN1Structure()); 68 } 69 70 return certs; 71 } 72 catch (ClassCastException e) 73 { 74 throw new CMSException("error processing certs", e); 75 } 76 } 77 78 static List getAttributeCertificatesFromStore(Store attrStore) 79 throws CMSException 80 { 81 List certs = new ArrayList(); 82 83 try 84 { 85 for (Iterator it = attrStore.getMatches(null).iterator(); it.hasNext();) 86 { 87 X509AttributeCertificateHolder attrCert = (X509AttributeCertificateHolder)it.next(); 88 89 certs.add(new DERTaggedObject(false, 2, attrCert.toASN1Structure())); 90 } 91 92 return certs; 93 } 94 catch (ClassCastException e) 95 { 96 throw new CMSException("error processing certs", e); 97 } 98 } 99 100 101 static List getCRLsFromStore(Store crlStore) 102 throws CMSException 103 { 104 List crls = new ArrayList(); 105 106 try 107 { 108 for (Iterator it = crlStore.getMatches(null).iterator(); it.hasNext();) 109 { 110 Object rev = it.next(); 111 112 if (rev instanceof X509CRLHolder) 113 { 114 X509CRLHolder c = (X509CRLHolder)rev; 115 116 crls.add(c.toASN1Structure()); 117 } 118 // BEGIN android-removed 119 // else if (rev instanceof OtherRevocationInfoFormat) 120 // { 121 // OtherRevocationInfoFormat infoFormat = OtherRevocationInfoFormat.getInstance(rev); 122 // 123 // validateInfoFormat(infoFormat); 124 // 125 // crls.add(new DERTaggedObject(false, 1, infoFormat)); 126 // } 127 // END android-removed 128 else if (rev instanceof ASN1TaggedObject) 129 { 130 crls.add(rev); 131 } 132 } 133 134 return crls; 135 } 136 catch (ClassCastException e) 137 { 138 throw new CMSException("error processing certs", e); 139 } 140 } 141 142 // BEGIN android-removed 143 // private static void validateInfoFormat(OtherRevocationInfoFormat infoFormat) 144 // { 145 // if (CMSObjectIdentifiers.id_ri_ocsp_response.equals(infoFormat.getInfoFormat())) 146 // { 147 // OCSPResponse resp = OCSPResponse.getInstance(infoFormat.getInfo()); 148 // 149 // if (resp.getResponseStatus().getValue().intValue() != OCSPResponseStatus.SUCCESSFUL) 150 // { 151 // throw new IllegalArgumentException("cannot add unsuccessful OCSP response to CMS SignedData"); 152 // } 153 // } 154 // } 155 // 156 // static Collection getOthersFromStore(ASN1ObjectIdentifier otherRevocationInfoFormat, Store otherRevocationInfos) 157 // { 158 // List others = new ArrayList(); 159 // 160 // for (Iterator it = otherRevocationInfos.getMatches(null).iterator(); it.hasNext();) 161 // { 162 // ASN1Encodable info = (ASN1Encodable)it.next(); 163 // OtherRevocationInfoFormat infoFormat = new OtherRevocationInfoFormat(otherRevocationInfoFormat, info); 164 // validateInfoFormat(infoFormat); 165 // 166 // others.add(new DERTaggedObject(false, 1, infoFormat)); 167 // } 168 // 169 // return others; 170 // } 171 // END android-removed 172 173 static ASN1Set createBerSetFromList(List derObjects) 174 { 175 ASN1EncodableVector v = new ASN1EncodableVector(); 176 177 for (Iterator it = derObjects.iterator(); it.hasNext();) 178 { 179 v.add((ASN1Encodable)it.next()); 180 } 181 182 return new BERSet(v); 183 } 184 185 static ASN1Set createDerSetFromList(List derObjects) 186 { 187 ASN1EncodableVector v = new ASN1EncodableVector(); 188 189 for (Iterator it = derObjects.iterator(); it.hasNext();) 190 { 191 v.add((ASN1Encodable)it.next()); 192 } 193 194 return new DERSet(v); 195 } 196 197 static OutputStream createBEROctetOutputStream(OutputStream s, 198 int tagNo, boolean isExplicit, int bufferSize) throws IOException 199 { 200 BEROctetStringGenerator octGen = new BEROctetStringGenerator(s, tagNo, isExplicit); 201 202 if (bufferSize != 0) 203 { 204 return octGen.getOctetOutputStream(new byte[bufferSize]); 205 } 206 207 return octGen.getOctetOutputStream(); 208 } 209 210 private static ContentInfo readContentInfo( 211 ASN1InputStream in) 212 throws CMSException 213 { 214 try 215 { 216 return ContentInfo.getInstance(in.readObject()); 217 } 218 catch (IOException e) 219 { 220 throw new CMSException("IOException reading content.", e); 221 } 222 catch (ClassCastException e) 223 { 224 throw new CMSException("Malformed content.", e); 225 } 226 catch (IllegalArgumentException e) 227 { 228 throw new CMSException("Malformed content.", e); 229 } 230 } 231 232 static byte[] getPasswordBytes(int scheme, char[] password) 233 { 234 if (scheme == PasswordRecipient.PKCS5_SCHEME2) 235 { 236 return PKCS5PasswordToBytes(password); 237 } 238 239 return PKCS5PasswordToUTF8Bytes(password); 240 } 241 242 /** 243 * converts a password to a byte array according to the scheme in 244 * PKCS5 (ascii, no padding) 245 * 246 * @param password a character array representing the password. 247 * @return a byte array representing the password. 248 */ 249 private static byte[] PKCS5PasswordToBytes( 250 char[] password) 251 { 252 if (password != null) 253 { 254 byte[] bytes = new byte[password.length]; 255 256 for (int i = 0; i != bytes.length; i++) 257 { 258 bytes[i] = (byte)password[i]; 259 } 260 261 return bytes; 262 } 263 else 264 { 265 return new byte[0]; 266 } 267 } 268 269 /** 270 * converts a password to a byte array according to the scheme in 271 * PKCS5 (UTF-8, no padding) 272 * 273 * @param password a character array representing the password. 274 * @return a byte array representing the password. 275 */ 276 private static byte[] PKCS5PasswordToUTF8Bytes( 277 char[] password) 278 { 279 if (password != null) 280 { 281 return Strings.toUTF8ByteArray(password); 282 } 283 else 284 { 285 return new byte[0]; 286 } 287 } 288 289 public static byte[] streamToByteArray( 290 InputStream in) 291 throws IOException 292 { 293 return Streams.readAll(in); 294 } 295 296 public static byte[] streamToByteArray( 297 InputStream in, 298 int limit) 299 throws IOException 300 { 301 return Streams.readAllLimited(in, limit); 302 } 303 304 static InputStream attachDigestsToInputStream(Collection digests, InputStream s) 305 { 306 InputStream result = s; 307 Iterator it = digests.iterator(); 308 while (it.hasNext()) 309 { 310 DigestCalculator digest = (DigestCalculator)it.next(); 311 result = new TeeInputStream(result, digest.getOutputStream()); 312 } 313 return result; 314 } 315 316 static OutputStream attachSignersToOutputStream(Collection signers, OutputStream s) 317 { 318 OutputStream result = s; 319 Iterator it = signers.iterator(); 320 while (it.hasNext()) 321 { 322 SignerInfoGenerator signerGen = (SignerInfoGenerator)it.next(); 323 result = getSafeTeeOutputStream(result, signerGen.getCalculatingOutputStream()); 324 } 325 return result; 326 } 327 328 static OutputStream getSafeOutputStream(OutputStream s) 329 { 330 return s == null ? new NullOutputStream() : s; 331 } 332 333 static OutputStream getSafeTeeOutputStream(OutputStream s1, 334 OutputStream s2) 335 { 336 return s1 == null ? getSafeOutputStream(s2) 337 : s2 == null ? getSafeOutputStream(s1) : new TeeOutputStream( 338 s1, s2); 339 } 340 } 341