1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 
27 package sun.security.pkcs;
28 
29 import java.io.*;
30 import java.math.BigInteger;
31 import java.net.URI;
32 import java.util.*;
33 import java.security.cert.X509Certificate;
34 import java.security.cert.CertificateException;
35 import java.security.cert.CertificateEncodingException;
36 import java.security.cert.CertificateExpiredException;
37 import java.security.cert.CertificateNotYetValidException;
38 import java.security.cert.CertificateParsingException;
39 import java.security.cert.X509CRL;
40 import java.security.cert.CRLException;
41 import java.security.cert.CertificateFactory;
42 import java.security.*;
43 
44 import sun.security.timestamp.*;
45 
46 import javax.security.auth.x500.X500Principal;
47 
48 import sun.security.util.*;
49 import sun.security.x509.AlgorithmId;
50 import sun.security.x509.X509CertImpl;
51 import sun.security.x509.X509CertInfo;
52 import sun.security.x509.X509CRLImpl;
53 import sun.security.x509.X500Name;
54 
55 /**
56  * PKCS7 as defined in RSA Laboratories PKCS7 Technical Note. Profile
57  * Supports only <tt>SignedData</tt> ContentInfo
58  * type, where to the type of data signed is plain Data.
59  * For signedData, <tt>crls</tt>, <tt>attributes</tt> and
60  * PKCS#6 Extended Certificates are not supported.
61  *
62  * @author Benjamin Renaud
63  */
64 public class PKCS7 {
65 
66     private ObjectIdentifier contentType;
67 
68     // the ASN.1 members for a signedData (and other) contentTypes
69     private BigInteger version = null;
70     private AlgorithmId[] digestAlgorithmIds = null;
71     private ContentInfo contentInfo = null;
72     private X509Certificate[] certificates = null;
73     private X509CRL[] crls = null;
74     private SignerInfo[] signerInfos = null;
75 
76     private boolean oldStyle = false; // Is this JDK1.1.x-style?
77 
78     private Principal[] certIssuerNames;
79 
80     // BEGIN Android-removed: unused in Android
81     /*
82     /*
83      * Random number generator for creating nonce values
84      * (Lazy initialization)
85      *
86     private static class SecureRandomHolder {
87         static final SecureRandom RANDOM;
88         static {
89             SecureRandom tmp = null;
90             try {
91                 tmp = SecureRandom.getInstance("SHA1PRNG");
92             } catch (NoSuchAlgorithmException e) {
93                 // should not happen
94             }
95             RANDOM = tmp;
96         }
97     }
98 
99     /*
100      * Object identifier for the timestamping key purpose.
101      *
102     private static final String KP_TIMESTAMPING_OID = "1.3.6.1.5.5.7.3.8";
103 
104     /*
105      * Object identifier for extendedKeyUsage extension
106      *
107     private static final String EXTENDED_KEY_USAGE_OID = "2.5.29.37";
108     */
109     // END Android-removed: unused on Android
110 
111     /**
112      * Unmarshals a PKCS7 block from its encoded form, parsing the
113      * encoded bytes from the InputStream.
114      *
115      * @param in an input stream holding at least one PKCS7 block.
116      * @exception ParsingException on parsing errors.
117      * @exception IOException on other errors.
118      */
PKCS7(InputStream in)119     public PKCS7(InputStream in) throws ParsingException, IOException {
120         DataInputStream dis = new DataInputStream(in);
121         byte[] data = new byte[dis.available()];
122         dis.readFully(data);
123 
124         parse(new DerInputStream(data));
125     }
126 
127     /**
128      * Unmarshals a PKCS7 block from its encoded form, parsing the
129      * encoded bytes from the DerInputStream.
130      *
131      * @param derin a DerInputStream holding at least one PKCS7 block.
132      * @exception ParsingException on parsing errors.
133      */
PKCS7(DerInputStream derin)134     public PKCS7(DerInputStream derin) throws ParsingException {
135         parse(derin);
136     }
137 
138     /**
139      * Unmarshals a PKCS7 block from its encoded form, parsing the
140      * encoded bytes.
141      *
142      * @param bytes the encoded bytes.
143      * @exception ParsingException on parsing errors.
144      */
PKCS7(byte[] bytes)145     public PKCS7(byte[] bytes) throws ParsingException {
146         try {
147             DerInputStream derin = new DerInputStream(bytes);
148             parse(derin);
149         } catch (IOException ioe1) {
150             ParsingException pe = new ParsingException(
151                 "Unable to parse the encoded bytes");
152             pe.initCause(ioe1);
153             throw pe;
154         }
155     }
156 
157     /*
158      * Parses a PKCS#7 block.
159      */
parse(DerInputStream derin)160     private void parse(DerInputStream derin)
161         throws ParsingException
162     {
163         try {
164             derin.mark(derin.available());
165             // try new (i.e., JDK1.2) style
166             parse(derin, false);
167         } catch (IOException ioe) {
168             try {
169                 derin.reset();
170                 // try old (i.e., JDK1.1.x) style
171                 parse(derin, true);
172                 oldStyle = true;
173             } catch (IOException ioe1) {
174                 ParsingException pe = new ParsingException(
175                     ioe1.getMessage());
176                 pe.initCause(ioe);
177                 pe.addSuppressed(ioe1);
178                 throw pe;
179             }
180         }
181     }
182 
183     /**
184      * Parses a PKCS#7 block.
185      *
186      * @param derin the ASN.1 encoding of the PKCS#7 block.
187      * @param oldStyle flag indicating whether or not the given PKCS#7 block
188      * is encoded according to JDK1.1.x.
189      */
parse(DerInputStream derin, boolean oldStyle)190     private void parse(DerInputStream derin, boolean oldStyle)
191         throws IOException
192     {
193         contentInfo = new ContentInfo(derin, oldStyle);
194         contentType = contentInfo.contentType;
195         DerValue content = contentInfo.getContent();
196 
197         if (contentType.equals((Object)ContentInfo.SIGNED_DATA_OID)) {
198             parseSignedData(content);
199         } else if (contentType.equals((Object)ContentInfo.OLD_SIGNED_DATA_OID)) {
200             // This is for backwards compatibility with JDK 1.1.x
201             parseOldSignedData(content);
202         } else if (contentType.equals((Object)
203                        ContentInfo.NETSCAPE_CERT_SEQUENCE_OID)){
204             parseNetscapeCertChain(content);
205         } else {
206             throw new ParsingException("content type " + contentType +
207                                        " not supported.");
208         }
209     }
210 
211     /**
212      * Construct an initialized PKCS7 block.
213      *
214      * @param digestAlgorithmIds the message digest algorithm identifiers.
215      * @param contentInfo the content information.
216      * @param certificates an array of X.509 certificates.
217      * @param crls an array of CRLs
218      * @param signerInfos an array of signer information.
219      */
PKCS7(AlgorithmId[] digestAlgorithmIds, ContentInfo contentInfo, X509Certificate[] certificates, X509CRL[] crls, SignerInfo[] signerInfos)220     public PKCS7(AlgorithmId[] digestAlgorithmIds,
221                  ContentInfo contentInfo,
222                  X509Certificate[] certificates,
223                  X509CRL[] crls,
224                  SignerInfo[] signerInfos) {
225 
226         version = BigInteger.ONE;
227         this.digestAlgorithmIds = digestAlgorithmIds;
228         this.contentInfo = contentInfo;
229         this.certificates = certificates;
230         this.crls = crls;
231         this.signerInfos = signerInfos;
232     }
233 
PKCS7(AlgorithmId[] digestAlgorithmIds, ContentInfo contentInfo, X509Certificate[] certificates, SignerInfo[] signerInfos)234     public PKCS7(AlgorithmId[] digestAlgorithmIds,
235                  ContentInfo contentInfo,
236                  X509Certificate[] certificates,
237                  SignerInfo[] signerInfos) {
238         this(digestAlgorithmIds, contentInfo, certificates, null, signerInfos);
239     }
240 
parseNetscapeCertChain(DerValue val)241     private void parseNetscapeCertChain(DerValue val)
242     throws ParsingException, IOException {
243         DerInputStream dis = new DerInputStream(val.toByteArray());
244         DerValue[] contents = dis.getSequence(2, true);
245         certificates = new X509Certificate[contents.length];
246 
247         CertificateFactory certfac = null;
248         try {
249             certfac = CertificateFactory.getInstance("X.509");
250         } catch (CertificateException ce) {
251             // do nothing
252         }
253 
254         for (int i=0; i < contents.length; i++) {
255             ByteArrayInputStream bais = null;
256             try {
257                 byte[] original = contents[i].getOriginalEncodedForm();
258                 if (certfac == null)
259                     certificates[i] = new X509CertImpl(contents[i], original);
260                 else {
261                     bais = new ByteArrayInputStream(original);
262                     certificates[i] = new VerbatimX509Certificate(
263                         (X509Certificate)certfac.generateCertificate(bais),
264                         original);
265                     bais.close();
266                     bais = null;
267                 }
268             } catch (CertificateException ce) {
269                 ParsingException pe = new ParsingException(ce.getMessage());
270                 pe.initCause(ce);
271                 throw pe;
272             } catch (IOException ioe) {
273                 ParsingException pe = new ParsingException(ioe.getMessage());
274                 pe.initCause(ioe);
275                 throw pe;
276             } finally {
277                 if (bais != null)
278                     bais.close();
279             }
280         }
281     }
282 
parseSignedData(DerValue val)283     private void parseSignedData(DerValue val)
284         throws ParsingException, IOException {
285 
286         DerInputStream dis = val.toDerInputStream();
287 
288         // Version
289         version = dis.getBigInteger();
290 
291         // digestAlgorithmIds
292         DerValue[] digestAlgorithmIdVals = dis.getSet(1);
293         int len = digestAlgorithmIdVals.length;
294         digestAlgorithmIds = new AlgorithmId[len];
295         try {
296             for (int i = 0; i < len; i++) {
297                 DerValue oid = digestAlgorithmIdVals[i];
298                 digestAlgorithmIds[i] = AlgorithmId.parse(oid);
299             }
300 
301         } catch (IOException e) {
302             ParsingException pe =
303                 new ParsingException("Error parsing digest AlgorithmId IDs: " +
304                                      e.getMessage());
305             pe.initCause(e);
306             throw pe;
307         }
308         // contentInfo
309         contentInfo = new ContentInfo(dis);
310 
311         CertificateFactory certfac = null;
312         try {
313             certfac = CertificateFactory.getInstance("X.509");
314         } catch (CertificateException ce) {
315             // do nothing
316         }
317 
318         /*
319          * check if certificates (implicit tag) are provided
320          * (certificates are OPTIONAL)
321          */
322         if ((byte)(dis.peekByte()) == (byte)0xA0) {
323             DerValue[] certVals = dis.getSet(2, true, true);
324 
325             len = certVals.length;
326             certificates = new X509Certificate[len];
327             int count = 0;
328 
329             for (int i = 0; i < len; i++) {
330                 ByteArrayInputStream bais = null;
331                 try {
332                     byte tag = certVals[i].getTag();
333                     // We only parse the normal certificate. Other types of
334                     // CertificateChoices ignored.
335                     if (tag == DerValue.tag_Sequence) {
336                         byte[] original = certVals[i].getOriginalEncodedForm();
337                         if (certfac == null) {
338                             certificates[count] = new X509CertImpl(certVals[i], original);
339                         } else {
340                             bais = new ByteArrayInputStream(original);
341                             certificates[count] = new VerbatimX509Certificate(
342                                 (X509Certificate)certfac.generateCertificate(bais),
343                                 original);
344                             bais.close();
345                             bais = null;
346                         }
347                         count++;
348                     }
349                 } catch (CertificateException ce) {
350                     ParsingException pe = new ParsingException(ce.getMessage());
351                     pe.initCause(ce);
352                     throw pe;
353                 } catch (IOException ioe) {
354                     ParsingException pe = new ParsingException(ioe.getMessage());
355                     pe.initCause(ioe);
356                     throw pe;
357                 } finally {
358                     if (bais != null)
359                         bais.close();
360                 }
361             }
362             if (count != len) {
363                 certificates = Arrays.copyOf(certificates, count);
364             }
365         }
366 
367         // check if crls (implicit tag) are provided (crls are OPTIONAL)
368         if ((byte)(dis.peekByte()) == (byte)0xA1) {
369             DerValue[] crlVals = dis.getSet(1, true);
370 
371             len = crlVals.length;
372             crls = new X509CRL[len];
373 
374             for (int i = 0; i < len; i++) {
375                 ByteArrayInputStream bais = null;
376                 try {
377                     if (certfac == null)
378                         crls[i] = new X509CRLImpl(crlVals[i]);
379                     else {
380                         byte[] encoded = crlVals[i].toByteArray();
381                         bais = new ByteArrayInputStream(encoded);
382                         crls[i] = (X509CRL) certfac.generateCRL(bais);
383                         bais.close();
384                         bais = null;
385                     }
386                 } catch (CRLException e) {
387                     ParsingException pe =
388                         new ParsingException(e.getMessage());
389                     pe.initCause(e);
390                     throw pe;
391                 } finally {
392                     if (bais != null)
393                         bais.close();
394                 }
395             }
396         }
397 
398         // signerInfos
399         DerValue[] signerInfoVals = dis.getSet(1);
400 
401         len = signerInfoVals.length;
402         signerInfos = new SignerInfo[len];
403 
404         for (int i = 0; i < len; i++) {
405             DerInputStream in = signerInfoVals[i].toDerInputStream();
406             signerInfos[i] = new SignerInfo(in);
407         }
408     }
409 
410     /*
411      * Parses an old-style SignedData encoding (for backwards
412      * compatibility with JDK1.1.x).
413      */
parseOldSignedData(DerValue val)414     private void parseOldSignedData(DerValue val)
415         throws ParsingException, IOException
416     {
417         DerInputStream dis = val.toDerInputStream();
418 
419         // Version
420         version = dis.getBigInteger();
421 
422         // digestAlgorithmIds
423         DerValue[] digestAlgorithmIdVals = dis.getSet(1);
424         int len = digestAlgorithmIdVals.length;
425 
426         digestAlgorithmIds = new AlgorithmId[len];
427         try {
428             for (int i = 0; i < len; i++) {
429                 DerValue oid = digestAlgorithmIdVals[i];
430                 digestAlgorithmIds[i] = AlgorithmId.parse(oid);
431             }
432         } catch (IOException e) {
433             throw new ParsingException("Error parsing digest AlgorithmId IDs");
434         }
435 
436         // contentInfo
437         contentInfo = new ContentInfo(dis, true);
438 
439         // certificates
440         CertificateFactory certfac = null;
441         try {
442             certfac = CertificateFactory.getInstance("X.509");
443         } catch (CertificateException ce) {
444             // do nothing
445         }
446         DerValue[] certVals = dis.getSet(2, false, true);
447         len = certVals.length;
448         certificates = new X509Certificate[len];
449 
450         for (int i = 0; i < len; i++) {
451             ByteArrayInputStream bais = null;
452             try {
453                 byte[] original = certVals[i].getOriginalEncodedForm();
454                 if (certfac == null)
455                     certificates[i] = new X509CertImpl(certVals[i], original);
456                 else {
457                     bais = new ByteArrayInputStream(original);
458                     certificates[i] = new VerbatimX509Certificate(
459                         (X509Certificate)certfac.generateCertificate(bais),
460                         original);
461                     bais.close();
462                     bais = null;
463                 }
464             } catch (CertificateException ce) {
465                 ParsingException pe = new ParsingException(ce.getMessage());
466                 pe.initCause(ce);
467                 throw pe;
468             } catch (IOException ioe) {
469                 ParsingException pe = new ParsingException(ioe.getMessage());
470                 pe.initCause(ioe);
471                 throw pe;
472             } finally {
473                 if (bais != null)
474                     bais.close();
475             }
476         }
477 
478         // crls are ignored.
479         dis.getSet(0);
480 
481         // signerInfos
482         DerValue[] signerInfoVals = dis.getSet(1);
483         len = signerInfoVals.length;
484         signerInfos = new SignerInfo[len];
485         for (int i = 0; i < len; i++) {
486             DerInputStream in = signerInfoVals[i].toDerInputStream();
487             signerInfos[i] = new SignerInfo(in, true);
488         }
489     }
490 
491     /**
492      * Encodes the signed data to an output stream.
493      *
494      * @param out the output stream to write the encoded data to.
495      * @exception IOException on encoding errors.
496      */
encodeSignedData(OutputStream out)497     public void encodeSignedData(OutputStream out) throws IOException {
498         DerOutputStream derout = new DerOutputStream();
499         encodeSignedData(derout);
500         out.write(derout.toByteArray());
501     }
502 
503     /**
504      * Encodes the signed data to a DerOutputStream.
505      *
506      * @param out the DerOutputStream to write the encoded data to.
507      * @exception IOException on encoding errors.
508      */
encodeSignedData(DerOutputStream out)509     public void encodeSignedData(DerOutputStream out)
510         throws IOException
511     {
512         DerOutputStream signedData = new DerOutputStream();
513 
514         // version
515         signedData.putInteger(version);
516 
517         // digestAlgorithmIds
518         signedData.putOrderedSetOf(DerValue.tag_Set, digestAlgorithmIds);
519 
520         // contentInfo
521         contentInfo.encode(signedData);
522 
523         // certificates (optional)
524         if (certificates != null && certificates.length != 0) {
525             // cast to X509CertImpl[] since X509CertImpl implements DerEncoder
526             X509CertImpl implCerts[] = new X509CertImpl[certificates.length];
527             for (int i = 0; i < certificates.length; i++) {
528                 if (certificates[i] instanceof X509CertImpl)
529                     implCerts[i] = (X509CertImpl) certificates[i];
530                 else {
531                     try {
532                         byte[] encoded = certificates[i].getEncoded();
533                         implCerts[i] = new X509CertImpl(encoded);
534                     } catch (CertificateException ce) {
535                         throw new IOException(ce);
536                     }
537                 }
538             }
539 
540             // Add the certificate set (tagged with [0] IMPLICIT)
541             // to the signed data
542             signedData.putOrderedSetOf((byte)0xA0, implCerts);
543         }
544 
545         // CRLs (optional)
546         if (crls != null && crls.length != 0) {
547             // cast to X509CRLImpl[] since X509CRLImpl implements DerEncoder
548             Set<X509CRLImpl> implCRLs = new HashSet<X509CRLImpl>(crls.length);
549             for (X509CRL crl: crls) {
550                 if (crl instanceof X509CRLImpl)
551                     implCRLs.add((X509CRLImpl) crl);
552                 else {
553                     try {
554                         byte[] encoded = crl.getEncoded();
555                         implCRLs.add(new X509CRLImpl(encoded));
556                     } catch (CRLException ce) {
557                         throw new IOException(ce);
558                     }
559                 }
560             }
561 
562             // Add the CRL set (tagged with [1] IMPLICIT)
563             // to the signed data
564             signedData.putOrderedSetOf((byte)0xA1,
565                     implCRLs.toArray(new X509CRLImpl[implCRLs.size()]));
566         }
567 
568         // signerInfos
569         signedData.putOrderedSetOf(DerValue.tag_Set, signerInfos);
570 
571         // making it a signed data block
572         DerValue signedDataSeq = new DerValue(DerValue.tag_Sequence,
573                                               signedData.toByteArray());
574 
575         // making it a content info sequence
576         ContentInfo block = new ContentInfo(ContentInfo.SIGNED_DATA_OID,
577                                             signedDataSeq);
578 
579         // writing out the contentInfo sequence
580         block.encode(out);
581     }
582 
583     /**
584      * This verifies a given SignerInfo.
585      *
586      * @param info the signer information.
587      * @param bytes the DER encoded content information.
588      *
589      * @exception NoSuchAlgorithmException on unrecognized algorithms.
590      * @exception SignatureException on signature handling errors.
591      */
verify(SignerInfo info, byte[] bytes)592     public SignerInfo verify(SignerInfo info, byte[] bytes)
593     throws NoSuchAlgorithmException, SignatureException {
594         return info.verify(this, bytes);
595     }
596 
597     /**
598      * This verifies a given SignerInfo.
599      *
600      * @param info the signer information.
601      * @param dataInputStream the DER encoded content information.
602      *
603      * @exception NoSuchAlgorithmException on unrecognized algorithms.
604      * @exception SignatureException on signature handling errors.
605      */
verify(SignerInfo info, InputStream dataInputStream)606     public SignerInfo verify(SignerInfo info, InputStream dataInputStream)
607     throws NoSuchAlgorithmException, SignatureException, IOException {
608         return info.verify(this, dataInputStream);
609     }
610 
611     /**
612      * Returns all signerInfos which self-verify.
613      *
614      * @param bytes the DER encoded content information.
615      *
616      * @exception NoSuchAlgorithmException on unrecognized algorithms.
617      * @exception SignatureException on signature handling errors.
618      */
verify(byte[] bytes)619     public SignerInfo[] verify(byte[] bytes)
620     throws NoSuchAlgorithmException, SignatureException {
621 
622         Vector<SignerInfo> intResult = new Vector<SignerInfo>();
623         for (int i = 0; i < signerInfos.length; i++) {
624 
625             SignerInfo signerInfo = verify(signerInfos[i], bytes);
626             if (signerInfo != null) {
627                 intResult.addElement(signerInfo);
628             }
629         }
630         if (!intResult.isEmpty()) {
631 
632             SignerInfo[] result = new SignerInfo[intResult.size()];
633             intResult.copyInto(result);
634             return result;
635         }
636         return null;
637     }
638 
639     /**
640      * Returns all signerInfos which self-verify.
641      *
642      * @exception NoSuchAlgorithmException on unrecognized algorithms.
643      * @exception SignatureException on signature handling errors.
644      */
verify()645     public SignerInfo[] verify()
646     throws NoSuchAlgorithmException, SignatureException {
647         return verify(null);
648     }
649 
650     /**
651      * Returns the version number of this PKCS7 block.
652      * @return the version or null if version is not specified
653      *         for the content type.
654      */
getVersion()655     public  BigInteger getVersion() {
656         return version;
657     }
658 
659     /**
660      * Returns the message digest algorithms specified in this PKCS7 block.
661      * @return the array of Digest Algorithms or null if none are specified
662      *         for the content type.
663      */
getDigestAlgorithmIds()664     public AlgorithmId[] getDigestAlgorithmIds() {
665         return  digestAlgorithmIds;
666     }
667 
668     /**
669      * Returns the content information specified in this PKCS7 block.
670      */
getContentInfo()671     public ContentInfo getContentInfo() {
672         return contentInfo;
673     }
674 
675     /**
676      * Returns the X.509 certificates listed in this PKCS7 block.
677      * @return a clone of the array of X.509 certificates or null if
678      *         none are specified for the content type.
679      */
getCertificates()680     public X509Certificate[] getCertificates() {
681         if (certificates != null)
682             return certificates.clone();
683         else
684             return null;
685     }
686 
687     /**
688      * Returns the X.509 crls listed in this PKCS7 block.
689      * @return a clone of the array of X.509 crls or null if none
690      *         are specified for the content type.
691      */
getCRLs()692     public X509CRL[] getCRLs() {
693         if (crls != null)
694             return crls.clone();
695         else
696             return null;
697     }
698 
699     /**
700      * Returns the signer's information specified in this PKCS7 block.
701      * @return the array of Signer Infos or null if none are specified
702      *         for the content type.
703      */
getSignerInfos()704     public SignerInfo[] getSignerInfos() {
705         return signerInfos;
706     }
707 
708     /**
709      * Returns the X.509 certificate listed in this PKCS7 block
710      * which has a matching serial number and Issuer name, or
711      * null if one is not found.
712      *
713      * @param serial the serial number of the certificate to retrieve.
714      * @param issuerName the Distinguished Name of the Issuer.
715      */
getCertificate(BigInteger serial, X500Name issuerName)716     public X509Certificate getCertificate(BigInteger serial, X500Name issuerName) {
717         if (certificates != null) {
718             if (certIssuerNames == null)
719                 populateCertIssuerNames();
720             for (int i = 0; i < certificates.length; i++) {
721                 X509Certificate cert = certificates[i];
722                 BigInteger thisSerial = cert.getSerialNumber();
723                 if (serial.equals(thisSerial)
724                     && issuerName.equals(certIssuerNames[i]))
725                 {
726                     return cert;
727                 }
728             }
729         }
730         return null;
731     }
732 
733     /**
734      * Populate array of Issuer DNs from certificates and convert
735      * each Principal to type X500Name if necessary.
736      */
populateCertIssuerNames()737     private void populateCertIssuerNames() {
738         if (certificates == null)
739             return;
740 
741         certIssuerNames = new Principal[certificates.length];
742         for (int i = 0; i < certificates.length; i++) {
743             X509Certificate cert = certificates[i];
744             Principal certIssuerName = cert.getIssuerDN();
745             if (!(certIssuerName instanceof X500Name)) {
746                 // must extract the original encoded form of DN for
747                 // subsequent name comparison checks (converting to a
748                 // String and back to an encoded DN could cause the
749                 // types of String attribute values to be changed)
750                 try {
751                     X509CertInfo tbsCert =
752                         new X509CertInfo(cert.getTBSCertificate());
753                     certIssuerName = (Principal)
754                         tbsCert.get(X509CertInfo.ISSUER + "." +
755                                     X509CertInfo.DN_NAME);
756                 } catch (Exception e) {
757                     // error generating X500Name object from the cert's
758                     // issuer DN, leave name as is.
759                 }
760             }
761             certIssuerNames[i] = certIssuerName;
762         }
763     }
764 
765     /**
766      * Returns the PKCS7 block in a printable string form.
767      */
toString()768     public String toString() {
769         String out = "";
770 
771         out += contentInfo + "\n";
772         if (version != null)
773             out += "PKCS7 :: version: " + Debug.toHexString(version) + "\n";
774         if (digestAlgorithmIds != null) {
775             out += "PKCS7 :: digest AlgorithmIds: \n";
776             for (int i = 0; i < digestAlgorithmIds.length; i++)
777                 out += "\t" + digestAlgorithmIds[i] + "\n";
778         }
779         if (certificates != null) {
780             out += "PKCS7 :: certificates: \n";
781             for (int i = 0; i < certificates.length; i++)
782                 out += "\t" + i + ".   " + certificates[i] + "\n";
783         }
784         if (crls != null) {
785             out += "PKCS7 :: crls: \n";
786             for (int i = 0; i < crls.length; i++)
787                 out += "\t" + i + ".   " + crls[i] + "\n";
788         }
789         if (signerInfos != null) {
790             out += "PKCS7 :: signer infos: \n";
791             for (int i = 0; i < signerInfos.length; i++)
792                 out += ("\t" + i + ".  " + signerInfos[i] + "\n");
793         }
794         return out;
795     }
796 
797     /**
798      * Returns true if this is a JDK1.1.x-style PKCS#7 block, and false
799      * otherwise.
800      */
isOldStyle()801     public boolean isOldStyle() {
802         return this.oldStyle;
803     }
804 
805     // BEGIN Android-added
806     /**
807      * For legacy reasons we need to return exactly the original encoded certificate bytes, instead
808      * of letting the underlying implementation have a shot at re-encoding the data.
809      */
810     private static class VerbatimX509Certificate extends WrappedX509Certificate {
811         private byte[] encodedVerbatim;
812 
VerbatimX509Certificate(X509Certificate wrapped, byte[] encodedVerbatim)813         public VerbatimX509Certificate(X509Certificate wrapped, byte[] encodedVerbatim) {
814             super(wrapped);
815             this.encodedVerbatim = encodedVerbatim;
816         }
817 
818         @Override
getEncoded()819         public byte[] getEncoded() throws CertificateEncodingException {
820             return encodedVerbatim;
821         }
822     }
823 
824     private static class WrappedX509Certificate extends X509Certificate {
825         private final X509Certificate wrapped;
826 
WrappedX509Certificate(X509Certificate wrapped)827         public WrappedX509Certificate(X509Certificate wrapped) {
828             this.wrapped = wrapped;
829         }
830 
831         @Override
getCriticalExtensionOIDs()832         public Set<String> getCriticalExtensionOIDs() {
833             return wrapped.getCriticalExtensionOIDs();
834         }
835 
836         @Override
getExtensionValue(String oid)837         public byte[] getExtensionValue(String oid) {
838             return wrapped.getExtensionValue(oid);
839         }
840 
841         @Override
getNonCriticalExtensionOIDs()842         public Set<String> getNonCriticalExtensionOIDs() {
843             return wrapped.getNonCriticalExtensionOIDs();
844         }
845 
846         @Override
hasUnsupportedCriticalExtension()847         public boolean hasUnsupportedCriticalExtension() {
848             return wrapped.hasUnsupportedCriticalExtension();
849         }
850 
851         @Override
checkValidity()852         public void checkValidity()
853                 throws CertificateExpiredException, CertificateNotYetValidException {
854             wrapped.checkValidity();
855         }
856 
857         @Override
checkValidity(Date date)858         public void checkValidity(Date date)
859                 throws CertificateExpiredException, CertificateNotYetValidException {
860             wrapped.checkValidity(date);
861         }
862 
863         @Override
getVersion()864         public int getVersion() {
865             return wrapped.getVersion();
866         }
867 
868         @Override
getSerialNumber()869         public BigInteger getSerialNumber() {
870             return wrapped.getSerialNumber();
871         }
872 
873         @Override
getIssuerDN()874         public Principal getIssuerDN() {
875             return wrapped.getIssuerDN();
876         }
877 
878         @Override
getSubjectDN()879         public Principal getSubjectDN() {
880             return wrapped.getSubjectDN();
881         }
882 
883         @Override
getNotBefore()884         public Date getNotBefore() {
885             return wrapped.getNotBefore();
886         }
887 
888         @Override
getNotAfter()889         public Date getNotAfter() {
890             return wrapped.getNotAfter();
891         }
892 
893         @Override
getTBSCertificate()894         public byte[] getTBSCertificate() throws CertificateEncodingException {
895             return wrapped.getTBSCertificate();
896         }
897 
898         @Override
getSignature()899         public byte[] getSignature() {
900             return wrapped.getSignature();
901         }
902 
903         @Override
getSigAlgName()904         public String getSigAlgName() {
905             return wrapped.getSigAlgName();
906         }
907 
908         @Override
getSigAlgOID()909         public String getSigAlgOID() {
910             return wrapped.getSigAlgOID();
911         }
912 
913         @Override
getSigAlgParams()914         public byte[] getSigAlgParams() {
915             return wrapped.getSigAlgParams();
916         }
917 
918         @Override
getIssuerUniqueID()919         public boolean[] getIssuerUniqueID() {
920             return wrapped.getIssuerUniqueID();
921         }
922 
923         @Override
getSubjectUniqueID()924         public boolean[] getSubjectUniqueID() {
925             return wrapped.getSubjectUniqueID();
926         }
927 
928         @Override
getKeyUsage()929         public boolean[] getKeyUsage() {
930             return wrapped.getKeyUsage();
931         }
932 
933         @Override
getBasicConstraints()934         public int getBasicConstraints() {
935             return wrapped.getBasicConstraints();
936         }
937 
938         @Override
getEncoded()939         public byte[] getEncoded() throws CertificateEncodingException {
940             return wrapped.getEncoded();
941         }
942 
943         @Override
verify(PublicKey key)944         public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException,
945                 InvalidKeyException, NoSuchProviderException, SignatureException {
946             wrapped.verify(key);
947         }
948 
949         @Override
verify(PublicKey key, String sigProvider)950         public void verify(PublicKey key, String sigProvider)
951                 throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
952                 NoSuchProviderException, SignatureException {
953             wrapped.verify(key, sigProvider);
954         }
955 
956         @Override
toString()957         public String toString() {
958             return wrapped.toString();
959         }
960 
961         @Override
getPublicKey()962         public PublicKey getPublicKey() {
963             return wrapped.getPublicKey();
964         }
965 
966         @Override
getExtendedKeyUsage()967         public List<String> getExtendedKeyUsage() throws CertificateParsingException {
968             return wrapped.getExtendedKeyUsage();
969         }
970 
971         @Override
getIssuerAlternativeNames()972         public Collection<List<?>> getIssuerAlternativeNames() throws CertificateParsingException {
973             return wrapped.getIssuerAlternativeNames();
974         }
975 
976         @Override
getIssuerX500Principal()977         public X500Principal getIssuerX500Principal() {
978             return wrapped.getIssuerX500Principal();
979         }
980 
981         @Override
getSubjectAlternativeNames()982         public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException {
983             return wrapped.getSubjectAlternativeNames();
984         }
985 
986         @Override
getSubjectX500Principal()987         public X500Principal getSubjectX500Principal() {
988             return wrapped.getSubjectX500Principal();
989         }
990 
991         @Override
verify(PublicKey key, Provider sigProvider)992         public void verify(PublicKey key, Provider sigProvider) throws CertificateException,
993                 NoSuchAlgorithmException, InvalidKeyException, SignatureException {
994             wrapped.verify(key, sigProvider);
995         }
996     }
997     // END Android-added
998 
999     // BEGIN Android-removed: unused in Android
1000     /**
1001      * Assembles a PKCS #7 signed data message that optionally includes a
1002      * signature timestamp.
1003      *
1004      * @param signature the signature bytes
1005      * @param signerChain the signer's X.509 certificate chain
1006      * @param content the content that is signed; specify null to not include
1007      *        it in the PKCS7 data
1008      * @param signatureAlgorithm the name of the signature algorithm
1009      * @param tsaURI the URI of the Timestamping Authority; or null if no
1010      *         timestamp is requested
1011      * @param tSAPolicyID the TSAPolicyID of the Timestamping Authority as a
1012      *         numerical object identifier; or null if we leave the TSA server
1013      *         to choose one. This argument is only used when tsaURI is provided
1014      * @return the bytes of the encoded PKCS #7 signed data message
1015      * @throws NoSuchAlgorithmException The exception is thrown if the signature
1016      *         algorithm is unrecognised.
1017      * @throws CertificateException The exception is thrown if an error occurs
1018      *         while processing the signer's certificate or the TSA's
1019      *         certificate.
1020      * @throws IOException The exception is thrown if an error occurs while
1021      *         generating the signature timestamp or while generating the signed
1022      *         data message.
1023      *
1024     public static byte[] generateSignedData(byte[] signature,
1025             X509Certificate[] signerChain,
1026             byte[] content,
1027             String signatureAlgorithm,
1028             URI tsaURI,
1029             String tSAPolicyID)
1030             throws CertificateException, IOException, NoSuchAlgorithmException
1031     {
1032 
1033         // Generate the timestamp token
1034         PKCS9Attributes unauthAttrs = null;
1035         if (tsaURI != null) {
1036             // Timestamp the signature
1037             HttpTimestamper tsa = new HttpTimestamper(tsaURI);
1038             byte[] tsToken = generateTimestampToken(tsa, tSAPolicyID, signature);
1039 
1040             // Insert the timestamp token into the PKCS #7 signer info element
1041             // (as an unsigned attribute)
1042             unauthAttrs =
1043                     new PKCS9Attributes(new PKCS9Attribute[]{
1044                             new PKCS9Attribute(
1045                                     PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_STR,
1046                                     tsToken)});
1047         }
1048 
1049         // Create the SignerInfo
1050         X500Name issuerName =
1051                 X500Name.asX500Name(signerChain[0].getIssuerX500Principal());
1052         BigInteger serialNumber = signerChain[0].getSerialNumber();
1053         String encAlg = AlgorithmId.getEncAlgFromSigAlg(signatureAlgorithm);
1054         String digAlg = AlgorithmId.getDigAlgFromSigAlg(signatureAlgorithm);
1055         SignerInfo signerInfo = new SignerInfo(issuerName, serialNumber,
1056                 AlgorithmId.get(digAlg), null,
1057                 AlgorithmId.get(encAlg),
1058                 signature, unauthAttrs);
1059 
1060         // Create the PKCS #7 signed data message
1061         SignerInfo[] signerInfos = {signerInfo};
1062         AlgorithmId[] algorithms = {signerInfo.getDigestAlgorithmId()};
1063         // Include or exclude content
1064         ContentInfo contentInfo = (content == null)
1065                 ? new ContentInfo(ContentInfo.DATA_OID, null)
1066                 : new ContentInfo(content);
1067         PKCS7 pkcs7 = new PKCS7(algorithms, contentInfo,
1068                 signerChain, signerInfos);
1069         ByteArrayOutputStream p7out = new ByteArrayOutputStream();
1070         pkcs7.encodeSignedData(p7out);
1071 
1072         return p7out.toByteArray();
1073     }
1074 
1075     /**
1076      * Requests, processes and validates a timestamp token from a TSA using
1077      * common defaults. Uses the following defaults in the timestamp request:
1078      * SHA-1 for the hash algorithm, a 64-bit nonce, and request certificate
1079      * set to true.
1080      *
1081      * @param tsa the timestamping authority to use
1082      * @param tSAPolicyID the TSAPolicyID of the Timestamping Authority as a
1083      *         numerical object identifier; or null if we leave the TSA server
1084      *         to choose one
1085      * @param toBeTimestamped the token that is to be timestamped
1086      * @return the encoded timestamp token
1087      * @throws IOException The exception is thrown if an error occurs while
1088      *                     communicating with the TSA, or a non-null
1089      *                     TSAPolicyID is specified in the request but it
1090      *                     does not match the one in the reply
1091      * @throws CertificateException The exception is thrown if the TSA's
1092      *                     certificate is not permitted for timestamping.
1093      *
1094     private static byte[] generateTimestampToken(Timestamper tsa,
1095             String tSAPolicyID,
1096             byte[] toBeTimestamped)
1097             throws IOException, CertificateException
1098     {
1099         // Generate a timestamp
1100         MessageDigest messageDigest = null;
1101         TSRequest tsQuery = null;
1102         try {
1103             // SHA-1 is always used.
1104             messageDigest = MessageDigest.getInstance("SHA-1");
1105             tsQuery = new TSRequest(tSAPolicyID, toBeTimestamped, messageDigest);
1106         } catch (NoSuchAlgorithmException e) {
1107             // ignore
1108         }
1109 
1110         // Generate a nonce
1111         BigInteger nonce = null;
1112         if (SecureRandomHolder.RANDOM != null) {
1113             nonce = new BigInteger(64, SecureRandomHolder.RANDOM);
1114             tsQuery.setNonce(nonce);
1115         }
1116         tsQuery.requestCertificate(true);
1117 
1118         TSResponse tsReply = tsa.generateTimestamp(tsQuery);
1119         int status = tsReply.getStatusCode();
1120         // Handle TSP error
1121         if (status != 0 && status != 1) {
1122             throw new IOException("Error generating timestamp: " +
1123                     tsReply.getStatusCodeAsText() + " " +
1124                     tsReply.getFailureCodeAsText());
1125         }
1126 
1127         if (tSAPolicyID != null &&
1128                 !tSAPolicyID.equals(tsReply.getTimestampToken().getPolicyID())) {
1129             throw new IOException("TSAPolicyID changed in "
1130                     + "timestamp token");
1131         }
1132         PKCS7 tsToken = tsReply.getToken();
1133 
1134         TimestampToken tst = tsReply.getTimestampToken();
1135         if (!tst.getHashAlgorithm().getName().equals("SHA-1")) {
1136             throw new IOException("Digest algorithm not SHA-1 in "
1137                     + "timestamp token");
1138         }
1139         if (!MessageDigest.isEqual(tst.getHashedMessage(),
1140                 tsQuery.getHashedMessage())) {
1141             throw new IOException("Digest octets changed in timestamp token");
1142         }
1143 
1144         BigInteger replyNonce = tst.getNonce();
1145         if (replyNonce == null && nonce != null) {
1146             throw new IOException("Nonce missing in timestamp token");
1147         }
1148         if (replyNonce != null && !replyNonce.equals(nonce)) {
1149             throw new IOException("Nonce changed in timestamp token");
1150         }
1151 
1152         // Examine the TSA's certificate (if present)
1153         for (SignerInfo si: tsToken.getSignerInfos()) {
1154             X509Certificate cert = si.getCertificate(tsToken);
1155             if (cert == null) {
1156                 // Error, we've already set tsRequestCertificate = true
1157                 throw new CertificateException(
1158                         "Certificate not included in timestamp token");
1159             } else {
1160                 if (!cert.getCriticalExtensionOIDs().contains(
1161                         EXTENDED_KEY_USAGE_OID)) {
1162                     throw new CertificateException(
1163                             "Certificate is not valid for timestamping");
1164                 }
1165                 List<String> keyPurposes = cert.getExtendedKeyUsage();
1166                 if (keyPurposes == null ||
1167                         !keyPurposes.contains(KP_TIMESTAMPING_OID)) {
1168                     throw new CertificateException(
1169                             "Certificate is not valid for timestamping");
1170                 }
1171             }
1172         }
1173         return tsReply.getEncodedToken();
1174     }
1175     END Android-removed */
1176 }
1177