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