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