/*
 * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.security.x509;

import java.io.BufferedReader;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.AlgorithmParameterSpec;
import java.security.cert.*;
import java.security.cert.Certificate;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import javax.security.auth.x500.X500Principal;

import sun.security.util.*;
import sun.security.provider.X509Factory;

The X509CertImpl class represents an X.509 certificate. These certificates are widely used to support authentication and other functionality in Internet security systems. Common applications include Privacy Enhanced Mail (PEM), Transport Layer Security (SSL), code signing for trusted software distribution, and Secure Electronic Transactions (SET). There is a commercial infrastructure ready to manage large scale deployments of X.509 identity certificates.

These certificates are managed and vouched for by Certificate Authorities (CAs). CAs are services which create certificates by placing data in the X.509 standard format and then digitally signing that data. Such signatures are quite difficult to forge. CAs act as trusted third parties, making introductions between agents who have no direct knowledge of each other. CA certificates are either signed by themselves, or by some other CA such as a "root" CA.

RFC 1422 is very informative, though it does not describe much of the recent work being done with X.509 certificates. That includes a 1996 version (X.509v3) and a variety of enhancements being made to facilitate an explosion of personal certificates used as "Internet Drivers' Licences", or with SET for credit card transactions.

More recent work includes the IETF PKIX Working Group efforts, especially RFC2459.

Author:Dave Brownell, Amit Kapoor, Hemma Prafullchandra
See Also:
/** * The X509CertImpl class represents an X.509 certificate. These certificates * are widely used to support authentication and other functionality in * Internet security systems. Common applications include Privacy Enhanced * Mail (PEM), Transport Layer Security (SSL), code signing for trusted * software distribution, and Secure Electronic Transactions (SET). There * is a commercial infrastructure ready to manage large scale deployments * of X.509 identity certificates. * * <P>These certificates are managed and vouched for by <em>Certificate * Authorities</em> (CAs). CAs are services which create certificates by * placing data in the X.509 standard format and then digitally signing * that data. Such signatures are quite difficult to forge. CAs act as * trusted third parties, making introductions between agents who have no * direct knowledge of each other. CA certificates are either signed by * themselves, or by some other CA such as a "root" CA. * * <P>RFC 1422 is very informative, though it does not describe much * of the recent work being done with X.509 certificates. That includes * a 1996 version (X.509v3) and a variety of enhancements being made to * facilitate an explosion of personal certificates used as "Internet * Drivers' Licences", or with SET for credit card transactions. * * <P>More recent work includes the IETF PKIX Working Group efforts, * especially RFC2459. * * @author Dave Brownell * @author Amit Kapoor * @author Hemma Prafullchandra * @see X509CertInfo */
public class X509CertImpl extends X509Certificate implements DerEncoder { private static final long serialVersionUID = -3457612960190864406L; private static final char DOT = '.';
Public attribute names.
/** * Public attribute names. */
public static final String NAME = "x509"; public static final String INFO = X509CertInfo.NAME; public static final String ALG_ID = "algorithm"; public static final String SIGNATURE = "signature"; public static final String SIGNED_CERT = "signed_cert";
The following are defined for ease-of-use. These are the most frequently retrieved attributes.
/** * The following are defined for ease-of-use. These * are the most frequently retrieved attributes. */
// x509.info.subject.dname public static final String SUBJECT_DN = NAME + DOT + INFO + DOT + X509CertInfo.SUBJECT + DOT + X509CertInfo.DN_NAME; // x509.info.issuer.dname public static final String ISSUER_DN = NAME + DOT + INFO + DOT + X509CertInfo.ISSUER + DOT + X509CertInfo.DN_NAME; // x509.info.serialNumber.number public static final String SERIAL_ID = NAME + DOT + INFO + DOT + X509CertInfo.SERIAL_NUMBER + DOT + CertificateSerialNumber.NUMBER; // x509.info.key.value public static final String PUBLIC_KEY = NAME + DOT + INFO + DOT + X509CertInfo.KEY + DOT + CertificateX509Key.KEY; // x509.info.version.value public static final String VERSION = NAME + DOT + INFO + DOT + X509CertInfo.VERSION + DOT + CertificateVersion.VERSION; // x509.algorithm public static final String SIG_ALG = NAME + DOT + ALG_ID; // x509.signature public static final String SIG = NAME + DOT + SIGNATURE; // when we sign and decode we set this to true // this is our means to make certificates immutable private boolean readOnly = false; // Certificate data, and its envelope private byte[] signedCert = null; protected X509CertInfo info = null; protected AlgorithmId algId = null; protected byte[] signature = null; // recognized extension OIDS private static final String KEY_USAGE_OID = "2.5.29.15"; private static final String EXTENDED_KEY_USAGE_OID = "2.5.29.37"; private static final String BASIC_CONSTRAINT_OID = "2.5.29.19"; private static final String SUBJECT_ALT_NAME_OID = "2.5.29.17"; private static final String ISSUER_ALT_NAME_OID = "2.5.29.18"; private static final String AUTH_INFO_ACCESS_OID = "1.3.6.1.5.5.7.1.1"; // number of standard key usage bits. private static final int NUM_STANDARD_KEY_USAGE = 9; // SubjectAlterntativeNames cache private Collection<List<?>> subjectAlternativeNames; // IssuerAlternativeNames cache private Collection<List<?>> issuerAlternativeNames; // ExtendedKeyUsage cache private List<String> extKeyUsage; // AuthorityInformationAccess cache private Set<AccessDescription> authInfoAccess;
PublicKey that has previously been used to verify the signature of this certificate. Null if the certificate has not yet been verified.
/** * PublicKey that has previously been used to verify * the signature of this certificate. Null if the certificate has not * yet been verified. */
private PublicKey verifiedPublicKey;
If verifiedPublicKey is not null, name of the provider used to successfully verify the signature of this certificate, or the empty String if no provider was explicitly specified.
/** * If verifiedPublicKey is not null, name of the provider used to * successfully verify the signature of this certificate, or the * empty String if no provider was explicitly specified. */
private String verifiedProvider;
If verifiedPublicKey is not null, result of the verification using verifiedPublicKey and verifiedProvider. If true, verification was successful, if false, it failed.
/** * If verifiedPublicKey is not null, result of the verification using * verifiedPublicKey and verifiedProvider. If true, verification was * successful, if false, it failed. */
private boolean verificationResult;
Default constructor.
/** * Default constructor. */
public X509CertImpl() { }
Unmarshals a certificate from its encoded form, parsing the encoded bytes. This form of constructor is used by agents which need to examine and use certificate contents. That is, this is one of the more commonly used constructors. Note that the buffer must include only a certificate, and no "garbage" may be left at the end. If you need to ignore data at the end of a certificate, use another constructor.
Params:
  • certData – the encoded bytes, with no trailing padding.
Throws:
/** * Unmarshals a certificate from its encoded form, parsing the * encoded bytes. This form of constructor is used by agents which * need to examine and use certificate contents. That is, this is * one of the more commonly used constructors. Note that the buffer * must include only a certificate, and no "garbage" may be left at * the end. If you need to ignore data at the end of a certificate, * use another constructor. * * @param certData the encoded bytes, with no trailing padding. * @exception CertificateException on parsing and initialization errors. */
public X509CertImpl(byte[] certData) throws CertificateException { try { parse(new DerValue(certData)); } catch (IOException e) { signedCert = null; throw new CertificateException("Unable to initialize, " + e, e); } }
unmarshals an X.509 certificate from an input stream. If the certificate is RFC1421 hex-encoded, then it must begin with the line X509Factory.BEGIN_CERT and end with the line X509Factory.END_CERT.
Params:
  • in – an input stream holding at least one certificate that may be either DER-encoded or RFC1421 hex-encoded version of the DER-encoded certificate.
Throws:
/** * unmarshals an X.509 certificate from an input stream. If the * certificate is RFC1421 hex-encoded, then it must begin with * the line X509Factory.BEGIN_CERT and end with the line * X509Factory.END_CERT. * * @param in an input stream holding at least one certificate that may * be either DER-encoded or RFC1421 hex-encoded version of the * DER-encoded certificate. * @exception CertificateException on parsing and initialization errors. */
public X509CertImpl(InputStream in) throws CertificateException { DerValue der = null; BufferedInputStream inBuffered = new BufferedInputStream(in); // First try reading stream as HEX-encoded DER-encoded bytes, // since not mistakable for raw DER try { inBuffered.mark(Integer.MAX_VALUE); der = readRFC1421Cert(inBuffered); } catch (IOException ioe) { try { // Next, try reading stream as raw DER-encoded bytes inBuffered.reset(); der = new DerValue(inBuffered); } catch (IOException ioe1) { throw new CertificateException("Input stream must be " + "either DER-encoded bytes " + "or RFC1421 hex-encoded " + "DER-encoded bytes: " + ioe1.getMessage(), ioe1); } } try { parse(der); } catch (IOException ioe) { signedCert = null; throw new CertificateException("Unable to parse DER value of " + "certificate, " + ioe, ioe); } }
read input stream as HEX-encoded DER-encoded bytes
Params:
  • in – InputStream to read
Throws:
  • IOException – if stream can not be interpreted as RFC1421 encoded bytes
Returns:DerValue corresponding to decoded HEX-encoded bytes
/** * read input stream as HEX-encoded DER-encoded bytes * * @param in InputStream to read * @return DerValue corresponding to decoded HEX-encoded bytes * @throws IOException if stream can not be interpreted as RFC1421 * encoded bytes */
private DerValue readRFC1421Cert(InputStream in) throws IOException { DerValue der = null; String line = null; BufferedReader certBufferedReader = new BufferedReader(new InputStreamReader(in, "ASCII")); try { line = certBufferedReader.readLine(); } catch (IOException ioe1) { throw new IOException("Unable to read InputStream: " + ioe1.getMessage()); } if (line.equals(X509Factory.BEGIN_CERT)) { /* stream appears to be hex-encoded bytes */ ByteArrayOutputStream decstream = new ByteArrayOutputStream(); try { while ((line = certBufferedReader.readLine()) != null) { if (line.equals(X509Factory.END_CERT)) { der = new DerValue(decstream.toByteArray()); break; } else { decstream.write(Pem.decode(line)); } } } catch (IOException ioe2) { throw new IOException("Unable to read InputStream: " + ioe2.getMessage()); } } else { throw new IOException("InputStream is not RFC1421 hex-encoded " + "DER bytes"); } return der; }
Construct an initialized X509 Certificate. The certificate is stored in raw form and has to be signed to be useful.
Params:
  • certInfo – the X509CertificateInfo which the Certificate is to be created from.
/** * Construct an initialized X509 Certificate. The certificate is stored * in raw form and has to be signed to be useful. * * @param certInfo the X509CertificateInfo which the Certificate is to be * created from. */
public X509CertImpl(X509CertInfo certInfo) { this.info = certInfo; }
Unmarshal a certificate from its encoded form, parsing a DER value. This form of constructor is used by agents which need to examine and use certificate contents.
Params:
  • derVal – the der value containing the encoded cert.
Throws:
/** * Unmarshal a certificate from its encoded form, parsing a DER value. * This form of constructor is used by agents which need to examine * and use certificate contents. * * @param derVal the der value containing the encoded cert. * @exception CertificateException on parsing and initialization errors. */
public X509CertImpl(DerValue derVal) throws CertificateException { try { parse(derVal); } catch (IOException e) { signedCert = null; throw new CertificateException("Unable to initialize, " + e, e); } }
Appends the certificate to an output stream.
Params:
  • out – an input stream to which the certificate is appended.
Throws:
/** * Appends the certificate to an output stream. * * @param out an input stream to which the certificate is appended. * @exception CertificateEncodingException on encoding errors. */
public void encode(OutputStream out) throws CertificateEncodingException { if (signedCert == null) throw new CertificateEncodingException( "Null certificate to encode"); try { out.write(signedCert.clone()); } catch (IOException e) { throw new CertificateEncodingException(e.toString()); } }
DER encode this object onto an output stream. Implements the DerEncoder interface.
Params:
  • out – the output stream on which to write the DER encoding.
Throws:
/** * DER encode this object onto an output stream. * Implements the <code>DerEncoder</code> interface. * * @param out the output stream on which to write the DER encoding. * * @exception IOException on encoding error. */
public void derEncode(OutputStream out) throws IOException { if (signedCert == null) throw new IOException("Null certificate to encode"); out.write(signedCert.clone()); }
Returns the encoded form of this certificate. It is assumed that each certificate type would have only a single form of encoding; for example, X.509 certificates would be encoded as ASN.1 DER.
Throws:
  • CertificateEncodingException – if an encoding error occurs.
/** * Returns the encoded form of this certificate. It is * assumed that each certificate type would have only a single * form of encoding; for example, X.509 certificates would * be encoded as ASN.1 DER. * * @exception CertificateEncodingException if an encoding error occurs. */
public byte[] getEncoded() throws CertificateEncodingException { return getEncodedInternal().clone(); }
Returned the encoding as an uncloned byte array. Callers must guarantee that they neither modify it nor expose it to untrusted code.
/** * Returned the encoding as an uncloned byte array. Callers must * guarantee that they neither modify it nor expose it to untrusted * code. */
public byte[] getEncodedInternal() throws CertificateEncodingException { if (signedCert == null) { throw new CertificateEncodingException( "Null certificate to encode"); } return signedCert; }
Throws an exception if the certificate was not signed using the verification key provided. Successfully verifying a certificate does not indicate that one should trust the entity which it represents.
Params:
  • key – the public key used for verification.
Throws:
/** * Throws an exception if the certificate was not signed using the * verification key provided. Successfully verifying a certificate * does <em>not</em> indicate that one should trust the entity which * it represents. * * @param key the public key used for verification. * * @exception InvalidKeyException on incorrect key. * @exception NoSuchAlgorithmException on unsupported signature * algorithms. * @exception NoSuchProviderException if there's no default provider. * @exception SignatureException on signature errors. * @exception CertificateException on encoding errors. */
public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException { verify(key, ""); }
Throws an exception if the certificate was not signed using the verification key provided. Successfully verifying a certificate does not indicate that one should trust the entity which it represents.
Params:
  • key – the public key used for verification.
  • sigProvider – the name of the provider.
Throws:
/** * Throws an exception if the certificate was not signed using the * verification key provided. Successfully verifying a certificate * does <em>not</em> indicate that one should trust the entity which * it represents. * * @param key the public key used for verification. * @param sigProvider the name of the provider. * * @exception NoSuchAlgorithmException on unsupported signature * algorithms. * @exception InvalidKeyException on incorrect key. * @exception NoSuchProviderException on incorrect provider. * @exception SignatureException on signature errors. * @exception CertificateException on encoding errors. */
public synchronized void verify(PublicKey key, String sigProvider) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException { if (sigProvider == null) { sigProvider = ""; } if ((verifiedPublicKey != null) && verifiedPublicKey.equals(key)) { // this certificate has already been verified using // this public key. Make sure providers match, too. if (sigProvider.equals(verifiedProvider)) { if (verificationResult) { return; } else { throw new SignatureException("Signature does not match."); } } } if (signedCert == null) { throw new CertificateEncodingException("Uninitialized certificate"); } // Verify the signature ... Signature sigVerf = null; String sigName = algId.getName(); if (sigProvider.isEmpty()) { sigVerf = Signature.getInstance(sigName); } else { sigVerf = Signature.getInstance(sigName, sigProvider); } try { SignatureUtil.initVerifyWithParam(sigVerf, key, SignatureUtil.getParamSpec(sigName, getSigAlgParams())); } catch (ProviderException e) { throw new CertificateException(e.getMessage(), e.getCause()); } catch (InvalidAlgorithmParameterException e) { throw new CertificateException(e); } byte[] rawCert = info.getEncodedInfo(); sigVerf.update(rawCert, 0, rawCert.length); // verify may throw SignatureException for invalid encodings, etc. verificationResult = sigVerf.verify(signature); verifiedPublicKey = key; verifiedProvider = sigProvider; if (verificationResult == false) { throw new SignatureException("Signature does not match."); } }
Throws an exception if the certificate was not signed using the verification key provided. This method uses the signature verification engine supplied by the specified provider. Note that the specified Provider object does not have to be registered in the provider list. Successfully verifying a certificate does not indicate that one should trust the entity which it represents.
Params:
  • key – the public key used for verification.
  • sigProvider – the provider.
Throws:
/** * Throws an exception if the certificate was not signed using the * verification key provided. This method uses the signature verification * engine supplied by the specified provider. Note that the specified * Provider object does not have to be registered in the provider list. * Successfully verifying a certificate does <em>not</em> indicate that one * should trust the entity which it represents. * * @param key the public key used for verification. * @param sigProvider the provider. * * @exception NoSuchAlgorithmException on unsupported signature * algorithms. * @exception InvalidKeyException on incorrect key. * @exception SignatureException on signature errors. * @exception CertificateException on encoding errors. */
public synchronized void verify(PublicKey key, Provider sigProvider) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, SignatureException { if (signedCert == null) { throw new CertificateEncodingException("Uninitialized certificate"); } // Verify the signature ... Signature sigVerf = null; String sigName = algId.getName(); if (sigProvider == null) { sigVerf = Signature.getInstance(sigName); } else { sigVerf = Signature.getInstance(sigName, sigProvider); } try { SignatureUtil.initVerifyWithParam(sigVerf, key, SignatureUtil.getParamSpec(sigName, getSigAlgParams())); } catch (ProviderException e) { throw new CertificateException(e.getMessage(), e.getCause()); } catch (InvalidAlgorithmParameterException e) { throw new CertificateException(e); } byte[] rawCert = info.getEncodedInfo(); sigVerf.update(rawCert, 0, rawCert.length); // verify may throw SignatureException for invalid encodings, etc. verificationResult = sigVerf.verify(signature); verifiedPublicKey = key; if (verificationResult == false) { throw new SignatureException("Signature does not match."); } }
Creates an X.509 certificate, and signs it using the given key (associating a signature algorithm and an X.500 name). This operation is used to implement the certificate generation functionality of a certificate authority.
Params:
  • key – the private key used for signing.
  • algorithm – the name of the signature algorithm used.
Throws:
/** * Creates an X.509 certificate, and signs it using the given key * (associating a signature algorithm and an X.500 name). * This operation is used to implement the certificate generation * functionality of a certificate authority. * * @param key the private key used for signing. * @param algorithm the name of the signature algorithm used. * * @exception InvalidKeyException on incorrect key. * @exception NoSuchAlgorithmException on unsupported signature * algorithms. * @exception NoSuchProviderException if there's no default provider. * @exception SignatureException on signature errors. * @exception CertificateException on encoding errors. */
public void sign(PrivateKey key, String algorithm) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException { sign(key, algorithm, null); }
Creates an X.509 certificate, and signs it using the given key (associating a signature algorithm and an X.500 name). This operation is used to implement the certificate generation functionality of a certificate authority.
Params:
  • key – the private key used for signing.
  • algorithm – the name of the signature algorithm used.
  • provider – the name of the provider.
Throws:
/** * Creates an X.509 certificate, and signs it using the given key * (associating a signature algorithm and an X.500 name). * This operation is used to implement the certificate generation * functionality of a certificate authority. * * @param key the private key used for signing. * @param algorithm the name of the signature algorithm used. * @param provider the name of the provider. * * @exception NoSuchAlgorithmException on unsupported signature * algorithms. * @exception InvalidKeyException on incorrect key. * @exception NoSuchProviderException on incorrect provider. * @exception SignatureException on signature errors. * @exception CertificateException on encoding errors. */
public void sign(PrivateKey key, String algorithm, String provider) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException { try { sign(key, null, algorithm, provider); } catch (InvalidAlgorithmParameterException e) { // should not happen; re-throw just in case throw new SignatureException(e); } }
Creates an X.509 certificate, and signs it using the given key (associating a signature algorithm and an X.500 name), signature parameters, and security provider. If the given provider name is null or empty, the implementation look up will be based on provider configurations. This operation is used to implement the certificate generation functionality of a certificate authority.
Params:
  • key – the private key used for signing
  • signingParams – the parameters used for signing
  • algorithm – the name of the signature algorithm used
  • provider – the name of the provider, may be null
Throws:
/** * Creates an X.509 certificate, and signs it using the given key * (associating a signature algorithm and an X.500 name), signature * parameters, and security provider. If the given provider name * is null or empty, the implementation look up will be based on * provider configurations. * This operation is used to implement the certificate generation * functionality of a certificate authority. * * @param key the private key used for signing * @param signingParams the parameters used for signing * @param algorithm the name of the signature algorithm used * @param provider the name of the provider, may be null * * @exception NoSuchAlgorithmException on unsupported signature * algorithms * @exception InvalidKeyException on incorrect key * @exception InvalidAlgorithmParameterException on invalid signature * parameters * @exception NoSuchProviderException on incorrect provider * @exception SignatureException on signature errors * @exception CertificateException on encoding errors */
public void sign(PrivateKey key, AlgorithmParameterSpec signingParams, String algorithm, String provider) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchProviderException, SignatureException { try { if (readOnly) { throw new CertificateEncodingException( "cannot over-write existing certificate"); } Signature sigEngine = null; if (provider == null || provider.isEmpty()) { sigEngine = Signature.getInstance(algorithm); } else { sigEngine = Signature.getInstance(algorithm, provider); } SignatureUtil.initSignWithParam(sigEngine, key, signingParams, null); if (signingParams != null) { algId = AlgorithmId.get(sigEngine.getParameters()); } else { // in case the name is reset algId = AlgorithmId.get(sigEngine.getAlgorithm()); } DerOutputStream out = new DerOutputStream(); DerOutputStream tmp = new DerOutputStream(); // encode certificate info info.encode(tmp); byte[] rawCert = tmp.toByteArray(); // encode algorithm identifier algId.encode(tmp); // Create and encode the signature itself. sigEngine.update(rawCert, 0, rawCert.length); signature = sigEngine.sign(); tmp.putBitString(signature); // Wrap the signed data in a SEQUENCE { data, algorithm, sig } out.write(DerValue.tag_Sequence, tmp); signedCert = out.toByteArray(); readOnly = true; } catch (IOException e) { throw new CertificateEncodingException(e.toString()); } }
Checks that the certificate is currently valid, i.e. the current time is within the specified validity period.
Throws:
/** * Checks that the certificate is currently valid, i.e. the current * time is within the specified validity period. * * @exception CertificateExpiredException if the certificate has expired. * @exception CertificateNotYetValidException if the certificate is not * yet valid. */
public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException { Date date = new Date(); checkValidity(date); }
Checks that the specified date is within the certificate's validity period, or basically if the certificate would be valid at the specified date/time.
Params:
  • date – the Date to check against to see if this certificate is valid at that date/time.
Throws:
/** * Checks that the specified date is within the certificate's * validity period, or basically if the certificate would be * valid at the specified date/time. * * @param date the Date to check against to see if this certificate * is valid at that date/time. * * @exception CertificateExpiredException if the certificate has expired * with respect to the <code>date</code> supplied. * @exception CertificateNotYetValidException if the certificate is not * yet valid with respect to the <code>date</code> supplied. */
public void checkValidity(Date date) throws CertificateExpiredException, CertificateNotYetValidException { CertificateValidity interval = null; try { interval = (CertificateValidity)info.get(CertificateValidity.NAME); } catch (Exception e) { throw new CertificateNotYetValidException("Incorrect validity period"); } if (interval == null) throw new CertificateNotYetValidException("Null validity period"); interval.valid(date); }
Return the requested attribute from the certificate. Note that the X509CertInfo is not cloned for performance reasons. Callers must ensure that they do not modify it. All other attributes are cloned.
Params:
  • name – the name of the attribute.
Throws:
/** * Return the requested attribute from the certificate. * * Note that the X509CertInfo is not cloned for performance reasons. * Callers must ensure that they do not modify it. All other * attributes are cloned. * * @param name the name of the attribute. * @exception CertificateParsingException on invalid attribute identifier. */
public Object get(String name) throws CertificateParsingException { X509AttributeName attr = new X509AttributeName(name); String id = attr.getPrefix(); if (!(id.equalsIgnoreCase(NAME))) { throw new CertificateParsingException("Invalid root of " + "attribute name, expected [" + NAME + "], received " + "[" + id + "]"); } attr = new X509AttributeName(attr.getSuffix()); id = attr.getPrefix(); if (id.equalsIgnoreCase(INFO)) { if (info == null) { return null; } if (attr.getSuffix() != null) { try { return info.get(attr.getSuffix()); } catch (IOException e) { throw new CertificateParsingException(e.toString()); } catch (CertificateException e) { throw new CertificateParsingException(e.toString()); } } else { return info; } } else if (id.equalsIgnoreCase(ALG_ID)) { return(algId); } else if (id.equalsIgnoreCase(SIGNATURE)) { if (signature != null) return signature.clone(); else return null; } else if (id.equalsIgnoreCase(SIGNED_CERT)) { if (signedCert != null) return signedCert.clone(); else return null; } else { throw new CertificateParsingException("Attribute name not " + "recognized or get() not allowed for the same: " + id); } }
Set the requested attribute in the certificate.
Params:
  • name – the name of the attribute.
  • obj – the value of the attribute.
Throws:
/** * Set the requested attribute in the certificate. * * @param name the name of the attribute. * @param obj the value of the attribute. * @exception CertificateException on invalid attribute identifier. * @exception IOException on encoding error of attribute. */
public void set(String name, Object obj) throws CertificateException, IOException { // check if immutable if (readOnly) throw new CertificateException("cannot over-write existing" + " certificate"); X509AttributeName attr = new X509AttributeName(name); String id = attr.getPrefix(); if (!(id.equalsIgnoreCase(NAME))) { throw new CertificateException("Invalid root of attribute name," + " expected [" + NAME + "], received " + id); } attr = new X509AttributeName(attr.getSuffix()); id = attr.getPrefix(); if (id.equalsIgnoreCase(INFO)) { if (attr.getSuffix() == null) { if (!(obj instanceof X509CertInfo)) { throw new CertificateException("Attribute value should" + " be of type X509CertInfo."); } info = (X509CertInfo)obj; signedCert = null; //reset this as certificate data has changed } else { info.set(attr.getSuffix(), obj); signedCert = null; //reset this as certificate data has changed } } else { throw new CertificateException("Attribute name not recognized or " + "set() not allowed for the same: " + id); } }
Delete the requested attribute from the certificate.
Params:
  • name – the name of the attribute.
Throws:
/** * Delete the requested attribute from the certificate. * * @param name the name of the attribute. * @exception CertificateException on invalid attribute identifier. * @exception IOException on other errors. */
public void delete(String name) throws CertificateException, IOException { // check if immutable if (readOnly) throw new CertificateException("cannot over-write existing" + " certificate"); X509AttributeName attr = new X509AttributeName(name); String id = attr.getPrefix(); if (!(id.equalsIgnoreCase(NAME))) { throw new CertificateException("Invalid root of attribute name," + " expected [" + NAME + "], received " + id); } attr = new X509AttributeName(attr.getSuffix()); id = attr.getPrefix(); if (id.equalsIgnoreCase(INFO)) { if (attr.getSuffix() != null) { info = null; } else { info.delete(attr.getSuffix()); } } else if (id.equalsIgnoreCase(ALG_ID)) { algId = null; } else if (id.equalsIgnoreCase(SIGNATURE)) { signature = null; } else if (id.equalsIgnoreCase(SIGNED_CERT)) { signedCert = null; } else { throw new CertificateException("Attribute name not recognized or " + "delete() not allowed for the same: " + id); } }
Return an enumeration of names of attributes existing within this attribute.
/** * Return an enumeration of names of attributes existing within this * attribute. */
public Enumeration<String> getElements() { AttributeNameEnumeration elements = new AttributeNameEnumeration(); elements.addElement(NAME + DOT + INFO); elements.addElement(NAME + DOT + ALG_ID); elements.addElement(NAME + DOT + SIGNATURE); elements.addElement(NAME + DOT + SIGNED_CERT); return elements.elements(); }
Return the name of this attribute.
/** * Return the name of this attribute. */
public String getName() { return(NAME); }
Returns a printable representation of the certificate. This does not contain all the information available to distinguish this from any other certificate. The certificate must be fully constructed before this function may be called.
/** * Returns a printable representation of the certificate. This does not * contain all the information available to distinguish this from any * other certificate. The certificate must be fully constructed * before this function may be called. */
public String toString() { if (info == null || algId == null || signature == null) return ""; HexDumpEncoder encoder = new HexDumpEncoder(); return "[\n" + info + '\n' + " Algorithm: [" + algId + "]\n" + " Signature:\n" + encoder.encodeBuffer(signature) + "\n]"; } // the strongly typed gets, as per java.security.cert.X509Certificate
Gets the publickey from this certificate.
Returns:the publickey.
/** * Gets the publickey from this certificate. * * @return the publickey. */
public PublicKey getPublicKey() { if (info == null) return null; try { PublicKey key = (PublicKey)info.get(CertificateX509Key.NAME + DOT + CertificateX509Key.KEY); return key; } catch (Exception e) { return null; } }
Gets the version number from the certificate.
Returns:the version number, i.e. 1, 2 or 3.
/** * Gets the version number from the certificate. * * @return the version number, i.e. 1, 2 or 3. */
public int getVersion() { if (info == null) return -1; try { int vers = ((Integer)info.get(CertificateVersion.NAME + DOT + CertificateVersion.VERSION)).intValue(); return vers+1; } catch (Exception e) { return -1; } }
Gets the serial number from the certificate.
Returns:the serial number.
/** * Gets the serial number from the certificate. * * @return the serial number. */
public BigInteger getSerialNumber() { SerialNumber ser = getSerialNumberObject(); return ser != null ? ser.getNumber() : null; }
Gets the serial number from the certificate as a SerialNumber object.
Returns:the serial number.
/** * Gets the serial number from the certificate as * a SerialNumber object. * * @return the serial number. */
public SerialNumber getSerialNumberObject() { if (info == null) return null; try { SerialNumber ser = (SerialNumber)info.get( CertificateSerialNumber.NAME + DOT + CertificateSerialNumber.NUMBER); return ser; } catch (Exception e) { return null; } }
Gets the subject distinguished name from the certificate.
Returns:the subject name.
/** * Gets the subject distinguished name from the certificate. * * @return the subject name. */
public Principal getSubjectDN() { if (info == null) return null; try { Principal subject = (Principal)info.get(X509CertInfo.SUBJECT + DOT + X509CertInfo.DN_NAME); return subject; } catch (Exception e) { return null; } }
Get subject name as X500Principal. Overrides implementation in X509Certificate with a slightly more efficient version that is also aware of X509CertImpl mutability.
/** * Get subject name as X500Principal. Overrides implementation in * X509Certificate with a slightly more efficient version that is * also aware of X509CertImpl mutability. */
public X500Principal getSubjectX500Principal() { if (info == null) { return null; } try { X500Principal subject = (X500Principal)info.get( X509CertInfo.SUBJECT + DOT + "x500principal"); return subject; } catch (Exception e) { return null; } }
Gets the issuer distinguished name from the certificate.
Returns:the issuer name.
/** * Gets the issuer distinguished name from the certificate. * * @return the issuer name. */
public Principal getIssuerDN() { if (info == null) return null; try { Principal issuer = (Principal)info.get(X509CertInfo.ISSUER + DOT + X509CertInfo.DN_NAME); return issuer; } catch (Exception e) { return null; } }
Get issuer name as X500Principal. Overrides implementation in X509Certificate with a slightly more efficient version that is also aware of X509CertImpl mutability.
/** * Get issuer name as X500Principal. Overrides implementation in * X509Certificate with a slightly more efficient version that is * also aware of X509CertImpl mutability. */
public X500Principal getIssuerX500Principal() { if (info == null) { return null; } try { X500Principal issuer = (X500Principal)info.get( X509CertInfo.ISSUER + DOT + "x500principal"); return issuer; } catch (Exception e) { return null; } }
Gets the notBefore date from the validity period of the certificate.
Returns:the start date of the validity period.
/** * Gets the notBefore date from the validity period of the certificate. * * @return the start date of the validity period. */
public Date getNotBefore() { if (info == null) return null; try { Date d = (Date) info.get(CertificateValidity.NAME + DOT + CertificateValidity.NOT_BEFORE); return d; } catch (Exception e) { return null; } }
Gets the notAfter date from the validity period of the certificate.
Returns:the end date of the validity period.
/** * Gets the notAfter date from the validity period of the certificate. * * @return the end date of the validity period. */
public Date getNotAfter() { if (info == null) return null; try { Date d = (Date) info.get(CertificateValidity.NAME + DOT + CertificateValidity.NOT_AFTER); return d; } catch (Exception e) { return null; } }
Gets the DER encoded certificate informations, the tbsCertificate from this certificate. This can be used to verify the signature independently.
Throws:
Returns:the DER encoded certificate information.
/** * Gets the DER encoded certificate informations, the * <code>tbsCertificate</code> from this certificate. * This can be used to verify the signature independently. * * @return the DER encoded certificate information. * @exception CertificateEncodingException if an encoding error occurs. */
public byte[] getTBSCertificate() throws CertificateEncodingException { if (info != null) { return info.getEncodedInfo(); } else throw new CertificateEncodingException("Uninitialized certificate"); }
Gets the raw Signature bits from the certificate.
Returns:the signature.
/** * Gets the raw Signature bits from the certificate. * * @return the signature. */
public byte[] getSignature() { if (signature == null) return null; return signature.clone(); }
Gets the signature algorithm name for the certificate signature algorithm. For example, the string "SHA-1/DSA" or "DSS".
Returns:the signature algorithm name.
/** * Gets the signature algorithm name for the certificate * signature algorithm. * For example, the string "SHA-1/DSA" or "DSS". * * @return the signature algorithm name. */
public String getSigAlgName() { if (algId == null) return null; return (algId.getName()); }
Gets the signature algorithm OID string from the certificate. For example, the string "1.2.840.10040.4.3"
Returns:the signature algorithm oid string.
/** * Gets the signature algorithm OID string from the certificate. * For example, the string "1.2.840.10040.4.3" * * @return the signature algorithm oid string. */
public String getSigAlgOID() { if (algId == null) return null; ObjectIdentifier oid = algId.getOID(); return (oid.toString()); }
Gets the DER encoded signature algorithm parameters from this certificate's signature algorithm.
Returns:the DER encoded signature algorithm parameters, or null if no parameters are present.
/** * Gets the DER encoded signature algorithm parameters from this * certificate's signature algorithm. * * @return the DER encoded signature algorithm parameters, or * null if no parameters are present. */
public byte[] getSigAlgParams() { if (algId == null) return null; try { return algId.getEncodedParams(); } catch (IOException e) { return null; } }
Gets the Issuer Unique Identity from the certificate.
Returns:the Issuer Unique Identity.
/** * Gets the Issuer Unique Identity from the certificate. * * @return the Issuer Unique Identity. */
public boolean[] getIssuerUniqueID() { if (info == null) return null; try { UniqueIdentity id = (UniqueIdentity)info.get( X509CertInfo.ISSUER_ID); if (id == null) return null; else return (id.getId()); } catch (Exception e) { return null; } }
Gets the Subject Unique Identity from the certificate.
Returns:the Subject Unique Identity.
/** * Gets the Subject Unique Identity from the certificate. * * @return the Subject Unique Identity. */
public boolean[] getSubjectUniqueID() { if (info == null) return null; try { UniqueIdentity id = (UniqueIdentity)info.get( X509CertInfo.SUBJECT_ID); if (id == null) return null; else return (id.getId()); } catch (Exception e) { return null; } } public KeyIdentifier getAuthKeyId() { AuthorityKeyIdentifierExtension aki = getAuthorityKeyIdentifierExtension(); if (aki != null) { try { return (KeyIdentifier)aki.get( AuthorityKeyIdentifierExtension.KEY_ID); } catch (IOException ioe) {} // not possible } return null; }
Returns the subject's key identifier, or null
/** * Returns the subject's key identifier, or null */
public KeyIdentifier getSubjectKeyId() { SubjectKeyIdentifierExtension ski = getSubjectKeyIdentifierExtension(); if (ski != null) { try { return ski.get(SubjectKeyIdentifierExtension.KEY_ID); } catch (IOException ioe) {} // not possible } return null; }
Get AuthorityKeyIdentifier extension
Returns:AuthorityKeyIdentifier object or null (if no such object in certificate)
/** * Get AuthorityKeyIdentifier extension * @return AuthorityKeyIdentifier object or null (if no such object * in certificate) */
public AuthorityKeyIdentifierExtension getAuthorityKeyIdentifierExtension() { return (AuthorityKeyIdentifierExtension) getExtension(PKIXExtensions.AuthorityKey_Id); }
Get BasicConstraints extension
Returns:BasicConstraints object or null (if no such object in certificate)
/** * Get BasicConstraints extension * @return BasicConstraints object or null (if no such object in * certificate) */
public BasicConstraintsExtension getBasicConstraintsExtension() { return (BasicConstraintsExtension) getExtension(PKIXExtensions.BasicConstraints_Id); }
Get CertificatePoliciesExtension
Returns:CertificatePoliciesExtension or null (if no such object in certificate)
/** * Get CertificatePoliciesExtension * @return CertificatePoliciesExtension or null (if no such object in * certificate) */
public CertificatePoliciesExtension getCertificatePoliciesExtension() { return (CertificatePoliciesExtension) getExtension(PKIXExtensions.CertificatePolicies_Id); }
Get ExtendedKeyUsage extension
Returns:ExtendedKeyUsage extension object or null (if no such object in certificate)
/** * Get ExtendedKeyUsage extension * @return ExtendedKeyUsage extension object or null (if no such object * in certificate) */
public ExtendedKeyUsageExtension getExtendedKeyUsageExtension() { return (ExtendedKeyUsageExtension) getExtension(PKIXExtensions.ExtendedKeyUsage_Id); }
Get IssuerAlternativeName extension
Returns:IssuerAlternativeName object or null (if no such object in certificate)
/** * Get IssuerAlternativeName extension * @return IssuerAlternativeName object or null (if no such object in * certificate) */
public IssuerAlternativeNameExtension getIssuerAlternativeNameExtension() { return (IssuerAlternativeNameExtension) getExtension(PKIXExtensions.IssuerAlternativeName_Id); }
Get NameConstraints extension
Returns:NameConstraints object or null (if no such object in certificate)
/** * Get NameConstraints extension * @return NameConstraints object or null (if no such object in certificate) */
public NameConstraintsExtension getNameConstraintsExtension() { return (NameConstraintsExtension) getExtension(PKIXExtensions.NameConstraints_Id); }
Get PolicyConstraints extension
Returns:PolicyConstraints object or null (if no such object in certificate)
/** * Get PolicyConstraints extension * @return PolicyConstraints object or null (if no such object in * certificate) */
public PolicyConstraintsExtension getPolicyConstraintsExtension() { return (PolicyConstraintsExtension) getExtension(PKIXExtensions.PolicyConstraints_Id); }
Get PolicyMappingsExtension extension
Returns:PolicyMappingsExtension object or null (if no such object in certificate)
/** * Get PolicyMappingsExtension extension * @return PolicyMappingsExtension object or null (if no such object * in certificate) */
public PolicyMappingsExtension getPolicyMappingsExtension() { return (PolicyMappingsExtension) getExtension(PKIXExtensions.PolicyMappings_Id); }
Get PrivateKeyUsage extension
Returns:PrivateKeyUsage object or null (if no such object in certificate)
/** * Get PrivateKeyUsage extension * @return PrivateKeyUsage object or null (if no such object in certificate) */
public PrivateKeyUsageExtension getPrivateKeyUsageExtension() { return (PrivateKeyUsageExtension) getExtension(PKIXExtensions.PrivateKeyUsage_Id); }
Get SubjectAlternativeName extension
Returns:SubjectAlternativeName object or null (if no such object in certificate)
/** * Get SubjectAlternativeName extension * @return SubjectAlternativeName object or null (if no such object in * certificate) */
public SubjectAlternativeNameExtension getSubjectAlternativeNameExtension() { return (SubjectAlternativeNameExtension) getExtension(PKIXExtensions.SubjectAlternativeName_Id); }
Get SubjectKeyIdentifier extension
Returns:SubjectKeyIdentifier object or null (if no such object in certificate)
/** * Get SubjectKeyIdentifier extension * @return SubjectKeyIdentifier object or null (if no such object in * certificate) */
public SubjectKeyIdentifierExtension getSubjectKeyIdentifierExtension() { return (SubjectKeyIdentifierExtension) getExtension(PKIXExtensions.SubjectKey_Id); }
Get CRLDistributionPoints extension
Returns:CRLDistributionPoints object or null (if no such object in certificate)
/** * Get CRLDistributionPoints extension * @return CRLDistributionPoints object or null (if no such object in * certificate) */
public CRLDistributionPointsExtension getCRLDistributionPointsExtension() { return (CRLDistributionPointsExtension) getExtension(PKIXExtensions.CRLDistributionPoints_Id); }
Return true if a critical extension is found that is not supported, otherwise return false.
/** * Return true if a critical extension is found that is * not supported, otherwise return false. */
public boolean hasUnsupportedCriticalExtension() { if (info == null) return false; try { CertificateExtensions exts = (CertificateExtensions)info.get( CertificateExtensions.NAME); if (exts == null) return false; return exts.hasUnsupportedCriticalExtension(); } catch (Exception e) { return false; } }
Gets a Set of the extension(s) marked CRITICAL in the certificate. In the returned set, each extension is represented by its OID string.
Returns:a set of the extension oid strings in the certificate that are marked critical.
/** * Gets a Set of the extension(s) marked CRITICAL in the * certificate. In the returned set, each extension is * represented by its OID string. * * @return a set of the extension oid strings in the * certificate that are marked critical. */
public Set<String> getCriticalExtensionOIDs() { if (info == null) { return null; } try { CertificateExtensions exts = (CertificateExtensions)info.get( CertificateExtensions.NAME); if (exts == null) { return null; } Set<String> extSet = new TreeSet<>(); for (Extension ex : exts.getAllExtensions()) { if (ex.isCritical()) { extSet.add(ex.getExtensionId().toString()); } } return extSet; } catch (Exception e) { return null; } }
Gets a Set of the extension(s) marked NON-CRITICAL in the certificate. In the returned set, each extension is represented by its OID string.
Returns:a set of the extension oid strings in the certificate that are NOT marked critical.
/** * Gets a Set of the extension(s) marked NON-CRITICAL in the * certificate. In the returned set, each extension is * represented by its OID string. * * @return a set of the extension oid strings in the * certificate that are NOT marked critical. */
public Set<String> getNonCriticalExtensionOIDs() { if (info == null) { return null; } try { CertificateExtensions exts = (CertificateExtensions)info.get( CertificateExtensions.NAME); if (exts == null) { return null; } Set<String> extSet = new TreeSet<>(); for (Extension ex : exts.getAllExtensions()) { if (!ex.isCritical()) { extSet.add(ex.getExtensionId().toString()); } } extSet.addAll(exts.getUnparseableExtensions().keySet()); return extSet; } catch (Exception e) { return null; } }
Gets the extension identified by the given ObjectIdentifier
Params:
  • oid – the Object Identifier value for the extension.
Returns:Extension or null if certificate does not contain this extension
/** * Gets the extension identified by the given ObjectIdentifier * * @param oid the Object Identifier value for the extension. * @return Extension or null if certificate does not contain this * extension */
public Extension getExtension(ObjectIdentifier oid) { if (info == null) { return null; } try { CertificateExtensions extensions; try { extensions = (CertificateExtensions)info.get(CertificateExtensions.NAME); } catch (CertificateException ce) { return null; } if (extensions == null) { return null; } else { Extension ex = extensions.getExtension(oid.toString()); if (ex != null) { return ex; } for (Extension ex2: extensions.getAllExtensions()) { if (ex2.getExtensionId().equals(oid)) { //XXXX May want to consider cloning this return ex2; } } /* no such extension in this certificate */ return null; } } catch (IOException ioe) { return null; } } public Extension getUnparseableExtension(ObjectIdentifier oid) { if (info == null) { return null; } try { CertificateExtensions extensions; try { extensions = (CertificateExtensions)info.get(CertificateExtensions.NAME); } catch (CertificateException ce) { return null; } if (extensions == null) { return null; } else { return extensions.getUnparseableExtensions().get(oid.toString()); } } catch (IOException ioe) { return null; } }
Gets the DER encoded extension identified by the given oid String.
Params:
  • oid – the Object Identifier value for the extension.
/** * Gets the DER encoded extension identified by the given * oid String. * * @param oid the Object Identifier value for the extension. */
public byte[] getExtensionValue(String oid) { try { ObjectIdentifier findOID = new ObjectIdentifier(oid); String extAlias = OIDMap.getName(findOID); Extension certExt = null; CertificateExtensions exts = (CertificateExtensions)info.get( CertificateExtensions.NAME); if (extAlias == null) { // may be unknown // get the extensions, search thru' for this oid if (exts == null) { return null; } for (Extension ex : exts.getAllExtensions()) { ObjectIdentifier inCertOID = ex.getExtensionId(); if (inCertOID.equals(findOID)) { certExt = ex; break; } } } else { // there's sub-class that can handle this extension try { certExt = (Extension)this.get(extAlias); } catch (CertificateException e) { // get() throws an Exception instead of returning null, ignore } } if (certExt == null) { if (exts != null) { certExt = exts.getUnparseableExtensions().get(oid); } if (certExt == null) { return null; } } byte[] extData = certExt.getExtensionValue(); if (extData == null) { return null; } DerOutputStream out = new DerOutputStream(); out.putOctetString(extData); return out.toByteArray(); } catch (Exception e) { return null; } }
Get a boolean array representing the bits of the KeyUsage extension, (oid = 2.5.29.15).
Returns:the bit values of this extension as an array of booleans.
/** * Get a boolean array representing the bits of the KeyUsage extension, * (oid = 2.5.29.15). * @return the bit values of this extension as an array of booleans. */
public boolean[] getKeyUsage() { try { String extAlias = OIDMap.getName(PKIXExtensions.KeyUsage_Id); if (extAlias == null) return null; KeyUsageExtension certExt = (KeyUsageExtension)this.get(extAlias); if (certExt == null) return null; boolean[] ret = certExt.getBits(); if (ret.length < NUM_STANDARD_KEY_USAGE) { boolean[] usageBits = new boolean[NUM_STANDARD_KEY_USAGE]; System.arraycopy(ret, 0, usageBits, 0, ret.length); ret = usageBits; } return ret; } catch (Exception e) { return null; } }
This method are the overridden implementation of getExtendedKeyUsage method in X509Certificate in the Sun provider. It is better performance-wise since it returns cached values.
/** * This method are the overridden implementation of * getExtendedKeyUsage method in X509Certificate in the Sun * provider. It is better performance-wise since it returns cached * values. */
public synchronized List<String> getExtendedKeyUsage() throws CertificateParsingException { if (readOnly && extKeyUsage != null) { return extKeyUsage; } else { ExtendedKeyUsageExtension ext = getExtendedKeyUsageExtension(); if (ext == null) { return null; } extKeyUsage = Collections.unmodifiableList(ext.getExtendedKeyUsage()); return extKeyUsage; } }
This static method is the default implementation of the getExtendedKeyUsage method in X509Certificate. A X509Certificate provider generally should overwrite this to provide among other things caching for better performance.
/** * This static method is the default implementation of the * getExtendedKeyUsage method in X509Certificate. A * X509Certificate provider generally should overwrite this to * provide among other things caching for better performance. */
public static List<String> getExtendedKeyUsage(X509Certificate cert) throws CertificateParsingException { try { byte[] ext = cert.getExtensionValue(EXTENDED_KEY_USAGE_OID); if (ext == null) return null; DerValue val = new DerValue(ext); byte[] data = val.getOctetString(); ExtendedKeyUsageExtension ekuExt = new ExtendedKeyUsageExtension(Boolean.FALSE, data); return Collections.unmodifiableList(ekuExt.getExtendedKeyUsage()); } catch (IOException ioe) { throw new CertificateParsingException(ioe); } }
Get the certificate constraints path length from the critical BasicConstraints extension, (oid = 2.5.29.19).
Returns:the length of the constraint.
/** * Get the certificate constraints path length from * the critical BasicConstraints extension, (oid = 2.5.29.19). * @return the length of the constraint. */
public int getBasicConstraints() { try { String extAlias = OIDMap.getName(PKIXExtensions.BasicConstraints_Id); if (extAlias == null) return -1; BasicConstraintsExtension certExt = (BasicConstraintsExtension)this.get(extAlias); if (certExt == null) return -1; if (((Boolean)certExt.get(BasicConstraintsExtension.IS_CA) ).booleanValue() == true) return ((Integer)certExt.get( BasicConstraintsExtension.PATH_LEN)).intValue(); else return -1; } catch (Exception e) { return -1; } }
Converts a GeneralNames structure into an immutable Collection of alternative names (subject or issuer) in the form required by getSubjectAlternativeNames or getIssuerAlternativeNames.
Params:
  • names – the GeneralNames to be converted
Returns:an immutable Collection of alternative names
/** * Converts a GeneralNames structure into an immutable Collection of * alternative names (subject or issuer) in the form required by * {@link #getSubjectAlternativeNames} or * {@link #getIssuerAlternativeNames}. * * @param names the GeneralNames to be converted * @return an immutable Collection of alternative names */
private static Collection<List<?>> makeAltNames(GeneralNames names) { if (names.isEmpty()) { return Collections.<List<?>>emptySet(); } List<List<?>> newNames = new ArrayList<>(); for (GeneralName gname : names.names()) { GeneralNameInterface name = gname.getName(); List<Object> nameEntry = new ArrayList<>(2); nameEntry.add(Integer.valueOf(name.getType())); switch (name.getType()) { case GeneralNameInterface.NAME_RFC822: nameEntry.add(((RFC822Name) name).getName()); break; case GeneralNameInterface.NAME_DNS: nameEntry.add(((DNSName) name).getName()); break; case GeneralNameInterface.NAME_DIRECTORY: nameEntry.add(((X500Name) name).getRFC2253Name()); break; case GeneralNameInterface.NAME_URI: nameEntry.add(((URIName) name).getName()); break; case GeneralNameInterface.NAME_IP: try { nameEntry.add(((IPAddressName) name).getName()); } catch (IOException ioe) { // IPAddressName in cert is bogus throw new RuntimeException("IPAddress cannot be parsed", ioe); } break; case GeneralNameInterface.NAME_OID: nameEntry.add(((OIDName) name).getOID().toString()); break; default: // add DER encoded form DerOutputStream derOut = new DerOutputStream(); try { name.encode(derOut); } catch (IOException ioe) { // should not occur since name has already been decoded // from cert (this would indicate a bug in our code) throw new RuntimeException("name cannot be encoded", ioe); } nameEntry.add(derOut.toByteArray()); break; } newNames.add(Collections.unmodifiableList(nameEntry)); } return Collections.unmodifiableCollection(newNames); }
Checks a Collection of altNames and clones any name entries of type byte [].
/** * Checks a Collection of altNames and clones any name entries of type * byte []. */
// only partially generified due to javac bug private static Collection<List<?>> cloneAltNames(Collection<List<?>> altNames) { boolean mustClone = false; for (List<?> nameEntry : altNames) { if (nameEntry.get(1) instanceof byte[]) { // must clone names mustClone = true; } } if (mustClone) { List<List<?>> namesCopy = new ArrayList<>(); for (List<?> nameEntry : altNames) { Object nameObject = nameEntry.get(1); if (nameObject instanceof byte[]) { List<Object> nameEntryCopy = new ArrayList<>(nameEntry); nameEntryCopy.set(1, ((byte[])nameObject).clone()); namesCopy.add(Collections.unmodifiableList(nameEntryCopy)); } else { namesCopy.add(nameEntry); } } return Collections.unmodifiableCollection(namesCopy); } else { return altNames; } }
This method are the overridden implementation of getSubjectAlternativeNames method in X509Certificate in the Sun provider. It is better performance-wise since it returns cached values.
/** * This method are the overridden implementation of * getSubjectAlternativeNames method in X509Certificate in the Sun * provider. It is better performance-wise since it returns cached * values. */
public synchronized Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException { // return cached value if we can if (readOnly && subjectAlternativeNames != null) { return cloneAltNames(subjectAlternativeNames); } SubjectAlternativeNameExtension subjectAltNameExt = getSubjectAlternativeNameExtension(); if (subjectAltNameExt == null) { return null; } GeneralNames names; try { names = subjectAltNameExt.get( SubjectAlternativeNameExtension.SUBJECT_NAME); } catch (IOException ioe) { // should not occur return Collections.<List<?>>emptySet(); } subjectAlternativeNames = makeAltNames(names); return subjectAlternativeNames; }
This static method is the default implementation of the getSubjectAlternaitveNames method in X509Certificate. A X509Certificate provider generally should overwrite this to provide among other things caching for better performance.
/** * This static method is the default implementation of the * getSubjectAlternaitveNames method in X509Certificate. A * X509Certificate provider generally should overwrite this to * provide among other things caching for better performance. */
public static Collection<List<?>> getSubjectAlternativeNames(X509Certificate cert) throws CertificateParsingException { try { byte[] ext = cert.getExtensionValue(SUBJECT_ALT_NAME_OID); if (ext == null) { return null; } DerValue val = new DerValue(ext); byte[] data = val.getOctetString(); SubjectAlternativeNameExtension subjectAltNameExt = new SubjectAlternativeNameExtension(Boolean.FALSE, data); GeneralNames names; try { names = subjectAltNameExt.get( SubjectAlternativeNameExtension.SUBJECT_NAME); } catch (IOException ioe) { // should not occur return Collections.<List<?>>emptySet(); } return makeAltNames(names); } catch (IOException ioe) { throw new CertificateParsingException(ioe); } }
This method are the overridden implementation of getIssuerAlternativeNames method in X509Certificate in the Sun provider. It is better performance-wise since it returns cached values.
/** * This method are the overridden implementation of * getIssuerAlternativeNames method in X509Certificate in the Sun * provider. It is better performance-wise since it returns cached * values. */
public synchronized Collection<List<?>> getIssuerAlternativeNames() throws CertificateParsingException { // return cached value if we can if (readOnly && issuerAlternativeNames != null) { return cloneAltNames(issuerAlternativeNames); } IssuerAlternativeNameExtension issuerAltNameExt = getIssuerAlternativeNameExtension(); if (issuerAltNameExt == null) { return null; } GeneralNames names; try { names = issuerAltNameExt.get( IssuerAlternativeNameExtension.ISSUER_NAME); } catch (IOException ioe) { // should not occur return Collections.<List<?>>emptySet(); } issuerAlternativeNames = makeAltNames(names); return issuerAlternativeNames; }
This static method is the default implementation of the getIssuerAlternaitveNames method in X509Certificate. A X509Certificate provider generally should overwrite this to provide among other things caching for better performance.
/** * This static method is the default implementation of the * getIssuerAlternaitveNames method in X509Certificate. A * X509Certificate provider generally should overwrite this to * provide among other things caching for better performance. */
public static Collection<List<?>> getIssuerAlternativeNames(X509Certificate cert) throws CertificateParsingException { try { byte[] ext = cert.getExtensionValue(ISSUER_ALT_NAME_OID); if (ext == null) { return null; } DerValue val = new DerValue(ext); byte[] data = val.getOctetString(); IssuerAlternativeNameExtension issuerAltNameExt = new IssuerAlternativeNameExtension(Boolean.FALSE, data); GeneralNames names; try { names = issuerAltNameExt.get( IssuerAlternativeNameExtension.ISSUER_NAME); } catch (IOException ioe) { // should not occur return Collections.<List<?>>emptySet(); } return makeAltNames(names); } catch (IOException ioe) { throw new CertificateParsingException(ioe); } } public AuthorityInfoAccessExtension getAuthorityInfoAccessExtension() { return (AuthorityInfoAccessExtension) getExtension(PKIXExtensions.AuthInfoAccess_Id); } /************************************************************/ /* * Cert is a SIGNED ASN.1 macro, a three elment sequence: * * - Data to be signed (ToBeSigned) -- the "raw" cert * - Signature algorithm (SigAlgId) * - The signature bits * * This routine unmarshals the certificate, saving the signature * parts away for later verification. */ private void parse(DerValue val) throws CertificateException, IOException { // check if can over write the certificate if (readOnly) throw new CertificateParsingException( "cannot over-write existing certificate"); if (val.data == null || val.tag != DerValue.tag_Sequence) throw new CertificateParsingException( "invalid DER-encoded certificate data"); signedCert = val.toByteArray(); DerValue[] seq = new DerValue[3]; seq[0] = val.data.getDerValue(); seq[1] = val.data.getDerValue(); seq[2] = val.data.getDerValue(); if (val.data.available() != 0) { throw new CertificateParsingException("signed overrun, bytes = " + val.data.available()); } if (seq[0].tag != DerValue.tag_Sequence) { throw new CertificateParsingException("signed fields invalid"); } algId = AlgorithmId.parse(seq[1]); signature = seq[2].getBitString(); if (seq[1].data.available() != 0) { throw new CertificateParsingException("algid field overrun"); } if (seq[2].data.available() != 0) throw new CertificateParsingException("signed fields overrun"); // The CertificateInfo info = new X509CertInfo(seq[0]); // the "inner" and "outer" signature algorithms must match AlgorithmId infoSigAlg = (AlgorithmId)info.get( CertificateAlgorithmId.NAME + DOT + CertificateAlgorithmId.ALGORITHM); if (! algId.equals(infoSigAlg)) throw new CertificateException("Signature algorithm mismatch"); readOnly = true; }
Extract the subject or issuer X500Principal from an X509Certificate. Parses the encoded form of the cert to preserve the principal's ASN.1 encoding.
/** * Extract the subject or issuer X500Principal from an X509Certificate. * Parses the encoded form of the cert to preserve the principal's * ASN.1 encoding. */
private static X500Principal getX500Principal(X509Certificate cert, boolean getIssuer) throws Exception { byte[] encoded = cert.getEncoded(); DerInputStream derIn = new DerInputStream(encoded); DerValue tbsCert = derIn.getSequence(3)[0]; DerInputStream tbsIn = tbsCert.data; DerValue tmp; tmp = tbsIn.getDerValue(); // skip version number if present if (tmp.isContextSpecific((byte)0)) { tmp = tbsIn.getDerValue(); } // tmp always contains serial number now tmp = tbsIn.getDerValue(); // skip signature tmp = tbsIn.getDerValue(); // issuer if (getIssuer == false) { tmp = tbsIn.getDerValue(); // skip validity tmp = tbsIn.getDerValue(); // subject } byte[] principalBytes = tmp.toByteArray(); return new X500Principal(principalBytes); }
Extract the subject X500Principal from an X509Certificate. Called from java.security.cert.X509Certificate.getSubjectX500Principal().
/** * Extract the subject X500Principal from an X509Certificate. * Called from java.security.cert.X509Certificate.getSubjectX500Principal(). */
public static X500Principal getSubjectX500Principal(X509Certificate cert) { try { return getX500Principal(cert, false); } catch (Exception e) { throw new RuntimeException("Could not parse subject", e); } }
Extract the issuer X500Principal from an X509Certificate. Called from java.security.cert.X509Certificate.getIssuerX500Principal().
/** * Extract the issuer X500Principal from an X509Certificate. * Called from java.security.cert.X509Certificate.getIssuerX500Principal(). */
public static X500Principal getIssuerX500Principal(X509Certificate cert) { try { return getX500Principal(cert, true); } catch (Exception e) { throw new RuntimeException("Could not parse issuer", e); } }
Returned the encoding of the given certificate for internal use. Callers must guarantee that they neither modify it nor expose it to untrusted code. Uses getEncodedInternal() if the certificate is instance of X509CertImpl, getEncoded() otherwise.
/** * Returned the encoding of the given certificate for internal use. * Callers must guarantee that they neither modify it nor expose it * to untrusted code. Uses getEncodedInternal() if the certificate * is instance of X509CertImpl, getEncoded() otherwise. */
public static byte[] getEncodedInternal(Certificate cert) throws CertificateEncodingException { if (cert instanceof X509CertImpl) { return ((X509CertImpl)cert).getEncodedInternal(); } else { return cert.getEncoded(); } }
Utility method to convert an arbitrary instance of X509Certificate to a X509CertImpl. Does a cast if possible, otherwise reparses the encoding.
/** * Utility method to convert an arbitrary instance of X509Certificate * to a X509CertImpl. Does a cast if possible, otherwise reparses * the encoding. */
public static X509CertImpl toImpl(X509Certificate cert) throws CertificateException { if (cert instanceof X509CertImpl) { return (X509CertImpl)cert; } else { return X509Factory.intern(cert); } }
Utility method to test if a certificate is self-issued. This is the case iff the subject and issuer X500Principals are equal.
/** * Utility method to test if a certificate is self-issued. This is * the case iff the subject and issuer X500Principals are equal. */
public static boolean isSelfIssued(X509Certificate cert) { X500Principal subject = cert.getSubjectX500Principal(); X500Principal issuer = cert.getIssuerX500Principal(); return subject.equals(issuer); }
Utility method to test if a certificate is self-signed. This is the case iff the subject and issuer X500Principals are equal AND the certificate's subject public key can be used to verify the certificate. In case of exception, returns false.
/** * Utility method to test if a certificate is self-signed. This is * the case iff the subject and issuer X500Principals are equal * AND the certificate's subject public key can be used to verify * the certificate. In case of exception, returns false. */
public static boolean isSelfSigned(X509Certificate cert, String sigProvider) { if (isSelfIssued(cert)) { try { if (sigProvider == null) { cert.verify(cert.getPublicKey()); } else { cert.verify(cert.getPublicKey(), sigProvider); } return true; } catch (Exception e) { // In case of exception, return false } } return false; } private ConcurrentHashMap<String,String> fingerprints = new ConcurrentHashMap<>(2); public String getFingerprint(String algorithm) { return fingerprints.computeIfAbsent(algorithm, x -> getFingerprint(x, this)); }
Gets the requested finger print of the certificate. The result only contains 0-9 and A-F. No small case, no colon.
/** * Gets the requested finger print of the certificate. The result * only contains 0-9 and A-F. No small case, no colon. */
public static String getFingerprint(String algorithm, X509Certificate cert) { try { byte[] encCertInfo = cert.getEncoded(); MessageDigest md = MessageDigest.getInstance(algorithm); byte[] digest = md.digest(encCertInfo); StringBuilder sb = new StringBuilder(digest.length * 2); for (int i = 0; i < digest.length; i++) { byte2hex(digest[i], sb); } return sb.toString(); } catch (NoSuchAlgorithmException | CertificateEncodingException e) { // ignored } return ""; }
Converts a byte to hex digit and writes to the supplied builder
/** * Converts a byte to hex digit and writes to the supplied builder */
private static void byte2hex(byte b, StringBuilder buf) { char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; int high = ((b & 0xf0) >> 4); int low = (b & 0x0f); buf.append(hexChars[high]) .append(hexChars[low]); } }