0001: /*
0002: * @(#)X509CertInfo.java 1.30 06/10/10
0003: *
0004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: *
0026: */
0027:
0028: package sun.security.x509;
0029:
0030: import java.io.IOException;
0031: import java.io.OutputStream;
0032: import java.io.InputStream;
0033:
0034: import java.security.cert.*;
0035: import java.util.Collection;
0036: import java.util.Enumeration;
0037: import java.util.Hashtable;
0038:
0039: import sun.security.util.*;
0040: import sun.misc.HexDumpEncoder;
0041:
0042: /**
0043: * The X509CertInfo class represents X.509 certificate information.
0044: *
0045: * <P>X.509 certificates have several base data elements, including:<UL>
0046: *
0047: * <LI>The <em>Subject Name</em>, an X.500 Distinguished Name for
0048: * the entity (subject) for which the certificate was issued.
0049: *
0050: * <LI>The <em>Subject Public Key</em>, the public key of the subject.
0051: * This is one of the most important parts of the certificate.
0052: *
0053: * <LI>The <em>Validity Period</em>, a time period (e.g. six months)
0054: * within which the certificate is valid (unless revoked).
0055: *
0056: * <LI>The <em>Issuer Name</em>, an X.500 Distinguished Name for the
0057: * Certificate Authority (CA) which issued the certificate.
0058: *
0059: * <LI>A <em>Serial Number</em> assigned by the CA, for use in
0060: * certificate revocation and other applications.
0061: *
0062: * @author Amit Kapoor
0063: * @author Hemma Prafullchandra
0064: * @version 1.23
0065: * @see CertAttrSet
0066: * @see X509CertImpl
0067: */
0068: public class X509CertInfo implements CertAttrSet {
0069: /**
0070: * Identifier for this attribute, to be used with the
0071: * get, set, delete methods of Certificate, x509 type.
0072: */
0073: public static final String IDENT = "x509.info";
0074: // Certificate attribute names
0075: public static final String NAME = "info";
0076: public static final String VERSION = CertificateVersion.NAME;
0077: public static final String SERIAL_NUMBER = CertificateSerialNumber.NAME;
0078: public static final String ALGORITHM_ID = CertificateAlgorithmId.NAME;
0079: public static final String ISSUER = CertificateIssuerName.NAME;
0080: public static final String VALIDITY = CertificateValidity.NAME;
0081: public static final String SUBJECT = CertificateSubjectName.NAME;
0082: public static final String KEY = CertificateX509Key.NAME;
0083: public static final String ISSUER_ID = CertificateIssuerUniqueIdentity.NAME;
0084: public static final String SUBJECT_ID = CertificateSubjectUniqueIdentity.NAME;
0085: public static final String EXTENSIONS = CertificateExtensions.NAME;
0086:
0087: // X509.v1 data
0088: protected CertificateVersion version = new CertificateVersion();
0089: protected CertificateSerialNumber serialNum = null;
0090: protected CertificateAlgorithmId algId = null;
0091: protected CertificateIssuerName issuer = null;
0092: protected CertificateValidity interval = null;
0093: protected CertificateSubjectName subject = null;
0094: protected CertificateX509Key pubKey = null;
0095:
0096: // X509.v2 & v3 extensions
0097: protected CertificateIssuerUniqueIdentity issuerUniqueId = null;
0098: protected CertificateSubjectUniqueIdentity subjectUniqueId = null;
0099:
0100: // X509.v3 extensions
0101: protected CertificateExtensions extensions = null;
0102:
0103: // Attribute numbers for internal manipulation
0104: private static final int ATTR_VERSION = 1;
0105: private static final int ATTR_SERIAL = 2;
0106: private static final int ATTR_ALGORITHM = 3;
0107: private static final int ATTR_ISSUER = 4;
0108: private static final int ATTR_VALIDITY = 5;
0109: private static final int ATTR_SUBJECT = 6;
0110: private static final int ATTR_KEY = 7;
0111: private static final int ATTR_ISSUER_ID = 8;
0112: private static final int ATTR_SUBJECT_ID = 9;
0113: private static final int ATTR_EXTENSIONS = 10;
0114:
0115: // DER encoded CertificateInfo data
0116: private byte[] rawCertInfo = null;
0117:
0118: // The certificate attribute name to integer mapping stored here
0119: private static final Hashtable map = new Hashtable();
0120: static {
0121: map.put(VERSION, new Integer(ATTR_VERSION));
0122: map.put(SERIAL_NUMBER, new Integer(ATTR_SERIAL));
0123: map.put(ALGORITHM_ID, new Integer(ATTR_ALGORITHM));
0124: map.put(ISSUER, new Integer(ATTR_ISSUER));
0125: map.put(VALIDITY, new Integer(ATTR_VALIDITY));
0126: map.put(SUBJECT, new Integer(ATTR_SUBJECT));
0127: map.put(KEY, new Integer(ATTR_KEY));
0128: map.put(ISSUER_ID, new Integer(ATTR_ISSUER_ID));
0129: map.put(SUBJECT_ID, new Integer(ATTR_SUBJECT_ID));
0130: map.put(EXTENSIONS, new Integer(ATTR_EXTENSIONS));
0131: }
0132:
0133: /**
0134: * Construct an uninitialized X509CertInfo on which <a href="#decode">
0135: * decode</a> must later be called (or which may be deserialized).
0136: */
0137: public X509CertInfo() {
0138: }
0139:
0140: /**
0141: * Unmarshals a certificate from its encoded form, parsing the
0142: * encoded bytes. This form of constructor is used by agents which
0143: * need to examine and use certificate contents. That is, this is
0144: * one of the more commonly used constructors. Note that the buffer
0145: * must include only a certificate, and no "garbage" may be left at
0146: * the end. If you need to ignore data at the end of a certificate,
0147: * use another constructor.
0148: *
0149: * @param cert the encoded bytes, with no trailing data.
0150: * @exception CertificateParsingException on parsing errors.
0151: */
0152: public X509CertInfo(byte[] cert) throws CertificateParsingException {
0153: try {
0154: DerValue in = new DerValue(cert);
0155:
0156: parse(in);
0157: } catch (IOException e) {
0158: CertificateParsingException parseException = new CertificateParsingException(
0159: e.toString());
0160: parseException.initCause(e);
0161: throw parseException;
0162: }
0163: }
0164:
0165: /**
0166: * Unmarshal a certificate from its encoded form, parsing a DER value.
0167: * This form of constructor is used by agents which need to examine
0168: * and use certificate contents.
0169: *
0170: * @param derVal the der value containing the encoded cert.
0171: * @exception CertificateParsingException on parsing errors.
0172: */
0173: public X509CertInfo(DerValue derVal)
0174: throws CertificateParsingException {
0175: try {
0176: parse(derVal);
0177: } catch (IOException e) {
0178: CertificateParsingException parseException = new CertificateParsingException(
0179: e.toString());
0180: parseException.initCause(e);
0181: throw parseException;
0182: }
0183: }
0184:
0185: /**
0186: * Decode an X.509 certificate from an input stream.
0187: *
0188: * @param in an input stream holding at least one certificate
0189: * @exception CertificateParsingException on decoding errors.
0190: * @exception IOException on other errors.
0191: */
0192: public void decode(InputStream in)
0193: throws CertificateParsingException, IOException {
0194: DerValue val = new DerValue(in);
0195:
0196: parse(val);
0197: }
0198:
0199: /**
0200: * Appends the certificate to an output stream.
0201: *
0202: * @param out an output stream to which the certificate is appended.
0203: * @exception CertificateException on encoding errors.
0204: * @exception IOException on other errors.
0205: */
0206: public void encode(OutputStream out) throws CertificateException,
0207: IOException {
0208: if (rawCertInfo == null) {
0209: DerOutputStream tmp = new DerOutputStream();
0210: emit(tmp);
0211: rawCertInfo = tmp.toByteArray();
0212: }
0213: out.write((byte[]) rawCertInfo.clone());
0214: }
0215:
0216: /**
0217: * Return an enumeration of names of attributes existing within this
0218: * attribute.
0219: */
0220: public Enumeration getElements() {
0221: AttributeNameEnumeration elements = new AttributeNameEnumeration();
0222: elements.addElement(VERSION);
0223: elements.addElement(SERIAL_NUMBER);
0224: elements.addElement(ALGORITHM_ID);
0225: elements.addElement(ISSUER);
0226: elements.addElement(VALIDITY);
0227: elements.addElement(SUBJECT);
0228: elements.addElement(KEY);
0229: elements.addElement(ISSUER_ID);
0230: elements.addElement(SUBJECT_ID);
0231: elements.addElement(EXTENSIONS);
0232:
0233: return (elements.elements());
0234: }
0235:
0236: /**
0237: * Return the name of this attribute.
0238: */
0239: public String getName() {
0240: return (NAME);
0241: }
0242:
0243: /**
0244: * Returns the encoded certificate info.
0245: *
0246: * @exception CertificateEncodingException on encoding information errors.
0247: */
0248: public byte[] getEncodedInfo() throws CertificateEncodingException {
0249: try {
0250: if (rawCertInfo == null) {
0251: DerOutputStream tmp = new DerOutputStream();
0252: emit(tmp);
0253: rawCertInfo = tmp.toByteArray();
0254: }
0255: return (byte[]) rawCertInfo.clone();
0256: } catch (IOException e) {
0257: throw new CertificateEncodingException(e.toString());
0258: } catch (CertificateException e) {
0259: throw new CertificateEncodingException(e.toString());
0260: }
0261: }
0262:
0263: /**
0264: * Compares two X509CertInfo objects. This is false if the
0265: * certificates are not both X.509 certs, otherwise it
0266: * compares them as binary data.
0267: *
0268: * @param other the object being compared with this one
0269: * @return true iff the certificates are equivalent
0270: */
0271: public boolean equals(Object other) {
0272: if (other instanceof X509CertInfo) {
0273: return equals((X509CertInfo) other);
0274: } else {
0275: return false;
0276: }
0277: }
0278:
0279: /**
0280: * Compares two certificates, returning false if any data
0281: * differs between the two.
0282: *
0283: * @param other the object being compared with this one
0284: * @return true iff the certificates are equivalent
0285: */
0286: public boolean equals(X509CertInfo other) {
0287: if (this == other) {
0288: return (true);
0289: } else if (rawCertInfo == null || other.rawCertInfo == null) {
0290: return (false);
0291: } else if (rawCertInfo.length != other.rawCertInfo.length) {
0292: return (false);
0293: }
0294: for (int i = 0; i < rawCertInfo.length; i++) {
0295: if (rawCertInfo[i] != other.rawCertInfo[i]) {
0296: return (false);
0297: }
0298: }
0299: return (true);
0300: }
0301:
0302: /**
0303: * Calculates a hash code value for the object. Objects
0304: * which are equal will also have the same hashcode.
0305: */
0306: public int hashCode() {
0307: int retval = 0;
0308:
0309: for (int i = 1; i < rawCertInfo.length; i++) {
0310: retval += rawCertInfo[i] * i;
0311: }
0312: return (retval);
0313: }
0314:
0315: /**
0316: * Returns a printable representation of the certificate.
0317: */
0318: public String toString() {
0319:
0320: if (subject == null || pubKey == null || interval == null
0321: || issuer == null || algId == null || serialNum == null) {
0322: throw new NullPointerException("X.509 cert is incomplete");
0323: }
0324: StringBuffer sb = new StringBuffer();
0325:
0326: sb.append("[\n");
0327: sb.append(" " + version.toString() + "\n");
0328: sb.append(" Subject: " + subject.toString() + "\n");
0329: sb.append(" Signature Algorithm: " + algId.toString() + "\n");
0330: sb.append(" Key: " + pubKey.toString() + "\n");
0331: sb.append(" " + interval.toString() + "\n");
0332: sb.append(" Issuer: " + issuer.toString() + "\n");
0333: sb.append(" " + serialNum.toString() + "\n");
0334:
0335: // optional v2, v3 extras
0336: if (issuerUniqueId != null) {
0337: sb.append(" Issuer Id:\n" + issuerUniqueId.toString()
0338: + "\n");
0339: }
0340: if (subjectUniqueId != null) {
0341: sb.append(" Subject Id:\n" + subjectUniqueId.toString()
0342: + "\n");
0343: }
0344: if (extensions != null) {
0345: Collection allExts = extensions.getAllExtensions();
0346: Object[] objs = allExts.toArray();
0347: sb.append("\nCertificate Extensions: " + objs.length);
0348: for (int i = 0; i < objs.length; i++) {
0349: sb.append("\n[" + (i + 1) + "]: ");
0350: Extension ext = (Extension) objs[i];
0351: try {
0352: if (OIDMap.getClass(ext.getExtensionId()) == null) {
0353: sb.append(ext.toString());
0354: byte[] extValue = ext.getExtensionValue();
0355: if (extValue != null) {
0356: DerOutputStream out = new DerOutputStream();
0357: out.putOctetString(extValue);
0358: extValue = out.toByteArray();
0359: HexDumpEncoder enc = new HexDumpEncoder();
0360: sb
0361: .append("Extension unknown: "
0362: + "DER encoded OCTET string =\n"
0363: + enc
0364: .encodeBuffer(extValue)
0365: + "\n");
0366: }
0367: } else
0368: sb.append(ext.toString()); //sub-class exists
0369: } catch (Exception e) {
0370: sb.append(", Error parsing this extension");
0371: }
0372: }
0373: }
0374: sb.append("\n]");
0375: return sb.toString();
0376: }
0377:
0378: /**
0379: * Set the certificate attribute.
0380: *
0381: * @params name the name of the Certificate attribute.
0382: * @params val the value of the Certificate attribute.
0383: * @exception CertificateException on invalid attributes.
0384: * @exception IOException on other errors.
0385: */
0386: public void set(String name, Object val)
0387: throws CertificateException, IOException {
0388: X509AttributeName attrName = new X509AttributeName(name);
0389:
0390: int attr = attributeMap(attrName.getPrefix());
0391: if (attr == 0) {
0392: throw new CertificateException(
0393: "Attribute name not recognized: " + name);
0394: }
0395: // set rawCertInfo to null, so that we are forced to re-encode
0396: rawCertInfo = null;
0397: String suffix = attrName.getSuffix();
0398:
0399: switch (attr) {
0400: case ATTR_VERSION:
0401: if (suffix == null) {
0402: setVersion(val);
0403: } else {
0404: version.set(suffix, val);
0405: }
0406: break;
0407:
0408: case ATTR_SERIAL:
0409: if (suffix == null) {
0410: setSerialNumber(val);
0411: } else {
0412: serialNum.set(suffix, val);
0413: }
0414: break;
0415:
0416: case ATTR_ALGORITHM:
0417: if (suffix == null) {
0418: setAlgorithmId(val);
0419: } else {
0420: algId.set(suffix, val);
0421: }
0422: break;
0423:
0424: case ATTR_ISSUER:
0425: if (suffix == null) {
0426: setIssuer(val);
0427: } else {
0428: issuer.set(suffix, val);
0429: }
0430: break;
0431:
0432: case ATTR_VALIDITY:
0433: if (suffix == null) {
0434: setValidity(val);
0435: } else {
0436: interval.set(suffix, val);
0437: }
0438: break;
0439:
0440: case ATTR_SUBJECT:
0441: if (suffix == null) {
0442: setSubject(val);
0443: } else {
0444: subject.set(suffix, val);
0445: }
0446: break;
0447:
0448: case ATTR_KEY:
0449: if (suffix == null) {
0450: setKey(val);
0451: } else {
0452: pubKey.set(suffix, val);
0453: }
0454: break;
0455:
0456: case ATTR_ISSUER_ID:
0457: if (suffix == null) {
0458: setIssuerUniqueId(val);
0459: } else {
0460: issuerUniqueId.set(suffix, val);
0461: }
0462: break;
0463:
0464: case ATTR_SUBJECT_ID:
0465: if (suffix == null) {
0466: setSubjectUniqueId(val);
0467: } else {
0468: subjectUniqueId.set(suffix, val);
0469: }
0470: break;
0471:
0472: case ATTR_EXTENSIONS:
0473: if (suffix == null) {
0474: setExtensions(val);
0475: } else {
0476: if (extensions == null)
0477: extensions = new CertificateExtensions();
0478: extensions.set(suffix, val);
0479: }
0480: break;
0481: }
0482: }
0483:
0484: /**
0485: * Delete the certificate attribute.
0486: *
0487: * @params name the name of the Certificate attribute.
0488: * @exception CertificateException on invalid attributes.
0489: * @exception IOException on other errors.
0490: */
0491: public void delete(String name) throws CertificateException,
0492: IOException {
0493: X509AttributeName attrName = new X509AttributeName(name);
0494:
0495: int attr = attributeMap(attrName.getPrefix());
0496: if (attr == 0) {
0497: throw new CertificateException(
0498: "Attribute name not recognized: " + name);
0499: }
0500: // set rawCertInfo to null, so that we are forced to re-encode
0501: rawCertInfo = null;
0502: String suffix = attrName.getSuffix();
0503:
0504: switch (attr) {
0505: case ATTR_VERSION:
0506: if (suffix == null) {
0507: version = null;
0508: } else {
0509: version.delete(suffix);
0510: }
0511: break;
0512: case (ATTR_SERIAL):
0513: if (suffix == null) {
0514: serialNum = null;
0515: } else {
0516: serialNum.delete(suffix);
0517: }
0518: break;
0519: case (ATTR_ALGORITHM):
0520: if (suffix == null) {
0521: algId = null;
0522: } else {
0523: algId.delete(suffix);
0524: }
0525: break;
0526: case (ATTR_ISSUER):
0527: if (suffix == null) {
0528: issuer = null;
0529: } else {
0530: issuer.delete(suffix);
0531: }
0532: break;
0533: case (ATTR_VALIDITY):
0534: if (suffix == null) {
0535: interval = null;
0536: } else {
0537: interval.delete(suffix);
0538: }
0539: break;
0540: case (ATTR_SUBJECT):
0541: if (suffix == null) {
0542: subject = null;
0543: } else {
0544: subject.delete(suffix);
0545: }
0546: break;
0547: case (ATTR_KEY):
0548: if (suffix == null) {
0549: pubKey = null;
0550: } else {
0551: pubKey.delete(suffix);
0552: }
0553: break;
0554: case (ATTR_ISSUER_ID):
0555: if (suffix == null) {
0556: issuerUniqueId = null;
0557: } else {
0558: issuerUniqueId.delete(suffix);
0559: }
0560: break;
0561: case (ATTR_SUBJECT_ID):
0562: if (suffix == null) {
0563: subjectUniqueId = null;
0564: } else {
0565: subjectUniqueId.delete(suffix);
0566: }
0567: break;
0568: case (ATTR_EXTENSIONS):
0569: if (suffix == null) {
0570: extensions = null;
0571: } else {
0572: if (extensions != null)
0573: extensions.delete(suffix);
0574: }
0575: break;
0576: }
0577: }
0578:
0579: /**
0580: * Get the certificate attribute.
0581: *
0582: * @params name the name of the Certificate attribute.
0583: *
0584: * @exception CertificateException on invalid attributes.
0585: * @exception IOException on other errors.
0586: */
0587: public Object get(String name) throws CertificateException,
0588: IOException {
0589: X509AttributeName attrName = new X509AttributeName(name);
0590:
0591: int attr = attributeMap(attrName.getPrefix());
0592: if (attr == 0) {
0593: throw new CertificateParsingException(
0594: "Attribute name not recognized: " + name);
0595: }
0596: String suffix = attrName.getSuffix();
0597:
0598: switch (attr) { // frequently used attributes first
0599: case (ATTR_EXTENSIONS):
0600: if (suffix == null) {
0601: return (extensions);
0602: } else {
0603: if (extensions == null) {
0604: return null;
0605: } else {
0606: return (extensions.get(suffix));
0607: }
0608: }
0609: case (ATTR_SUBJECT):
0610: if (suffix == null) {
0611: return (subject);
0612: } else {
0613: return (subject.get(suffix));
0614: }
0615: case (ATTR_ISSUER):
0616: if (suffix == null) {
0617: return (issuer);
0618: } else {
0619: return (issuer.get(suffix));
0620: }
0621: case (ATTR_KEY):
0622: if (suffix == null) {
0623: return (pubKey);
0624: } else {
0625: return (pubKey.get(suffix));
0626: }
0627: case (ATTR_ALGORITHM):
0628: if (suffix == null) {
0629: return (algId);
0630: } else {
0631: return (algId.get(suffix));
0632: }
0633: case (ATTR_VALIDITY):
0634: if (suffix == null) {
0635: return (interval);
0636: } else {
0637: return (interval.get(suffix));
0638: }
0639: case (ATTR_VERSION):
0640: if (suffix == null) {
0641: return (version);
0642: } else {
0643: return (version.get(suffix));
0644: }
0645: case (ATTR_SERIAL):
0646: if (suffix == null) {
0647: return (serialNum);
0648: } else {
0649: return (serialNum.get(suffix));
0650: }
0651: case (ATTR_ISSUER_ID):
0652: if (suffix == null) {
0653: return (issuerUniqueId);
0654: } else {
0655: if (issuerUniqueId == null)
0656: return null;
0657: else
0658: return (issuerUniqueId.get(suffix));
0659: }
0660: case (ATTR_SUBJECT_ID):
0661: if (suffix == null) {
0662: return (subjectUniqueId);
0663: } else {
0664: if (subjectUniqueId == null)
0665: return null;
0666: else
0667: return (subjectUniqueId.get(suffix));
0668: }
0669: }
0670: return null;
0671: }
0672:
0673: /*
0674: * This routine unmarshals the certificate information.
0675: */
0676: private void parse(DerValue val)
0677: throws CertificateParsingException, IOException {
0678: DerInputStream in;
0679: DerValue tmp;
0680:
0681: if (val.tag != DerValue.tag_Sequence) {
0682: throw new CertificateParsingException(
0683: "signed fields invalid");
0684: }
0685: rawCertInfo = val.toByteArray();
0686:
0687: in = val.data;
0688:
0689: // Version
0690: tmp = in.getDerValue();
0691: if (tmp.isContextSpecific((byte) 0)) {
0692: version = new CertificateVersion(tmp);
0693: tmp = in.getDerValue();
0694: }
0695:
0696: // Serial number ... an integer
0697: serialNum = new CertificateSerialNumber(tmp);
0698:
0699: // Algorithm Identifier
0700: algId = new CertificateAlgorithmId(in);
0701:
0702: // Issuer name
0703: issuer = new CertificateIssuerName(in);
0704: X500Name issuerDN = (X500Name) issuer
0705: .get(CertificateIssuerName.DN_NAME);
0706: if (issuerDN.isEmpty()) {
0707: throw new CertificateParsingException(
0708: "Empty issuer DN not allowed in X509Certificates");
0709: }
0710:
0711: // validity: SEQUENCE { start date, end date }
0712: interval = new CertificateValidity(in);
0713:
0714: // subject name
0715: subject = new CertificateSubjectName(in);
0716: X500Name subjectDN = (X500Name) subject
0717: .get(CertificateSubjectName.DN_NAME);
0718: if ((version.compare(CertificateVersion.V1) == 0)
0719: && subjectDN.isEmpty()) {
0720: throw new CertificateParsingException(
0721: "Empty subject DN not allowed in v1 certificate");
0722: }
0723:
0724: // public key
0725: pubKey = new CertificateX509Key(in);
0726:
0727: // If more data available, make sure version is not v1.
0728: if (in.available() != 0) {
0729: if (version.compare(CertificateVersion.V1) == 0) {
0730: throw new CertificateParsingException(
0731: "no more data allowed for version 1 certificate");
0732: }
0733: } else {
0734: return;
0735: }
0736:
0737: // Get the issuerUniqueId if present
0738: tmp = in.getDerValue();
0739: if (tmp.isContextSpecific((byte) 1)) {
0740: issuerUniqueId = new CertificateIssuerUniqueIdentity(tmp);
0741: if (in.available() == 0)
0742: return;
0743: tmp = in.getDerValue();
0744: }
0745:
0746: // Get the subjectUniqueId if present.
0747: if (tmp.isContextSpecific((byte) 2)) {
0748: subjectUniqueId = new CertificateSubjectUniqueIdentity(tmp);
0749: if (in.available() == 0)
0750: return;
0751: tmp = in.getDerValue();
0752: }
0753:
0754: // Get the extensions.
0755: if (version.compare(CertificateVersion.V3) != 0) {
0756: throw new CertificateParsingException(
0757: "Extensions not allowed in v2 certificate");
0758: }
0759: if (tmp.isConstructed() && tmp.isContextSpecific((byte) 3)) {
0760: extensions = new CertificateExtensions(tmp.data);
0761: }
0762:
0763: // verify X.509 V3 Certificate
0764: verifyCert(subject, extensions);
0765:
0766: }
0767:
0768: /*
0769: * Verify if X.509 V3 Certificate was compliant with RFC 2459
0770: */
0771: private void verifyCert(CertificateSubjectName subject,
0772: CertificateExtensions extensions)
0773: throws CertificateParsingException, IOException {
0774:
0775: // if SubjectName is empty, check for SubjectAlternativeNameExtension
0776: X500Name subjectDN = (X500Name) subject
0777: .get(CertificateSubjectName.DN_NAME);
0778: if (subjectDN.isEmpty()) {
0779: if (extensions == null) {
0780: throw new CertificateParsingException(
0781: "X.509 Certificate is "
0782: + "incomplete: subject field is empty, and certificate "
0783: + "has no extensions");
0784: }
0785: SubjectAlternativeNameExtension subjectAltNameExt = null;
0786: SubjectAlternativeNameExtension extValue = null;
0787: GeneralNames names = null;
0788: try {
0789: subjectAltNameExt = (SubjectAlternativeNameExtension) extensions
0790: .get(SubjectAlternativeNameExtension.NAME);
0791: names = (GeneralNames) subjectAltNameExt
0792: .get(SubjectAlternativeNameExtension.SUBJECT_NAME);
0793: } catch (IOException e) {
0794: throw new CertificateParsingException(
0795: "X.509 Certificate is "
0796: + "incomplete: subject field is empty, and "
0797: + "SubjectAlternativeName extension is absent");
0798: }
0799:
0800: // SubjectAlternativeName extension is empty or not marked critical
0801: if (names == null || names.isEmpty()) {
0802: throw new CertificateParsingException(
0803: "X.509 Certificate is "
0804: + "incomplete: subject field is empty, and "
0805: + "SubjectAlternativeName extension is empty");
0806: } else if (subjectAltNameExt.isCritical() == false) {
0807: throw new CertificateParsingException(
0808: "X.509 Certificate is "
0809: + "incomplete: SubjectAlternativeName extension MUST "
0810: + "be marked critical when subject field is empty");
0811: }
0812: }
0813: }
0814:
0815: /*
0816: * Marshal the contents of a "raw" certificate into a DER sequence.
0817: */
0818: private void emit(DerOutputStream out) throws CertificateException,
0819: IOException {
0820: DerOutputStream tmp = new DerOutputStream();
0821:
0822: // version number, iff not V1
0823: version.encode(tmp);
0824:
0825: // Encode serial number, issuer signing algorithm, issuer name
0826: // and validity
0827: serialNum.encode(tmp);
0828: algId.encode(tmp);
0829:
0830: if ((version.compare(CertificateVersion.V1) == 0)
0831: && (issuer.toString() == null))
0832: throw new CertificateParsingException(
0833: "Null issuer DN not allowed in v1 certificate");
0834:
0835: issuer.encode(tmp);
0836: interval.encode(tmp);
0837:
0838: // Encode subject (principal) and associated key
0839: if ((version.compare(CertificateVersion.V1) == 0)
0840: && (subject.toString() == null))
0841: throw new CertificateParsingException(
0842: "Null subject DN not allowed in v1 certificate");
0843: subject.encode(tmp);
0844: pubKey.encode(tmp);
0845:
0846: // Encode issuerUniqueId & subjectUniqueId.
0847: if (issuerUniqueId != null) {
0848: issuerUniqueId.encode(tmp);
0849: }
0850: if (subjectUniqueId != null) {
0851: subjectUniqueId.encode(tmp);
0852: }
0853:
0854: // Write all the extensions.
0855: if (extensions != null) {
0856: extensions.encode(tmp);
0857: }
0858:
0859: // Wrap the data; encoding of the "raw" cert is now complete.
0860: out.write(DerValue.tag_Sequence, tmp);
0861: }
0862:
0863: /**
0864: * Returns the integer attribute number for the passed attribute name.
0865: */
0866: private int attributeMap(String name) {
0867: Integer num = (Integer) map.get(name);
0868: if (num == null) {
0869: return (0);
0870: }
0871: return (num.intValue());
0872: }
0873:
0874: /**
0875: * Set the version number of the certificate.
0876: *
0877: * @params val the Object class value for the Extensions
0878: * @exception CertificateException on invalid data.
0879: */
0880: private void setVersion(Object val) throws CertificateException {
0881: if (!(val instanceof CertificateVersion)) {
0882: throw new CertificateException(
0883: "Version class type invalid.");
0884: }
0885: version = (CertificateVersion) val;
0886: }
0887:
0888: /**
0889: * Set the serial number of the certificate.
0890: *
0891: * @params val the Object class value for the CertificateSerialNumber
0892: * @exception CertificateException on invalid data.
0893: */
0894: private void setSerialNumber(Object val)
0895: throws CertificateException {
0896: if (!(val instanceof CertificateSerialNumber)) {
0897: throw new CertificateException(
0898: "SerialNumber class type invalid.");
0899: }
0900: serialNum = (CertificateSerialNumber) val;
0901: }
0902:
0903: /**
0904: * Set the algorithm id of the certificate.
0905: *
0906: * @params val the Object class value for the AlgorithmId
0907: * @exception CertificateException on invalid data.
0908: */
0909: private void setAlgorithmId(Object val) throws CertificateException {
0910: if (!(val instanceof CertificateAlgorithmId)) {
0911: throw new CertificateException(
0912: "AlgorithmId class type invalid.");
0913: }
0914: algId = (CertificateAlgorithmId) val;
0915: }
0916:
0917: /**
0918: * Set the issuer name of the certificate.
0919: *
0920: * @params val the Object class value for the issuer
0921: * @exception CertificateException on invalid data.
0922: */
0923: private void setIssuer(Object val) throws CertificateException {
0924: if (!(val instanceof CertificateIssuerName)) {
0925: throw new CertificateException("Issuer class type invalid.");
0926: }
0927: issuer = (CertificateIssuerName) val;
0928: }
0929:
0930: /**
0931: * Set the validity interval of the certificate.
0932: *
0933: * @params val the Object class value for the CertificateValidity
0934: * @exception CertificateException on invalid data.
0935: */
0936: private void setValidity(Object val) throws CertificateException {
0937: if (!(val instanceof CertificateValidity)) {
0938: throw new CertificateException(
0939: "CertificateValidity class type invalid.");
0940: }
0941: interval = (CertificateValidity) val;
0942: }
0943:
0944: /**
0945: * Set the subject name of the certificate.
0946: *
0947: * @params val the Object class value for the Subject
0948: * @exception CertificateException on invalid data.
0949: */
0950: private void setSubject(Object val) throws CertificateException {
0951: if (!(val instanceof CertificateSubjectName)) {
0952: throw new CertificateException(
0953: "Subject class type invalid.");
0954: }
0955: subject = (CertificateSubjectName) val;
0956: }
0957:
0958: /**
0959: * Set the public key in the certificate.
0960: *
0961: * @params val the Object class value for the PublicKey
0962: * @exception CertificateException on invalid data.
0963: */
0964: private void setKey(Object val) throws CertificateException {
0965: if (!(val instanceof CertificateX509Key)) {
0966: throw new CertificateException("Key class type invalid.");
0967: }
0968: pubKey = (CertificateX509Key) val;
0969: }
0970:
0971: /**
0972: * Set the Issuer Unique Identity in the certificate.
0973: *
0974: * @params val the Object class value for the IssuerUniqueId
0975: * @exception CertificateException
0976: */
0977: private void setIssuerUniqueId(Object val)
0978: throws CertificateException {
0979: if (version.compare(CertificateVersion.V2) < 0) {
0980: throw new CertificateException("Invalid version");
0981: }
0982: if (!(val instanceof CertificateIssuerUniqueIdentity)) {
0983: throw new CertificateException(
0984: "IssuerUniqueId class type invalid.");
0985: }
0986: issuerUniqueId = (CertificateIssuerUniqueIdentity) val;
0987: }
0988:
0989: /**
0990: * Set the Subject Unique Identity in the certificate.
0991: *
0992: * @params val the Object class value for the SubjectUniqueId
0993: * @exception CertificateException
0994: */
0995: private void setSubjectUniqueId(Object val)
0996: throws CertificateException {
0997: if (version.compare(CertificateVersion.V2) < 0) {
0998: throw new CertificateException("Invalid version");
0999: }
1000: if (!(val instanceof CertificateSubjectUniqueIdentity)) {
1001: throw new CertificateException(
1002: "SubjectUniqueId class type invalid.");
1003: }
1004: subjectUniqueId = (CertificateSubjectUniqueIdentity) val;
1005: }
1006:
1007: /**
1008: * Set the extensions in the certificate.
1009: *
1010: * @params val the Object class value for the Extensions
1011: * @exception CertificateException
1012: */
1013: private void setExtensions(Object val) throws CertificateException {
1014: if (version.compare(CertificateVersion.V3) < 0) {
1015: throw new CertificateException("Invalid version");
1016: }
1017: if (!(val instanceof CertificateExtensions)) {
1018: throw new CertificateException(
1019: "Extensions class type invalid.");
1020: }
1021: extensions = (CertificateExtensions) val;
1022: }
1023: }
|