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