All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tencent.kona.sun.security.x509.X509CertInfo Maven / Gradle / Ivy

Go to download

A Java security provider for supporting ShangMi algorithms in public key infrastructure

There is a newer version: 1.0.15
Show newest version
/*
 * Copyright (c) 1997, 2021, 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 com.tencent.kona.sun.security.x509;

import java.io.IOException;
import java.io.OutputStream;

import java.security.cert.*;
import java.util.*;

import com.tencent.kona.sun.security.util.DerInputStream;
import com.tencent.kona.sun.security.util.DerOutputStream;
import com.tencent.kona.sun.security.util.DerValue;
import com.tencent.kona.sun.security.util.HexDumpEncoder;

/**
 * The X509CertInfo class represents X.509 certificate information.
 *
 * 

X.509 certificates have several base data elements, including: * *

    *
  • The Subject Name, an X.500 Distinguished Name for * the entity (subject) for which the certificate was issued. * *
  • The Subject Public Key, the public key of the subject. * This is one of the most important parts of the certificate. * *
  • The Validity Period, a time period (e.g. six months) * within which the certificate is valid (unless revoked). * *
  • The Issuer Name, an X.500 Distinguished Name for the * Certificate Authority (CA) which issued the certificate. * *
  • A Serial Number assigned by the CA, for use in * certificate revocation and other applications. *
* * @author Amit Kapoor * @author Hemma Prafullchandra * @see CertAttrSet * @see X509CertImpl */ public class X509CertInfo implements CertAttrSet { /** * Identifier for this attribute, to be used with the * get, set, delete methods of Certificate, x509 type. */ public static final String IDENT = "x509.info"; // Certificate attribute names public static final String NAME = "info"; public static final String DN_NAME = "dname"; public static final String VERSION = CertificateVersion.NAME; public static final String SERIAL_NUMBER = CertificateSerialNumber.NAME; public static final String ALGORITHM_ID = CertificateAlgorithmId.NAME; public static final String ISSUER = "issuer"; public static final String SUBJECT = "subject"; public static final String VALIDITY = CertificateValidity.NAME; public static final String KEY = CertificateX509Key.NAME; public static final String ISSUER_ID = "issuerID"; public static final String SUBJECT_ID = "subjectID"; public static final String EXTENSIONS = CertificateExtensions.NAME; // X509.v1 data protected CertificateVersion version = new CertificateVersion(); protected CertificateSerialNumber serialNum = null; protected CertificateAlgorithmId algId = null; protected X500Name issuer = null; protected X500Name subject = null; protected CertificateValidity interval = null; protected CertificateX509Key pubKey = null; // X509.v2 & v3 extensions protected UniqueIdentity issuerUniqueId = null; protected UniqueIdentity subjectUniqueId = null; // X509.v3 extensions protected CertificateExtensions extensions = null; // Attribute numbers for internal manipulation private static final int ATTR_VERSION = 1; private static final int ATTR_SERIAL = 2; private static final int ATTR_ALGORITHM = 3; private static final int ATTR_ISSUER = 4; private static final int ATTR_VALIDITY = 5; private static final int ATTR_SUBJECT = 6; private static final int ATTR_KEY = 7; private static final int ATTR_ISSUER_ID = 8; private static final int ATTR_SUBJECT_ID = 9; private static final int ATTR_EXTENSIONS = 10; // DER encoded CertificateInfo data private byte[] rawCertInfo = null; // The certificate attribute name to integer mapping stored here private static final Map map = new HashMap(); static { map.put(VERSION, Integer.valueOf(ATTR_VERSION)); map.put(SERIAL_NUMBER, Integer.valueOf(ATTR_SERIAL)); map.put(ALGORITHM_ID, Integer.valueOf(ATTR_ALGORITHM)); map.put(ISSUER, Integer.valueOf(ATTR_ISSUER)); map.put(VALIDITY, Integer.valueOf(ATTR_VALIDITY)); map.put(SUBJECT, Integer.valueOf(ATTR_SUBJECT)); map.put(KEY, Integer.valueOf(ATTR_KEY)); map.put(ISSUER_ID, Integer.valueOf(ATTR_ISSUER_ID)); map.put(SUBJECT_ID, Integer.valueOf(ATTR_SUBJECT_ID)); map.put(EXTENSIONS, Integer.valueOf(ATTR_EXTENSIONS)); } /** * Construct an uninitialized X509CertInfo on which * decode must later be called (or which may be deserialized). */ public X509CertInfo() { } /** * 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 trailing data. * @exception CertificateParsingException on parsing errors. */ public X509CertInfo(byte[] cert) throws CertificateParsingException { try { DerValue in = new DerValue(cert); parse(in); } catch (IOException e) { throw new CertificateParsingException(e); } } /** * 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 CertificateParsingException on parsing errors. */ public X509CertInfo(DerValue derVal) throws CertificateParsingException { try { parse(derVal); } catch (IOException e) { throw new CertificateParsingException(e); } } /** * Appends the certificate to an output stream. * * @param out an output stream to which the certificate is appended. * @exception CertificateException on encoding errors. * @exception IOException on other errors. */ public void encode(OutputStream out) throws CertificateException, IOException { if (rawCertInfo == null) { DerOutputStream tmp = new DerOutputStream(); emit(tmp); rawCertInfo = tmp.toByteArray(); } out.write(rawCertInfo.clone()); } /** * Return an enumeration of names of attributes existing within this * attribute. */ public Enumeration getElements() { AttributeNameEnumeration elements = new AttributeNameEnumeration(); elements.addElement(VERSION); elements.addElement(SERIAL_NUMBER); elements.addElement(ALGORITHM_ID); elements.addElement(ISSUER); elements.addElement(VALIDITY); elements.addElement(SUBJECT); elements.addElement(KEY); elements.addElement(ISSUER_ID); elements.addElement(SUBJECT_ID); elements.addElement(EXTENSIONS); return elements.elements(); } /** * Return the name of this attribute. */ public String getName() { return(NAME); } /** * Returns the encoded certificate info. * * @exception CertificateEncodingException on encoding information errors. */ public byte[] getEncodedInfo() throws CertificateEncodingException { try { if (rawCertInfo == null) { DerOutputStream tmp = new DerOutputStream(); emit(tmp); rawCertInfo = tmp.toByteArray(); } return rawCertInfo.clone(); } catch (IOException e) { throw new CertificateEncodingException(e.toString()); } catch (CertificateException e) { throw new CertificateEncodingException(e.toString()); } } /** * Compares two X509CertInfo objects. 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 X509CertInfo) { return equals((X509CertInfo) other); } else { return false; } } /** * 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(X509CertInfo other) { if (this == other) { return(true); } else if (rawCertInfo == null || other.rawCertInfo == null) { return(false); } else if (rawCertInfo.length != other.rawCertInfo.length) { return(false); } for (int i = 0; i < rawCertInfo.length; i++) { if (rawCertInfo[i] != other.rawCertInfo[i]) { return(false); } } return(true); } /** * 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 = 1; i < rawCertInfo.length; i++) { retval += rawCertInfo[i] * i; } return(retval); } /** * Returns a printable representation of the certificate. */ public String toString() { if (subject == null || pubKey == null || interval == null || issuer == null || algId == null || serialNum == null) { throw new NullPointerException("X.509 cert is incomplete"); } StringBuilder sb = new StringBuilder(); sb.append("[\n") .append(" ").append(version).append('\n') .append(" Subject: ").append(subject).append('\n') .append(" Signature Algorithm: ").append(algId).append('\n') .append(" Key: ").append(pubKey).append('\n') .append(" ").append(interval).append('\n') .append(" Issuer: ").append(issuer).append('\n') .append(" ").append(serialNum).append('\n'); // optional v2, v3 extras if (issuerUniqueId != null) { sb.append(" Issuer Id:\n").append(issuerUniqueId).append('\n'); } if (subjectUniqueId != null) { sb.append(" Subject Id:\n").append(subjectUniqueId).append('\n'); } if (extensions != null) { Collection allExts = extensions.getAllExtensions(); com.tencent.kona.sun.security.x509.Extension[] exts = allExts.toArray(new com.tencent.kona.sun.security.x509.Extension[0]); sb.append("\nCertificate Extensions: ").append(exts.length); for (int i = 0; i < exts.length; i++) { sb.append("\n[").append(i+1).append("]: "); com.tencent.kona.sun.security.x509.Extension ext = exts[i]; try { if (OIDMap.getClass(ext.getExtensionId()) == null) { sb.append(ext); byte[] extValue = ext.getExtensionValue(); if (extValue != null) { DerOutputStream out = new DerOutputStream(); out.putOctetString(extValue); extValue = out.toByteArray(); HexDumpEncoder enc = new HexDumpEncoder(); sb.append("Extension unknown: ") .append("DER encoded OCTET string =\n") .append(enc.encodeBuffer(extValue)) .append('\n'); } } else { sb.append(ext); //sub-class exists } } catch (Exception e) { sb.append(", Error parsing this extension"); } } Map invalid = extensions.getUnparseableExtensions(); if (invalid.isEmpty() == false) { sb.append("\nUnparseable certificate extensions: ") .append(invalid.size()); int i = 1; for (Extension ext : invalid.values()) { sb.append("\n[") .append(i++) .append("]: ") .append(ext); } } } sb.append("\n]"); return sb.toString(); } /** * Set the certificate attribute. * * @param name the name of the Certificate attribute. * @param val the value of the Certificate attribute. * @exception CertificateException on invalid attributes. * @exception IOException on other errors. */ public void set(String name, Object val) throws CertificateException, IOException { X509AttributeName attrName = new X509AttributeName(name); int attr = attributeMap(attrName.getPrefix()); if (attr == 0) { throw new CertificateException("Attribute name not recognized: " + name); } // set rawCertInfo to null, so that we are forced to re-encode rawCertInfo = null; String suffix = attrName.getSuffix(); switch (attr) { case ATTR_VERSION: if (suffix == null) { setVersion(val); } else { version.set(suffix, val); } break; case ATTR_SERIAL: if (suffix == null) { setSerialNumber(val); } else { serialNum.set(suffix, val); } break; case ATTR_ALGORITHM: if (suffix == null) { setAlgorithmId(val); } else { algId.set(suffix, val); } break; case ATTR_ISSUER: setIssuer(val); break; case ATTR_VALIDITY: if (suffix == null) { setValidity(val); } else { interval.set(suffix, val); } break; case ATTR_SUBJECT: setSubject(val); break; case ATTR_KEY: if (suffix == null) { setKey(val); } else { pubKey.set(suffix, val); } break; case ATTR_ISSUER_ID: setIssuerUniqueId(val); break; case ATTR_SUBJECT_ID: setSubjectUniqueId(val); break; case ATTR_EXTENSIONS: if (suffix == null) { setExtensions(val); } else { if (extensions == null) extensions = new CertificateExtensions(); extensions.set(suffix, val); } break; } } /** * Delete the certificate attribute. * * @param name the name of the Certificate attribute. * @exception CertificateException on invalid attributes. * @exception IOException on other errors. */ public void delete(String name) throws CertificateException, IOException { X509AttributeName attrName = new X509AttributeName(name); int attr = attributeMap(attrName.getPrefix()); if (attr == 0) { throw new CertificateException("Attribute name not recognized: " + name); } // set rawCertInfo to null, so that we are forced to re-encode rawCertInfo = null; String suffix = attrName.getSuffix(); switch (attr) { case ATTR_VERSION: if (suffix == null) { version = null; } else { version.delete(suffix); } break; case (ATTR_SERIAL): if (suffix == null) { serialNum = null; } else { serialNum.delete(suffix); } break; case (ATTR_ALGORITHM): if (suffix == null) { algId = null; } else { algId.delete(suffix); } break; case (ATTR_ISSUER): issuer = null; break; case (ATTR_VALIDITY): if (suffix == null) { interval = null; } else { interval.delete(suffix); } break; case (ATTR_SUBJECT): subject = null; break; case (ATTR_KEY): if (suffix == null) { pubKey = null; } else { pubKey.delete(suffix); } break; case (ATTR_ISSUER_ID): issuerUniqueId = null; break; case (ATTR_SUBJECT_ID): subjectUniqueId = null; break; case (ATTR_EXTENSIONS): if (suffix == null) { extensions = null; } else { if (extensions != null) extensions.delete(suffix); } break; } } /** * Get the certificate attribute. * * @param name the name of the Certificate attribute. * * @exception CertificateException on invalid attributes. * @exception IOException on other errors. */ public Object get(String name) throws CertificateException, IOException { X509AttributeName attrName = new X509AttributeName(name); int attr = attributeMap(attrName.getPrefix()); if (attr == 0) { throw new CertificateParsingException( "Attribute name not recognized: " + name); } String suffix = attrName.getSuffix(); switch (attr) { // frequently used attributes first case (ATTR_EXTENSIONS): if (suffix == null) { return(extensions); } else { if (extensions == null) { return null; } else { return(extensions.get(suffix)); } } case (ATTR_SUBJECT): if (suffix == null) { return(subject); } else { return(getX500Name(suffix, false)); } case (ATTR_ISSUER): if (suffix == null) { return(issuer); } else { return(getX500Name(suffix, true)); } case (ATTR_KEY): if (suffix == null) { return(pubKey); } else { return(pubKey.get(suffix)); } case (ATTR_ALGORITHM): if (suffix == null) { return(algId); } else { return(algId.get(suffix)); } case (ATTR_VALIDITY): if (suffix == null) { return(interval); } else { return(interval.get(suffix)); } case (ATTR_VERSION): if (suffix == null) { return(version); } else { return(version.get(suffix)); } case (ATTR_SERIAL): if (suffix == null) { return(serialNum); } else { return(serialNum.get(suffix)); } case (ATTR_ISSUER_ID): return(issuerUniqueId); case (ATTR_SUBJECT_ID): return(subjectUniqueId); } return null; } /* * Get the Issuer or Subject name */ private Object getX500Name(String name, boolean getIssuer) throws IOException { if (name.equalsIgnoreCase(X509CertInfo.DN_NAME)) { return getIssuer ? issuer : subject; } else if (name.equalsIgnoreCase("x500principal")) { return getIssuer ? issuer.asX500Principal() : subject.asX500Principal(); } else { throw new IOException("Attribute name not recognized."); } } /* * This routine unmarshals the certificate information. */ private void parse(DerValue val) throws CertificateParsingException, IOException { DerInputStream in; DerValue tmp; if (val.tag != DerValue.tag_Sequence) { throw new CertificateParsingException("signed fields invalid"); } rawCertInfo = val.toByteArray(); in = val.data; // Version tmp = in.getDerValue(); if (tmp.isContextSpecific((byte)0)) { version = new CertificateVersion(tmp); tmp = in.getDerValue(); } // Serial number ... an integer serialNum = new CertificateSerialNumber(tmp); // Algorithm Identifier algId = new CertificateAlgorithmId(in); // Issuer name issuer = new X500Name(in); if (issuer.isEmpty()) { throw new CertificateParsingException( "Empty issuer DN not allowed in X509Certificates"); } // validity: SEQUENCE { start date, end date } interval = new CertificateValidity(in); // subject name subject = new X500Name(in); if ((version.compare(CertificateVersion.V1) == 0) && subject.isEmpty()) { throw new CertificateParsingException( "Empty subject DN not allowed in v1 certificate"); } // public key pubKey = new CertificateX509Key(in); // If more data available, make sure version is not v1. if (in.available() != 0) { if (version.compare(CertificateVersion.V1) == 0) { throw new CertificateParsingException( "no more data allowed for version 1 certificate"); } } else { return; } // Get the issuerUniqueId if present tmp = in.getDerValue(); if (tmp.isContextSpecific((byte)1)) { issuerUniqueId = new UniqueIdentity(tmp); if (in.available() == 0) return; tmp = in.getDerValue(); } // Get the subjectUniqueId if present. if (tmp.isContextSpecific((byte)2)) { subjectUniqueId = new UniqueIdentity(tmp); if (in.available() == 0) return; tmp = in.getDerValue(); } // Get the extensions. if (version.compare(CertificateVersion.V3) != 0) { throw new CertificateParsingException( "Extensions not allowed in v2 certificate"); } if (tmp.isConstructed() && tmp.isContextSpecific((byte)3)) { extensions = new CertificateExtensions(tmp.data); } // verify X.509 V3 Certificate verifyCert(subject, extensions); } /* * Verify if X.509 V3 Certificate is compliant with RFC 5280. */ private void verifyCert(X500Name subject, CertificateExtensions extensions) throws CertificateParsingException, IOException { // if SubjectName is empty, check for SubjectAlternativeNameExtension if (subject.isEmpty()) { if (extensions == null) { throw new CertificateParsingException("X.509 Certificate is " + "incomplete: subject field is empty, and certificate " + "has no extensions"); } SubjectAlternativeNameExtension subjectAltNameExt = null; GeneralNames names = null; try { subjectAltNameExt = (SubjectAlternativeNameExtension) extensions.get(SubjectAlternativeNameExtension.NAME); names = subjectAltNameExt.get( SubjectAlternativeNameExtension.SUBJECT_NAME); } catch (IOException e) { throw new CertificateParsingException("X.509 Certificate is " + "incomplete: subject field is empty, and " + "SubjectAlternativeName extension is absent"); } // SubjectAlternativeName extension is empty or not marked critical if (names == null || names.isEmpty()) { throw new CertificateParsingException("X.509 Certificate is " + "incomplete: subject field is empty, and " + "SubjectAlternativeName extension is empty"); } else if (subjectAltNameExt.isCritical() == false) { throw new CertificateParsingException("X.509 Certificate is " + "incomplete: SubjectAlternativeName extension MUST " + "be marked critical when subject field is empty"); } } } /* * Marshal the contents of a "raw" certificate into a DER sequence. */ private void emit(DerOutputStream out) throws CertificateException, IOException { DerOutputStream tmp = new DerOutputStream(); // version number, iff not V1 version.encode(tmp); // Encode serial number, issuer signing algorithm, issuer name // and validity serialNum.encode(tmp); algId.encode(tmp); if ((version.compare(CertificateVersion.V1) == 0) && (issuer.toString() == null)) throw new CertificateParsingException( "Null issuer DN not allowed in v1 certificate"); issuer.encode(tmp); interval.encode(tmp); // Encode subject (principal) and associated key if ((version.compare(CertificateVersion.V1) == 0) && (subject.toString() == null)) throw new CertificateParsingException( "Null subject DN not allowed in v1 certificate"); subject.encode(tmp); pubKey.encode(tmp); // Encode issuerUniqueId & subjectUniqueId. if (issuerUniqueId != null) { issuerUniqueId.encode(tmp, DerValue.createTag(DerValue.TAG_CONTEXT, false,(byte)1)); } if (subjectUniqueId != null) { subjectUniqueId.encode(tmp, DerValue.createTag(DerValue.TAG_CONTEXT, false,(byte)2)); } // Write all the extensions. if (extensions != null) { extensions.encode(tmp); } // Wrap the data; encoding of the "raw" cert is now complete. out.write(DerValue.tag_Sequence, tmp); } /** * Returns the integer attribute number for the passed attribute name. */ private int attributeMap(String name) { Integer num = map.get(name); if (num == null) { return 0; } return num.intValue(); } /** * Set the version number of the certificate. * * @param val the Object class value for the Extensions * @exception CertificateException on invalid data. */ private void setVersion(Object val) throws CertificateException { if (!(val instanceof CertificateVersion)) { throw new CertificateException("Version class type invalid."); } version = (CertificateVersion)val; } /** * Set the serial number of the certificate. * * @param val the Object class value for the CertificateSerialNumber * @exception CertificateException on invalid data. */ private void setSerialNumber(Object val) throws CertificateException { if (!(val instanceof CertificateSerialNumber)) { throw new CertificateException("SerialNumber class type invalid."); } serialNum = (CertificateSerialNumber)val; } /** * Set the algorithm id of the certificate. * * @param val the Object class value for the AlgorithmId * @exception CertificateException on invalid data. */ private void setAlgorithmId(Object val) throws CertificateException { if (!(val instanceof CertificateAlgorithmId)) { throw new CertificateException( "AlgorithmId class type invalid."); } algId = (CertificateAlgorithmId)val; } /** * Set the issuer name of the certificate. * * @param val the Object class value for the issuer * @exception CertificateException on invalid data. */ private void setIssuer(Object val) throws CertificateException { if (!(val instanceof X500Name)) { throw new CertificateException( "Issuer class type invalid."); } issuer = (X500Name)val; } /** * Set the validity interval of the certificate. * * @param val the Object class value for the CertificateValidity * @exception CertificateException on invalid data. */ private void setValidity(Object val) throws CertificateException { if (!(val instanceof CertificateValidity)) { throw new CertificateException( "CertificateValidity class type invalid."); } interval = (CertificateValidity)val; } /** * Set the subject name of the certificate. * * @param val the Object class value for the Subject * @exception CertificateException on invalid data. */ private void setSubject(Object val) throws CertificateException { if (!(val instanceof X500Name)) { throw new CertificateException( "Subject class type invalid."); } subject = (X500Name)val; } /** * Set the public key in the certificate. * * @param val the Object class value for the PublicKey * @exception CertificateException on invalid data. */ private void setKey(Object val) throws CertificateException { if (!(val instanceof CertificateX509Key)) { throw new CertificateException( "Key class type invalid."); } pubKey = (CertificateX509Key)val; } /** * Set the Issuer Unique Identity in the certificate. * * @param val the Object class value for the IssuerUniqueId * @exception CertificateException */ private void setIssuerUniqueId(Object val) throws CertificateException { if (version.compare(CertificateVersion.V2) < 0) { throw new CertificateException("Invalid version"); } if (!(val instanceof UniqueIdentity)) { throw new CertificateException( "IssuerUniqueId class type invalid."); } issuerUniqueId = (UniqueIdentity)val; } /** * Set the Subject Unique Identity in the certificate. * * @param val the Object class value for the SubjectUniqueId * @exception CertificateException */ private void setSubjectUniqueId(Object val) throws CertificateException { if (version.compare(CertificateVersion.V2) < 0) { throw new CertificateException("Invalid version"); } if (!(val instanceof UniqueIdentity)) { throw new CertificateException( "SubjectUniqueId class type invalid."); } subjectUniqueId = (UniqueIdentity)val; } /** * Set the extensions in the certificate. * * @param val the Object class value for the Extensions * @exception CertificateException */ private void setExtensions(Object val) throws CertificateException { if (version.compare(CertificateVersion.V3) < 0) { throw new CertificateException("Invalid version"); } if (!(val instanceof CertificateExtensions)) { throw new CertificateException( "Extensions class type invalid."); } extensions = (CertificateExtensions)val; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy