src/java.base/share/classes/sun/security/x509/X509CertImpl.java
changeset 47216 71c04702a3d5
parent 44476 e275cd2f9319
child 47478 438e0c9f2f17
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.security.x509;
       
    27 
       
    28 import java.io.BufferedReader;
       
    29 import java.io.BufferedInputStream;
       
    30 import java.io.ByteArrayOutputStream;
       
    31 import java.io.IOException;
       
    32 import java.io.InputStream;
       
    33 import java.io.InputStreamReader;
       
    34 import java.io.OutputStream;
       
    35 import java.math.BigInteger;
       
    36 import java.security.*;
       
    37 import java.security.cert.*;
       
    38 import java.security.cert.Certificate;
       
    39 import java.util.*;
       
    40 import java.util.concurrent.ConcurrentHashMap;
       
    41 
       
    42 import javax.security.auth.x500.X500Principal;
       
    43 
       
    44 import sun.security.util.HexDumpEncoder;
       
    45 import java.util.Base64;
       
    46 import sun.security.util.*;
       
    47 import sun.security.provider.X509Factory;
       
    48 
       
    49 /**
       
    50  * The X509CertImpl class represents an X.509 certificate. These certificates
       
    51  * are widely used to support authentication and other functionality in
       
    52  * Internet security systems.  Common applications include Privacy Enhanced
       
    53  * Mail (PEM), Transport Layer Security (SSL), code signing for trusted
       
    54  * software distribution, and Secure Electronic Transactions (SET).  There
       
    55  * is a commercial infrastructure ready to manage large scale deployments
       
    56  * of X.509 identity certificates.
       
    57  *
       
    58  * <P>These certificates are managed and vouched for by <em>Certificate
       
    59  * Authorities</em> (CAs).  CAs are services which create certificates by
       
    60  * placing data in the X.509 standard format and then digitally signing
       
    61  * that data.  Such signatures are quite difficult to forge.  CAs act as
       
    62  * trusted third parties, making introductions between agents who have no
       
    63  * direct knowledge of each other.  CA certificates are either signed by
       
    64  * themselves, or by some other CA such as a "root" CA.
       
    65  *
       
    66  * <P>RFC 1422 is very informative, though it does not describe much
       
    67  * of the recent work being done with X.509 certificates.  That includes
       
    68  * a 1996 version (X.509v3) and a variety of enhancements being made to
       
    69  * facilitate an explosion of personal certificates used as "Internet
       
    70  * Drivers' Licences", or with SET for credit card transactions.
       
    71  *
       
    72  * <P>More recent work includes the IETF PKIX Working Group efforts,
       
    73  * especially RFC2459.
       
    74  *
       
    75  * @author Dave Brownell
       
    76  * @author Amit Kapoor
       
    77  * @author Hemma Prafullchandra
       
    78  * @see X509CertInfo
       
    79  */
       
    80 public class X509CertImpl extends X509Certificate implements DerEncoder {
       
    81 
       
    82     private static final long serialVersionUID = -3457612960190864406L;
       
    83 
       
    84     private static final char DOT = '.';
       
    85     /**
       
    86      * Public attribute names.
       
    87      */
       
    88     public static final String NAME = "x509";
       
    89     public static final String INFO = X509CertInfo.NAME;
       
    90     public static final String ALG_ID = "algorithm";
       
    91     public static final String SIGNATURE = "signature";
       
    92     public static final String SIGNED_CERT = "signed_cert";
       
    93 
       
    94     /**
       
    95      * The following are defined for ease-of-use. These
       
    96      * are the most frequently retrieved attributes.
       
    97      */
       
    98     // x509.info.subject.dname
       
    99     public static final String SUBJECT_DN = NAME + DOT + INFO + DOT +
       
   100                                X509CertInfo.SUBJECT + DOT + X509CertInfo.DN_NAME;
       
   101     // x509.info.issuer.dname
       
   102     public static final String ISSUER_DN = NAME + DOT + INFO + DOT +
       
   103                                X509CertInfo.ISSUER + DOT + X509CertInfo.DN_NAME;
       
   104     // x509.info.serialNumber.number
       
   105     public static final String SERIAL_ID = NAME + DOT + INFO + DOT +
       
   106                                X509CertInfo.SERIAL_NUMBER + DOT +
       
   107                                CertificateSerialNumber.NUMBER;
       
   108     // x509.info.key.value
       
   109     public static final String PUBLIC_KEY = NAME + DOT + INFO + DOT +
       
   110                                X509CertInfo.KEY + DOT +
       
   111                                CertificateX509Key.KEY;
       
   112 
       
   113     // x509.info.version.value
       
   114     public static final String VERSION = NAME + DOT + INFO + DOT +
       
   115                                X509CertInfo.VERSION + DOT +
       
   116                                CertificateVersion.VERSION;
       
   117 
       
   118     // x509.algorithm
       
   119     public static final String SIG_ALG = NAME + DOT + ALG_ID;
       
   120 
       
   121     // x509.signature
       
   122     public static final String SIG = NAME + DOT + SIGNATURE;
       
   123 
       
   124     // when we sign and decode we set this to true
       
   125     // this is our means to make certificates immutable
       
   126     private boolean readOnly = false;
       
   127 
       
   128     // Certificate data, and its envelope
       
   129     private byte[]              signedCert = null;
       
   130     protected X509CertInfo      info = null;
       
   131     protected AlgorithmId       algId = null;
       
   132     protected byte[]            signature = null;
       
   133 
       
   134     // recognized extension OIDS
       
   135     private static final String KEY_USAGE_OID = "2.5.29.15";
       
   136     private static final String EXTENDED_KEY_USAGE_OID = "2.5.29.37";
       
   137     private static final String BASIC_CONSTRAINT_OID = "2.5.29.19";
       
   138     private static final String SUBJECT_ALT_NAME_OID = "2.5.29.17";
       
   139     private static final String ISSUER_ALT_NAME_OID = "2.5.29.18";
       
   140     private static final String AUTH_INFO_ACCESS_OID = "1.3.6.1.5.5.7.1.1";
       
   141 
       
   142     // number of standard key usage bits.
       
   143     private static final int NUM_STANDARD_KEY_USAGE = 9;
       
   144 
       
   145     // SubjectAlterntativeNames cache
       
   146     private Collection<List<?>> subjectAlternativeNames;
       
   147 
       
   148     // IssuerAlternativeNames cache
       
   149     private Collection<List<?>> issuerAlternativeNames;
       
   150 
       
   151     // ExtendedKeyUsage cache
       
   152     private List<String> extKeyUsage;
       
   153 
       
   154     // AuthorityInformationAccess cache
       
   155     private Set<AccessDescription> authInfoAccess;
       
   156 
       
   157     /**
       
   158      * PublicKey that has previously been used to verify
       
   159      * the signature of this certificate. Null if the certificate has not
       
   160      * yet been verified.
       
   161      */
       
   162     private PublicKey verifiedPublicKey;
       
   163     /**
       
   164      * If verifiedPublicKey is not null, name of the provider used to
       
   165      * successfully verify the signature of this certificate, or the
       
   166      * empty String if no provider was explicitly specified.
       
   167      */
       
   168     private String verifiedProvider;
       
   169     /**
       
   170      * If verifiedPublicKey is not null, result of the verification using
       
   171      * verifiedPublicKey and verifiedProvider. If true, verification was
       
   172      * successful, if false, it failed.
       
   173      */
       
   174     private boolean verificationResult;
       
   175 
       
   176     /**
       
   177      * Default constructor.
       
   178      */
       
   179     public X509CertImpl() { }
       
   180 
       
   181     /**
       
   182      * Unmarshals a certificate from its encoded form, parsing the
       
   183      * encoded bytes.  This form of constructor is used by agents which
       
   184      * need to examine and use certificate contents.  That is, this is
       
   185      * one of the more commonly used constructors.  Note that the buffer
       
   186      * must include only a certificate, and no "garbage" may be left at
       
   187      * the end.  If you need to ignore data at the end of a certificate,
       
   188      * use another constructor.
       
   189      *
       
   190      * @param certData the encoded bytes, with no trailing padding.
       
   191      * @exception CertificateException on parsing and initialization errors.
       
   192      */
       
   193     public X509CertImpl(byte[] certData) throws CertificateException {
       
   194         try {
       
   195             parse(new DerValue(certData));
       
   196         } catch (IOException e) {
       
   197             signedCert = null;
       
   198             throw new CertificateException("Unable to initialize, " + e, e);
       
   199         }
       
   200     }
       
   201 
       
   202     /**
       
   203      * unmarshals an X.509 certificate from an input stream.  If the
       
   204      * certificate is RFC1421 hex-encoded, then it must begin with
       
   205      * the line X509Factory.BEGIN_CERT and end with the line
       
   206      * X509Factory.END_CERT.
       
   207      *
       
   208      * @param in an input stream holding at least one certificate that may
       
   209      *        be either DER-encoded or RFC1421 hex-encoded version of the
       
   210      *        DER-encoded certificate.
       
   211      * @exception CertificateException on parsing and initialization errors.
       
   212      */
       
   213     public X509CertImpl(InputStream in) throws CertificateException {
       
   214 
       
   215         DerValue der = null;
       
   216 
       
   217         BufferedInputStream inBuffered = new BufferedInputStream(in);
       
   218 
       
   219         // First try reading stream as HEX-encoded DER-encoded bytes,
       
   220         // since not mistakable for raw DER
       
   221         try {
       
   222             inBuffered.mark(Integer.MAX_VALUE);
       
   223             der = readRFC1421Cert(inBuffered);
       
   224         } catch (IOException ioe) {
       
   225             try {
       
   226                 // Next, try reading stream as raw DER-encoded bytes
       
   227                 inBuffered.reset();
       
   228                 der = new DerValue(inBuffered);
       
   229             } catch (IOException ioe1) {
       
   230                 throw new CertificateException("Input stream must be " +
       
   231                                                "either DER-encoded bytes " +
       
   232                                                "or RFC1421 hex-encoded " +
       
   233                                                "DER-encoded bytes: " +
       
   234                                                ioe1.getMessage(), ioe1);
       
   235             }
       
   236         }
       
   237         try {
       
   238             parse(der);
       
   239         } catch (IOException ioe) {
       
   240             signedCert = null;
       
   241             throw new CertificateException("Unable to parse DER value of " +
       
   242                                            "certificate, " + ioe, ioe);
       
   243         }
       
   244     }
       
   245 
       
   246     /**
       
   247      * read input stream as HEX-encoded DER-encoded bytes
       
   248      *
       
   249      * @param in InputStream to read
       
   250      * @return DerValue corresponding to decoded HEX-encoded bytes
       
   251      * @throws IOException if stream can not be interpreted as RFC1421
       
   252      *                     encoded bytes
       
   253      */
       
   254     private DerValue readRFC1421Cert(InputStream in) throws IOException {
       
   255         DerValue der = null;
       
   256         String line = null;
       
   257         BufferedReader certBufferedReader =
       
   258             new BufferedReader(new InputStreamReader(in, "ASCII"));
       
   259         try {
       
   260             line = certBufferedReader.readLine();
       
   261         } catch (IOException ioe1) {
       
   262             throw new IOException("Unable to read InputStream: " +
       
   263                                   ioe1.getMessage());
       
   264         }
       
   265         if (line.equals(X509Factory.BEGIN_CERT)) {
       
   266             /* stream appears to be hex-encoded bytes */
       
   267             ByteArrayOutputStream decstream = new ByteArrayOutputStream();
       
   268             try {
       
   269                 while ((line = certBufferedReader.readLine()) != null) {
       
   270                     if (line.equals(X509Factory.END_CERT)) {
       
   271                         der = new DerValue(decstream.toByteArray());
       
   272                         break;
       
   273                     } else {
       
   274                         decstream.write(Pem.decode(line));
       
   275                     }
       
   276                 }
       
   277             } catch (IOException ioe2) {
       
   278                 throw new IOException("Unable to read InputStream: "
       
   279                                       + ioe2.getMessage());
       
   280             }
       
   281         } else {
       
   282             throw new IOException("InputStream is not RFC1421 hex-encoded " +
       
   283                                   "DER bytes");
       
   284         }
       
   285         return der;
       
   286     }
       
   287 
       
   288     /**
       
   289      * Construct an initialized X509 Certificate. The certificate is stored
       
   290      * in raw form and has to be signed to be useful.
       
   291      *
       
   292      * @param certInfo the X509CertificateInfo which the Certificate is to be
       
   293      *             created from.
       
   294      */
       
   295     public X509CertImpl(X509CertInfo certInfo) {
       
   296         this.info = certInfo;
       
   297     }
       
   298 
       
   299     /**
       
   300      * Unmarshal a certificate from its encoded form, parsing a DER value.
       
   301      * This form of constructor is used by agents which need to examine
       
   302      * and use certificate contents.
       
   303      *
       
   304      * @param derVal the der value containing the encoded cert.
       
   305      * @exception CertificateException on parsing and initialization errors.
       
   306      */
       
   307     public X509CertImpl(DerValue derVal) throws CertificateException {
       
   308         try {
       
   309             parse(derVal);
       
   310         } catch (IOException e) {
       
   311             signedCert = null;
       
   312             throw new CertificateException("Unable to initialize, " + e, e);
       
   313         }
       
   314     }
       
   315 
       
   316     /**
       
   317      * Appends the certificate to an output stream.
       
   318      *
       
   319      * @param out an input stream to which the certificate is appended.
       
   320      * @exception CertificateEncodingException on encoding errors.
       
   321      */
       
   322     public void encode(OutputStream out)
       
   323     throws CertificateEncodingException {
       
   324         if (signedCert == null)
       
   325             throw new CertificateEncodingException(
       
   326                           "Null certificate to encode");
       
   327         try {
       
   328             out.write(signedCert.clone());
       
   329         } catch (IOException e) {
       
   330             throw new CertificateEncodingException(e.toString());
       
   331         }
       
   332     }
       
   333 
       
   334     /**
       
   335      * DER encode this object onto an output stream.
       
   336      * Implements the <code>DerEncoder</code> interface.
       
   337      *
       
   338      * @param out the output stream on which to write the DER encoding.
       
   339      *
       
   340      * @exception IOException on encoding error.
       
   341      */
       
   342     public void derEncode(OutputStream out) throws IOException {
       
   343         if (signedCert == null)
       
   344             throw new IOException("Null certificate to encode");
       
   345         out.write(signedCert.clone());
       
   346     }
       
   347 
       
   348     /**
       
   349      * Returns the encoded form of this certificate. It is
       
   350      * assumed that each certificate type would have only a single
       
   351      * form of encoding; for example, X.509 certificates would
       
   352      * be encoded as ASN.1 DER.
       
   353      *
       
   354      * @exception CertificateEncodingException if an encoding error occurs.
       
   355      */
       
   356     public byte[] getEncoded() throws CertificateEncodingException {
       
   357         return getEncodedInternal().clone();
       
   358     }
       
   359 
       
   360     /**
       
   361      * Returned the encoding as an uncloned byte array. Callers must
       
   362      * guarantee that they neither modify it nor expose it to untrusted
       
   363      * code.
       
   364      */
       
   365     public byte[] getEncodedInternal() throws CertificateEncodingException {
       
   366         if (signedCert == null) {
       
   367             throw new CertificateEncodingException(
       
   368                           "Null certificate to encode");
       
   369         }
       
   370         return signedCert;
       
   371     }
       
   372 
       
   373     /**
       
   374      * Throws an exception if the certificate was not signed using the
       
   375      * verification key provided.  Successfully verifying a certificate
       
   376      * does <em>not</em> indicate that one should trust the entity which
       
   377      * it represents.
       
   378      *
       
   379      * @param key the public key used for verification.
       
   380      *
       
   381      * @exception InvalidKeyException on incorrect key.
       
   382      * @exception NoSuchAlgorithmException on unsupported signature
       
   383      * algorithms.
       
   384      * @exception NoSuchProviderException if there's no default provider.
       
   385      * @exception SignatureException on signature errors.
       
   386      * @exception CertificateException on encoding errors.
       
   387      */
       
   388     public void verify(PublicKey key)
       
   389     throws CertificateException, NoSuchAlgorithmException,
       
   390         InvalidKeyException, NoSuchProviderException, SignatureException {
       
   391 
       
   392         verify(key, "");
       
   393     }
       
   394 
       
   395     /**
       
   396      * Throws an exception if the certificate was not signed using the
       
   397      * verification key provided.  Successfully verifying a certificate
       
   398      * does <em>not</em> indicate that one should trust the entity which
       
   399      * it represents.
       
   400      *
       
   401      * @param key the public key used for verification.
       
   402      * @param sigProvider the name of the provider.
       
   403      *
       
   404      * @exception NoSuchAlgorithmException on unsupported signature
       
   405      * algorithms.
       
   406      * @exception InvalidKeyException on incorrect key.
       
   407      * @exception NoSuchProviderException on incorrect provider.
       
   408      * @exception SignatureException on signature errors.
       
   409      * @exception CertificateException on encoding errors.
       
   410      */
       
   411     public synchronized void verify(PublicKey key, String sigProvider)
       
   412             throws CertificateException, NoSuchAlgorithmException,
       
   413             InvalidKeyException, NoSuchProviderException, SignatureException {
       
   414         if (sigProvider == null) {
       
   415             sigProvider = "";
       
   416         }
       
   417         if ((verifiedPublicKey != null) && verifiedPublicKey.equals(key)) {
       
   418             // this certificate has already been verified using
       
   419             // this public key. Make sure providers match, too.
       
   420             if (sigProvider.equals(verifiedProvider)) {
       
   421                 if (verificationResult) {
       
   422                     return;
       
   423                 } else {
       
   424                     throw new SignatureException("Signature does not match.");
       
   425                 }
       
   426             }
       
   427         }
       
   428         if (signedCert == null) {
       
   429             throw new CertificateEncodingException("Uninitialized certificate");
       
   430         }
       
   431         // Verify the signature ...
       
   432         Signature sigVerf = null;
       
   433         if (sigProvider.length() == 0) {
       
   434             sigVerf = Signature.getInstance(algId.getName());
       
   435         } else {
       
   436             sigVerf = Signature.getInstance(algId.getName(), sigProvider);
       
   437         }
       
   438         sigVerf.initVerify(key);
       
   439 
       
   440         byte[] rawCert = info.getEncodedInfo();
       
   441         sigVerf.update(rawCert, 0, rawCert.length);
       
   442 
       
   443         // verify may throw SignatureException for invalid encodings, etc.
       
   444         verificationResult = sigVerf.verify(signature);
       
   445         verifiedPublicKey = key;
       
   446         verifiedProvider = sigProvider;
       
   447 
       
   448         if (verificationResult == false) {
       
   449             throw new SignatureException("Signature does not match.");
       
   450         }
       
   451     }
       
   452 
       
   453     /**
       
   454      * Throws an exception if the certificate was not signed using the
       
   455      * verification key provided.  This method uses the signature verification
       
   456      * engine supplied by the specified provider. Note that the specified
       
   457      * Provider object does not have to be registered in the provider list.
       
   458      * Successfully verifying a certificate does <em>not</em> indicate that one
       
   459      * should trust the entity which it represents.
       
   460      *
       
   461      * @param key the public key used for verification.
       
   462      * @param sigProvider the provider.
       
   463      *
       
   464      * @exception NoSuchAlgorithmException on unsupported signature
       
   465      * algorithms.
       
   466      * @exception InvalidKeyException on incorrect key.
       
   467      * @exception SignatureException on signature errors.
       
   468      * @exception CertificateException on encoding errors.
       
   469      */
       
   470     public synchronized void verify(PublicKey key, Provider sigProvider)
       
   471             throws CertificateException, NoSuchAlgorithmException,
       
   472             InvalidKeyException, SignatureException {
       
   473         if (signedCert == null) {
       
   474             throw new CertificateEncodingException("Uninitialized certificate");
       
   475         }
       
   476         // Verify the signature ...
       
   477         Signature sigVerf = null;
       
   478         if (sigProvider == null) {
       
   479             sigVerf = Signature.getInstance(algId.getName());
       
   480         } else {
       
   481             sigVerf = Signature.getInstance(algId.getName(), sigProvider);
       
   482         }
       
   483         sigVerf.initVerify(key);
       
   484 
       
   485         byte[] rawCert = info.getEncodedInfo();
       
   486         sigVerf.update(rawCert, 0, rawCert.length);
       
   487 
       
   488         // verify may throw SignatureException for invalid encodings, etc.
       
   489         verificationResult = sigVerf.verify(signature);
       
   490         verifiedPublicKey = key;
       
   491 
       
   492         if (verificationResult == false) {
       
   493             throw new SignatureException("Signature does not match.");
       
   494         }
       
   495     }
       
   496 
       
   497     /**
       
   498      * Creates an X.509 certificate, and signs it using the given key
       
   499      * (associating a signature algorithm and an X.500 name).
       
   500      * This operation is used to implement the certificate generation
       
   501      * functionality of a certificate authority.
       
   502      *
       
   503      * @param key the private key used for signing.
       
   504      * @param algorithm the name of the signature algorithm used.
       
   505      *
       
   506      * @exception InvalidKeyException on incorrect key.
       
   507      * @exception NoSuchAlgorithmException on unsupported signature
       
   508      * algorithms.
       
   509      * @exception NoSuchProviderException if there's no default provider.
       
   510      * @exception SignatureException on signature errors.
       
   511      * @exception CertificateException on encoding errors.
       
   512      */
       
   513     public void sign(PrivateKey key, String algorithm)
       
   514     throws CertificateException, NoSuchAlgorithmException,
       
   515         InvalidKeyException, NoSuchProviderException, SignatureException {
       
   516         sign(key, algorithm, null);
       
   517     }
       
   518 
       
   519     /**
       
   520      * Creates an X.509 certificate, and signs it using the given key
       
   521      * (associating a signature algorithm and an X.500 name).
       
   522      * This operation is used to implement the certificate generation
       
   523      * functionality of a certificate authority.
       
   524      *
       
   525      * @param key the private key used for signing.
       
   526      * @param algorithm the name of the signature algorithm used.
       
   527      * @param provider the name of the provider.
       
   528      *
       
   529      * @exception NoSuchAlgorithmException on unsupported signature
       
   530      * algorithms.
       
   531      * @exception InvalidKeyException on incorrect key.
       
   532      * @exception NoSuchProviderException on incorrect provider.
       
   533      * @exception SignatureException on signature errors.
       
   534      * @exception CertificateException on encoding errors.
       
   535      */
       
   536     public void sign(PrivateKey key, String algorithm, String provider)
       
   537     throws CertificateException, NoSuchAlgorithmException,
       
   538         InvalidKeyException, NoSuchProviderException, SignatureException {
       
   539         try {
       
   540             if (readOnly)
       
   541                 throw new CertificateEncodingException(
       
   542                               "cannot over-write existing certificate");
       
   543             Signature sigEngine = null;
       
   544             if ((provider == null) || (provider.length() == 0))
       
   545                 sigEngine = Signature.getInstance(algorithm);
       
   546             else
       
   547                 sigEngine = Signature.getInstance(algorithm, provider);
       
   548 
       
   549             sigEngine.initSign(key);
       
   550 
       
   551                                 // in case the name is reset
       
   552             algId = AlgorithmId.get(sigEngine.getAlgorithm());
       
   553 
       
   554             DerOutputStream out = new DerOutputStream();
       
   555             DerOutputStream tmp = new DerOutputStream();
       
   556 
       
   557             // encode certificate info
       
   558             info.encode(tmp);
       
   559             byte[] rawCert = tmp.toByteArray();
       
   560 
       
   561             // encode algorithm identifier
       
   562             algId.encode(tmp);
       
   563 
       
   564             // Create and encode the signature itself.
       
   565             sigEngine.update(rawCert, 0, rawCert.length);
       
   566             signature = sigEngine.sign();
       
   567             tmp.putBitString(signature);
       
   568 
       
   569             // Wrap the signed data in a SEQUENCE { data, algorithm, sig }
       
   570             out.write(DerValue.tag_Sequence, tmp);
       
   571             signedCert = out.toByteArray();
       
   572             readOnly = true;
       
   573 
       
   574         } catch (IOException e) {
       
   575             throw new CertificateEncodingException(e.toString());
       
   576       }
       
   577     }
       
   578 
       
   579     /**
       
   580      * Checks that the certificate is currently valid, i.e. the current
       
   581      * time is within the specified validity period.
       
   582      *
       
   583      * @exception CertificateExpiredException if the certificate has expired.
       
   584      * @exception CertificateNotYetValidException if the certificate is not
       
   585      * yet valid.
       
   586      */
       
   587     public void checkValidity()
       
   588     throws CertificateExpiredException, CertificateNotYetValidException {
       
   589         Date date = new Date();
       
   590         checkValidity(date);
       
   591     }
       
   592 
       
   593     /**
       
   594      * Checks that the specified date is within the certificate's
       
   595      * validity period, or basically if the certificate would be
       
   596      * valid at the specified date/time.
       
   597      *
       
   598      * @param date the Date to check against to see if this certificate
       
   599      *        is valid at that date/time.
       
   600      *
       
   601      * @exception CertificateExpiredException if the certificate has expired
       
   602      * with respect to the <code>date</code> supplied.
       
   603      * @exception CertificateNotYetValidException if the certificate is not
       
   604      * yet valid with respect to the <code>date</code> supplied.
       
   605      */
       
   606     public void checkValidity(Date date)
       
   607     throws CertificateExpiredException, CertificateNotYetValidException {
       
   608 
       
   609         CertificateValidity interval = null;
       
   610         try {
       
   611             interval = (CertificateValidity)info.get(CertificateValidity.NAME);
       
   612         } catch (Exception e) {
       
   613             throw new CertificateNotYetValidException("Incorrect validity period");
       
   614         }
       
   615         if (interval == null)
       
   616             throw new CertificateNotYetValidException("Null validity period");
       
   617         interval.valid(date);
       
   618     }
       
   619 
       
   620     /**
       
   621      * Return the requested attribute from the certificate.
       
   622      *
       
   623      * Note that the X509CertInfo is not cloned for performance reasons.
       
   624      * Callers must ensure that they do not modify it. All other
       
   625      * attributes are cloned.
       
   626      *
       
   627      * @param name the name of the attribute.
       
   628      * @exception CertificateParsingException on invalid attribute identifier.
       
   629      */
       
   630     public Object get(String name)
       
   631     throws CertificateParsingException {
       
   632         X509AttributeName attr = new X509AttributeName(name);
       
   633         String id = attr.getPrefix();
       
   634         if (!(id.equalsIgnoreCase(NAME))) {
       
   635             throw new CertificateParsingException("Invalid root of "
       
   636                           + "attribute name, expected [" + NAME +
       
   637                           "], received " + "[" + id + "]");
       
   638         }
       
   639         attr = new X509AttributeName(attr.getSuffix());
       
   640         id = attr.getPrefix();
       
   641 
       
   642         if (id.equalsIgnoreCase(INFO)) {
       
   643             if (info == null) {
       
   644                 return null;
       
   645             }
       
   646             if (attr.getSuffix() != null) {
       
   647                 try {
       
   648                     return info.get(attr.getSuffix());
       
   649                 } catch (IOException e) {
       
   650                     throw new CertificateParsingException(e.toString());
       
   651                 } catch (CertificateException e) {
       
   652                     throw new CertificateParsingException(e.toString());
       
   653                 }
       
   654             } else {
       
   655                 return info;
       
   656             }
       
   657         } else if (id.equalsIgnoreCase(ALG_ID)) {
       
   658             return(algId);
       
   659         } else if (id.equalsIgnoreCase(SIGNATURE)) {
       
   660             if (signature != null)
       
   661                 return signature.clone();
       
   662             else
       
   663                 return null;
       
   664         } else if (id.equalsIgnoreCase(SIGNED_CERT)) {
       
   665             if (signedCert != null)
       
   666                 return signedCert.clone();
       
   667             else
       
   668                 return null;
       
   669         } else {
       
   670             throw new CertificateParsingException("Attribute name not "
       
   671                  + "recognized or get() not allowed for the same: " + id);
       
   672         }
       
   673     }
       
   674 
       
   675     /**
       
   676      * Set the requested attribute in the certificate.
       
   677      *
       
   678      * @param name the name of the attribute.
       
   679      * @param obj the value of the attribute.
       
   680      * @exception CertificateException on invalid attribute identifier.
       
   681      * @exception IOException on encoding error of attribute.
       
   682      */
       
   683     public void set(String name, Object obj)
       
   684     throws CertificateException, IOException {
       
   685         // check if immutable
       
   686         if (readOnly)
       
   687             throw new CertificateException("cannot over-write existing"
       
   688                                            + " certificate");
       
   689 
       
   690         X509AttributeName attr = new X509AttributeName(name);
       
   691         String id = attr.getPrefix();
       
   692         if (!(id.equalsIgnoreCase(NAME))) {
       
   693             throw new CertificateException("Invalid root of attribute name,"
       
   694                            + " expected [" + NAME + "], received " + id);
       
   695         }
       
   696         attr = new X509AttributeName(attr.getSuffix());
       
   697         id = attr.getPrefix();
       
   698 
       
   699         if (id.equalsIgnoreCase(INFO)) {
       
   700             if (attr.getSuffix() == null) {
       
   701                 if (!(obj instanceof X509CertInfo)) {
       
   702                     throw new CertificateException("Attribute value should"
       
   703                                     + " be of type X509CertInfo.");
       
   704                 }
       
   705                 info = (X509CertInfo)obj;
       
   706                 signedCert = null;  //reset this as certificate data has changed
       
   707             } else {
       
   708                 info.set(attr.getSuffix(), obj);
       
   709                 signedCert = null;  //reset this as certificate data has changed
       
   710             }
       
   711         } else {
       
   712             throw new CertificateException("Attribute name not recognized or " +
       
   713                               "set() not allowed for the same: " + id);
       
   714         }
       
   715     }
       
   716 
       
   717     /**
       
   718      * Delete the requested attribute from the certificate.
       
   719      *
       
   720      * @param name the name of the attribute.
       
   721      * @exception CertificateException on invalid attribute identifier.
       
   722      * @exception IOException on other errors.
       
   723      */
       
   724     public void delete(String name)
       
   725     throws CertificateException, IOException {
       
   726         // check if immutable
       
   727         if (readOnly)
       
   728             throw new CertificateException("cannot over-write existing"
       
   729                                            + " certificate");
       
   730 
       
   731         X509AttributeName attr = new X509AttributeName(name);
       
   732         String id = attr.getPrefix();
       
   733         if (!(id.equalsIgnoreCase(NAME))) {
       
   734             throw new CertificateException("Invalid root of attribute name,"
       
   735                                    + " expected ["
       
   736                                    + NAME + "], received " + id);
       
   737         }
       
   738         attr = new X509AttributeName(attr.getSuffix());
       
   739         id = attr.getPrefix();
       
   740 
       
   741         if (id.equalsIgnoreCase(INFO)) {
       
   742             if (attr.getSuffix() != null) {
       
   743                 info = null;
       
   744             } else {
       
   745                 info.delete(attr.getSuffix());
       
   746             }
       
   747         } else if (id.equalsIgnoreCase(ALG_ID)) {
       
   748             algId = null;
       
   749         } else if (id.equalsIgnoreCase(SIGNATURE)) {
       
   750             signature = null;
       
   751         } else if (id.equalsIgnoreCase(SIGNED_CERT)) {
       
   752             signedCert = null;
       
   753         } else {
       
   754             throw new CertificateException("Attribute name not recognized or " +
       
   755                               "delete() not allowed for the same: " + id);
       
   756         }
       
   757     }
       
   758 
       
   759     /**
       
   760      * Return an enumeration of names of attributes existing within this
       
   761      * attribute.
       
   762      */
       
   763     public Enumeration<String> getElements() {
       
   764         AttributeNameEnumeration elements = new AttributeNameEnumeration();
       
   765         elements.addElement(NAME + DOT + INFO);
       
   766         elements.addElement(NAME + DOT + ALG_ID);
       
   767         elements.addElement(NAME + DOT + SIGNATURE);
       
   768         elements.addElement(NAME + DOT + SIGNED_CERT);
       
   769 
       
   770         return elements.elements();
       
   771     }
       
   772 
       
   773     /**
       
   774      * Return the name of this attribute.
       
   775      */
       
   776     public String getName() {
       
   777         return(NAME);
       
   778     }
       
   779 
       
   780     /**
       
   781      * Returns a printable representation of the certificate.  This does not
       
   782      * contain all the information available to distinguish this from any
       
   783      * other certificate.  The certificate must be fully constructed
       
   784      * before this function may be called.
       
   785      */
       
   786     public String toString() {
       
   787         if (info == null || algId == null || signature == null)
       
   788             return "";
       
   789 
       
   790         HexDumpEncoder encoder = new HexDumpEncoder();
       
   791         return "[\n" + info + '\n' +
       
   792             "  Algorithm: [" + algId + "]\n" +
       
   793             "  Signature:\n" + encoder.encodeBuffer(signature) + "\n]";
       
   794     }
       
   795 
       
   796     // the strongly typed gets, as per java.security.cert.X509Certificate
       
   797 
       
   798     /**
       
   799      * Gets the publickey from this certificate.
       
   800      *
       
   801      * @return the publickey.
       
   802      */
       
   803     public PublicKey getPublicKey() {
       
   804         if (info == null)
       
   805             return null;
       
   806         try {
       
   807             PublicKey key = (PublicKey)info.get(CertificateX509Key.NAME
       
   808                                 + DOT + CertificateX509Key.KEY);
       
   809             return key;
       
   810         } catch (Exception e) {
       
   811             return null;
       
   812         }
       
   813     }
       
   814 
       
   815     /**
       
   816      * Gets the version number from the certificate.
       
   817      *
       
   818      * @return the version number, i.e. 1, 2 or 3.
       
   819      */
       
   820     public int getVersion() {
       
   821         if (info == null)
       
   822             return -1;
       
   823         try {
       
   824             int vers = ((Integer)info.get(CertificateVersion.NAME
       
   825                         + DOT + CertificateVersion.VERSION)).intValue();
       
   826             return vers+1;
       
   827         } catch (Exception e) {
       
   828             return -1;
       
   829         }
       
   830     }
       
   831 
       
   832     /**
       
   833      * Gets the serial number from the certificate.
       
   834      *
       
   835      * @return the serial number.
       
   836      */
       
   837     public BigInteger getSerialNumber() {
       
   838         SerialNumber ser = getSerialNumberObject();
       
   839 
       
   840         return ser != null ? ser.getNumber() : null;
       
   841     }
       
   842 
       
   843     /**
       
   844      * Gets the serial number from the certificate as
       
   845      * a SerialNumber object.
       
   846      *
       
   847      * @return the serial number.
       
   848      */
       
   849     public SerialNumber getSerialNumberObject() {
       
   850         if (info == null)
       
   851             return null;
       
   852         try {
       
   853             SerialNumber ser = (SerialNumber)info.get(
       
   854                               CertificateSerialNumber.NAME + DOT +
       
   855                               CertificateSerialNumber.NUMBER);
       
   856            return ser;
       
   857         } catch (Exception e) {
       
   858             return null;
       
   859         }
       
   860     }
       
   861 
       
   862 
       
   863     /**
       
   864      * Gets the subject distinguished name from the certificate.
       
   865      *
       
   866      * @return the subject name.
       
   867      */
       
   868     public Principal getSubjectDN() {
       
   869         if (info == null)
       
   870             return null;
       
   871         try {
       
   872             Principal subject = (Principal)info.get(X509CertInfo.SUBJECT + DOT +
       
   873                                                     X509CertInfo.DN_NAME);
       
   874             return subject;
       
   875         } catch (Exception e) {
       
   876             return null;
       
   877         }
       
   878     }
       
   879 
       
   880     /**
       
   881      * Get subject name as X500Principal. Overrides implementation in
       
   882      * X509Certificate with a slightly more efficient version that is
       
   883      * also aware of X509CertImpl mutability.
       
   884      */
       
   885     public X500Principal getSubjectX500Principal() {
       
   886         if (info == null) {
       
   887             return null;
       
   888         }
       
   889         try {
       
   890             X500Principal subject = (X500Principal)info.get(
       
   891                                             X509CertInfo.SUBJECT + DOT +
       
   892                                             "x500principal");
       
   893             return subject;
       
   894         } catch (Exception e) {
       
   895             return null;
       
   896         }
       
   897     }
       
   898 
       
   899     /**
       
   900      * Gets the issuer distinguished name from the certificate.
       
   901      *
       
   902      * @return the issuer name.
       
   903      */
       
   904     public Principal getIssuerDN() {
       
   905         if (info == null)
       
   906             return null;
       
   907         try {
       
   908             Principal issuer = (Principal)info.get(X509CertInfo.ISSUER + DOT +
       
   909                                                    X509CertInfo.DN_NAME);
       
   910             return issuer;
       
   911         } catch (Exception e) {
       
   912             return null;
       
   913         }
       
   914     }
       
   915 
       
   916     /**
       
   917      * Get issuer name as X500Principal. Overrides implementation in
       
   918      * X509Certificate with a slightly more efficient version that is
       
   919      * also aware of X509CertImpl mutability.
       
   920      */
       
   921     public X500Principal getIssuerX500Principal() {
       
   922         if (info == null) {
       
   923             return null;
       
   924         }
       
   925         try {
       
   926             X500Principal issuer = (X500Principal)info.get(
       
   927                                             X509CertInfo.ISSUER + DOT +
       
   928                                             "x500principal");
       
   929             return issuer;
       
   930         } catch (Exception e) {
       
   931             return null;
       
   932         }
       
   933     }
       
   934 
       
   935     /**
       
   936      * Gets the notBefore date from the validity period of the certificate.
       
   937      *
       
   938      * @return the start date of the validity period.
       
   939      */
       
   940     public Date getNotBefore() {
       
   941         if (info == null)
       
   942             return null;
       
   943         try {
       
   944             Date d = (Date) info.get(CertificateValidity.NAME + DOT +
       
   945                                         CertificateValidity.NOT_BEFORE);
       
   946             return d;
       
   947         } catch (Exception e) {
       
   948             return null;
       
   949         }
       
   950     }
       
   951 
       
   952     /**
       
   953      * Gets the notAfter date from the validity period of the certificate.
       
   954      *
       
   955      * @return the end date of the validity period.
       
   956      */
       
   957     public Date getNotAfter() {
       
   958         if (info == null)
       
   959             return null;
       
   960         try {
       
   961             Date d = (Date) info.get(CertificateValidity.NAME + DOT +
       
   962                                      CertificateValidity.NOT_AFTER);
       
   963             return d;
       
   964         } catch (Exception e) {
       
   965             return null;
       
   966         }
       
   967     }
       
   968 
       
   969     /**
       
   970      * Gets the DER encoded certificate informations, the
       
   971      * <code>tbsCertificate</code> from this certificate.
       
   972      * This can be used to verify the signature independently.
       
   973      *
       
   974      * @return the DER encoded certificate information.
       
   975      * @exception CertificateEncodingException if an encoding error occurs.
       
   976      */
       
   977     public byte[] getTBSCertificate() throws CertificateEncodingException {
       
   978         if (info != null) {
       
   979             return info.getEncodedInfo();
       
   980         } else
       
   981             throw new CertificateEncodingException("Uninitialized certificate");
       
   982     }
       
   983 
       
   984     /**
       
   985      * Gets the raw Signature bits from the certificate.
       
   986      *
       
   987      * @return the signature.
       
   988      */
       
   989     public byte[] getSignature() {
       
   990         if (signature == null)
       
   991             return null;
       
   992         return signature.clone();
       
   993     }
       
   994 
       
   995     /**
       
   996      * Gets the signature algorithm name for the certificate
       
   997      * signature algorithm.
       
   998      * For example, the string "SHA-1/DSA" or "DSS".
       
   999      *
       
  1000      * @return the signature algorithm name.
       
  1001      */
       
  1002     public String getSigAlgName() {
       
  1003         if (algId == null)
       
  1004             return null;
       
  1005         return (algId.getName());
       
  1006     }
       
  1007 
       
  1008     /**
       
  1009      * Gets the signature algorithm OID string from the certificate.
       
  1010      * For example, the string "1.2.840.10040.4.3"
       
  1011      *
       
  1012      * @return the signature algorithm oid string.
       
  1013      */
       
  1014     public String getSigAlgOID() {
       
  1015         if (algId == null)
       
  1016             return null;
       
  1017         ObjectIdentifier oid = algId.getOID();
       
  1018         return (oid.toString());
       
  1019     }
       
  1020 
       
  1021     /**
       
  1022      * Gets the DER encoded signature algorithm parameters from this
       
  1023      * certificate's signature algorithm.
       
  1024      *
       
  1025      * @return the DER encoded signature algorithm parameters, or
       
  1026      *         null if no parameters are present.
       
  1027      */
       
  1028     public byte[] getSigAlgParams() {
       
  1029         if (algId == null)
       
  1030             return null;
       
  1031         try {
       
  1032             return algId.getEncodedParams();
       
  1033         } catch (IOException e) {
       
  1034             return null;
       
  1035         }
       
  1036     }
       
  1037 
       
  1038     /**
       
  1039      * Gets the Issuer Unique Identity from the certificate.
       
  1040      *
       
  1041      * @return the Issuer Unique Identity.
       
  1042      */
       
  1043     public boolean[] getIssuerUniqueID() {
       
  1044         if (info == null)
       
  1045             return null;
       
  1046         try {
       
  1047             UniqueIdentity id = (UniqueIdentity)info.get(
       
  1048                                  X509CertInfo.ISSUER_ID);
       
  1049             if (id == null)
       
  1050                 return null;
       
  1051             else
       
  1052                 return (id.getId());
       
  1053         } catch (Exception e) {
       
  1054             return null;
       
  1055         }
       
  1056     }
       
  1057 
       
  1058     /**
       
  1059      * Gets the Subject Unique Identity from the certificate.
       
  1060      *
       
  1061      * @return the Subject Unique Identity.
       
  1062      */
       
  1063     public boolean[] getSubjectUniqueID() {
       
  1064         if (info == null)
       
  1065             return null;
       
  1066         try {
       
  1067             UniqueIdentity id = (UniqueIdentity)info.get(
       
  1068                                  X509CertInfo.SUBJECT_ID);
       
  1069             if (id == null)
       
  1070                 return null;
       
  1071             else
       
  1072                 return (id.getId());
       
  1073         } catch (Exception e) {
       
  1074             return null;
       
  1075         }
       
  1076     }
       
  1077 
       
  1078     public KeyIdentifier getAuthKeyId() {
       
  1079         AuthorityKeyIdentifierExtension aki
       
  1080             = getAuthorityKeyIdentifierExtension();
       
  1081         if (aki != null) {
       
  1082             try {
       
  1083                 return (KeyIdentifier)aki.get(
       
  1084                     AuthorityKeyIdentifierExtension.KEY_ID);
       
  1085             } catch (IOException ioe) {} // not possible
       
  1086         }
       
  1087         return null;
       
  1088     }
       
  1089 
       
  1090     /**
       
  1091      * Returns the subject's key identifier, or null
       
  1092      */
       
  1093     public KeyIdentifier getSubjectKeyId() {
       
  1094         SubjectKeyIdentifierExtension ski = getSubjectKeyIdentifierExtension();
       
  1095         if (ski != null) {
       
  1096             try {
       
  1097                 return ski.get(SubjectKeyIdentifierExtension.KEY_ID);
       
  1098             } catch (IOException ioe) {} // not possible
       
  1099         }
       
  1100         return null;
       
  1101     }
       
  1102 
       
  1103     /**
       
  1104      * Get AuthorityKeyIdentifier extension
       
  1105      * @return AuthorityKeyIdentifier object or null (if no such object
       
  1106      * in certificate)
       
  1107      */
       
  1108     public AuthorityKeyIdentifierExtension getAuthorityKeyIdentifierExtension()
       
  1109     {
       
  1110         return (AuthorityKeyIdentifierExtension)
       
  1111             getExtension(PKIXExtensions.AuthorityKey_Id);
       
  1112     }
       
  1113 
       
  1114     /**
       
  1115      * Get BasicConstraints extension
       
  1116      * @return BasicConstraints object or null (if no such object in
       
  1117      * certificate)
       
  1118      */
       
  1119     public BasicConstraintsExtension getBasicConstraintsExtension() {
       
  1120         return (BasicConstraintsExtension)
       
  1121             getExtension(PKIXExtensions.BasicConstraints_Id);
       
  1122     }
       
  1123 
       
  1124     /**
       
  1125      * Get CertificatePoliciesExtension
       
  1126      * @return CertificatePoliciesExtension or null (if no such object in
       
  1127      * certificate)
       
  1128      */
       
  1129     public CertificatePoliciesExtension getCertificatePoliciesExtension() {
       
  1130         return (CertificatePoliciesExtension)
       
  1131             getExtension(PKIXExtensions.CertificatePolicies_Id);
       
  1132     }
       
  1133 
       
  1134     /**
       
  1135      * Get ExtendedKeyUsage extension
       
  1136      * @return ExtendedKeyUsage extension object or null (if no such object
       
  1137      * in certificate)
       
  1138      */
       
  1139     public ExtendedKeyUsageExtension getExtendedKeyUsageExtension() {
       
  1140         return (ExtendedKeyUsageExtension)
       
  1141             getExtension(PKIXExtensions.ExtendedKeyUsage_Id);
       
  1142     }
       
  1143 
       
  1144     /**
       
  1145      * Get IssuerAlternativeName extension
       
  1146      * @return IssuerAlternativeName object or null (if no such object in
       
  1147      * certificate)
       
  1148      */
       
  1149     public IssuerAlternativeNameExtension getIssuerAlternativeNameExtension() {
       
  1150         return (IssuerAlternativeNameExtension)
       
  1151             getExtension(PKIXExtensions.IssuerAlternativeName_Id);
       
  1152     }
       
  1153 
       
  1154     /**
       
  1155      * Get NameConstraints extension
       
  1156      * @return NameConstraints object or null (if no such object in certificate)
       
  1157      */
       
  1158     public NameConstraintsExtension getNameConstraintsExtension() {
       
  1159         return (NameConstraintsExtension)
       
  1160             getExtension(PKIXExtensions.NameConstraints_Id);
       
  1161     }
       
  1162 
       
  1163     /**
       
  1164      * Get PolicyConstraints extension
       
  1165      * @return PolicyConstraints object or null (if no such object in
       
  1166      * certificate)
       
  1167      */
       
  1168     public PolicyConstraintsExtension getPolicyConstraintsExtension() {
       
  1169         return (PolicyConstraintsExtension)
       
  1170             getExtension(PKIXExtensions.PolicyConstraints_Id);
       
  1171     }
       
  1172 
       
  1173     /**
       
  1174      * Get PolicyMappingsExtension extension
       
  1175      * @return PolicyMappingsExtension object or null (if no such object
       
  1176      * in certificate)
       
  1177      */
       
  1178     public PolicyMappingsExtension getPolicyMappingsExtension() {
       
  1179         return (PolicyMappingsExtension)
       
  1180             getExtension(PKIXExtensions.PolicyMappings_Id);
       
  1181     }
       
  1182 
       
  1183     /**
       
  1184      * Get PrivateKeyUsage extension
       
  1185      * @return PrivateKeyUsage object or null (if no such object in certificate)
       
  1186      */
       
  1187     public PrivateKeyUsageExtension getPrivateKeyUsageExtension() {
       
  1188         return (PrivateKeyUsageExtension)
       
  1189             getExtension(PKIXExtensions.PrivateKeyUsage_Id);
       
  1190     }
       
  1191 
       
  1192     /**
       
  1193      * Get SubjectAlternativeName extension
       
  1194      * @return SubjectAlternativeName object or null (if no such object in
       
  1195      * certificate)
       
  1196      */
       
  1197     public SubjectAlternativeNameExtension getSubjectAlternativeNameExtension()
       
  1198     {
       
  1199         return (SubjectAlternativeNameExtension)
       
  1200             getExtension(PKIXExtensions.SubjectAlternativeName_Id);
       
  1201     }
       
  1202 
       
  1203     /**
       
  1204      * Get SubjectKeyIdentifier extension
       
  1205      * @return SubjectKeyIdentifier object or null (if no such object in
       
  1206      * certificate)
       
  1207      */
       
  1208     public SubjectKeyIdentifierExtension getSubjectKeyIdentifierExtension() {
       
  1209         return (SubjectKeyIdentifierExtension)
       
  1210             getExtension(PKIXExtensions.SubjectKey_Id);
       
  1211     }
       
  1212 
       
  1213     /**
       
  1214      * Get CRLDistributionPoints extension
       
  1215      * @return CRLDistributionPoints object or null (if no such object in
       
  1216      * certificate)
       
  1217      */
       
  1218     public CRLDistributionPointsExtension getCRLDistributionPointsExtension() {
       
  1219         return (CRLDistributionPointsExtension)
       
  1220             getExtension(PKIXExtensions.CRLDistributionPoints_Id);
       
  1221     }
       
  1222 
       
  1223     /**
       
  1224      * Return true if a critical extension is found that is
       
  1225      * not supported, otherwise return false.
       
  1226      */
       
  1227     public boolean hasUnsupportedCriticalExtension() {
       
  1228         if (info == null)
       
  1229             return false;
       
  1230         try {
       
  1231             CertificateExtensions exts = (CertificateExtensions)info.get(
       
  1232                                          CertificateExtensions.NAME);
       
  1233             if (exts == null)
       
  1234                 return false;
       
  1235             return exts.hasUnsupportedCriticalExtension();
       
  1236         } catch (Exception e) {
       
  1237             return false;
       
  1238         }
       
  1239     }
       
  1240 
       
  1241     /**
       
  1242      * Gets a Set of the extension(s) marked CRITICAL in the
       
  1243      * certificate. In the returned set, each extension is
       
  1244      * represented by its OID string.
       
  1245      *
       
  1246      * @return a set of the extension oid strings in the
       
  1247      * certificate that are marked critical.
       
  1248      */
       
  1249     public Set<String> getCriticalExtensionOIDs() {
       
  1250         if (info == null) {
       
  1251             return null;
       
  1252         }
       
  1253         try {
       
  1254             CertificateExtensions exts = (CertificateExtensions)info.get(
       
  1255                                          CertificateExtensions.NAME);
       
  1256             if (exts == null) {
       
  1257                 return null;
       
  1258             }
       
  1259             Set<String> extSet = new TreeSet<>();
       
  1260             for (Extension ex : exts.getAllExtensions()) {
       
  1261                 if (ex.isCritical()) {
       
  1262                     extSet.add(ex.getExtensionId().toString());
       
  1263                 }
       
  1264             }
       
  1265             return extSet;
       
  1266         } catch (Exception e) {
       
  1267             return null;
       
  1268         }
       
  1269     }
       
  1270 
       
  1271     /**
       
  1272      * Gets a Set of the extension(s) marked NON-CRITICAL in the
       
  1273      * certificate. In the returned set, each extension is
       
  1274      * represented by its OID string.
       
  1275      *
       
  1276      * @return a set of the extension oid strings in the
       
  1277      * certificate that are NOT marked critical.
       
  1278      */
       
  1279     public Set<String> getNonCriticalExtensionOIDs() {
       
  1280         if (info == null) {
       
  1281             return null;
       
  1282         }
       
  1283         try {
       
  1284             CertificateExtensions exts = (CertificateExtensions)info.get(
       
  1285                                          CertificateExtensions.NAME);
       
  1286             if (exts == null) {
       
  1287                 return null;
       
  1288             }
       
  1289             Set<String> extSet = new TreeSet<>();
       
  1290             for (Extension ex : exts.getAllExtensions()) {
       
  1291                 if (!ex.isCritical()) {
       
  1292                     extSet.add(ex.getExtensionId().toString());
       
  1293                 }
       
  1294             }
       
  1295             extSet.addAll(exts.getUnparseableExtensions().keySet());
       
  1296             return extSet;
       
  1297         } catch (Exception e) {
       
  1298             return null;
       
  1299         }
       
  1300     }
       
  1301 
       
  1302     /**
       
  1303      * Gets the extension identified by the given ObjectIdentifier
       
  1304      *
       
  1305      * @param oid the Object Identifier value for the extension.
       
  1306      * @return Extension or null if certificate does not contain this
       
  1307      *         extension
       
  1308      */
       
  1309     public Extension getExtension(ObjectIdentifier oid) {
       
  1310         if (info == null) {
       
  1311             return null;
       
  1312         }
       
  1313         try {
       
  1314             CertificateExtensions extensions;
       
  1315             try {
       
  1316                 extensions = (CertificateExtensions)info.get(CertificateExtensions.NAME);
       
  1317             } catch (CertificateException ce) {
       
  1318                 return null;
       
  1319             }
       
  1320             if (extensions == null) {
       
  1321                 return null;
       
  1322             } else {
       
  1323                 Extension ex = extensions.getExtension(oid.toString());
       
  1324                 if (ex != null) {
       
  1325                     return ex;
       
  1326                 }
       
  1327                 for (Extension ex2: extensions.getAllExtensions()) {
       
  1328                     if (ex2.getExtensionId().equals(oid)) {
       
  1329                         //XXXX May want to consider cloning this
       
  1330                         return ex2;
       
  1331                     }
       
  1332                 }
       
  1333                 /* no such extension in this certificate */
       
  1334                 return null;
       
  1335             }
       
  1336         } catch (IOException ioe) {
       
  1337             return null;
       
  1338         }
       
  1339     }
       
  1340 
       
  1341     public Extension getUnparseableExtension(ObjectIdentifier oid) {
       
  1342         if (info == null) {
       
  1343             return null;
       
  1344         }
       
  1345         try {
       
  1346             CertificateExtensions extensions;
       
  1347             try {
       
  1348                 extensions = (CertificateExtensions)info.get(CertificateExtensions.NAME);
       
  1349             } catch (CertificateException ce) {
       
  1350                 return null;
       
  1351             }
       
  1352             if (extensions == null) {
       
  1353                 return null;
       
  1354             } else {
       
  1355                 return extensions.getUnparseableExtensions().get(oid.toString());
       
  1356             }
       
  1357         } catch (IOException ioe) {
       
  1358             return null;
       
  1359         }
       
  1360     }
       
  1361 
       
  1362     /**
       
  1363      * Gets the DER encoded extension identified by the given
       
  1364      * oid String.
       
  1365      *
       
  1366      * @param oid the Object Identifier value for the extension.
       
  1367      */
       
  1368     public byte[] getExtensionValue(String oid) {
       
  1369         try {
       
  1370             ObjectIdentifier findOID = new ObjectIdentifier(oid);
       
  1371             String extAlias = OIDMap.getName(findOID);
       
  1372             Extension certExt = null;
       
  1373             CertificateExtensions exts = (CertificateExtensions)info.get(
       
  1374                                      CertificateExtensions.NAME);
       
  1375 
       
  1376             if (extAlias == null) { // may be unknown
       
  1377                 // get the extensions, search thru' for this oid
       
  1378                 if (exts == null) {
       
  1379                     return null;
       
  1380                 }
       
  1381 
       
  1382                 for (Extension ex : exts.getAllExtensions()) {
       
  1383                     ObjectIdentifier inCertOID = ex.getExtensionId();
       
  1384                     if (inCertOID.equals(findOID)) {
       
  1385                         certExt = ex;
       
  1386                         break;
       
  1387                     }
       
  1388                 }
       
  1389             } else { // there's sub-class that can handle this extension
       
  1390                 try {
       
  1391                     certExt = (Extension)this.get(extAlias);
       
  1392                 } catch (CertificateException e) {
       
  1393                     // get() throws an Exception instead of returning null, ignore
       
  1394                 }
       
  1395             }
       
  1396             if (certExt == null) {
       
  1397                 if (exts != null) {
       
  1398                     certExt = exts.getUnparseableExtensions().get(oid);
       
  1399                 }
       
  1400                 if (certExt == null) {
       
  1401                     return null;
       
  1402                 }
       
  1403             }
       
  1404             byte[] extData = certExt.getExtensionValue();
       
  1405             if (extData == null) {
       
  1406                 return null;
       
  1407             }
       
  1408             DerOutputStream out = new DerOutputStream();
       
  1409             out.putOctetString(extData);
       
  1410             return out.toByteArray();
       
  1411         } catch (Exception e) {
       
  1412             return null;
       
  1413         }
       
  1414     }
       
  1415 
       
  1416     /**
       
  1417      * Get a boolean array representing the bits of the KeyUsage extension,
       
  1418      * (oid = 2.5.29.15).
       
  1419      * @return the bit values of this extension as an array of booleans.
       
  1420      */
       
  1421     public boolean[] getKeyUsage() {
       
  1422         try {
       
  1423             String extAlias = OIDMap.getName(PKIXExtensions.KeyUsage_Id);
       
  1424             if (extAlias == null)
       
  1425                 return null;
       
  1426 
       
  1427             KeyUsageExtension certExt = (KeyUsageExtension)this.get(extAlias);
       
  1428             if (certExt == null)
       
  1429                 return null;
       
  1430 
       
  1431             boolean[] ret = certExt.getBits();
       
  1432             if (ret.length < NUM_STANDARD_KEY_USAGE) {
       
  1433                 boolean[] usageBits = new boolean[NUM_STANDARD_KEY_USAGE];
       
  1434                 System.arraycopy(ret, 0, usageBits, 0, ret.length);
       
  1435                 ret = usageBits;
       
  1436             }
       
  1437             return ret;
       
  1438         } catch (Exception e) {
       
  1439             return null;
       
  1440         }
       
  1441     }
       
  1442 
       
  1443     /**
       
  1444      * This method are the overridden implementation of
       
  1445      * getExtendedKeyUsage method in X509Certificate in the Sun
       
  1446      * provider. It is better performance-wise since it returns cached
       
  1447      * values.
       
  1448      */
       
  1449     public synchronized List<String> getExtendedKeyUsage()
       
  1450         throws CertificateParsingException {
       
  1451         if (readOnly && extKeyUsage != null) {
       
  1452             return extKeyUsage;
       
  1453         } else {
       
  1454             ExtendedKeyUsageExtension ext = getExtendedKeyUsageExtension();
       
  1455             if (ext == null) {
       
  1456                 return null;
       
  1457             }
       
  1458             extKeyUsage =
       
  1459                 Collections.unmodifiableList(ext.getExtendedKeyUsage());
       
  1460             return extKeyUsage;
       
  1461         }
       
  1462     }
       
  1463 
       
  1464     /**
       
  1465      * This static method is the default implementation of the
       
  1466      * getExtendedKeyUsage method in X509Certificate. A
       
  1467      * X509Certificate provider generally should overwrite this to
       
  1468      * provide among other things caching for better performance.
       
  1469      */
       
  1470     public static List<String> getExtendedKeyUsage(X509Certificate cert)
       
  1471         throws CertificateParsingException {
       
  1472         try {
       
  1473             byte[] ext = cert.getExtensionValue(EXTENDED_KEY_USAGE_OID);
       
  1474             if (ext == null)
       
  1475                 return null;
       
  1476             DerValue val = new DerValue(ext);
       
  1477             byte[] data = val.getOctetString();
       
  1478 
       
  1479             ExtendedKeyUsageExtension ekuExt =
       
  1480                 new ExtendedKeyUsageExtension(Boolean.FALSE, data);
       
  1481             return Collections.unmodifiableList(ekuExt.getExtendedKeyUsage());
       
  1482         } catch (IOException ioe) {
       
  1483             throw new CertificateParsingException(ioe);
       
  1484         }
       
  1485     }
       
  1486 
       
  1487     /**
       
  1488      * Get the certificate constraints path length from the
       
  1489      * the critical BasicConstraints extension, (oid = 2.5.29.19).
       
  1490      * @return the length of the constraint.
       
  1491      */
       
  1492     public int getBasicConstraints() {
       
  1493         try {
       
  1494             String extAlias = OIDMap.getName(PKIXExtensions.BasicConstraints_Id);
       
  1495             if (extAlias == null)
       
  1496                 return -1;
       
  1497             BasicConstraintsExtension certExt =
       
  1498                         (BasicConstraintsExtension)this.get(extAlias);
       
  1499             if (certExt == null)
       
  1500                 return -1;
       
  1501 
       
  1502             if (((Boolean)certExt.get(BasicConstraintsExtension.IS_CA)
       
  1503                  ).booleanValue() == true)
       
  1504                 return ((Integer)certExt.get(
       
  1505                         BasicConstraintsExtension.PATH_LEN)).intValue();
       
  1506             else
       
  1507                 return -1;
       
  1508         } catch (Exception e) {
       
  1509             return -1;
       
  1510         }
       
  1511     }
       
  1512 
       
  1513     /**
       
  1514      * Converts a GeneralNames structure into an immutable Collection of
       
  1515      * alternative names (subject or issuer) in the form required by
       
  1516      * {@link #getSubjectAlternativeNames} or
       
  1517      * {@link #getIssuerAlternativeNames}.
       
  1518      *
       
  1519      * @param names the GeneralNames to be converted
       
  1520      * @return an immutable Collection of alternative names
       
  1521      */
       
  1522     private static Collection<List<?>> makeAltNames(GeneralNames names) {
       
  1523         if (names.isEmpty()) {
       
  1524             return Collections.<List<?>>emptySet();
       
  1525         }
       
  1526         List<List<?>> newNames = new ArrayList<>();
       
  1527         for (GeneralName gname : names.names()) {
       
  1528             GeneralNameInterface name = gname.getName();
       
  1529             List<Object> nameEntry = new ArrayList<>(2);
       
  1530             nameEntry.add(Integer.valueOf(name.getType()));
       
  1531             switch (name.getType()) {
       
  1532             case GeneralNameInterface.NAME_RFC822:
       
  1533                 nameEntry.add(((RFC822Name) name).getName());
       
  1534                 break;
       
  1535             case GeneralNameInterface.NAME_DNS:
       
  1536                 nameEntry.add(((DNSName) name).getName());
       
  1537                 break;
       
  1538             case GeneralNameInterface.NAME_DIRECTORY:
       
  1539                 nameEntry.add(((X500Name) name).getRFC2253Name());
       
  1540                 break;
       
  1541             case GeneralNameInterface.NAME_URI:
       
  1542                 nameEntry.add(((URIName) name).getName());
       
  1543                 break;
       
  1544             case GeneralNameInterface.NAME_IP:
       
  1545                 try {
       
  1546                     nameEntry.add(((IPAddressName) name).getName());
       
  1547                 } catch (IOException ioe) {
       
  1548                     // IPAddressName in cert is bogus
       
  1549                     throw new RuntimeException("IPAddress cannot be parsed",
       
  1550                         ioe);
       
  1551                 }
       
  1552                 break;
       
  1553             case GeneralNameInterface.NAME_OID:
       
  1554                 nameEntry.add(((OIDName) name).getOID().toString());
       
  1555                 break;
       
  1556             default:
       
  1557                 // add DER encoded form
       
  1558                 DerOutputStream derOut = new DerOutputStream();
       
  1559                 try {
       
  1560                     name.encode(derOut);
       
  1561                 } catch (IOException ioe) {
       
  1562                     // should not occur since name has already been decoded
       
  1563                     // from cert (this would indicate a bug in our code)
       
  1564                     throw new RuntimeException("name cannot be encoded", ioe);
       
  1565                 }
       
  1566                 nameEntry.add(derOut.toByteArray());
       
  1567                 break;
       
  1568             }
       
  1569             newNames.add(Collections.unmodifiableList(nameEntry));
       
  1570         }
       
  1571         return Collections.unmodifiableCollection(newNames);
       
  1572     }
       
  1573 
       
  1574     /**
       
  1575      * Checks a Collection of altNames and clones any name entries of type
       
  1576      * byte [].
       
  1577      */ // only partially generified due to javac bug
       
  1578     private static Collection<List<?>> cloneAltNames(Collection<List<?>> altNames) {
       
  1579         boolean mustClone = false;
       
  1580         for (List<?> nameEntry : altNames) {
       
  1581             if (nameEntry.get(1) instanceof byte[]) {
       
  1582                 // must clone names
       
  1583                 mustClone = true;
       
  1584             }
       
  1585         }
       
  1586         if (mustClone) {
       
  1587             List<List<?>> namesCopy = new ArrayList<>();
       
  1588             for (List<?> nameEntry : altNames) {
       
  1589                 Object nameObject = nameEntry.get(1);
       
  1590                 if (nameObject instanceof byte[]) {
       
  1591                     List<Object> nameEntryCopy =
       
  1592                                         new ArrayList<>(nameEntry);
       
  1593                     nameEntryCopy.set(1, ((byte[])nameObject).clone());
       
  1594                     namesCopy.add(Collections.unmodifiableList(nameEntryCopy));
       
  1595                 } else {
       
  1596                     namesCopy.add(nameEntry);
       
  1597                 }
       
  1598             }
       
  1599             return Collections.unmodifiableCollection(namesCopy);
       
  1600         } else {
       
  1601             return altNames;
       
  1602         }
       
  1603     }
       
  1604 
       
  1605     /**
       
  1606      * This method are the overridden implementation of
       
  1607      * getSubjectAlternativeNames method in X509Certificate in the Sun
       
  1608      * provider. It is better performance-wise since it returns cached
       
  1609      * values.
       
  1610      */
       
  1611     public synchronized Collection<List<?>> getSubjectAlternativeNames()
       
  1612         throws CertificateParsingException {
       
  1613         // return cached value if we can
       
  1614         if (readOnly && subjectAlternativeNames != null)  {
       
  1615             return cloneAltNames(subjectAlternativeNames);
       
  1616         }
       
  1617         SubjectAlternativeNameExtension subjectAltNameExt =
       
  1618             getSubjectAlternativeNameExtension();
       
  1619         if (subjectAltNameExt == null) {
       
  1620             return null;
       
  1621         }
       
  1622         GeneralNames names;
       
  1623         try {
       
  1624             names = subjectAltNameExt.get(
       
  1625                     SubjectAlternativeNameExtension.SUBJECT_NAME);
       
  1626         } catch (IOException ioe) {
       
  1627             // should not occur
       
  1628             return Collections.<List<?>>emptySet();
       
  1629         }
       
  1630         subjectAlternativeNames = makeAltNames(names);
       
  1631         return subjectAlternativeNames;
       
  1632     }
       
  1633 
       
  1634     /**
       
  1635      * This static method is the default implementation of the
       
  1636      * getSubjectAlternaitveNames method in X509Certificate. A
       
  1637      * X509Certificate provider generally should overwrite this to
       
  1638      * provide among other things caching for better performance.
       
  1639      */
       
  1640     public static Collection<List<?>> getSubjectAlternativeNames(X509Certificate cert)
       
  1641         throws CertificateParsingException {
       
  1642         try {
       
  1643             byte[] ext = cert.getExtensionValue(SUBJECT_ALT_NAME_OID);
       
  1644             if (ext == null) {
       
  1645                 return null;
       
  1646             }
       
  1647             DerValue val = new DerValue(ext);
       
  1648             byte[] data = val.getOctetString();
       
  1649 
       
  1650             SubjectAlternativeNameExtension subjectAltNameExt =
       
  1651                 new SubjectAlternativeNameExtension(Boolean.FALSE,
       
  1652                                                     data);
       
  1653 
       
  1654             GeneralNames names;
       
  1655             try {
       
  1656                 names = subjectAltNameExt.get(
       
  1657                         SubjectAlternativeNameExtension.SUBJECT_NAME);
       
  1658             }  catch (IOException ioe) {
       
  1659                 // should not occur
       
  1660                 return Collections.<List<?>>emptySet();
       
  1661             }
       
  1662             return makeAltNames(names);
       
  1663         } catch (IOException ioe) {
       
  1664             throw new CertificateParsingException(ioe);
       
  1665         }
       
  1666     }
       
  1667 
       
  1668     /**
       
  1669      * This method are the overridden implementation of
       
  1670      * getIssuerAlternativeNames method in X509Certificate in the Sun
       
  1671      * provider. It is better performance-wise since it returns cached
       
  1672      * values.
       
  1673      */
       
  1674     public synchronized Collection<List<?>> getIssuerAlternativeNames()
       
  1675         throws CertificateParsingException {
       
  1676         // return cached value if we can
       
  1677         if (readOnly && issuerAlternativeNames != null) {
       
  1678             return cloneAltNames(issuerAlternativeNames);
       
  1679         }
       
  1680         IssuerAlternativeNameExtension issuerAltNameExt =
       
  1681             getIssuerAlternativeNameExtension();
       
  1682         if (issuerAltNameExt == null) {
       
  1683             return null;
       
  1684         }
       
  1685         GeneralNames names;
       
  1686         try {
       
  1687             names = issuerAltNameExt.get(
       
  1688                     IssuerAlternativeNameExtension.ISSUER_NAME);
       
  1689         } catch (IOException ioe) {
       
  1690             // should not occur
       
  1691             return Collections.<List<?>>emptySet();
       
  1692         }
       
  1693         issuerAlternativeNames = makeAltNames(names);
       
  1694         return issuerAlternativeNames;
       
  1695     }
       
  1696 
       
  1697     /**
       
  1698      * This static method is the default implementation of the
       
  1699      * getIssuerAlternaitveNames method in X509Certificate. A
       
  1700      * X509Certificate provider generally should overwrite this to
       
  1701      * provide among other things caching for better performance.
       
  1702      */
       
  1703     public static Collection<List<?>> getIssuerAlternativeNames(X509Certificate cert)
       
  1704         throws CertificateParsingException {
       
  1705         try {
       
  1706             byte[] ext = cert.getExtensionValue(ISSUER_ALT_NAME_OID);
       
  1707             if (ext == null) {
       
  1708                 return null;
       
  1709             }
       
  1710 
       
  1711             DerValue val = new DerValue(ext);
       
  1712             byte[] data = val.getOctetString();
       
  1713 
       
  1714             IssuerAlternativeNameExtension issuerAltNameExt =
       
  1715                 new IssuerAlternativeNameExtension(Boolean.FALSE,
       
  1716                                                     data);
       
  1717             GeneralNames names;
       
  1718             try {
       
  1719                 names = issuerAltNameExt.get(
       
  1720                         IssuerAlternativeNameExtension.ISSUER_NAME);
       
  1721             }  catch (IOException ioe) {
       
  1722                 // should not occur
       
  1723                 return Collections.<List<?>>emptySet();
       
  1724             }
       
  1725             return makeAltNames(names);
       
  1726         } catch (IOException ioe) {
       
  1727             throw new CertificateParsingException(ioe);
       
  1728         }
       
  1729     }
       
  1730 
       
  1731     public AuthorityInfoAccessExtension getAuthorityInfoAccessExtension() {
       
  1732         return (AuthorityInfoAccessExtension)
       
  1733             getExtension(PKIXExtensions.AuthInfoAccess_Id);
       
  1734     }
       
  1735 
       
  1736     /************************************************************/
       
  1737 
       
  1738     /*
       
  1739      * Cert is a SIGNED ASN.1 macro, a three elment sequence:
       
  1740      *
       
  1741      *  - Data to be signed (ToBeSigned) -- the "raw" cert
       
  1742      *  - Signature algorithm (SigAlgId)
       
  1743      *  - The signature bits
       
  1744      *
       
  1745      * This routine unmarshals the certificate, saving the signature
       
  1746      * parts away for later verification.
       
  1747      */
       
  1748     private void parse(DerValue val)
       
  1749     throws CertificateException, IOException {
       
  1750         // check if can over write the certificate
       
  1751         if (readOnly)
       
  1752             throw new CertificateParsingException(
       
  1753                       "cannot over-write existing certificate");
       
  1754 
       
  1755         if (val.data == null || val.tag != DerValue.tag_Sequence)
       
  1756             throw new CertificateParsingException(
       
  1757                       "invalid DER-encoded certificate data");
       
  1758 
       
  1759         signedCert = val.toByteArray();
       
  1760         DerValue[] seq = new DerValue[3];
       
  1761 
       
  1762         seq[0] = val.data.getDerValue();
       
  1763         seq[1] = val.data.getDerValue();
       
  1764         seq[2] = val.data.getDerValue();
       
  1765 
       
  1766         if (val.data.available() != 0) {
       
  1767             throw new CertificateParsingException("signed overrun, bytes = "
       
  1768                                      + val.data.available());
       
  1769         }
       
  1770         if (seq[0].tag != DerValue.tag_Sequence) {
       
  1771             throw new CertificateParsingException("signed fields invalid");
       
  1772         }
       
  1773 
       
  1774         algId = AlgorithmId.parse(seq[1]);
       
  1775         signature = seq[2].getBitString();
       
  1776 
       
  1777         if (seq[1].data.available() != 0) {
       
  1778             throw new CertificateParsingException("algid field overrun");
       
  1779         }
       
  1780         if (seq[2].data.available() != 0)
       
  1781             throw new CertificateParsingException("signed fields overrun");
       
  1782 
       
  1783         // The CertificateInfo
       
  1784         info = new X509CertInfo(seq[0]);
       
  1785 
       
  1786         // the "inner" and "outer" signature algorithms must match
       
  1787         AlgorithmId infoSigAlg = (AlgorithmId)info.get(
       
  1788                                               CertificateAlgorithmId.NAME
       
  1789                                               + DOT +
       
  1790                                               CertificateAlgorithmId.ALGORITHM);
       
  1791         if (! algId.equals(infoSigAlg))
       
  1792             throw new CertificateException("Signature algorithm mismatch");
       
  1793         readOnly = true;
       
  1794     }
       
  1795 
       
  1796     /**
       
  1797      * Extract the subject or issuer X500Principal from an X509Certificate.
       
  1798      * Parses the encoded form of the cert to preserve the principal's
       
  1799      * ASN.1 encoding.
       
  1800      */
       
  1801     private static X500Principal getX500Principal(X509Certificate cert,
       
  1802             boolean getIssuer) throws Exception {
       
  1803         byte[] encoded = cert.getEncoded();
       
  1804         DerInputStream derIn = new DerInputStream(encoded);
       
  1805         DerValue tbsCert = derIn.getSequence(3)[0];
       
  1806         DerInputStream tbsIn = tbsCert.data;
       
  1807         DerValue tmp;
       
  1808         tmp = tbsIn.getDerValue();
       
  1809         // skip version number if present
       
  1810         if (tmp.isContextSpecific((byte)0)) {
       
  1811           tmp = tbsIn.getDerValue();
       
  1812         }
       
  1813         // tmp always contains serial number now
       
  1814         tmp = tbsIn.getDerValue();              // skip signature
       
  1815         tmp = tbsIn.getDerValue();              // issuer
       
  1816         if (getIssuer == false) {
       
  1817             tmp = tbsIn.getDerValue();          // skip validity
       
  1818             tmp = tbsIn.getDerValue();          // subject
       
  1819         }
       
  1820         byte[] principalBytes = tmp.toByteArray();
       
  1821         return new X500Principal(principalBytes);
       
  1822     }
       
  1823 
       
  1824     /**
       
  1825      * Extract the subject X500Principal from an X509Certificate.
       
  1826      * Called from java.security.cert.X509Certificate.getSubjectX500Principal().
       
  1827      */
       
  1828     public static X500Principal getSubjectX500Principal(X509Certificate cert) {
       
  1829         try {
       
  1830             return getX500Principal(cert, false);
       
  1831         } catch (Exception e) {
       
  1832             throw new RuntimeException("Could not parse subject", e);
       
  1833         }
       
  1834     }
       
  1835 
       
  1836     /**
       
  1837      * Extract the issuer X500Principal from an X509Certificate.
       
  1838      * Called from java.security.cert.X509Certificate.getIssuerX500Principal().
       
  1839      */
       
  1840     public static X500Principal getIssuerX500Principal(X509Certificate cert) {
       
  1841         try {
       
  1842             return getX500Principal(cert, true);
       
  1843         } catch (Exception e) {
       
  1844             throw new RuntimeException("Could not parse issuer", e);
       
  1845         }
       
  1846     }
       
  1847 
       
  1848     /**
       
  1849      * Returned the encoding of the given certificate for internal use.
       
  1850      * Callers must guarantee that they neither modify it nor expose it
       
  1851      * to untrusted code. Uses getEncodedInternal() if the certificate
       
  1852      * is instance of X509CertImpl, getEncoded() otherwise.
       
  1853      */
       
  1854     public static byte[] getEncodedInternal(Certificate cert)
       
  1855             throws CertificateEncodingException {
       
  1856         if (cert instanceof X509CertImpl) {
       
  1857             return ((X509CertImpl)cert).getEncodedInternal();
       
  1858         } else {
       
  1859             return cert.getEncoded();
       
  1860         }
       
  1861     }
       
  1862 
       
  1863     /**
       
  1864      * Utility method to convert an arbitrary instance of X509Certificate
       
  1865      * to a X509CertImpl. Does a cast if possible, otherwise reparses
       
  1866      * the encoding.
       
  1867      */
       
  1868     public static X509CertImpl toImpl(X509Certificate cert)
       
  1869             throws CertificateException {
       
  1870         if (cert instanceof X509CertImpl) {
       
  1871             return (X509CertImpl)cert;
       
  1872         } else {
       
  1873             return X509Factory.intern(cert);
       
  1874         }
       
  1875     }
       
  1876 
       
  1877     /**
       
  1878      * Utility method to test if a certificate is self-issued. This is
       
  1879      * the case iff the subject and issuer X500Principals are equal.
       
  1880      */
       
  1881     public static boolean isSelfIssued(X509Certificate cert) {
       
  1882         X500Principal subject = cert.getSubjectX500Principal();
       
  1883         X500Principal issuer = cert.getIssuerX500Principal();
       
  1884         return subject.equals(issuer);
       
  1885     }
       
  1886 
       
  1887     /**
       
  1888      * Utility method to test if a certificate is self-signed. This is
       
  1889      * the case iff the subject and issuer X500Principals are equal
       
  1890      * AND the certificate's subject public key can be used to verify
       
  1891      * the certificate. In case of exception, returns false.
       
  1892      */
       
  1893     public static boolean isSelfSigned(X509Certificate cert,
       
  1894         String sigProvider) {
       
  1895         if (isSelfIssued(cert)) {
       
  1896             try {
       
  1897                 if (sigProvider == null) {
       
  1898                     cert.verify(cert.getPublicKey());
       
  1899                 } else {
       
  1900                     cert.verify(cert.getPublicKey(), sigProvider);
       
  1901                 }
       
  1902                 return true;
       
  1903             } catch (Exception e) {
       
  1904                 // In case of exception, return false
       
  1905             }
       
  1906         }
       
  1907         return false;
       
  1908     }
       
  1909 
       
  1910     private ConcurrentHashMap<String,String> fingerprints =
       
  1911             new ConcurrentHashMap<>(2);
       
  1912 
       
  1913     public String getFingerprint(String algorithm) {
       
  1914         return fingerprints.computeIfAbsent(algorithm,
       
  1915             x -> getFingerprint(x, this));
       
  1916     }
       
  1917 
       
  1918     /**
       
  1919      * Gets the requested finger print of the certificate. The result
       
  1920      * only contains 0-9 and A-F. No small case, no colon.
       
  1921      */
       
  1922     public static String getFingerprint(String algorithm,
       
  1923             X509Certificate cert) {
       
  1924         try {
       
  1925             byte[] encCertInfo = cert.getEncoded();
       
  1926             MessageDigest md = MessageDigest.getInstance(algorithm);
       
  1927             byte[] digest = md.digest(encCertInfo);
       
  1928             StringBuilder sb = new StringBuilder(digest.length * 2);
       
  1929             for (int i = 0; i < digest.length; i++) {
       
  1930                 byte2hex(digest[i], sb);
       
  1931             }
       
  1932             return sb.toString();
       
  1933         } catch (NoSuchAlgorithmException | CertificateEncodingException e) {
       
  1934             // ignored
       
  1935         }
       
  1936         return "";
       
  1937     }
       
  1938 
       
  1939     /**
       
  1940      * Converts a byte to hex digit and writes to the supplied builder
       
  1941      */
       
  1942     private static void byte2hex(byte b, StringBuilder buf) {
       
  1943         char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
       
  1944                 '9', 'A', 'B', 'C', 'D', 'E', 'F' };
       
  1945         int high = ((b & 0xf0) >> 4);
       
  1946         int low = (b & 0x0f);
       
  1947         buf.append(hexChars[high])
       
  1948             .append(hexChars[low]);
       
  1949     }
       
  1950 }