0N/A/*
2362N/A * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.security.x509;
0N/A
0N/Aimport java.io.IOException;
0N/Aimport java.io.OutputStream;
0N/A
0N/Aimport java.security.cert.*;
0N/Aimport java.util.*;
0N/A
0N/Aimport sun.security.util.*;
0N/Aimport sun.misc.HexDumpEncoder;
0N/A
0N/A
0N/A/**
0N/A * The X509CertInfo class represents X.509 certificate information.
0N/A *
0N/A * <P>X.509 certificates have several base data elements, including:<UL>
0N/A *
0N/A * <LI>The <em>Subject Name</em>, an X.500 Distinguished Name for
0N/A * the entity (subject) for which the certificate was issued.
0N/A *
0N/A * <LI>The <em>Subject Public Key</em>, the public key of the subject.
0N/A * This is one of the most important parts of the certificate.
0N/A *
0N/A * <LI>The <em>Validity Period</em>, a time period (e.g. six months)
0N/A * within which the certificate is valid (unless revoked).
0N/A *
0N/A * <LI>The <em>Issuer Name</em>, an X.500 Distinguished Name for the
0N/A * Certificate Authority (CA) which issued the certificate.
0N/A *
0N/A * <LI>A <em>Serial Number</em> assigned by the CA, for use in
0N/A * certificate revocation and other applications.
0N/A *
0N/A * @author Amit Kapoor
0N/A * @author Hemma Prafullchandra
0N/A * @see CertAttrSet
0N/A * @see X509CertImpl
0N/A */
0N/Apublic class X509CertInfo implements CertAttrSet<String> {
0N/A /**
0N/A * Identifier for this attribute, to be used with the
0N/A * get, set, delete methods of Certificate, x509 type.
0N/A */
0N/A public static final String IDENT = "x509.info";
0N/A // Certificate attribute names
0N/A public static final String NAME = "info";
0N/A public static final String VERSION = CertificateVersion.NAME;
0N/A public static final String SERIAL_NUMBER = CertificateSerialNumber.NAME;
0N/A public static final String ALGORITHM_ID = CertificateAlgorithmId.NAME;
0N/A public static final String ISSUER = CertificateIssuerName.NAME;
0N/A public static final String VALIDITY = CertificateValidity.NAME;
0N/A public static final String SUBJECT = CertificateSubjectName.NAME;
0N/A public static final String KEY = CertificateX509Key.NAME;
0N/A public static final String ISSUER_ID = CertificateIssuerUniqueIdentity.NAME;
0N/A public static final String SUBJECT_ID = CertificateSubjectUniqueIdentity.NAME;
0N/A public static final String EXTENSIONS = CertificateExtensions.NAME;
0N/A
0N/A // X509.v1 data
0N/A protected CertificateVersion version = new CertificateVersion();
0N/A protected CertificateSerialNumber serialNum = null;
0N/A protected CertificateAlgorithmId algId = null;
0N/A protected CertificateIssuerName issuer = null;
0N/A protected CertificateValidity interval = null;
0N/A protected CertificateSubjectName subject = null;
0N/A protected CertificateX509Key pubKey = null;
0N/A
0N/A // X509.v2 & v3 extensions
0N/A protected CertificateIssuerUniqueIdentity issuerUniqueId = null;
0N/A protected CertificateSubjectUniqueIdentity subjectUniqueId = null;
0N/A
0N/A // X509.v3 extensions
0N/A protected CertificateExtensions extensions = null;
0N/A
0N/A // Attribute numbers for internal manipulation
0N/A private static final int ATTR_VERSION = 1;
0N/A private static final int ATTR_SERIAL = 2;
0N/A private static final int ATTR_ALGORITHM = 3;
0N/A private static final int ATTR_ISSUER = 4;
0N/A private static final int ATTR_VALIDITY = 5;
0N/A private static final int ATTR_SUBJECT = 6;
0N/A private static final int ATTR_KEY = 7;
0N/A private static final int ATTR_ISSUER_ID = 8;
0N/A private static final int ATTR_SUBJECT_ID = 9;
0N/A private static final int ATTR_EXTENSIONS = 10;
0N/A
0N/A // DER encoded CertificateInfo data
0N/A private byte[] rawCertInfo = null;
0N/A
0N/A // The certificate attribute name to integer mapping stored here
0N/A private static final Map<String,Integer> map = new HashMap<String,Integer>();
0N/A static {
0N/A map.put(VERSION, Integer.valueOf(ATTR_VERSION));
0N/A map.put(SERIAL_NUMBER, Integer.valueOf(ATTR_SERIAL));
0N/A map.put(ALGORITHM_ID, Integer.valueOf(ATTR_ALGORITHM));
0N/A map.put(ISSUER, Integer.valueOf(ATTR_ISSUER));
0N/A map.put(VALIDITY, Integer.valueOf(ATTR_VALIDITY));
0N/A map.put(SUBJECT, Integer.valueOf(ATTR_SUBJECT));
0N/A map.put(KEY, Integer.valueOf(ATTR_KEY));
0N/A map.put(ISSUER_ID, Integer.valueOf(ATTR_ISSUER_ID));
0N/A map.put(SUBJECT_ID, Integer.valueOf(ATTR_SUBJECT_ID));
0N/A map.put(EXTENSIONS, Integer.valueOf(ATTR_EXTENSIONS));
0N/A }
0N/A
0N/A /**
0N/A * Construct an uninitialized X509CertInfo on which <a href="#decode">
0N/A * decode</a> must later be called (or which may be deserialized).
0N/A */
0N/A public X509CertInfo() { }
0N/A
0N/A /**
0N/A * Unmarshals a certificate from its encoded form, parsing the
0N/A * encoded bytes. This form of constructor is used by agents which
0N/A * need to examine and use certificate contents. That is, this is
0N/A * one of the more commonly used constructors. Note that the buffer
0N/A * must include only a certificate, and no "garbage" may be left at
0N/A * the end. If you need to ignore data at the end of a certificate,
0N/A * use another constructor.
0N/A *
0N/A * @param cert the encoded bytes, with no trailing data.
0N/A * @exception CertificateParsingException on parsing errors.
0N/A */
0N/A public X509CertInfo(byte[] cert) throws CertificateParsingException {
0N/A try {
0N/A DerValue in = new DerValue(cert);
0N/A
0N/A parse(in);
0N/A } catch (IOException e) {
0N/A CertificateParsingException parseException =
0N/A new CertificateParsingException(e.toString());
0N/A parseException.initCause(e);
0N/A throw parseException;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Unmarshal a certificate from its encoded form, parsing a DER value.
0N/A * This form of constructor is used by agents which need to examine
0N/A * and use certificate contents.
0N/A *
0N/A * @param derVal the der value containing the encoded cert.
0N/A * @exception CertificateParsingException on parsing errors.
0N/A */
0N/A public X509CertInfo(DerValue derVal) throws CertificateParsingException {
0N/A try {
0N/A parse(derVal);
0N/A } catch (IOException e) {
0N/A CertificateParsingException parseException =
0N/A new CertificateParsingException(e.toString());
0N/A parseException.initCause(e);
0N/A throw parseException;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Appends the certificate to an output stream.
0N/A *
0N/A * @param out an output stream to which the certificate is appended.
0N/A * @exception CertificateException on encoding errors.
0N/A * @exception IOException on other errors.
0N/A */
0N/A public void encode(OutputStream out)
0N/A throws CertificateException, IOException {
0N/A if (rawCertInfo == null) {
0N/A DerOutputStream tmp = new DerOutputStream();
0N/A emit(tmp);
0N/A rawCertInfo = tmp.toByteArray();
0N/A }
0N/A out.write(rawCertInfo.clone());
0N/A }
0N/A
0N/A /**
0N/A * Return an enumeration of names of attributes existing within this
0N/A * attribute.
0N/A */
0N/A public Enumeration<String> getElements() {
0N/A AttributeNameEnumeration elements = new AttributeNameEnumeration();
0N/A elements.addElement(VERSION);
0N/A elements.addElement(SERIAL_NUMBER);
0N/A elements.addElement(ALGORITHM_ID);
0N/A elements.addElement(ISSUER);
0N/A elements.addElement(VALIDITY);
0N/A elements.addElement(SUBJECT);
0N/A elements.addElement(KEY);
0N/A elements.addElement(ISSUER_ID);
0N/A elements.addElement(SUBJECT_ID);
0N/A elements.addElement(EXTENSIONS);
0N/A
0N/A return elements.elements();
0N/A }
0N/A
0N/A /**
0N/A * Return the name of this attribute.
0N/A */
0N/A public String getName() {
0N/A return(NAME);
0N/A }
0N/A
0N/A /**
0N/A * Returns the encoded certificate info.
0N/A *
0N/A * @exception CertificateEncodingException on encoding information errors.
0N/A */
0N/A public byte[] getEncodedInfo() throws CertificateEncodingException {
0N/A try {
0N/A if (rawCertInfo == null) {
0N/A DerOutputStream tmp = new DerOutputStream();
0N/A emit(tmp);
0N/A rawCertInfo = tmp.toByteArray();
0N/A }
0N/A return rawCertInfo.clone();
0N/A } catch (IOException e) {
0N/A throw new CertificateEncodingException(e.toString());
0N/A } catch (CertificateException e) {
0N/A throw new CertificateEncodingException(e.toString());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Compares two X509CertInfo objects. This is false if the
0N/A * certificates are not both X.509 certs, otherwise it
0N/A * compares them as binary data.
0N/A *
0N/A * @param other the object being compared with this one
0N/A * @return true iff the certificates are equivalent
0N/A */
0N/A public boolean equals(Object other) {
0N/A if (other instanceof X509CertInfo) {
0N/A return equals((X509CertInfo) other);
0N/A } else {
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Compares two certificates, returning false if any data
0N/A * differs between the two.
0N/A *
0N/A * @param other the object being compared with this one
0N/A * @return true iff the certificates are equivalent
0N/A */
0N/A public boolean equals(X509CertInfo other) {
0N/A if (this == other) {
0N/A return(true);
0N/A } else if (rawCertInfo == null || other.rawCertInfo == null) {
0N/A return(false);
0N/A } else if (rawCertInfo.length != other.rawCertInfo.length) {
0N/A return(false);
0N/A }
0N/A for (int i = 0; i < rawCertInfo.length; i++) {
0N/A if (rawCertInfo[i] != other.rawCertInfo[i]) {
0N/A return(false);
0N/A }
0N/A }
0N/A return(true);
0N/A }
0N/A
0N/A /**
0N/A * Calculates a hash code value for the object. Objects
0N/A * which are equal will also have the same hashcode.
0N/A */
0N/A public int hashCode() {
0N/A int retval = 0;
0N/A
0N/A for (int i = 1; i < rawCertInfo.length; i++) {
0N/A retval += rawCertInfo[i] * i;
0N/A }
0N/A return(retval);
0N/A }
0N/A
0N/A /**
0N/A * Returns a printable representation of the certificate.
0N/A */
0N/A public String toString() {
0N/A
0N/A if (subject == null || pubKey == null || interval == null
0N/A || issuer == null || algId == null || serialNum == null) {
0N/A throw new NullPointerException("X.509 cert is incomplete");
0N/A }
0N/A StringBuilder sb = new StringBuilder();
0N/A
0N/A sb.append("[\n");
0N/A sb.append(" " + version.toString() + "\n");
0N/A sb.append(" Subject: " + subject.toString() + "\n");
0N/A sb.append(" Signature Algorithm: " + algId.toString() + "\n");
0N/A sb.append(" Key: " + pubKey.toString() + "\n");
0N/A sb.append(" " + interval.toString() + "\n");
0N/A sb.append(" Issuer: " + issuer.toString() + "\n");
0N/A sb.append(" " + serialNum.toString() + "\n");
0N/A
0N/A // optional v2, v3 extras
0N/A if (issuerUniqueId != null) {
0N/A sb.append(" Issuer Id:\n" + issuerUniqueId.toString() + "\n");
0N/A }
0N/A if (subjectUniqueId != null) {
0N/A sb.append(" Subject Id:\n" + subjectUniqueId.toString() + "\n");
0N/A }
0N/A if (extensions != null) {
0N/A Collection allExts = extensions.getAllExtensions();
0N/A Object[] objs = allExts.toArray();
0N/A sb.append("\nCertificate Extensions: " + objs.length);
0N/A for (int i = 0; i < objs.length; i++) {
0N/A sb.append("\n[" + (i+1) + "]: ");
0N/A Extension ext = (Extension)objs[i];
0N/A try {
0N/A if (OIDMap.getClass(ext.getExtensionId()) == null) {
0N/A sb.append(ext.toString());
0N/A byte[] extValue = ext.getExtensionValue();
0N/A if (extValue != null) {
0N/A DerOutputStream out = new DerOutputStream();
0N/A out.putOctetString(extValue);
0N/A extValue = out.toByteArray();
0N/A HexDumpEncoder enc = new HexDumpEncoder();
0N/A sb.append("Extension unknown: "
0N/A + "DER encoded OCTET string =\n"
0N/A + enc.encodeBuffer(extValue) + "\n");
0N/A }
0N/A } else
0N/A sb.append(ext.toString()); //sub-class exists
0N/A } catch (Exception e) {
0N/A sb.append(", Error parsing this extension");
0N/A }
0N/A }
0N/A Map<String,Extension> invalid = extensions.getUnparseableExtensions();
0N/A if (invalid.isEmpty() == false) {
0N/A sb.append("\nUnparseable certificate extensions: " + invalid.size());
0N/A int i = 1;
0N/A for (Extension ext : invalid.values()) {
0N/A sb.append("\n[" + (i++) + "]: ");
0N/A sb.append(ext);
0N/A }
0N/A }
0N/A }
0N/A sb.append("\n]");
0N/A return sb.toString();
0N/A }
0N/A
0N/A /**
0N/A * Set the certificate attribute.
0N/A *
0N/A * @params name the name of the Certificate attribute.
0N/A * @params val the value of the Certificate attribute.
0N/A * @exception CertificateException on invalid attributes.
0N/A * @exception IOException on other errors.
0N/A */
0N/A public void set(String name, Object val)
0N/A throws CertificateException, IOException {
0N/A X509AttributeName attrName = new X509AttributeName(name);
0N/A
0N/A int attr = attributeMap(attrName.getPrefix());
0N/A if (attr == 0) {
0N/A throw new CertificateException("Attribute name not recognized: "
0N/A + name);
0N/A }
0N/A // set rawCertInfo to null, so that we are forced to re-encode
0N/A rawCertInfo = null;
0N/A String suffix = attrName.getSuffix();
0N/A
0N/A switch (attr) {
0N/A case ATTR_VERSION:
0N/A if (suffix == null) {
0N/A setVersion(val);
0N/A } else {
0N/A version.set(suffix, val);
0N/A }
0N/A break;
0N/A
0N/A case ATTR_SERIAL:
0N/A if (suffix == null) {
0N/A setSerialNumber(val);
0N/A } else {
0N/A serialNum.set(suffix, val);
0N/A }
0N/A break;
0N/A
0N/A case ATTR_ALGORITHM:
0N/A if (suffix == null) {
0N/A setAlgorithmId(val);
0N/A } else {
0N/A algId.set(suffix, val);
0N/A }
0N/A break;
0N/A
0N/A case ATTR_ISSUER:
0N/A if (suffix == null) {
0N/A setIssuer(val);
0N/A } else {
0N/A issuer.set(suffix, val);
0N/A }
0N/A break;
0N/A
0N/A case ATTR_VALIDITY:
0N/A if (suffix == null) {
0N/A setValidity(val);
0N/A } else {
0N/A interval.set(suffix, val);
0N/A }
0N/A break;
0N/A
0N/A case ATTR_SUBJECT:
0N/A if (suffix == null) {
0N/A setSubject(val);
0N/A } else {
0N/A subject.set(suffix, val);
0N/A }
0N/A break;
0N/A
0N/A case ATTR_KEY:
0N/A if (suffix == null) {
0N/A setKey(val);
0N/A } else {
0N/A pubKey.set(suffix, val);
0N/A }
0N/A break;
0N/A
0N/A case ATTR_ISSUER_ID:
0N/A if (suffix == null) {
0N/A setIssuerUniqueId(val);
0N/A } else {
0N/A issuerUniqueId.set(suffix, val);
0N/A }
0N/A break;
0N/A
0N/A case ATTR_SUBJECT_ID:
0N/A if (suffix == null) {
0N/A setSubjectUniqueId(val);
0N/A } else {
0N/A subjectUniqueId.set(suffix, val);
0N/A }
0N/A break;
0N/A
0N/A case ATTR_EXTENSIONS:
0N/A if (suffix == null) {
0N/A setExtensions(val);
0N/A } else {
0N/A if (extensions == null)
0N/A extensions = new CertificateExtensions();
0N/A extensions.set(suffix, val);
0N/A }
0N/A break;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Delete the certificate attribute.
0N/A *
0N/A * @params name the name of the Certificate attribute.
0N/A * @exception CertificateException on invalid attributes.
0N/A * @exception IOException on other errors.
0N/A */
0N/A public void delete(String name)
0N/A throws CertificateException, IOException {
0N/A X509AttributeName attrName = new X509AttributeName(name);
0N/A
0N/A int attr = attributeMap(attrName.getPrefix());
0N/A if (attr == 0) {
0N/A throw new CertificateException("Attribute name not recognized: "
0N/A + name);
0N/A }
0N/A // set rawCertInfo to null, so that we are forced to re-encode
0N/A rawCertInfo = null;
0N/A String suffix = attrName.getSuffix();
0N/A
0N/A switch (attr) {
0N/A case ATTR_VERSION:
0N/A if (suffix == null) {
0N/A version = null;
0N/A } else {
0N/A version.delete(suffix);
0N/A }
0N/A break;
0N/A case (ATTR_SERIAL):
0N/A if (suffix == null) {
0N/A serialNum = null;
0N/A } else {
0N/A serialNum.delete(suffix);
0N/A }
0N/A break;
0N/A case (ATTR_ALGORITHM):
0N/A if (suffix == null) {
0N/A algId = null;
0N/A } else {
0N/A algId.delete(suffix);
0N/A }
0N/A break;
0N/A case (ATTR_ISSUER):
0N/A if (suffix == null) {
0N/A issuer = null;
0N/A } else {
0N/A issuer.delete(suffix);
0N/A }
0N/A break;
0N/A case (ATTR_VALIDITY):
0N/A if (suffix == null) {
0N/A interval = null;
0N/A } else {
0N/A interval.delete(suffix);
0N/A }
0N/A break;
0N/A case (ATTR_SUBJECT):
0N/A if (suffix == null) {
0N/A subject = null;
0N/A } else {
0N/A subject.delete(suffix);
0N/A }
0N/A break;
0N/A case (ATTR_KEY):
0N/A if (suffix == null) {
0N/A pubKey = null;
0N/A } else {
0N/A pubKey.delete(suffix);
0N/A }
0N/A break;
0N/A case (ATTR_ISSUER_ID):
0N/A if (suffix == null) {
0N/A issuerUniqueId = null;
0N/A } else {
0N/A issuerUniqueId.delete(suffix);
0N/A }
0N/A break;
0N/A case (ATTR_SUBJECT_ID):
0N/A if (suffix == null) {
0N/A subjectUniqueId = null;
0N/A } else {
0N/A subjectUniqueId.delete(suffix);
0N/A }
0N/A break;
0N/A case (ATTR_EXTENSIONS):
0N/A if (suffix == null) {
0N/A extensions = null;
0N/A } else {
0N/A if (extensions != null)
0N/A extensions.delete(suffix);
0N/A }
0N/A break;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Get the certificate attribute.
0N/A *
0N/A * @params name the name of the Certificate attribute.
0N/A *
0N/A * @exception CertificateException on invalid attributes.
0N/A * @exception IOException on other errors.
0N/A */
0N/A public Object get(String name)
0N/A throws CertificateException, IOException {
0N/A X509AttributeName attrName = new X509AttributeName(name);
0N/A
0N/A int attr = attributeMap(attrName.getPrefix());
0N/A if (attr == 0) {
0N/A throw new CertificateParsingException(
0N/A "Attribute name not recognized: " + name);
0N/A }
0N/A String suffix = attrName.getSuffix();
0N/A
0N/A switch (attr) { // frequently used attributes first
0N/A case (ATTR_EXTENSIONS):
0N/A if (suffix == null) {
0N/A return(extensions);
0N/A } else {
0N/A if (extensions == null) {
0N/A return null;
0N/A } else {
0N/A return(extensions.get(suffix));
0N/A }
0N/A }
0N/A case (ATTR_SUBJECT):
0N/A if (suffix == null) {
0N/A return(subject);
0N/A } else {
0N/A return(subject.get(suffix));
0N/A }
0N/A case (ATTR_ISSUER):
0N/A if (suffix == null) {
0N/A return(issuer);
0N/A } else {
0N/A return(issuer.get(suffix));
0N/A }
0N/A case (ATTR_KEY):
0N/A if (suffix == null) {
0N/A return(pubKey);
0N/A } else {
0N/A return(pubKey.get(suffix));
0N/A }
0N/A case (ATTR_ALGORITHM):
0N/A if (suffix == null) {
0N/A return(algId);
0N/A } else {
0N/A return(algId.get(suffix));
0N/A }
0N/A case (ATTR_VALIDITY):
0N/A if (suffix == null) {
0N/A return(interval);
0N/A } else {
0N/A return(interval.get(suffix));
0N/A }
0N/A case (ATTR_VERSION):
0N/A if (suffix == null) {
0N/A return(version);
0N/A } else {
0N/A return(version.get(suffix));
0N/A }
0N/A case (ATTR_SERIAL):
0N/A if (suffix == null) {
0N/A return(serialNum);
0N/A } else {
0N/A return(serialNum.get(suffix));
0N/A }
0N/A case (ATTR_ISSUER_ID):
0N/A if (suffix == null) {
0N/A return(issuerUniqueId);
0N/A } else {
0N/A if (issuerUniqueId == null)
0N/A return null;
0N/A else
0N/A return(issuerUniqueId.get(suffix));
0N/A }
0N/A case (ATTR_SUBJECT_ID):
0N/A if (suffix == null) {
0N/A return(subjectUniqueId);
0N/A } else {
0N/A if (subjectUniqueId == null)
0N/A return null;
0N/A else
0N/A return(subjectUniqueId.get(suffix));
0N/A }
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A /*
0N/A * This routine unmarshals the certificate information.
0N/A */
0N/A private void parse(DerValue val)
0N/A throws CertificateParsingException, IOException {
0N/A DerInputStream in;
0N/A DerValue tmp;
0N/A
0N/A if (val.tag != DerValue.tag_Sequence) {
0N/A throw new CertificateParsingException("signed fields invalid");
0N/A }
0N/A rawCertInfo = val.toByteArray();
0N/A
0N/A in = val.data;
0N/A
0N/A // Version
0N/A tmp = in.getDerValue();
0N/A if (tmp.isContextSpecific((byte)0)) {
0N/A version = new CertificateVersion(tmp);
0N/A tmp = in.getDerValue();
0N/A }
0N/A
0N/A // Serial number ... an integer
0N/A serialNum = new CertificateSerialNumber(tmp);
0N/A
0N/A // Algorithm Identifier
0N/A algId = new CertificateAlgorithmId(in);
0N/A
0N/A // Issuer name
0N/A issuer = new CertificateIssuerName(in);
0N/A X500Name issuerDN = (X500Name)issuer.get(CertificateIssuerName.DN_NAME);
0N/A if (issuerDN.isEmpty()) {
0N/A throw new CertificateParsingException(
0N/A "Empty issuer DN not allowed in X509Certificates");
0N/A }
0N/A
0N/A // validity: SEQUENCE { start date, end date }
0N/A interval = new CertificateValidity(in);
0N/A
0N/A // subject name
0N/A subject = new CertificateSubjectName(in);
0N/A X500Name subjectDN = (X500Name)subject.get(CertificateSubjectName.DN_NAME);
0N/A if ((version.compare(CertificateVersion.V1) == 0) &&
0N/A subjectDN.isEmpty()) {
0N/A throw new CertificateParsingException(
0N/A "Empty subject DN not allowed in v1 certificate");
0N/A }
0N/A
0N/A // public key
0N/A pubKey = new CertificateX509Key(in);
0N/A
0N/A // If more data available, make sure version is not v1.
0N/A if (in.available() != 0) {
0N/A if (version.compare(CertificateVersion.V1) == 0) {
0N/A throw new CertificateParsingException(
0N/A "no more data allowed for version 1 certificate");
0N/A }
0N/A } else {
0N/A return;
0N/A }
0N/A
0N/A // Get the issuerUniqueId if present
0N/A tmp = in.getDerValue();
0N/A if (tmp.isContextSpecific((byte)1)) {
0N/A issuerUniqueId = new CertificateIssuerUniqueIdentity(tmp);
0N/A if (in.available() == 0)
0N/A return;
0N/A tmp = in.getDerValue();
0N/A }
0N/A
0N/A // Get the subjectUniqueId if present.
0N/A if (tmp.isContextSpecific((byte)2)) {
0N/A subjectUniqueId = new CertificateSubjectUniqueIdentity(tmp);
0N/A if (in.available() == 0)
0N/A return;
0N/A tmp = in.getDerValue();
0N/A }
0N/A
0N/A // Get the extensions.
0N/A if (version.compare(CertificateVersion.V3) != 0) {
0N/A throw new CertificateParsingException(
0N/A "Extensions not allowed in v2 certificate");
0N/A }
0N/A if (tmp.isConstructed() && tmp.isContextSpecific((byte)3)) {
0N/A extensions = new CertificateExtensions(tmp.data);
0N/A }
0N/A
0N/A // verify X.509 V3 Certificate
0N/A verifyCert(subject, extensions);
0N/A
0N/A }
0N/A
0N/A /*
0N/A * Verify if X.509 V3 Certificate is compliant with RFC 3280.
0N/A */
0N/A private void verifyCert(CertificateSubjectName subject,
0N/A CertificateExtensions extensions)
0N/A throws CertificateParsingException, IOException {
0N/A
0N/A // if SubjectName is empty, check for SubjectAlternativeNameExtension
0N/A X500Name subjectDN = (X500Name)subject.get(CertificateSubjectName.DN_NAME);
0N/A if (subjectDN.isEmpty()) {
0N/A if (extensions == null) {
0N/A throw new CertificateParsingException("X.509 Certificate is " +
0N/A "incomplete: subject field is empty, and certificate " +
0N/A "has no extensions");
0N/A }
0N/A SubjectAlternativeNameExtension subjectAltNameExt = null;
0N/A SubjectAlternativeNameExtension extValue = null;
0N/A GeneralNames names = null;
0N/A try {
0N/A subjectAltNameExt = (SubjectAlternativeNameExtension)
0N/A extensions.get(SubjectAlternativeNameExtension.NAME);
0N/A names = (GeneralNames) subjectAltNameExt.get
0N/A (SubjectAlternativeNameExtension.SUBJECT_NAME);
0N/A } catch (IOException e) {
0N/A throw new CertificateParsingException("X.509 Certificate is " +
0N/A "incomplete: subject field is empty, and " +
0N/A "SubjectAlternativeName extension is absent");
0N/A }
0N/A
0N/A // SubjectAlternativeName extension is empty or not marked critical
0N/A if (names == null || names.isEmpty()) {
0N/A throw new CertificateParsingException("X.509 Certificate is " +
0N/A "incomplete: subject field is empty, and " +
0N/A "SubjectAlternativeName extension is empty");
0N/A } else if (subjectAltNameExt.isCritical() == false) {
0N/A throw new CertificateParsingException("X.509 Certificate is " +
0N/A "incomplete: SubjectAlternativeName extension MUST " +
0N/A "be marked critical when subject field is empty");
0N/A }
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Marshal the contents of a "raw" certificate into a DER sequence.
0N/A */
0N/A private void emit(DerOutputStream out)
0N/A throws CertificateException, IOException {
0N/A DerOutputStream tmp = new DerOutputStream();
0N/A
0N/A // version number, iff not V1
0N/A version.encode(tmp);
0N/A
0N/A // Encode serial number, issuer signing algorithm, issuer name
0N/A // and validity
0N/A serialNum.encode(tmp);
0N/A algId.encode(tmp);
0N/A
0N/A if ((version.compare(CertificateVersion.V1) == 0) &&
0N/A (issuer.toString() == null))
0N/A throw new CertificateParsingException(
0N/A "Null issuer DN not allowed in v1 certificate");
0N/A
0N/A issuer.encode(tmp);
0N/A interval.encode(tmp);
0N/A
0N/A // Encode subject (principal) and associated key
0N/A if ((version.compare(CertificateVersion.V1) == 0) &&
0N/A (subject.toString() == null))
0N/A throw new CertificateParsingException(
0N/A "Null subject DN not allowed in v1 certificate");
0N/A subject.encode(tmp);
0N/A pubKey.encode(tmp);
0N/A
0N/A // Encode issuerUniqueId & subjectUniqueId.
0N/A if (issuerUniqueId != null) {
0N/A issuerUniqueId.encode(tmp);
0N/A }
0N/A if (subjectUniqueId != null) {
0N/A subjectUniqueId.encode(tmp);
0N/A }
0N/A
0N/A // Write all the extensions.
0N/A if (extensions != null) {
0N/A extensions.encode(tmp);
0N/A }
0N/A
0N/A // Wrap the data; encoding of the "raw" cert is now complete.
0N/A out.write(DerValue.tag_Sequence, tmp);
0N/A }
0N/A
0N/A /**
0N/A * Returns the integer attribute number for the passed attribute name.
0N/A */
0N/A private int attributeMap(String name) {
0N/A Integer num = map.get(name);
0N/A if (num == null) {
0N/A return 0;
0N/A }
0N/A return num.intValue();
0N/A }
0N/A
0N/A /**
0N/A * Set the version number of the certificate.
0N/A *
0N/A * @params val the Object class value for the Extensions
0N/A * @exception CertificateException on invalid data.
0N/A */
0N/A private void setVersion(Object val) throws CertificateException {
0N/A if (!(val instanceof CertificateVersion)) {
0N/A throw new CertificateException("Version class type invalid.");
0N/A }
0N/A version = (CertificateVersion)val;
0N/A }
0N/A
0N/A /**
0N/A * Set the serial number of the certificate.
0N/A *
0N/A * @params val the Object class value for the CertificateSerialNumber
0N/A * @exception CertificateException on invalid data.
0N/A */
0N/A private void setSerialNumber(Object val) throws CertificateException {
0N/A if (!(val instanceof CertificateSerialNumber)) {
0N/A throw new CertificateException("SerialNumber class type invalid.");
0N/A }
0N/A serialNum = (CertificateSerialNumber)val;
0N/A }
0N/A
0N/A /**
0N/A * Set the algorithm id of the certificate.
0N/A *
0N/A * @params val the Object class value for the AlgorithmId
0N/A * @exception CertificateException on invalid data.
0N/A */
0N/A private void setAlgorithmId(Object val) throws CertificateException {
0N/A if (!(val instanceof CertificateAlgorithmId)) {
0N/A throw new CertificateException(
0N/A "AlgorithmId class type invalid.");
0N/A }
0N/A algId = (CertificateAlgorithmId)val;
0N/A }
0N/A
0N/A /**
0N/A * Set the issuer name of the certificate.
0N/A *
0N/A * @params val the Object class value for the issuer
0N/A * @exception CertificateException on invalid data.
0N/A */
0N/A private void setIssuer(Object val) throws CertificateException {
0N/A if (!(val instanceof CertificateIssuerName)) {
0N/A throw new CertificateException(
0N/A "Issuer class type invalid.");
0N/A }
0N/A issuer = (CertificateIssuerName)val;
0N/A }
0N/A
0N/A /**
0N/A * Set the validity interval of the certificate.
0N/A *
0N/A * @params val the Object class value for the CertificateValidity
0N/A * @exception CertificateException on invalid data.
0N/A */
0N/A private void setValidity(Object val) throws CertificateException {
0N/A if (!(val instanceof CertificateValidity)) {
0N/A throw new CertificateException(
0N/A "CertificateValidity class type invalid.");
0N/A }
0N/A interval = (CertificateValidity)val;
0N/A }
0N/A
0N/A /**
0N/A * Set the subject name of the certificate.
0N/A *
0N/A * @params val the Object class value for the Subject
0N/A * @exception CertificateException on invalid data.
0N/A */
0N/A private void setSubject(Object val) throws CertificateException {
0N/A if (!(val instanceof CertificateSubjectName)) {
0N/A throw new CertificateException(
0N/A "Subject class type invalid.");
0N/A }
0N/A subject = (CertificateSubjectName)val;
0N/A }
0N/A
0N/A /**
0N/A * Set the public key in the certificate.
0N/A *
0N/A * @params val the Object class value for the PublicKey
0N/A * @exception CertificateException on invalid data.
0N/A */
0N/A private void setKey(Object val) throws CertificateException {
0N/A if (!(val instanceof CertificateX509Key)) {
0N/A throw new CertificateException(
0N/A "Key class type invalid.");
0N/A }
0N/A pubKey = (CertificateX509Key)val;
0N/A }
0N/A
0N/A /**
0N/A * Set the Issuer Unique Identity in the certificate.
0N/A *
0N/A * @params val the Object class value for the IssuerUniqueId
0N/A * @exception CertificateException
0N/A */
0N/A private void setIssuerUniqueId(Object val) throws CertificateException {
0N/A if (version.compare(CertificateVersion.V2) < 0) {
0N/A throw new CertificateException("Invalid version");
0N/A }
0N/A if (!(val instanceof CertificateIssuerUniqueIdentity)) {
0N/A throw new CertificateException(
0N/A "IssuerUniqueId class type invalid.");
0N/A }
0N/A issuerUniqueId = (CertificateIssuerUniqueIdentity)val;
0N/A }
0N/A
0N/A /**
0N/A * Set the Subject Unique Identity in the certificate.
0N/A *
0N/A * @params val the Object class value for the SubjectUniqueId
0N/A * @exception CertificateException
0N/A */
0N/A private void setSubjectUniqueId(Object val) throws CertificateException {
0N/A if (version.compare(CertificateVersion.V2) < 0) {
0N/A throw new CertificateException("Invalid version");
0N/A }
0N/A if (!(val instanceof CertificateSubjectUniqueIdentity)) {
0N/A throw new CertificateException(
0N/A "SubjectUniqueId class type invalid.");
0N/A }
0N/A subjectUniqueId = (CertificateSubjectUniqueIdentity)val;
0N/A }
0N/A
0N/A /**
0N/A * Set the extensions in the certificate.
0N/A *
0N/A * @params val the Object class value for the Extensions
0N/A * @exception CertificateException
0N/A */
0N/A private void setExtensions(Object val) throws CertificateException {
0N/A if (version.compare(CertificateVersion.V3) < 0) {
0N/A throw new CertificateException("Invalid version");
0N/A }
0N/A if (!(val instanceof CertificateExtensions)) {
0N/A throw new CertificateException(
0N/A "Extensions class type invalid.");
0N/A }
0N/A extensions = (CertificateExtensions)val;
0N/A }
0N/A}