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