Home | History | Annotate | Download | only in pkcs
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 1996, 2011, 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.util.*;
     32 import java.security.cert.X509Certificate;
     33 import java.security.cert.CertificateException;
     34 import java.security.cert.CertificateEncodingException;
     35 import java.security.cert.CertificateExpiredException;
     36 import java.security.cert.CertificateNotYetValidException;
     37 import java.security.cert.CertificateParsingException;
     38 import java.security.cert.X509CRL;
     39 import java.security.cert.CRLException;
     40 import java.security.cert.CertificateFactory;
     41 import java.security.*;
     42 
     43 import javax.security.auth.x500.X500Principal;
     44 
     45 import sun.security.util.*;
     46 import sun.security.x509.AlgorithmId;
     47 import sun.security.x509.CertificateIssuerName;
     48 import sun.security.x509.X509CertImpl;
     49 import sun.security.x509.X509CertInfo;
     50 import sun.security.x509.X509CRLImpl;
     51 import sun.security.x509.X500Name;
     52 
     53 /**
     54  * PKCS7 as defined in RSA Laboratories PKCS7 Technical Note. Profile
     55  * Supports only <tt>SignedData</tt> ContentInfo
     56  * type, where to the type of data signed is plain Data.
     57  * For signedData, <tt>crls</tt>, <tt>attributes</tt> and
     58  * PKCS#6 Extended Certificates are not supported.
     59  *
     60  * @author Benjamin Renaud
     61  */
     62 public class PKCS7 {
     63 
     64     private ObjectIdentifier contentType;
     65 
     66     // the ASN.1 members for a signedData (and other) contentTypes
     67     private BigInteger version = null;
     68     private AlgorithmId[] digestAlgorithmIds = null;
     69     private ContentInfo contentInfo = null;
     70     private X509Certificate[] certificates = null;
     71     private X509CRL[] crls = null;
     72     private SignerInfo[] signerInfos = null;
     73 
     74     private boolean oldStyle = false; // Is this JDK1.1.x-style?
     75 
     76     private Principal[] certIssuerNames;
     77 
     78     /**
     79      * Unmarshals a PKCS7 block from its encoded form, parsing the
     80      * encoded bytes from the InputStream.
     81      *
     82      * @param in an input stream holding at least one PKCS7 block.
     83      * @exception ParsingException on parsing errors.
     84      * @exception IOException on other errors.
     85      */
     86     public PKCS7(InputStream in) throws ParsingException, IOException {
     87         DataInputStream dis = new DataInputStream(in);
     88         byte[] data = new byte[dis.available()];
     89         dis.readFully(data);
     90 
     91         parse(new DerInputStream(data));
     92     }
     93 
     94     /**
     95      * Unmarshals a PKCS7 block from its encoded form, parsing the
     96      * encoded bytes from the DerInputStream.
     97      *
     98      * @param derin a DerInputStream holding at least one PKCS7 block.
     99      * @exception ParsingException on parsing errors.
    100      */
    101     public PKCS7(DerInputStream derin) throws ParsingException {
    102         parse(derin);
    103     }
    104 
    105     /**
    106      * Unmarshals a PKCS7 block from its encoded form, parsing the
    107      * encoded bytes.
    108      *
    109      * @param bytes the encoded bytes.
    110      * @exception ParsingException on parsing errors.
    111      */
    112     public PKCS7(byte[] bytes) throws ParsingException {
    113         try {
    114             DerInputStream derin = new DerInputStream(bytes);
    115             parse(derin);
    116         } catch (IOException ioe1) {
    117             ParsingException pe = new ParsingException(
    118                 "Unable to parse the encoded bytes");
    119             pe.initCause(ioe1);
    120             throw pe;
    121         }
    122     }
    123 
    124     /*
    125      * Parses a PKCS#7 block.
    126      */
    127     private void parse(DerInputStream derin)
    128         throws ParsingException
    129     {
    130         try {
    131             derin.mark(derin.available());
    132             // try new (i.e., JDK1.2) style
    133             parse(derin, false);
    134         } catch (IOException ioe) {
    135             try {
    136                 derin.reset();
    137                 // try old (i.e., JDK1.1.x) style
    138                 parse(derin, true);
    139                 oldStyle = true;
    140             } catch (IOException ioe1) {
    141                 ParsingException pe = new ParsingException(
    142                     ioe1.getMessage());
    143                 pe.initCause(ioe);
    144                 pe.addSuppressed(ioe1);
    145                 throw pe;
    146             }
    147         }
    148     }
    149 
    150     /**
    151      * Parses a PKCS#7 block.
    152      *
    153      * @param derin the ASN.1 encoding of the PKCS#7 block.
    154      * @param oldStyle flag indicating whether or not the given PKCS#7 block
    155      * is encoded according to JDK1.1.x.
    156      */
    157     private void parse(DerInputStream derin, boolean oldStyle)
    158         throws IOException
    159     {
    160         contentInfo = new ContentInfo(derin, oldStyle);
    161         contentType = contentInfo.contentType;
    162         DerValue content = contentInfo.getContent();
    163 
    164         if (contentType.equals(ContentInfo.SIGNED_DATA_OID)) {
    165             parseSignedData(content);
    166         } else if (contentType.equals(ContentInfo.OLD_SIGNED_DATA_OID)) {
    167             // This is for backwards compatibility with JDK 1.1.x
    168             parseOldSignedData(content);
    169         } else if (contentType.equals(ContentInfo.NETSCAPE_CERT_SEQUENCE_OID)){
    170             parseNetscapeCertChain(content);
    171         } else {
    172             throw new ParsingException("content type " + contentType +
    173                                        " not supported.");
    174         }
    175     }
    176 
    177     /**
    178      * Construct an initialized PKCS7 block.
    179      *
    180      * @param digestAlgorithmIds the message digest algorithm identifiers.
    181      * @param contentInfo the content information.
    182      * @param certificates an array of X.509 certificates.
    183      * @param crls an array of CRLs
    184      * @param signerInfos an array of signer information.
    185      */
    186     public PKCS7(AlgorithmId[] digestAlgorithmIds,
    187                  ContentInfo contentInfo,
    188                  X509Certificate[] certificates,
    189                  X509CRL[] crls,
    190                  SignerInfo[] signerInfos) {
    191 
    192         version = BigInteger.ONE;
    193         this.digestAlgorithmIds = digestAlgorithmIds;
    194         this.contentInfo = contentInfo;
    195         this.certificates = certificates;
    196         this.crls = crls;
    197         this.signerInfos = signerInfos;
    198     }
    199 
    200     public PKCS7(AlgorithmId[] digestAlgorithmIds,
    201                  ContentInfo contentInfo,
    202                  X509Certificate[] certificates,
    203                  SignerInfo[] signerInfos) {
    204         this(digestAlgorithmIds, contentInfo, certificates, null, signerInfos);
    205     }
    206 
    207     private void parseNetscapeCertChain(DerValue val)
    208     throws ParsingException, IOException {
    209         DerInputStream dis = new DerInputStream(val.toByteArray());
    210         DerValue[] contents = dis.getSequence(2, true);
    211         certificates = new X509Certificate[contents.length];
    212 
    213         CertificateFactory certfac = null;
    214         try {
    215             certfac = CertificateFactory.getInstance("X.509");
    216         } catch (CertificateException ce) {
    217             // do nothing
    218         }
    219 
    220         for (int i=0; i < contents.length; i++) {
    221             ByteArrayInputStream bais = null;
    222             try {
    223                 byte[] original = contents[i].getOriginalEncodedForm();
    224                 if (certfac == null)
    225                     certificates[i] = new X509CertImpl(contents[i], original);
    226                 else {
    227                     bais = new ByteArrayInputStream(original);
    228                     certificates[i] = new VerbatimX509Certificate(
    229                         (X509Certificate)certfac.generateCertificate(bais),
    230                         original);
    231                     bais.close();
    232                     bais = null;
    233                 }
    234             } catch (CertificateException ce) {
    235                 ParsingException pe = new ParsingException(ce.getMessage());
    236                 pe.initCause(ce);
    237                 throw pe;
    238             } catch (IOException ioe) {
    239                 ParsingException pe = new ParsingException(ioe.getMessage());
    240                 pe.initCause(ioe);
    241                 throw pe;
    242             } finally {
    243                 if (bais != null)
    244                     bais.close();
    245             }
    246         }
    247     }
    248 
    249     private void parseSignedData(DerValue val)
    250         throws ParsingException, IOException {
    251 
    252         DerInputStream dis = val.toDerInputStream();
    253 
    254         // Version
    255         version = dis.getBigInteger();
    256 
    257         // digestAlgorithmIds
    258         DerValue[] digestAlgorithmIdVals = dis.getSet(1);
    259         int len = digestAlgorithmIdVals.length;
    260         digestAlgorithmIds = new AlgorithmId[len];
    261         try {
    262             for (int i = 0; i < len; i++) {
    263                 DerValue oid = digestAlgorithmIdVals[i];
    264                 digestAlgorithmIds[i] = AlgorithmId.parse(oid);
    265             }
    266 
    267         } catch (IOException e) {
    268             ParsingException pe =
    269                 new ParsingException("Error parsing digest AlgorithmId IDs: " +
    270                                      e.getMessage());
    271             pe.initCause(e);
    272             throw pe;
    273         }
    274         // contentInfo
    275         contentInfo = new ContentInfo(dis);
    276 
    277         CertificateFactory certfac = null;
    278         try {
    279             certfac = CertificateFactory.getInstance("X.509");
    280         } catch (CertificateException ce) {
    281             // do nothing
    282         }
    283 
    284         /*
    285          * check if certificates (implicit tag) are provided
    286          * (certificates are OPTIONAL)
    287          */
    288         if ((byte)(dis.peekByte()) == (byte)0xA0) {
    289             DerValue[] certVals = dis.getSet(2, true, true);
    290 
    291             len = certVals.length;
    292             certificates = new X509Certificate[len];
    293             int count = 0;
    294 
    295             for (int i = 0; i < len; i++) {
    296                 ByteArrayInputStream bais = null;
    297                 try {
    298                     byte tag = certVals[i].getTag();
    299                     // We only parse the normal certificate. Other types of
    300                     // CertificateChoices ignored.
    301                     if (tag == DerValue.tag_Sequence) {
    302                         byte[] original = certVals[i].getOriginalEncodedForm();
    303                         if (certfac == null) {
    304                             certificates[count] = new X509CertImpl(certVals[i], original);
    305                         } else {
    306                             bais = new ByteArrayInputStream(original);
    307                             certificates[count] = new VerbatimX509Certificate(
    308                                 (X509Certificate)certfac.generateCertificate(bais),
    309                                 original);
    310                             bais.close();
    311                             bais = null;
    312                         }
    313                         count++;
    314                     }
    315                 } catch (CertificateException ce) {
    316                     ParsingException pe = new ParsingException(ce.getMessage());
    317                     pe.initCause(ce);
    318                     throw pe;
    319                 } catch (IOException ioe) {
    320                     ParsingException pe = new ParsingException(ioe.getMessage());
    321                     pe.initCause(ioe);
    322                     throw pe;
    323                 } finally {
    324                     if (bais != null)
    325                         bais.close();
    326                 }
    327             }
    328             if (count != len) {
    329                 certificates = Arrays.copyOf(certificates, count);
    330             }
    331         }
    332 
    333         // check if crls (implicit tag) are provided (crls are OPTIONAL)
    334         if ((byte)(dis.peekByte()) == (byte)0xA1) {
    335             DerValue[] crlVals = dis.getSet(1, true);
    336 
    337             len = crlVals.length;
    338             crls = new X509CRL[len];
    339 
    340             for (int i = 0; i < len; i++) {
    341                 ByteArrayInputStream bais = null;
    342                 try {
    343                     if (certfac == null)
    344                         crls[i] = new X509CRLImpl(crlVals[i]);
    345                     else {
    346                         byte[] encoded = crlVals[i].toByteArray();
    347                         bais = new ByteArrayInputStream(encoded);
    348                         crls[i] = (X509CRL) certfac.generateCRL(bais);
    349                         bais.close();
    350                         bais = null;
    351                     }
    352                 } catch (CRLException e) {
    353                     ParsingException pe =
    354                         new ParsingException(e.getMessage());
    355                     pe.initCause(e);
    356                     throw pe;
    357                 } finally {
    358                     if (bais != null)
    359                         bais.close();
    360                 }
    361             }
    362         }
    363 
    364         // signerInfos
    365         DerValue[] signerInfoVals = dis.getSet(1);
    366 
    367         len = signerInfoVals.length;
    368         signerInfos = new SignerInfo[len];
    369 
    370         for (int i = 0; i < len; i++) {
    371             DerInputStream in = signerInfoVals[i].toDerInputStream();
    372             signerInfos[i] = new SignerInfo(in);
    373         }
    374     }
    375 
    376     /*
    377      * Parses an old-style SignedData encoding (for backwards
    378      * compatibility with JDK1.1.x).
    379      */
    380     private void parseOldSignedData(DerValue val)
    381         throws ParsingException, IOException
    382     {
    383         DerInputStream dis = val.toDerInputStream();
    384 
    385         // Version
    386         version = dis.getBigInteger();
    387 
    388         // digestAlgorithmIds
    389         DerValue[] digestAlgorithmIdVals = dis.getSet(1);
    390         int len = digestAlgorithmIdVals.length;
    391 
    392         digestAlgorithmIds = new AlgorithmId[len];
    393         try {
    394             for (int i = 0; i < len; i++) {
    395                 DerValue oid = digestAlgorithmIdVals[i];
    396                 digestAlgorithmIds[i] = AlgorithmId.parse(oid);
    397             }
    398         } catch (IOException e) {
    399             throw new ParsingException("Error parsing digest AlgorithmId IDs");
    400         }
    401 
    402         // contentInfo
    403         contentInfo = new ContentInfo(dis, true);
    404 
    405         // certificates
    406         CertificateFactory certfac = null;
    407         try {
    408             certfac = CertificateFactory.getInstance("X.509");
    409         } catch (CertificateException ce) {
    410             // do nothing
    411         }
    412         DerValue[] certVals = dis.getSet(2, false, true);
    413         len = certVals.length;
    414         certificates = new X509Certificate[len];
    415 
    416         for (int i = 0; i < len; i++) {
    417             ByteArrayInputStream bais = null;
    418             try {
    419                 byte[] original = certVals[i].getOriginalEncodedForm();
    420                 if (certfac == null)
    421                     certificates[i] = new X509CertImpl(certVals[i], original);
    422                 else {
    423                     bais = new ByteArrayInputStream(original);
    424                     certificates[i] = new VerbatimX509Certificate(
    425                         (X509Certificate)certfac.generateCertificate(bais),
    426                         original);
    427                     bais.close();
    428                     bais = null;
    429                 }
    430             } catch (CertificateException ce) {
    431                 ParsingException pe = new ParsingException(ce.getMessage());
    432                 pe.initCause(ce);
    433                 throw pe;
    434             } catch (IOException ioe) {
    435                 ParsingException pe = new ParsingException(ioe.getMessage());
    436                 pe.initCause(ioe);
    437                 throw pe;
    438             } finally {
    439                 if (bais != null)
    440                     bais.close();
    441             }
    442         }
    443 
    444         // crls are ignored.
    445         dis.getSet(0);
    446 
    447         // signerInfos
    448         DerValue[] signerInfoVals = dis.getSet(1);
    449         len = signerInfoVals.length;
    450         signerInfos = new SignerInfo[len];
    451         for (int i = 0; i < len; i++) {
    452             DerInputStream in = signerInfoVals[i].toDerInputStream();
    453             signerInfos[i] = new SignerInfo(in, true);
    454         }
    455     }
    456 
    457     /**
    458      * Encodes the signed data to an output stream.
    459      *
    460      * @param out the output stream to write the encoded data to.
    461      * @exception IOException on encoding errors.
    462      */
    463     public void encodeSignedData(OutputStream out) throws IOException {
    464         DerOutputStream derout = new DerOutputStream();
    465         encodeSignedData(derout);
    466         out.write(derout.toByteArray());
    467     }
    468 
    469     /**
    470      * Encodes the signed data to a DerOutputStream.
    471      *
    472      * @param out the DerOutputStream to write the encoded data to.
    473      * @exception IOException on encoding errors.
    474      */
    475     public void encodeSignedData(DerOutputStream out)
    476         throws IOException
    477     {
    478         DerOutputStream signedData = new DerOutputStream();
    479 
    480         // version
    481         signedData.putInteger(version);
    482 
    483         // digestAlgorithmIds
    484         signedData.putOrderedSetOf(DerValue.tag_Set, digestAlgorithmIds);
    485 
    486         // contentInfo
    487         contentInfo.encode(signedData);
    488 
    489         // certificates (optional)
    490         if (certificates != null && certificates.length != 0) {
    491             // cast to X509CertImpl[] since X509CertImpl implements DerEncoder
    492             X509CertImpl implCerts[] = new X509CertImpl[certificates.length];
    493             for (int i = 0; i < certificates.length; i++) {
    494                 if (certificates[i] instanceof X509CertImpl)
    495                     implCerts[i] = (X509CertImpl) certificates[i];
    496                 else {
    497                     try {
    498                         byte[] encoded = certificates[i].getEncoded();
    499                         implCerts[i] = new X509CertImpl(encoded);
    500                     } catch (CertificateException ce) {
    501                         IOException ie = new IOException(ce.getMessage());
    502                         ie.initCause(ce);
    503                         throw ie;
    504                     }
    505                 }
    506             }
    507 
    508             // Add the certificate set (tagged with [0] IMPLICIT)
    509             // to the signed data
    510             signedData.putOrderedSetOf((byte)0xA0, implCerts);
    511         }
    512 
    513         // CRLs (optional)
    514         if (crls != null && crls.length != 0) {
    515             // cast to X509CRLImpl[] since X509CRLImpl implements DerEncoder
    516             Set<X509CRLImpl> implCRLs = new HashSet<X509CRLImpl>(crls.length);
    517             for (X509CRL crl: crls) {
    518                 if (crl instanceof X509CRLImpl)
    519                     implCRLs.add((X509CRLImpl) crl);
    520                 else {
    521                     try {
    522                         byte[] encoded = crl.getEncoded();
    523                         implCRLs.add(new X509CRLImpl(encoded));
    524                     } catch (CRLException ce) {
    525                         IOException ie = new IOException(ce.getMessage());
    526                         ie.initCause(ce);
    527                         throw ie;
    528                     }
    529                 }
    530             }
    531 
    532             // Add the CRL set (tagged with [1] IMPLICIT)
    533             // to the signed data
    534             signedData.putOrderedSetOf((byte)0xA1,
    535                     implCRLs.toArray(new X509CRLImpl[implCRLs.size()]));
    536         }
    537 
    538         // signerInfos
    539         signedData.putOrderedSetOf(DerValue.tag_Set, signerInfos);
    540 
    541         // making it a signed data block
    542         DerValue signedDataSeq = new DerValue(DerValue.tag_Sequence,
    543                                               signedData.toByteArray());
    544 
    545         // making it a content info sequence
    546         ContentInfo block = new ContentInfo(ContentInfo.SIGNED_DATA_OID,
    547                                             signedDataSeq);
    548 
    549         // writing out the contentInfo sequence
    550         block.encode(out);
    551     }
    552 
    553     /**
    554      * This verifies a given SignerInfo.
    555      *
    556      * @param info the signer information.
    557      * @param bytes the DER encoded content information.
    558      *
    559      * @exception NoSuchAlgorithmException on unrecognized algorithms.
    560      * @exception SignatureException on signature handling errors.
    561      */
    562     public SignerInfo verify(SignerInfo info, byte[] bytes)
    563     throws NoSuchAlgorithmException, SignatureException {
    564         return info.verify(this, bytes);
    565     }
    566 
    567     /**
    568      * This verifies a given SignerInfo.
    569      *
    570      * @param info the signer information.
    571      * @param dataInputStream the DER encoded content information.
    572      *
    573      * @exception NoSuchAlgorithmException on unrecognized algorithms.
    574      * @exception SignatureException on signature handling errors.
    575      */
    576     public SignerInfo verify(SignerInfo info, InputStream dataInputStream)
    577     throws NoSuchAlgorithmException, SignatureException, IOException {
    578         return info.verify(this, dataInputStream);
    579     }
    580 
    581     /**
    582      * Returns all signerInfos which self-verify.
    583      *
    584      * @param bytes the DER encoded content information.
    585      *
    586      * @exception NoSuchAlgorithmException on unrecognized algorithms.
    587      * @exception SignatureException on signature handling errors.
    588      */
    589     public SignerInfo[] verify(byte[] bytes)
    590     throws NoSuchAlgorithmException, SignatureException {
    591 
    592         Vector<SignerInfo> intResult = new Vector<SignerInfo>();
    593         for (int i = 0; i < signerInfos.length; i++) {
    594 
    595             SignerInfo signerInfo = verify(signerInfos[i], bytes);
    596             if (signerInfo != null) {
    597                 intResult.addElement(signerInfo);
    598             }
    599         }
    600         if (intResult.size() != 0) {
    601 
    602             SignerInfo[] result = new SignerInfo[intResult.size()];
    603             intResult.copyInto(result);
    604             return result;
    605         }
    606         return null;
    607     }
    608 
    609     /**
    610      * Returns all signerInfos which self-verify.
    611      *
    612      * @exception NoSuchAlgorithmException on unrecognized algorithms.
    613      * @exception SignatureException on signature handling errors.
    614      */
    615     public SignerInfo[] verify()
    616     throws NoSuchAlgorithmException, SignatureException {
    617         return verify(null);
    618     }
    619 
    620     /**
    621      * Returns the version number of this PKCS7 block.
    622      * @return the version or null if version is not specified
    623      *         for the content type.
    624      */
    625     public  BigInteger getVersion() {
    626         return version;
    627     }
    628 
    629     /**
    630      * Returns the message digest algorithms specified in this PKCS7 block.
    631      * @return the array of Digest Algorithms or null if none are specified
    632      *         for the content type.
    633      */
    634     public AlgorithmId[] getDigestAlgorithmIds() {
    635         return  digestAlgorithmIds;
    636     }
    637 
    638     /**
    639      * Returns the content information specified in this PKCS7 block.
    640      */
    641     public ContentInfo getContentInfo() {
    642         return contentInfo;
    643     }
    644 
    645     /**
    646      * Returns the X.509 certificates listed in this PKCS7 block.
    647      * @return a clone of the array of X.509 certificates or null if
    648      *         none are specified for the content type.
    649      */
    650     public X509Certificate[] getCertificates() {
    651         if (certificates != null)
    652             return certificates.clone();
    653         else
    654             return null;
    655     }
    656 
    657     /**
    658      * Returns the X.509 crls listed in this PKCS7 block.
    659      * @return a clone of the array of X.509 crls or null if none
    660      *         are specified for the content type.
    661      */
    662     public X509CRL[] getCRLs() {
    663         if (crls != null)
    664             return crls.clone();
    665         else
    666             return null;
    667     }
    668 
    669     /**
    670      * Returns the signer's information specified in this PKCS7 block.
    671      * @return the array of Signer Infos or null if none are specified
    672      *         for the content type.
    673      */
    674     public SignerInfo[] getSignerInfos() {
    675         return signerInfos;
    676     }
    677 
    678     /**
    679      * Returns the X.509 certificate listed in this PKCS7 block
    680      * which has a matching serial number and Issuer name, or
    681      * null if one is not found.
    682      *
    683      * @param serial the serial number of the certificate to retrieve.
    684      * @param issuerName the Distinguished Name of the Issuer.
    685      */
    686     public X509Certificate getCertificate(BigInteger serial, X500Name issuerName) {
    687         if (certificates != null) {
    688             if (certIssuerNames == null)
    689                 populateCertIssuerNames();
    690             for (int i = 0; i < certificates.length; i++) {
    691                 X509Certificate cert = certificates[i];
    692                 BigInteger thisSerial = cert.getSerialNumber();
    693                 if (serial.equals(thisSerial)
    694                     && issuerName.equals(certIssuerNames[i]))
    695                 {
    696                     return cert;
    697                 }
    698             }
    699         }
    700         return null;
    701     }
    702 
    703     /**
    704      * Populate array of Issuer DNs from certificates and convert
    705      * each Principal to type X500Name if necessary.
    706      */
    707     private void populateCertIssuerNames() {
    708         if (certificates == null)
    709             return;
    710 
    711         certIssuerNames = new Principal[certificates.length];
    712         for (int i = 0; i < certificates.length; i++) {
    713             X509Certificate cert = certificates[i];
    714             Principal certIssuerName = cert.getIssuerDN();
    715             if (!(certIssuerName instanceof X500Name)) {
    716                 // must extract the original encoded form of DN for
    717                 // subsequent name comparison checks (converting to a
    718                 // String and back to an encoded DN could cause the
    719                 // types of String attribute values to be changed)
    720                 try {
    721                     X509CertInfo tbsCert =
    722                         new X509CertInfo(cert.getTBSCertificate());
    723                     certIssuerName = (Principal)
    724                         tbsCert.get(CertificateIssuerName.NAME + "." +
    725                                     CertificateIssuerName.DN_NAME);
    726                 } catch (Exception e) {
    727                     // error generating X500Name object from the cert's
    728                     // issuer DN, leave name as is.
    729                 }
    730             }
    731             certIssuerNames[i] = certIssuerName;
    732         }
    733     }
    734 
    735     /**
    736      * Returns the PKCS7 block in a printable string form.
    737      */
    738     public String toString() {
    739         String out = "";
    740 
    741         out += contentInfo + "\n";
    742         if (version != null)
    743             out += "PKCS7 :: version: " + Debug.toHexString(version) + "\n";
    744         if (digestAlgorithmIds != null) {
    745             out += "PKCS7 :: digest AlgorithmIds: \n";
    746             for (int i = 0; i < digestAlgorithmIds.length; i++)
    747                 out += "\t" + digestAlgorithmIds[i] + "\n";
    748         }
    749         if (certificates != null) {
    750             out += "PKCS7 :: certificates: \n";
    751             for (int i = 0; i < certificates.length; i++)
    752                 out += "\t" + i + ".   " + certificates[i] + "\n";
    753         }
    754         if (crls != null) {
    755             out += "PKCS7 :: crls: \n";
    756             for (int i = 0; i < crls.length; i++)
    757                 out += "\t" + i + ".   " + crls[i] + "\n";
    758         }
    759         if (signerInfos != null) {
    760             out += "PKCS7 :: signer infos: \n";
    761             for (int i = 0; i < signerInfos.length; i++)
    762                 out += ("\t" + i + ".  " + signerInfos[i] + "\n");
    763         }
    764         return out;
    765     }
    766 
    767     /**
    768      * Returns true if this is a JDK1.1.x-style PKCS#7 block, and false
    769      * otherwise.
    770      */
    771     public boolean isOldStyle() {
    772         return this.oldStyle;
    773     }
    774 
    775     /**
    776      * For legacy reasons we need to return exactly the original encoded certificate bytes, instead
    777      * of letting the underlying implementation have a shot at re-encoding the data.
    778      */
    779     private static class VerbatimX509Certificate extends WrappedX509Certificate {
    780         private byte[] encodedVerbatim;
    781 
    782         public VerbatimX509Certificate(X509Certificate wrapped, byte[] encodedVerbatim) {
    783             super(wrapped);
    784             this.encodedVerbatim = encodedVerbatim;
    785         }
    786 
    787         @Override
    788         public byte[] getEncoded() throws CertificateEncodingException {
    789             return encodedVerbatim;
    790         }
    791     }
    792 
    793     private static class WrappedX509Certificate extends X509Certificate {
    794         private final X509Certificate wrapped;
    795 
    796         public WrappedX509Certificate(X509Certificate wrapped) {
    797             this.wrapped = wrapped;
    798         }
    799 
    800         @Override
    801         public Set<String> getCriticalExtensionOIDs() {
    802             return wrapped.getCriticalExtensionOIDs();
    803         }
    804 
    805         @Override
    806         public byte[] getExtensionValue(String oid) {
    807             return wrapped.getExtensionValue(oid);
    808         }
    809 
    810         @Override
    811         public Set<String> getNonCriticalExtensionOIDs() {
    812             return wrapped.getNonCriticalExtensionOIDs();
    813         }
    814 
    815         @Override
    816         public boolean hasUnsupportedCriticalExtension() {
    817             return wrapped.hasUnsupportedCriticalExtension();
    818         }
    819 
    820         @Override
    821         public void checkValidity()
    822                 throws CertificateExpiredException, CertificateNotYetValidException {
    823             wrapped.checkValidity();
    824         }
    825 
    826         @Override
    827         public void checkValidity(Date date)
    828                 throws CertificateExpiredException, CertificateNotYetValidException {
    829             wrapped.checkValidity(date);
    830         }
    831 
    832         @Override
    833         public int getVersion() {
    834             return wrapped.getVersion();
    835         }
    836 
    837         @Override
    838         public BigInteger getSerialNumber() {
    839             return wrapped.getSerialNumber();
    840         }
    841 
    842         @Override
    843         public Principal getIssuerDN() {
    844             return wrapped.getIssuerDN();
    845         }
    846 
    847         @Override
    848         public Principal getSubjectDN() {
    849             return wrapped.getSubjectDN();
    850         }
    851 
    852         @Override
    853         public Date getNotBefore() {
    854             return wrapped.getNotBefore();
    855         }
    856 
    857         @Override
    858         public Date getNotAfter() {
    859             return wrapped.getNotAfter();
    860         }
    861 
    862         @Override
    863         public byte[] getTBSCertificate() throws CertificateEncodingException {
    864             return wrapped.getTBSCertificate();
    865         }
    866 
    867         @Override
    868         public byte[] getSignature() {
    869             return wrapped.getSignature();
    870         }
    871 
    872         @Override
    873         public String getSigAlgName() {
    874             return wrapped.getSigAlgName();
    875         }
    876 
    877         @Override
    878         public String getSigAlgOID() {
    879             return wrapped.getSigAlgOID();
    880         }
    881 
    882         @Override
    883         public byte[] getSigAlgParams() {
    884             return wrapped.getSigAlgParams();
    885         }
    886 
    887         @Override
    888         public boolean[] getIssuerUniqueID() {
    889             return wrapped.getIssuerUniqueID();
    890         }
    891 
    892         @Override
    893         public boolean[] getSubjectUniqueID() {
    894             return wrapped.getSubjectUniqueID();
    895         }
    896 
    897         @Override
    898         public boolean[] getKeyUsage() {
    899             return wrapped.getKeyUsage();
    900         }
    901 
    902         @Override
    903         public int getBasicConstraints() {
    904             return wrapped.getBasicConstraints();
    905         }
    906 
    907         @Override
    908         public byte[] getEncoded() throws CertificateEncodingException {
    909             return wrapped.getEncoded();
    910         }
    911 
    912         @Override
    913         public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException,
    914                 InvalidKeyException, NoSuchProviderException, SignatureException {
    915             wrapped.verify(key);
    916         }
    917 
    918         @Override
    919         public void verify(PublicKey key, String sigProvider)
    920                 throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
    921                 NoSuchProviderException, SignatureException {
    922             wrapped.verify(key, sigProvider);
    923         }
    924 
    925         @Override
    926         public String toString() {
    927             return wrapped.toString();
    928         }
    929 
    930         @Override
    931         public PublicKey getPublicKey() {
    932             return wrapped.getPublicKey();
    933         }
    934 
    935         @Override
    936         public List<String> getExtendedKeyUsage() throws CertificateParsingException {
    937             return wrapped.getExtendedKeyUsage();
    938         }
    939 
    940         @Override
    941         public Collection<List<?>> getIssuerAlternativeNames() throws CertificateParsingException {
    942             return wrapped.getIssuerAlternativeNames();
    943         }
    944 
    945         @Override
    946         public X500Principal getIssuerX500Principal() {
    947             return wrapped.getIssuerX500Principal();
    948         }
    949 
    950         @Override
    951         public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException {
    952             return wrapped.getSubjectAlternativeNames();
    953         }
    954 
    955         @Override
    956         public X500Principal getSubjectX500Principal() {
    957             return wrapped.getSubjectX500Principal();
    958         }
    959 
    960         @Override
    961         public void verify(PublicKey key, Provider sigProvider) throws CertificateException,
    962                 NoSuchAlgorithmException, InvalidKeyException, SignatureException {
    963             wrapped.verify(key, sigProvider);
    964         }
    965     }
    966 }
    967