/*
 * Copyright (c) 1997, 2004, 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.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.math.BigInteger;
import java.security.*;
import java.util.Date;
import java.util.Enumeration;

import sun.security.util.*;     // DER

Author:David Brownell
See Also:
  • CertAndKeyGen
Deprecated: Use the new X509Certificate class. This class is only restored for backwards compatibility.
/** * @author David Brownell * * @see CertAndKeyGen * @deprecated Use the new X509Certificate class. * This class is only restored for backwards compatibility. */
@Deprecated public class X509Cert implements Certificate, Serializable { static final long serialVersionUID = -52595524744692374L; /* * NOTE: All fields are marked transient, because we do not want them to * be included in the class description when we serialize an object of * this class. We override "writeObject" and "readObject" to use the * ASN.1 encoding of a certificate as the serialized form, instead of * calling the default routines which would operate on the field values. * * MAKE SURE TO MARK ANY FIELDS THAT ARE ADDED IN THE FUTURE AS TRANSIENT. */ /* The algorithm id */ transient protected AlgorithmId algid; /* * Certificate data, and its envelope */ transient private byte rawCert []; transient private byte signature []; transient private byte signedCert []; /* * X509.v1 data (parsed) */ transient private X500Name subject; // from subject transient private PublicKey pubkey; transient private Date notafter; // from CA (constructor) transient private Date notbefore; transient private int version; // from CA (signAndEncode) transient private BigInteger serialnum; transient private X500Name issuer; transient private AlgorithmId issuerSigAlg; /* * flag to indicate whether or not this certificate has already been parsed * (through a call to one of the constructors or the "decode" or * "readObject" methods). This is to ensure that certificates are * immutable. */ transient private boolean parsed=false; /* * X509.v2 extensions */ /* * X509.v3 extensions */ /* * Other extensions ... Netscape, Verisign, SET, etc */
Construct a uninitialized X509 Cert on which decode must later be called (or which may be deserialized).
/** * Construct a uninitialized X509 Cert on which <a href="#decode"> * decode</a> must later be called (or which may be deserialized). */
// XXX deprecated, delete this public X509Cert() { }
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:
  • cert – the encoded bytes, with no terminatu (CONSUMED)
Throws:
  • IOException – when the certificate is improperly encoded.
/** * 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 cert the encoded bytes, with no terminatu (CONSUMED) * @exception IOException when the certificate is improperly encoded. */
public X509Cert(byte cert []) throws IOException { DerValue in = new DerValue (cert); parse (in); if (in.data.available () != 0) throw new CertParseError ("garbage at end"); signedCert = cert; }
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 most commonly used constructors.
Params:
  • buf – the buffer holding the encoded bytes
  • offset – the offset in the buffer where the bytes begin
  • len – how many bytes of certificate exist
Throws:
  • IOException – when the certificate is improperly encoded.
/** * 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 most commonly used constructors. * * @param buf the buffer holding the encoded bytes * @param offset the offset in the buffer where the bytes begin * @param len how many bytes of certificate exist * * @exception IOException when the certificate is improperly encoded. */
public X509Cert(byte buf [], int offset, int len) throws IOException { DerValue in = new DerValue (buf, offset, len); parse (in); if (in.data.available () != 0) throw new CertParseError ("garbage at end"); signedCert = new byte [len]; System.arraycopy (buf, offset, signedCert, 0, len); }
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:
  • IOException – when the certificate is improperly encoded.
/** * 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 IOException when the certificate is improperly encoded. */
public X509Cert(DerValue derVal) throws IOException { parse (derVal); if (derVal.data.available () != 0) throw new CertParseError ("garbage at end"); signedCert = derVal.toByteArray (); }
Partially constructs a certificate from descriptive parameters. This constructor may be used by Certificate Authority (CA) code, which later signs and encodes the certificate. Also, self-signed certificates serve as CA certificates, and are sometimes used as certificate requests.

Until the certificate has been signed and encoded, some of the mandatory fields in the certificate will not be available via accessor functions: the serial number, issuer name and signing algorithm, and of course the signed certificate. The fields passed to this constructor are available, and must be non-null.

Note that the public key being signed is generally independent of the signature algorithm being used. So for example Diffie-Hellman keys (which do not support signatures) can be placed in X.509 certificates when some other signature algorithm (e.g. DSS/DSA, or one of the RSA based algorithms) is used.

Params:
  • subjectName – the X.500 distinguished name being certified
  • subjectPublicKey – the public key being certified. This must be an "X509Key" implementing the "PublicKey" interface.
  • notBefore – the first time the certificate is valid
  • notAfter – the last time the certificate is valid
Throws:
See Also:
  • CertAndKeyGen
/** * Partially constructs a certificate from descriptive parameters. * This constructor may be used by Certificate Authority (CA) code, * which later <a href="#signAndEncode">signs and encodes</a> the * certificate. Also, self-signed certificates serve as CA certificates, * and are sometimes used as certificate requests. * * <P>Until the certificate has been signed and encoded, some of * the mandatory fields in the certificate will not be available * via accessor functions: the serial number, issuer name and signing * algorithm, and of course the signed certificate. The fields passed * to this constructor are available, and must be non-null. * * <P>Note that the public key being signed is generally independent of * the signature algorithm being used. So for example Diffie-Hellman * keys (which do not support signatures) can be placed in X.509 * certificates when some other signature algorithm (e.g. DSS/DSA, * or one of the RSA based algorithms) is used. * * @see CertAndKeyGen * * @param subjectName the X.500 distinguished name being certified * @param subjectPublicKey the public key being certified. This * must be an "X509Key" implementing the "PublicKey" interface. * @param notBefore the first time the certificate is valid * @param notAfter the last time the certificate is valid * * @exception CertException if the public key is inappropriate */
public X509Cert(X500Name subjectName, X509Key subjectPublicKey, Date notBefore, Date notAfter) throws CertException { subject = subjectName; if (!(subjectPublicKey instanceof PublicKey)) throw new CertException (CertException.err_INVALID_PUBLIC_KEY, "Doesn't implement PublicKey interface"); // The X509 cert API requires X509 keys, else things break. pubkey = subjectPublicKey; notbefore = notBefore; notafter = notAfter; version = 0; }
Decode an X.509 certificate from an input stream.
Params:
  • in – an input stream holding at least one certificate
Throws:
  • IOException – when the certificate is improperly encoded, or if it has already been parsed.
/** * Decode an X.509 certificate from an input stream. * * @param in an input stream holding at least one certificate * @exception IOException when the certificate is improperly encoded, or * if it has already been parsed. */
public void decode(InputStream in) throws IOException { DerValue val = new DerValue(in); parse(val); signedCert = val.toByteArray(); }
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 IOException when appending fails. */
public void encode (OutputStream out) throws IOException { out.write (getSignedCert ()); }
Compares two certificates. This is false if the certificates are not both X.509 certs, otherwise it compares them as binary data.
Params:
  • other – the object being compared with this one
Returns:true iff the certificates are equivalent
/** * Compares two certificates. This is false if the * certificates are not both X.509 certs, otherwise it * compares them as binary data. * * @param other the object being compared with this one * @return true iff the certificates are equivalent */
public boolean equals (Object other) { if (other instanceof X509Cert) return equals ((X509Cert) other); else return false; }
Compares two certificates, returning false if any data differs between the two.
Params:
  • other – the object being compared with this one
Returns:true iff the certificates are equivalent
/** * Compares two certificates, returning false if any data * differs between the two. * * @param other the object being compared with this one * @return true iff the certificates are equivalent */
public boolean equals (X509Cert src) { if (this == src) return true; if (signedCert == null || src.signedCert == null) return false; if (signedCert.length != src.signedCert.length) return false; for (int i = 0; i < signedCert.length; i++) if (signedCert [i] != src.signedCert [i]) return false; return true; }
Returns the "X.509" format identifier.
/** Returns the "X.509" format identifier. */
public String getFormat () // for Certificate { return "X.509"; }
Returns getIssuerName
/** Returns <a href="#getIssuerName">getIssuerName</a> */
public Principal getGuarantor () // for Certificate { return getIssuerName (); } /** Returns <a href="#getSubjectName">getSubjectName</a> */ public Principal getPrincipal () { return getSubjectName (); }
Throws an exception if the certificate is invalid because it is now outside of the certificate's validity period, or because it was not signed using the verification key provided. Successfully verifying a certificate does not indicate that one should trust the entity which it represents.

Note that since this class represents only a single X.509 certificate, it cannot know anything about the certificate chain which is used to provide the verification key and to establish trust. Other code must manage and use those cert chains.

For now, you must walk the cert chain being used to verify any given cert. Start at the root, which is a self-signed certificate; verify it using the key inside the certificate. Then use that to verify the next certificate in the chain, issued by that CA. In this manner, verify each certificate until you reach the particular certificate you wish to verify. You should not use a certificate if any of the verification operations for its certificate chain were unsuccessful.

Params:
  • issuerPublicKey – the public key of the issuing CA
Throws:
/** * Throws an exception if the certificate is invalid because it is * now outside of the certificate's validity period, or because it * 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. * * <P><em>Note that since this class represents only a single X.509 * certificate, it cannot know anything about the certificate chain * which is used to provide the verification key and to establish trust. * Other code must manage and use those cert chains. * * <P>For now, you must walk the cert chain being used to verify any * given cert. Start at the root, which is a self-signed certificate; * verify it using the key inside the certificate. Then use that to * verify the next certificate in the chain, issued by that CA. In * this manner, verify each certificate until you reach the particular * certificate you wish to verify. You should not use a certificate * if any of the verification operations for its certificate chain * were unsuccessful. * </em> * * @param issuerPublicKey the public key of the issuing CA * @exception CertException when the certificate is not valid. */
public void verify (PublicKey issuerPublicKey) throws CertException { Date now = new Date (); if (now.before (notbefore)) throw new CertException (CertException.verf_INVALID_NOTBEFORE); if (now.after (notafter)) throw new CertException (CertException.verf_INVALID_EXPIRED); if (signedCert == null) throw new CertException (CertException.verf_INVALID_SIG, "?? certificate is not signed yet ??"); // // Verify the signature ... // String algName = null; try { Signature sigVerf = null; algName = issuerSigAlg.getName(); sigVerf = Signature.getInstance(algName); sigVerf.initVerify (issuerPublicKey); sigVerf.update (rawCert, 0, rawCert.length); if (!sigVerf.verify (signature)) { throw new CertException (CertException.verf_INVALID_SIG, "Signature ... by <" + issuer + "> for <" + subject + ">"); } // Gag -- too many catch clauses, let most through. } catch (NoSuchAlgorithmException e) { throw new CertException (CertException.verf_INVALID_SIG, "Unsupported signature algorithm (" + algName + ")"); } catch (InvalidKeyException e) { // e.printStackTrace(); throw new CertException (CertException.err_INVALID_PUBLIC_KEY, "Algorithm (" + algName + ") rejected public key"); } catch (SignatureException e) { throw new CertException (CertException.verf_INVALID_SIG, "Signature by <" + issuer + "> for <" + subject + ">"); } }
Creates an X.509 certificate, and signs it using the issuer passed (associating a signature algorithm and an X.500 name). This operation is used to implement the certificate generation functionality of a certificate authority.
Params:
  • serial – the serial number of the certificate (non-null)
  • issuer – the certificate issuer (CA) (non-null)
Throws:
See Also:
Returns:the signed certificate, as returned by getSignedCert
/** * Creates an X.509 certificate, and signs it using the issuer * passed (associating a signature algorithm and an X.500 name). * This operation is used to implement the certificate generation * functionality of a certificate authority. * * @see #getSignedCert * @see #getSigner * @see CertAndKeyGen * * @param serial the serial number of the certificate (non-null) * @param issuer the certificate issuer (CA) (non-null) * @return the signed certificate, as returned by getSignedCert * * @exception IOException if any of the data could not be encoded, * or when any mandatory data was omitted * @exception SignatureException on signing failures */
public byte [] encodeAndSign ( BigInteger serial, X500Signer issuer ) throws IOException, SignatureException { rawCert = null; /* * Get the remaining cert parameters, and make sure we have enough. * * We deduce version based on what attribute data are available * For now, we have no attributes, so we always deduce X.509v1 ! */ version = 0; serialnum = serial; this.issuer = issuer.getSigner (); issuerSigAlg = issuer.getAlgorithmId (); if (subject == null || pubkey == null || notbefore == null || notafter == null) throw new IOException ("not enough cert parameters"); /* * Encode the raw cert, create its signature and put it * into the envelope. */ rawCert = DERencode (); signedCert = sign (issuer, rawCert); return signedCert; }
Returns an X500Signer that may be used to create signatures. Those signature may in turn be verified using this certificate (or a copy of it).

NOTE: If the private key is by itself capable of creating signatures, this fact may not be recognized at this time. Specifically, the case of DSS/DSA keys which get their algorithm parameters from higher in the certificate chain is not supportable without using an X509CertChain API, and there is no current support for other sources of algorithm parameters.

Params:
  • algorithm – the signature algorithm to be used. Note that a given public/private key pair may support several such algorithms.
  • privateKey – the private key used to create the signature, which must correspond to the public key in this certificate
Throws:
Returns:the Signer object
/** * Returns an X500Signer that may be used to create signatures. Those * signature may in turn be verified using this certificate (or a * copy of it). * * <P><em><b>NOTE:</b> If the private key is by itself capable of * creating signatures, this fact may not be recognized at this time. * Specifically, the case of DSS/DSA keys which get their algorithm * parameters from higher in the certificate chain is not supportable * without using an X509CertChain API, and there is no current support * for other sources of algorithm parameters.</em> * * @param algorithm the signature algorithm to be used. Note that a * given public/private key pair may support several such algorithms. * @param privateKey the private key used to create the signature, * which must correspond to the public key in this certificate * @return the Signer object * * @exception NoSuchAlgorithmException if the signature * algorithm is not supported * @exception InvalidKeyException if either the key in the certificate, * or the private key parameter, does not support the requested * signature algorithm */
public X500Signer getSigner (AlgorithmId algorithmId, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException { String algorithm; Signature sig; if (privateKey instanceof Key) { Key key = (Key)privateKey; algorithm = key.getAlgorithm(); } else { throw new InvalidKeyException("private key not a key!"); } sig = Signature.getInstance(algorithmId.getName()); if (!pubkey.getAlgorithm ().equals (algorithm)) { throw new InvalidKeyException( "Private key algorithm " + algorithm + " incompatible with certificate " + pubkey.getAlgorithm()); } sig.initSign (privateKey); return new X500Signer (sig, subject); }
Returns a signature object that may be used to verify signatures created using a specified signature algorithm and the public key contained in this certificate.

NOTE: If the public key in this certificate is not by itself capable of verifying signatures, this may not be recognized at this time. Specifically, the case of DSS/DSA keys which get their algorithm parameters from higher in the certificate chain is not supportable without using an X509CertChain API, and there is no current support for other sources of algorithm parameters.

Params:
  • algorithm – the algorithm of the signature to be verified
Throws:
Returns:the Signature object
/** * Returns a signature object that may be used to verify signatures * created using a specified signature algorithm and the public key * contained in this certificate. * * <P><em><b>NOTE:</b> If the public key in this certificate is not by * itself capable of verifying signatures, this may not be recognized * at this time. Specifically, the case of DSS/DSA keys which get * their algorithm parameters from higher in the certificate chain * is not supportable without using an X509CertChain API, and there * is no current support for other sources of algorithm parameters.</em> * * @param algorithm the algorithm of the signature to be verified * @return the Signature object * @exception NoSuchAlgorithmException if the signature * algorithm is not supported * @exception InvalidKeyException if the key in the certificate * does not support the requested signature algorithm */
public Signature getVerifier(String algorithm) throws NoSuchAlgorithmException, InvalidKeyException { String algName; Signature sig; sig = Signature.getInstance(algorithm); sig.initVerify (pubkey); return sig; }
Return the signed X.509 certificate as a byte array. The bytes are in standard DER marshaled form. Null is returned in the case of a partially constructed cert.
/** * Return the signed X.509 certificate as a byte array. * The bytes are in standard DER marshaled form. * Null is returned in the case of a partially constructed cert. */
public byte [] getSignedCert () { return signedCert.clone(); }
Returns the certificate's serial number. Null is returned in the case of a partially constructed cert.
/** * Returns the certificate's serial number. * Null is returned in the case of a partially constructed cert. */
public BigInteger getSerialNumber () { return serialnum; }
Returns the subject's X.500 distinguished name.
/** * Returns the subject's X.500 distinguished name. */
public X500Name getSubjectName () { return subject; }
Returns the certificate issuer's X.500 distinguished name. Null is returned in the case of a partially constructed cert.
/** * Returns the certificate issuer's X.500 distinguished name. * Null is returned in the case of a partially constructed cert. */
public X500Name getIssuerName () { return issuer; }
Returns the algorithm used by the issuer to sign the certificate. Null is returned in the case of a partially constructed cert.
/** * Returns the algorithm used by the issuer to sign the certificate. * Null is returned in the case of a partially constructed cert. */
public AlgorithmId getIssuerAlgorithmId () { return issuerSigAlg; }
Returns the first time the certificate is valid.
/** * Returns the first time the certificate is valid. */
public Date getNotBefore () { return new Date(notbefore.getTime()); }
Returns the last time the certificate is valid.
/** * Returns the last time the certificate is valid. */
public Date getNotAfter () { return new Date(notafter.getTime()); }
Returns the subject's public key. Note that some public key algorithms support an optional certificate generation policy where the keys in the certificates are not in themselves sufficient to perform a public key operation. Those keys need to be augmented by algorithm parameters, which the certificate generation policy chose not to place in the certificate.

Two such public key algorithms are: DSS/DSA, where algorithm parameters could be acquired from a CA certificate in the chain of issuers; and Diffie-Hellman, with a similar solution although the CA then needs both a Diffie-Hellman certificate and a signature capable certificate.

/** * Returns the subject's public key. Note that some public key * algorithms support an optional certificate generation policy * where the keys in the certificates are not in themselves sufficient * to perform a public key operation. Those keys need to be augmented * by algorithm parameters, which the certificate generation policy * chose not to place in the certificate. * * <P>Two such public key algorithms are: DSS/DSA, where algorithm * parameters could be acquired from a CA certificate in the chain * of issuers; and Diffie-Hellman, with a similar solution although * the CA then needs both a Diffie-Hellman certificate and a signature * capable certificate. */
public PublicKey getPublicKey () { return pubkey; }
Returns the X.509 version number of this certificate, zero based. That is, "2" indicates an X.509 version 3 (1993) certificate, and "0" indicates X.509v1 (1988). Zero is returned in the case of a partially constructed cert.
/** * Returns the X.509 version number of this certificate, zero based. * That is, "2" indicates an X.509 version 3 (1993) certificate, * and "0" indicates X.509v1 (1988). * Zero is returned in the case of a partially constructed cert. */
public int getVersion () { return version; }
Calculates a hash code value for the object. Objects which are equal will also have the same hashcode.
/** * Calculates a hash code value for the object. Objects * which are equal will also have the same hashcode. */
public int hashCode () { int retval = 0; for (int i = 0; i < signedCert.length; i++) retval += signedCert [i] * i; return retval; }
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; in particular, if you are creating certificates you must call encodeAndSign() before calling this function.
/** * 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; in particular, if you are * creating certificates you must call encodeAndSign() before calling * this function. */
public String toString () { String s; if (subject == null || pubkey == null || notbefore == null || notafter == null || issuer == null || issuerSigAlg == null || serialnum == null) throw new NullPointerException ("X.509 cert is incomplete"); s = " X.509v" + (version + 1) + " certificate,\n"; s += " Subject is " + subject + "\n"; s += " Key: " + pubkey; s += " Validity <" + notbefore + "> until <" + notafter + ">\n"; s += " Issuer is " + issuer + "\n"; s += " Issuer signature used " + issuerSigAlg.toString () + "\n"; s += " Serial number = " + Debug.toHexString(serialnum) + "\n"; // optional v2, v3 extras return "[\n" + s + "]"; }
Returns a printable representation of the certificate.
Params:
  • detailed – true iff lots of detail is requested
/** * Returns a printable representation of the certificate. * * @param detailed true iff lots of detail is requested */
public String toString (boolean detailed) { return toString (); } /************************************************************/ /* * 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 IOException { if (parsed == true) { throw new IOException("Certificate already parsed"); } 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 CertParseError ("signed overrun, bytes = " + val.data.available ()); if (seq [0].tag != DerValue.tag_Sequence) throw new CertParseError ("signed fields invalid"); rawCert = seq [0].toByteArray (); // XXX slow; fixme! issuerSigAlg = AlgorithmId.parse (seq [1]); signature = seq [2].getBitString (); if (seq [1].data.available () != 0) { // XXX why was this error check commented out? // It was originally part of the next check. throw new CertParseError ("algid field overrun"); } if (seq [2].data.available () != 0) throw new CertParseError ("signed fields overrun"); /* * Let's have fun parsing the cert itself. */ DerInputStream in; DerValue tmp; in = seq [0].data; /* * Version -- this is optional (default zero). If it's there it's * the first field and is specially tagged. * * Both branches leave "tmp" holding a value for the serial * number that comes next. */ version = 0; tmp = in.getDerValue (); if (tmp.isConstructed () && tmp.isContextSpecific ()) { version = tmp.data.getInteger(); if (tmp.data.available () != 0) throw new IOException ("X.509 version, bad format"); tmp = in.getDerValue (); } /* * serial number ... an integer */ serialnum = tmp.getBigInteger (); /* * algorithm type for CA's signature ... needs to match the * one on the envelope, and that's about it! different IDs * may represent a signature attack. In general we want to * inherit parameters. */ tmp = in.getDerValue (); { AlgorithmId algid; algid = AlgorithmId.parse(tmp); if (!algid.equals (issuerSigAlg)) throw new CertParseError ("CA Algorithm mismatch!"); this.algid = algid; } /* * issuer name */ issuer = new X500Name (in); /* * validity: SEQUENCE { start date, end date } */ tmp = in.getDerValue (); if (tmp.tag != DerValue.tag_Sequence) throw new CertParseError ("corrupt validity field"); notbefore = tmp.data.getUTCTime (); notafter = tmp.data.getUTCTime (); if (tmp.data.available () != 0) throw new CertParseError ("excess validity data"); /* * subject name and public key */ subject = new X500Name (in); tmp = in.getDerValue (); pubkey = X509Key.parse (tmp); /* * XXX for v2 and later, a bunch of tagged options follow */ if (in.available () != 0) { /* * Until we parse V2/V3 data ... ignore it. * // throw new CertParseError ("excess cert data"); System.out.println ( "@end'o'cert, optional V2/V3 data unparsed: " + in.available () + " bytes" ); */ } parsed = true; } /* * Encode only the parts that will later be signed. */ private byte [] DERencode () throws IOException { DerOutputStream raw = new DerOutputStream (); encode (raw); return raw.toByteArray (); } /* * Marshal the contents of a "raw" certificate into a DER sequence. */ private void encode (DerOutputStream out) throws IOException { DerOutputStream tmp = new DerOutputStream (); /* * encode serial number, issuer signing algorithm, * and issuer name into the data we'll return */ tmp.putInteger (serialnum); issuerSigAlg.encode (tmp); issuer.encode (tmp); /* * Validity is a two element sequence ... encode the * elements, then wrap them into the data we'll return */ { DerOutputStream seq = new DerOutputStream (); seq.putUTCTime (notbefore); seq.putUTCTime (notafter); tmp.write (DerValue.tag_Sequence, seq); } /* * Encode subject (principal) and associated key */ subject.encode (tmp); tmp.write(pubkey.getEncoded()); /* * Wrap the data; encoding of the "raw" cert is now complete. */ out.write (DerValue.tag_Sequence, tmp); } /* * Calculate the signature of the "raw" certificate, * and marshal the cert with the signature and a * description of the signing algorithm. */ private byte [] sign (X500Signer issuer, byte data []) throws IOException, SignatureException { /* * Encode the to-be-signed data, then the algorithm used * to create the signature. */ DerOutputStream out = new DerOutputStream (); DerOutputStream tmp = new DerOutputStream (); tmp.write (data); issuer.getAlgorithmId ().encode(tmp); /* * Create and encode the signature itself. */ issuer.update (data, 0, data.length); signature = issuer.sign (); tmp.putBitString (signature); /* * Wrap the signed data in a SEQUENCE { data, algorithm, sig } */ out.write (DerValue.tag_Sequence, tmp); return out.toByteArray (); }
Serialization write ... X.509 certificates serialize as themselves, and they're parsed when they get read back. (Actually they serialize as some type data from the serialization subsystem, then the cert data.)
/** * Serialization write ... X.509 certificates serialize as * themselves, and they're parsed when they get read back. * (Actually they serialize as some type data from the * serialization subsystem, then the cert data.) */
private void writeObject (java.io.ObjectOutputStream stream) throws IOException { encode(stream); }
Serialization read ... X.509 certificates serialize as themselves, and they're parsed when they get read back.
/** * Serialization read ... X.509 certificates serialize as * themselves, and they're parsed when they get read back. */
private void readObject (ObjectInputStream stream) throws IOException { decode(stream); } }