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