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

Save This Page
Home » openjdk-7 » sun.security » x509 » [javadoc | source]