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