0001: /*
0002: * @(#)X509CertImpl.java 1.5 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: /*
0029: * Note that there are two versions of X509CertImpl, this
0030: * subsetted one for CDC/FP and another for the security optional
0031: * package. Be sure you're editing the right one!
0032: */
0033:
0034: package sun.security.x509;
0035:
0036: import java.io.BufferedReader;
0037: import java.io.BufferedInputStream;
0038: import java.io.ByteArrayOutputStream;
0039: import java.io.IOException;
0040: import java.io.InputStream;
0041: import java.io.InputStreamReader;
0042: import java.io.OutputStream;
0043: import java.math.BigInteger;
0044: import java.security.*;
0045: import java.security.cert.*;
0046: import java.security.cert.Certificate;
0047: import java.util.*;
0048:
0049: import javax.security.auth.x500.X500Principal;
0050:
0051: import sun.misc.HexDumpEncoder;
0052: import sun.misc.BASE64Decoder;
0053: import sun.security.util.*;
0054: import sun.security.provider.X509Factory;
0055:
0056: /**
0057: * The X509CertImpl class represents an X.509 certificate. These certificates
0058: * are widely used to support authentication and other functionality in
0059: * Internet security systems. Common applications include Privacy Enhanced
0060: * Mail (PEM), Transport Layer Security (SSL), code signing for trusted
0061: * software distribution, and Secure Electronic Transactions (SET). There
0062: * is a commercial infrastructure ready to manage large scale deployments
0063: * of X.509 identity certificates.
0064: *
0065: * <P>These certificates are managed and vouched for by <em>Certificate
0066: * Authorities</em> (CAs). CAs are services which create certificates by
0067: * placing data in the X.509 standard format and then digitally signing
0068: * that data. Such signatures are quite difficult to forge. CAs act as
0069: * trusted third parties, making introductions between agents who have no
0070: * direct knowledge of each other. CA certificates are either signed by
0071: * themselves, or by some other CA such as a "root" CA.
0072: *
0073: * <P>RFC 1422 is very informative, though it does not describe much
0074: * of the recent work being done with X.509 certificates. That includes
0075: * a 1996 version (X.509v3) and a variety of enhancements being made to
0076: * facilitate an explosion of personal certificates used as "Internet
0077: * Drivers' Licences", or with SET for credit card transactions.
0078: *
0079: * <P>More recent work includes the IETF PKIX Working Group efforts,
0080: * especially RFC2459.
0081: *
0082: * @author Dave Brownell
0083: * @author Amit Kapoor
0084: * @author Hemma Prafullchandra
0085: * @version 1.109 02/02/00
0086: * @see X509CertInfo
0087: */
0088: public class X509CertImpl extends X509Certificate implements DerEncoder {
0089:
0090: private static final String DOT = ".";
0091: /**
0092: * Public attribute names.
0093: */
0094: public static final String NAME = "x509";
0095: public static final String INFO = X509CertInfo.NAME;
0096: public static final String ALG_ID = "algorithm";
0097: public static final String SIGNATURE = "signature";
0098: public static final String SIGNED_CERT = "signed_cert";
0099:
0100: /**
0101: * The following are defined for ease-of-use. These
0102: * are the most frequently retrieved attributes.
0103: */
0104: // x509.info.subject.dname
0105: public static final String SUBJECT_DN = NAME + DOT + INFO + DOT
0106: + X509CertInfo.SUBJECT + DOT
0107: + CertificateSubjectName.DN_NAME;
0108: // x509.info.issuer.dname
0109: public static final String ISSUER_DN = NAME + DOT + INFO + DOT
0110: + X509CertInfo.ISSUER + DOT + CertificateIssuerName.DN_NAME;
0111: // x509.info.serialNumber.number
0112: public static final String SERIAL_ID = NAME + DOT + INFO + DOT
0113: + X509CertInfo.SERIAL_NUMBER + DOT
0114: + CertificateSerialNumber.NUMBER;
0115: // x509.info.key.value
0116: public static final String PUBLIC_KEY = NAME + DOT + INFO + DOT
0117: + X509CertInfo.KEY + DOT + CertificateX509Key.KEY;
0118:
0119: // x509.info.version.value
0120: public static final String VERSION = NAME + DOT + INFO + DOT
0121: + X509CertInfo.VERSION + DOT + CertificateVersion.VERSION;
0122:
0123: // x509.algorithm
0124: public static final String SIG_ALG = NAME + DOT + ALG_ID;
0125:
0126: // x509.signature
0127: public static final String SIG = NAME + DOT + SIGNATURE;
0128:
0129: // when we sign and decode we set this to true
0130: // this is our means to make certificates immutable
0131: private boolean readOnly = false;
0132:
0133: // Certificate data, and its envelope
0134: private byte[] signedCert = null;
0135: protected X509CertInfo info = null;
0136: protected AlgorithmId algId = null;
0137: protected byte[] signature = null;
0138:
0139: // recognized extension OIDS
0140: private static final String KEY_USAGE_OID = "2.5.29.15";
0141: private static final String EXTENDED_KEY_USAGE_OID = "2.5.29.37";
0142: private static final String BASIC_CONSTRAINT_OID = "2.5.29.19";
0143: private static final String SUBJECT_ALT_NAME_OID = "2.5.29.17";
0144: private static final String ISSUER_ALT_NAME_OID = "2.5.29.18";
0145:
0146: // number of standard key usage bits.
0147: private static final int NUM_STANDARD_KEY_USAGE = 9;
0148:
0149: // SubjectAlterntativeNames cache
0150: private Collection subjectAlternativeNames;
0151:
0152: // IssuerAlternativeNames cache
0153: private Collection issuerAlternativeNames;
0154:
0155: // ExtendedKeyUsage cache
0156: private List extKeyUsage;
0157:
0158: /**
0159: * PublicKey that has previously been used to verify
0160: * the signature of this certificate. Null if the certificate has not
0161: * yet been verified.
0162: */
0163: private PublicKey verifiedPublicKey;
0164: /**
0165: * If verifiedPublicKey is not null, name of the provider used to
0166: * successfully verify the signature of this certificate, or the
0167: * empty String if no provider was explicitly specified.
0168: */
0169: private String verifiedProvider;
0170: /**
0171: * If verifiedPublicKey is not null, result of the verification using
0172: * verifiedPublicKey and verifiedProvider. If true, verification was
0173: * successful, if false, it failed.
0174: */
0175: private boolean verificationResult;
0176:
0177: /**
0178: * Default constructor.
0179: */
0180: public X509CertImpl() {
0181: }
0182:
0183: /**
0184: * Unmarshals a certificate from its encoded form, parsing the
0185: * encoded bytes. This form of constructor is used by agents which
0186: * need to examine and use certificate contents. That is, this is
0187: * one of the more commonly used constructors. Note that the buffer
0188: * must include only a certificate, and no "garbage" may be left at
0189: * the end. If you need to ignore data at the end of a certificate,
0190: * use another constructor.
0191: *
0192: * @param certData the encoded bytes, with no trailing padding.
0193: * @exception CertificateException on parsing and initialization errors.
0194: */
0195: public X509CertImpl(byte[] certData) throws CertificateException {
0196: try {
0197: parse(new DerValue(certData));
0198: } catch (IOException e) {
0199: signedCert = null;
0200: CertificateException ce = new CertificateException(
0201: "Unable to initialize, " + e);
0202: ce.initCause(e);
0203: throw ce;
0204: }
0205: }
0206:
0207: /**
0208: * unmarshals an X.509 certificate from an input stream. If the
0209: * certificate is RFC1421 hex-encoded, then it must begin with
0210: * the line X509Factory.BEGIN_CERT and end with the line
0211: * X509Factory.END_CERT.
0212: *
0213: * @param in an input stream holding at least one certificate that may
0214: * be either DER-encoded or RFC1421 hex-encoded version of the
0215: * DER-encoded certificate.
0216: * @exception CertificateException on parsing and initialization errors.
0217: */
0218: public X509CertImpl(InputStream in) throws CertificateException {
0219:
0220: DerValue der = null;
0221:
0222: BufferedInputStream inBuffered = new BufferedInputStream(in);
0223:
0224: // First try reading stream as HEX-encoded DER-encoded bytes,
0225: // since not mistakable for raw DER
0226: try {
0227: inBuffered.mark(Integer.MAX_VALUE);
0228: der = readRFC1421Cert(inBuffered);
0229: } catch (IOException ioe) {
0230: try {
0231: // Next, try reading stream as raw DER-encoded bytes
0232: inBuffered.reset();
0233: der = new DerValue(inBuffered);
0234: } catch (IOException ioe1) {
0235: CertificateException ce = new CertificateException(
0236: "Input stream must be "
0237: + "either DER-encoded bytes "
0238: + "or RFC1421 hex-encoded "
0239: + "DER-encoded bytes: "
0240: + ioe1.getMessage());
0241: ce.initCause(ioe1);
0242: throw ce;
0243: }
0244: }
0245: try {
0246: parse(der);
0247: } catch (IOException ioe) {
0248: signedCert = null;
0249: CertificateException ce = new CertificateException(
0250: "Unable to parse DER value of " + "certificate, "
0251: + ioe);
0252: ce.initCause(ioe);
0253: throw ce;
0254: }
0255: }
0256:
0257: /**
0258: * read input stream as HEX-encoded DER-encoded bytes
0259: *
0260: * @param in InputStream to read
0261: * @returns DerValue corresponding to decoded HEX-encoded bytes
0262: * @throws IOException if stream can not be interpreted as RFC1421
0263: * encoded bytes
0264: */
0265: private DerValue readRFC1421Cert(InputStream in) throws IOException {
0266: DerValue der = null;
0267: String line = null;
0268: BufferedReader certBufferedReader = new BufferedReader(
0269: new InputStreamReader(in));
0270: try {
0271: line = certBufferedReader.readLine();
0272: } catch (IOException ioe1) {
0273: throw new IOException("Unable to read InputStream: "
0274: + ioe1.getMessage());
0275: }
0276: if (line.equals(X509Factory.BEGIN_CERT)) {
0277: /* stream appears to be hex-encoded bytes */
0278: BASE64Decoder decoder = new BASE64Decoder();
0279: ByteArrayOutputStream decstream = new ByteArrayOutputStream();
0280: try {
0281: while ((line = certBufferedReader.readLine()) != null) {
0282: if (line.equals(X509Factory.END_CERT)) {
0283: der = new DerValue(decstream.toByteArray());
0284: break;
0285: } else {
0286: decstream.write(decoder.decodeBuffer(line));
0287: }
0288: }
0289: } catch (IOException ioe2) {
0290: throw new IOException("Unable to read InputStream: "
0291: + ioe2.getMessage());
0292: }
0293: } else {
0294: throw new IOException(
0295: "InputStream is not RFC1421 hex-encoded "
0296: + "DER bytes");
0297: }
0298: return der;
0299: }
0300:
0301: /**
0302: * Construct an initialized X509 Certificate. The certificate is stored
0303: * in raw form and has to be signed to be useful.
0304: *
0305: * @params info the X509CertificateInfo which the Certificate is to be
0306: * created from.
0307: */
0308: public X509CertImpl(X509CertInfo certInfo) {
0309: this .info = certInfo;
0310: }
0311:
0312: /**
0313: * Unmarshal a certificate from its encoded form, parsing a DER value.
0314: * This form of constructor is used by agents which need to examine
0315: * and use certificate contents.
0316: *
0317: * @param derVal the der value containing the encoded cert.
0318: * @exception CertificateException on parsing and initialization errors.
0319: */
0320: public X509CertImpl(DerValue derVal) throws CertificateException {
0321: try {
0322: parse(derVal);
0323: } catch (IOException e) {
0324: signedCert = null;
0325: CertificateException ce = new CertificateException(
0326: "Unable to initialize, " + e);
0327: ce.initCause(e);
0328: throw ce;
0329: }
0330: }
0331:
0332: /**
0333: * Appends the certificate to an output stream.
0334: *
0335: * @param out an input stream to which the certificate is appended.
0336: * @exception CertificateEncodingException on encoding errors.
0337: */
0338: public void encode(OutputStream out)
0339: throws CertificateEncodingException {
0340: if (signedCert == null)
0341: throw new CertificateEncodingException(
0342: "Null certificate to encode");
0343: try {
0344: out.write((byte[]) signedCert.clone());
0345: } catch (IOException e) {
0346: throw new CertificateEncodingException(e.toString());
0347: }
0348: }
0349:
0350: /**
0351: * DER encode this object onto an output stream.
0352: * Implements the <code>DerEncoder</code> interface.
0353: *
0354: * @param out the output stream on which to write the DER encoding.
0355: *
0356: * @exception IOException on encoding error.
0357: */
0358: public void derEncode(OutputStream out) throws IOException {
0359: if (signedCert == null)
0360: throw new IOException("Null certificate to encode");
0361: out.write((byte[]) signedCert.clone());
0362: }
0363:
0364: /**
0365: * Returns the encoded form of this certificate. It is
0366: * assumed that each certificate type would have only a single
0367: * form of encoding; for example, X.509 certificates would
0368: * be encoded as ASN.1 DER.
0369: *
0370: * @exception CertificateEncodingException if an encoding error occurs.
0371: */
0372: public byte[] getEncoded() throws CertificateEncodingException {
0373: return (byte[]) getEncodedInternal().clone();
0374: }
0375:
0376: /**
0377: * Returned the encoding as an uncloned byte array. Callers must
0378: * guarantee that they neither modify it nor expose it to untrusted
0379: * code.
0380: */
0381: public byte[] getEncodedInternal()
0382: throws CertificateEncodingException {
0383: if (signedCert == null) {
0384: throw new CertificateEncodingException(
0385: "Null certificate to encode");
0386: }
0387: return signedCert;
0388: }
0389:
0390: /**
0391: * Throws an exception if the certificate was not signed using the
0392: * verification key provided. Successfully verifying a certificate
0393: * does <em>not</em> indicate that one should trust the entity which
0394: * it represents.
0395: *
0396: * @param key the public key used for verification.
0397: *
0398: * @exception InvalidKeyException on incorrect key.
0399: * @exception NoSuchAlgorithmException on unsupported signature
0400: * algorithms.
0401: * @exception NoSuchProviderException if there's no default provider.
0402: * @exception SignatureException on signature errors.
0403: * @exception CertificateException on encoding errors.
0404: */
0405: public void verify(PublicKey key) throws CertificateException,
0406: NoSuchAlgorithmException, InvalidKeyException,
0407: NoSuchProviderException, SignatureException {
0408:
0409: verify(key, "");
0410: }
0411:
0412: /**
0413: * Throws an exception if the certificate was not signed using the
0414: * verification key provided. Successfully verifying a certificate
0415: * does <em>not</em> indicate that one should trust the entity which
0416: * it represents.
0417: *
0418: * @param key the public key used for verification.
0419: * @param sigProvider the name of the provider.
0420: *
0421: * @exception NoSuchAlgorithmException on unsupported signature
0422: * algorithms.
0423: * @exception InvalidKeyException on incorrect key.
0424: * @exception NoSuchProviderException on incorrect provider.
0425: * @exception SignatureException on signature errors.
0426: * @exception CertificateException on encoding errors.
0427: */
0428: public synchronized void verify(PublicKey key, String sigProvider)
0429: throws CertificateException, NoSuchAlgorithmException,
0430: InvalidKeyException, NoSuchProviderException,
0431: SignatureException {
0432: if (sigProvider == null) {
0433: sigProvider = "";
0434: }
0435: if ((verifiedPublicKey != null)
0436: && verifiedPublicKey.equals(key)) {
0437: // this certificate has already been verified using
0438: // this public key. Make sure providers match, too.
0439: if (sigProvider.equals(verifiedProvider)) {
0440: if (verificationResult) {
0441: return;
0442: } else {
0443: throw new SignatureException(
0444: "Signature does not match.");
0445: }
0446: }
0447: }
0448: if (signedCert == null) {
0449: throw new CertificateEncodingException(
0450: "Uninitialized certificate");
0451: }
0452: // Verify the signature ...
0453: Signature sigVerf = null;
0454: if (sigProvider.length() == 0) {
0455: sigVerf = Signature.getInstance(algId.getName());
0456: } else {
0457: sigVerf = Signature.getInstance(algId.getName(),
0458: sigProvider);
0459: }
0460: sigVerf.initVerify(key);
0461:
0462: byte[] rawCert = info.getEncodedInfo();
0463: sigVerf.update(rawCert, 0, rawCert.length);
0464:
0465: // verify may throw SignatureException for invalid encodings, etc.
0466: verificationResult = sigVerf.verify(signature);
0467: verifiedPublicKey = key;
0468: verifiedProvider = sigProvider;
0469:
0470: if (verificationResult == false) {
0471: throw new SignatureException("Signature does not match.");
0472: }
0473: }
0474:
0475: /**
0476: * Creates an X.509 certificate, and signs it using the given key
0477: * (associating a signature algorithm and an X.500 name).
0478: * This operation is used to implement the certificate generation
0479: * functionality of a certificate authority.
0480: *
0481: * @param key the private key used for signing.
0482: * @param algorithm the name of the signature algorithm used.
0483: *
0484: * @exception InvalidKeyException on incorrect key.
0485: * @exception NoSuchAlgorithmException on unsupported signature
0486: * algorithms.
0487: * @exception NoSuchProviderException if there's no default provider.
0488: * @exception SignatureException on signature errors.
0489: * @exception CertificateException on encoding errors.
0490: */
0491: public void sign(PrivateKey key, String algorithm)
0492: throws CertificateException, NoSuchAlgorithmException,
0493: InvalidKeyException, NoSuchProviderException,
0494: SignatureException {
0495: sign(key, algorithm, null);
0496: }
0497:
0498: /**
0499: * Creates an X.509 certificate, and signs it using the given key
0500: * (associating a signature algorithm and an X.500 name).
0501: * This operation is used to implement the certificate generation
0502: * functionality of a certificate authority.
0503: *
0504: * @param key the private key used for signing.
0505: * @param algorithm the name of the signature algorithm used.
0506: * @param provider the name of the provider.
0507: *
0508: * @exception NoSuchAlgorithmException on unsupported signature
0509: * algorithms.
0510: * @exception InvalidKeyException on incorrect key.
0511: * @exception NoSuchProviderException on incorrect provider.
0512: * @exception SignatureException on signature errors.
0513: * @exception CertificateException on encoding errors.
0514: */
0515: public void sign(PrivateKey key, String algorithm, String provider)
0516: throws CertificateException, NoSuchAlgorithmException,
0517: InvalidKeyException, NoSuchProviderException,
0518: SignatureException {
0519: try {
0520: if (readOnly)
0521: throw new CertificateEncodingException(
0522: "cannot over-write existing certificate");
0523: Signature sigEngine = null;
0524: if ((provider == null) || (provider.length() == 0))
0525: sigEngine = Signature.getInstance(algorithm);
0526: else
0527: sigEngine = Signature.getInstance(algorithm, provider);
0528:
0529: sigEngine.initSign(key);
0530:
0531: // in case the name is reset
0532: algId = AlgorithmId.get(sigEngine.getAlgorithm());
0533:
0534: DerOutputStream out = new DerOutputStream();
0535: DerOutputStream tmp = new DerOutputStream();
0536:
0537: // encode certificate info
0538: info.encode(tmp);
0539: byte[] rawCert = tmp.toByteArray();
0540:
0541: // encode algorithm identifier
0542: algId.encode(tmp);
0543:
0544: // Create and encode the signature itself.
0545: sigEngine.update(rawCert, 0, rawCert.length);
0546: signature = sigEngine.sign();
0547: tmp.putBitString(signature);
0548:
0549: // Wrap the signed data in a SEQUENCE { data, algorithm, sig }
0550: out.write(DerValue.tag_Sequence, tmp);
0551: signedCert = out.toByteArray();
0552: readOnly = true;
0553:
0554: } catch (IOException e) {
0555: throw new CertificateEncodingException(e.toString());
0556: }
0557: }
0558:
0559: /**
0560: * Checks that the certificate is currently valid, i.e. the current
0561: * time is within the specified validity period.
0562: *
0563: * @exception CertificateExpiredException if the certificate has expired.
0564: * @exception CertificateNotYetValidException if the certificate is not
0565: * yet valid.
0566: */
0567: public void checkValidity() throws CertificateExpiredException,
0568: CertificateNotYetValidException {
0569: Date date = new Date();
0570: checkValidity(date);
0571: }
0572:
0573: /**
0574: * Checks that the specified date is within the certificate's
0575: * validity period, or basically if the certificate would be
0576: * valid at the specified date/time.
0577: *
0578: * @param date the Date to check against to see if this certificate
0579: * is valid at that date/time.
0580: *
0581: * @exception CertificateExpiredException if the certificate has expired
0582: * with respect to the <code>date</code> supplied.
0583: * @exception CertificateNotYetValidException if the certificate is not
0584: * yet valid with respect to the <code>date</code> supplied.
0585: */
0586: public void checkValidity(Date date)
0587: throws CertificateExpiredException,
0588: CertificateNotYetValidException {
0589:
0590: CertificateValidity interval = null;
0591: try {
0592: interval = (CertificateValidity) info
0593: .get(CertificateValidity.NAME);
0594: } catch (Exception e) {
0595: throw new CertificateNotYetValidException(
0596: "Incorrect validity period");
0597: }
0598: if (interval == null)
0599: throw new CertificateNotYetValidException(
0600: "Null validity period");
0601: interval.valid(date);
0602: }
0603:
0604: /**
0605: * Return the requested attribute from the certificate.
0606: *
0607: * Note that the X509CertInfo is not cloned for performance reasons.
0608: * Callers must ensure that they do not modify it. All other
0609: * attributes are cloned.
0610: *
0611: * @param name the name of the attribute.
0612: * @exception CertificateParsingException on invalid attribute identifier.
0613: */
0614: public Object get(String name) throws CertificateParsingException {
0615: X509AttributeName attr = new X509AttributeName(name);
0616: String id = attr.getPrefix();
0617: if (!(id.equalsIgnoreCase(NAME))) {
0618: throw new CertificateParsingException("Invalid root of "
0619: + "attribute name, expected [" + NAME
0620: + "], received " + "[" + id + "]");
0621: }
0622: attr = new X509AttributeName(attr.getSuffix());
0623: id = attr.getPrefix();
0624:
0625: if (id.equalsIgnoreCase(INFO)) {
0626: if (info == null) {
0627: return null;
0628: }
0629: if (attr.getSuffix() != null) {
0630: try {
0631: return info.get(attr.getSuffix());
0632: } catch (IOException e) {
0633: throw new CertificateParsingException(e.toString());
0634: } catch (CertificateException e) {
0635: throw new CertificateParsingException(e.toString());
0636: }
0637: } else {
0638: return info;
0639: }
0640: } else if (id.equalsIgnoreCase(ALG_ID)) {
0641: return (algId);
0642: } else if (id.equalsIgnoreCase(SIGNATURE)) {
0643: if (signature != null)
0644: return signature.clone();
0645: else
0646: return null;
0647: } else if (id.equalsIgnoreCase(SIGNED_CERT)) {
0648: if (signedCert != null)
0649: return signedCert.clone();
0650: else
0651: return null;
0652: } else {
0653: throw new CertificateParsingException("Attribute name not "
0654: + "recognized or get() not allowed for the same: "
0655: + id);
0656: }
0657: }
0658:
0659: /**
0660: * Set the requested attribute in the certificate.
0661: *
0662: * @param name the name of the attribute.
0663: * @param obj the value of the attribute.
0664: * @exception CertificateException on invalid attribute identifier.
0665: * @exception IOException on encoding error of attribute.
0666: */
0667: public void set(String name, Object obj)
0668: throws CertificateException, IOException {
0669: // check if immutable
0670: if (readOnly)
0671: throw new CertificateException("cannot over-write existing"
0672: + " certificate");
0673:
0674: X509AttributeName attr = new X509AttributeName(name);
0675: String id = attr.getPrefix();
0676: if (!(id.equalsIgnoreCase(NAME))) {
0677: throw new CertificateException(
0678: "Invalid root of attribute name," + " expected ["
0679: + NAME + "], received " + id);
0680: }
0681: attr = new X509AttributeName(attr.getSuffix());
0682: id = attr.getPrefix();
0683:
0684: if (id.equalsIgnoreCase(INFO)) {
0685: if (attr.getSuffix() == null) {
0686: if (!(obj instanceof X509CertInfo)) {
0687: throw new CertificateException(
0688: "Attribute value should"
0689: + " be of type X509CertInfo.");
0690: }
0691: info = (X509CertInfo) obj;
0692: signedCert = null; //reset this as certificate data has changed
0693: } else {
0694: info.set(attr.getSuffix(), obj);
0695: signedCert = null; //reset this as certificate data has changed
0696: }
0697: } else {
0698: throw new CertificateException(
0699: "Attribute name not recognized or "
0700: + "set() not allowed for the same: " + id);
0701: }
0702: }
0703:
0704: /**
0705: * Delete the requested attribute from the certificate.
0706: *
0707: * @param name the name of the attribute.
0708: * @exception CertificateException on invalid attribute identifier.
0709: * @exception IOException on other errors.
0710: */
0711: public void delete(String name) throws CertificateException,
0712: IOException {
0713: // check if immutable
0714: if (readOnly)
0715: throw new CertificateException("cannot over-write existing"
0716: + " certificate");
0717:
0718: X509AttributeName attr = new X509AttributeName(name);
0719: String id = attr.getPrefix();
0720: if (!(id.equalsIgnoreCase(NAME))) {
0721: throw new CertificateException(
0722: "Invalid root of attribute name," + " expected ["
0723: + NAME + "], received " + id);
0724: }
0725: attr = new X509AttributeName(attr.getSuffix());
0726: id = attr.getPrefix();
0727:
0728: if (id.equalsIgnoreCase(INFO)) {
0729: if (attr.getSuffix() != null) {
0730: info = null;
0731: } else {
0732: info.delete(attr.getSuffix());
0733: }
0734: } else if (id.equalsIgnoreCase(ALG_ID)) {
0735: algId = null;
0736: } else if (id.equalsIgnoreCase(SIGNATURE)) {
0737: signature = null;
0738: } else if (id.equalsIgnoreCase(SIGNED_CERT)) {
0739: signedCert = null;
0740: } else {
0741: throw new CertificateException(
0742: "Attribute name not recognized or "
0743: + "delete() not allowed for the same: "
0744: + id);
0745: }
0746: }
0747:
0748: /**
0749: * Return an enumeration of names of attributes existing within this
0750: * attribute.
0751: */
0752: public Enumeration getElements() {
0753: AttributeNameEnumeration elements = new AttributeNameEnumeration();
0754: elements.addElement(NAME + DOT + INFO);
0755: elements.addElement(NAME + DOT + ALG_ID);
0756: elements.addElement(NAME + DOT + SIGNATURE);
0757: elements.addElement(NAME + DOT + SIGNED_CERT);
0758:
0759: return (elements.elements());
0760: }
0761:
0762: /**
0763: * Return the name of this attribute.
0764: */
0765: public String getName() {
0766: return (NAME);
0767: }
0768:
0769: /**
0770: * Returns a printable representation of the certificate. This does not
0771: * contain all the information available to distinguish this from any
0772: * other certificate. The certificate must be fully constructed
0773: * before this function may be called.
0774: */
0775: public String toString() {
0776: if (info == null || algId == null || signature == null)
0777: return "";
0778:
0779: StringBuffer sb = new StringBuffer();
0780:
0781: sb.append("[\n");
0782: sb.append(info.toString() + "\n");
0783: sb.append(" Algorithm: [" + algId.toString() + "]\n");
0784:
0785: HexDumpEncoder encoder = new HexDumpEncoder();
0786: sb.append(" Signature:\n" + encoder.encodeBuffer(signature));
0787: sb.append("\n]");
0788:
0789: return sb.toString();
0790: }
0791:
0792: // the strongly typed gets, as per java.security.cert.X509Certificate
0793:
0794: /**
0795: * Gets the publickey from this certificate.
0796: *
0797: * @return the publickey.
0798: */
0799: public PublicKey getPublicKey() {
0800: if (info == null)
0801: return null;
0802: try {
0803: PublicKey key = (PublicKey) info
0804: .get(CertificateX509Key.NAME + DOT
0805: + CertificateX509Key.KEY);
0806: return key;
0807: } catch (Exception e) {
0808: return null;
0809: }
0810: }
0811:
0812: /**
0813: * Gets the version number from the certificate.
0814: *
0815: * @return the version number, i.e. 1, 2 or 3.
0816: */
0817: public int getVersion() {
0818: if (info == null)
0819: return -1;
0820: try {
0821: int vers = ((Integer) info.get(CertificateVersion.NAME
0822: + DOT + CertificateVersion.VERSION)).intValue();
0823: return vers + 1;
0824: } catch (Exception e) {
0825: return -1;
0826: }
0827: }
0828:
0829: /**
0830: * Gets the serial number from the certificate.
0831: *
0832: * @return the serial number.
0833: */
0834: public BigInteger getSerialNumber() {
0835: if (info == null)
0836: return null;
0837: try {
0838: SerialNumber ser = (SerialNumber) info
0839: .get(CertificateSerialNumber.NAME + DOT
0840: + CertificateSerialNumber.NUMBER);
0841: return ser.getNumber();
0842: } catch (Exception e) {
0843: return null;
0844: }
0845: }
0846:
0847: /**
0848: * Gets the subject distinguished name from the certificate.
0849: *
0850: * @return the subject name.
0851: */
0852: public Principal getSubjectDN() {
0853: if (info == null)
0854: return null;
0855: try {
0856: Principal subject = (Principal) info
0857: .get(CertificateSubjectName.NAME + DOT
0858: + CertificateSubjectName.DN_NAME);
0859: return subject;
0860: } catch (Exception e) {
0861: return null;
0862: }
0863: }
0864:
0865: /**
0866: * Get subject name as X500Principal. Overrides implementation in
0867: * X509Certificate with a slightly more efficient version that is
0868: * also aware of X509CertImpl mutability.
0869: */
0870: public X500Principal getSubjectX500Principal() {
0871: if (info == null) {
0872: return null;
0873: }
0874: try {
0875: X500Principal subject = (X500Principal) info
0876: .get(CertificateSubjectName.NAME + DOT
0877: + CertificateSubjectName.DN_PRINCIPAL);
0878: return subject;
0879: } catch (Exception e) {
0880: return null;
0881: }
0882: }
0883:
0884: /**
0885: * Gets the issuer distinguished name from the certificate.
0886: *
0887: * @return the issuer name.
0888: */
0889: public Principal getIssuerDN() {
0890: if (info == null)
0891: return null;
0892: try {
0893: Principal issuer = (Principal) info
0894: .get(CertificateIssuerName.NAME + DOT
0895: + CertificateIssuerName.DN_NAME);
0896: return issuer;
0897: } catch (Exception e) {
0898: return null;
0899: }
0900: }
0901:
0902: /**
0903: * Get issuer name as X500Principal. Overrides implementation in
0904: * X509Certificate with a slightly more efficient version that is
0905: * also aware of X509CertImpl mutability.
0906: */
0907: public X500Principal getIssuerX500Principal() {
0908: if (info == null) {
0909: return null;
0910: }
0911: try {
0912: X500Principal issuer = (X500Principal) info
0913: .get(CertificateIssuerName.NAME + DOT
0914: + CertificateIssuerName.DN_PRINCIPAL);
0915: return issuer;
0916: } catch (Exception e) {
0917: return null;
0918: }
0919: }
0920:
0921: /**
0922: * Gets the notBefore date from the validity period of the certificate.
0923: *
0924: * @return the start date of the validity period.
0925: */
0926: public Date getNotBefore() {
0927: if (info == null)
0928: return null;
0929: try {
0930: Date d = (Date) info.get(CertificateValidity.NAME + DOT
0931: + CertificateValidity.NOT_BEFORE);
0932: return d;
0933: } catch (Exception e) {
0934: return null;
0935: }
0936: }
0937:
0938: /**
0939: * Gets the notAfter date from the validity period of the certificate.
0940: *
0941: * @return the end date of the validity period.
0942: */
0943: public Date getNotAfter() {
0944: if (info == null)
0945: return null;
0946: try {
0947: Date d = (Date) info.get(CertificateValidity.NAME + DOT
0948: + CertificateValidity.NOT_AFTER);
0949: return d;
0950: } catch (Exception e) {
0951: return null;
0952: }
0953: }
0954:
0955: /**
0956: * Gets the DER encoded certificate informations, the
0957: * <code>tbsCertificate</code> from this certificate.
0958: * This can be used to verify the signature independently.
0959: *
0960: * @return the DER encoded certificate information.
0961: * @exception CertificateEncodingException if an encoding error occurs.
0962: */
0963: public byte[] getTBSCertificate()
0964: throws CertificateEncodingException {
0965: if (info != null) {
0966: return info.getEncodedInfo();
0967: } else
0968: throw new CertificateEncodingException(
0969: "Uninitialized certificate");
0970: }
0971:
0972: /**
0973: * Gets the raw Signature bits from the certificate.
0974: *
0975: * @return the signature.
0976: */
0977: public byte[] getSignature() {
0978: if (signature == null)
0979: return null;
0980: byte[] dup = new byte[signature.length];
0981: System.arraycopy(signature, 0, dup, 0, dup.length);
0982: return dup;
0983: }
0984:
0985: /**
0986: * Gets the signature algorithm name for the certificate
0987: * signature algorithm.
0988: * For example, the string "SHA-1/DSA" or "DSS".
0989: *
0990: * @return the signature algorithm name.
0991: */
0992: public String getSigAlgName() {
0993: if (algId == null)
0994: return null;
0995: return (algId.getName());
0996: }
0997:
0998: /**
0999: * Gets the signature algorithm OID string from the certificate.
1000: * For example, the string "1.2.840.10040.4.3"
1001: *
1002: * @return the signature algorithm oid string.
1003: */
1004: public String getSigAlgOID() {
1005: if (algId == null)
1006: return null;
1007: ObjectIdentifier oid = algId.getOID();
1008: return (oid.toString());
1009: }
1010:
1011: /**
1012: * Gets the DER encoded signature algorithm parameters from this
1013: * certificate's signature algorithm.
1014: *
1015: * @return the DER encoded signature algorithm parameters, or
1016: * null if no parameters are present.
1017: */
1018: public byte[] getSigAlgParams() {
1019: if (algId == null)
1020: return null;
1021: try {
1022: return algId.getEncodedParams();
1023: } catch (IOException e) {
1024: return null;
1025: }
1026: }
1027:
1028: /**
1029: * Gets the Issuer Unique Identity from the certificate.
1030: *
1031: * @return the Issuer Unique Identity.
1032: */
1033: public boolean[] getIssuerUniqueID() {
1034: if (info == null)
1035: return null;
1036: try {
1037: UniqueIdentity id = (UniqueIdentity) info
1038: .get(CertificateIssuerUniqueIdentity.NAME + DOT
1039: + CertificateIssuerUniqueIdentity.ID);
1040: if (id == null)
1041: return null;
1042: else
1043: return (id.getId());
1044: } catch (Exception e) {
1045: return null;
1046: }
1047: }
1048:
1049: /**
1050: * Gets the Subject Unique Identity from the certificate.
1051: *
1052: * @return the Subject Unique Identity.
1053: */
1054: public boolean[] getSubjectUniqueID() {
1055: if (info == null)
1056: return null;
1057: try {
1058: UniqueIdentity id = (UniqueIdentity) info
1059: .get(CertificateSubjectUniqueIdentity.NAME + DOT
1060: + CertificateSubjectUniqueIdentity.ID);
1061: if (id == null)
1062: return null;
1063: else
1064: return (id.getId());
1065: } catch (Exception e) {
1066: return null;
1067: }
1068: }
1069:
1070: /**
1071: * Get AuthorityKeyIdentifier extension
1072: * @return AuthorityKeyIdentifier object or null (if no such object
1073: * in certificate)
1074: */
1075: public AuthorityKeyIdentifierExtension getAuthorityKeyIdentifierExtension() {
1076: return (AuthorityKeyIdentifierExtension) getExtension(PKIXExtensions.AuthorityKey_Id);
1077: }
1078:
1079: /**
1080: * Get BasicConstraints extension
1081: * @return BasicConstraints object or null (if no such object in
1082: * certificate)
1083: */
1084: public BasicConstraintsExtension getBasicConstraintsExtension() {
1085: return (BasicConstraintsExtension) getExtension(PKIXExtensions.BasicConstraints_Id);
1086: }
1087:
1088: /**
1089: * Get CertificatePoliciesExtension
1090: * @return CertificatePoliciesExtension or null (if no such object in
1091: * certificate)
1092: * CDC/FP Subsets away CertificatePoliciesExtension.
1093: public CertificatePoliciesExtension getCertificatePoliciesExtension() {
1094: return (CertificatePoliciesExtension)
1095: getExtension(PKIXExtensions.CertificatePolicies_Id);
1096: }
1097: */
1098:
1099: /**
1100: * Get ExtendedKeyUsage extension
1101: * @return ExtendedKeyUsage extension object or null (if no such object
1102: * in certificate)
1103: */
1104: public ExtendedKeyUsageExtension getExtendedKeyUsageExtension() {
1105: return (ExtendedKeyUsageExtension) getExtension(PKIXExtensions.ExtendedKeyUsage_Id);
1106: }
1107:
1108: /**
1109: * Get IssuerAlternativeName extension
1110: * @return IssuerAlternativeName object or null (if no such object in
1111: * certificate)
1112: */
1113: public IssuerAlternativeNameExtension getIssuerAlternativeNameExtension() {
1114: return (IssuerAlternativeNameExtension) getExtension(PKIXExtensions.IssuerAlternativeName_Id);
1115: }
1116:
1117: /**
1118: * Get NameConstraints extension
1119: * @return NameConstraints object or null (if no such object in certificate)
1120: */
1121: public NameConstraintsExtension getNameConstraintsExtension() {
1122: return (NameConstraintsExtension) getExtension(PKIXExtensions.NameConstraints_Id);
1123: }
1124:
1125: /**
1126: * Get PolicyConstraints extension
1127: * @return PolicyConstraints object or null (if no such object in
1128: * certificate)
1129: */
1130: public PolicyConstraintsExtension getPolicyConstraintsExtension() {
1131: return (PolicyConstraintsExtension) getExtension(PKIXExtensions.PolicyConstraints_Id);
1132: }
1133:
1134: /**
1135: * Get PolicyMappingsExtension extension
1136: * @return PolicyMappingsExtension object or null (if no such object
1137: * in certificate)
1138: */
1139: public PolicyMappingsExtension getPolicyMappingsExtension() {
1140: return (PolicyMappingsExtension) getExtension(PKIXExtensions.PolicyMappings_Id);
1141: }
1142:
1143: /**
1144: * Get PrivateKeyUsage extension
1145: * @return PrivateKeyUsage object or null (if no such object in certificate)
1146: */
1147: public PrivateKeyUsageExtension getPrivateKeyUsageExtension() {
1148: return (PrivateKeyUsageExtension) getExtension(PKIXExtensions.PrivateKeyUsage_Id);
1149: }
1150:
1151: /**
1152: * Get SubjectAlternativeName extension
1153: * @return SubjectAlternativeName object or null (if no such object in
1154: * certificate)
1155: */
1156: public SubjectAlternativeNameExtension getSubjectAlternativeNameExtension() {
1157: return (SubjectAlternativeNameExtension) getExtension(PKIXExtensions.SubjectAlternativeName_Id);
1158: }
1159:
1160: /**
1161: * Get SubjectKeyIdentifier extension
1162: * @return SubjectKeyIdentifier object or null (if no such object in
1163: * certificate)
1164: */
1165: public SubjectKeyIdentifierExtension getSubjectKeyIdentifierExtension() {
1166: return (SubjectKeyIdentifierExtension) getExtension(PKIXExtensions.SubjectKey_Id);
1167: }
1168:
1169: /**
1170: * Get CRLDistributionPoints extension
1171: * @return CRLDistributionPoints object or null (if no such object in
1172: * certificate)
1173: * CDC/FP moves CRLDistributionPointsExtension to the
1174: * security optional package.
1175: public CRLDistributionPointsExtension getCRLDistributionPointsExtension() {
1176: return (CRLDistributionPointsExtension)
1177: getExtension(PKIXExtensions.CRLDistributionPoints_Id);
1178: }
1179: */
1180:
1181: /**
1182: * Return true if a critical extension is found that is
1183: * not supported, otherwise return false.
1184: */
1185: public boolean hasUnsupportedCriticalExtension() {
1186: if (info == null)
1187: return false;
1188: try {
1189: CertificateExtensions exts = (CertificateExtensions) info
1190: .get(CertificateExtensions.NAME);
1191: if (exts == null)
1192: return false;
1193: return exts.hasUnsupportedCriticalExtension();
1194: } catch (Exception e) {
1195: return false;
1196: }
1197: }
1198:
1199: /**
1200: * Gets a Set of the extension(s) marked CRITICAL in the
1201: * certificate. In the returned set, each extension is
1202: * represented by its OID string.
1203: *
1204: * @return a set of the extension oid strings in the
1205: * certificate that are marked critical.
1206: */
1207: public Set getCriticalExtensionOIDs() {
1208: if (info == null)
1209: return null;
1210: try {
1211: CertificateExtensions exts = (CertificateExtensions) info
1212: .get(CertificateExtensions.NAME);
1213: if (exts == null)
1214: return null;
1215: HashSet extSet = new HashSet(11);
1216: Extension ex;
1217: for (Enumeration e = exts.getElements(); e
1218: .hasMoreElements();) {
1219: ex = (Extension) e.nextElement();
1220: if (ex.isCritical())
1221: extSet.add(((ObjectIdentifier) ex.getExtensionId())
1222: .toString());
1223: }
1224: return extSet;
1225: } catch (Exception e) {
1226: return null;
1227: }
1228: }
1229:
1230: /**
1231: * Gets a Set of the extension(s) marked NON-CRITICAL in the
1232: * certificate. In the returned set, each extension is
1233: * represented by its OID string.
1234: *
1235: * @return a set of the extension oid strings in the
1236: * certificate that are NOT marked critical.
1237: */
1238: public Set getNonCriticalExtensionOIDs() {
1239: if (info == null)
1240: return null;
1241: try {
1242: CertificateExtensions exts = (CertificateExtensions) info
1243: .get(CertificateExtensions.NAME);
1244: if (exts == null)
1245: return null;
1246:
1247: HashSet extSet = new HashSet(11);
1248: Extension ex;
1249: for (Enumeration e = exts.getElements(); e
1250: .hasMoreElements();) {
1251: ex = (Extension) e.nextElement();
1252: if (!ex.isCritical())
1253: extSet.add(((ObjectIdentifier) ex.getExtensionId())
1254: .toString());
1255: }
1256: return extSet;
1257: } catch (Exception e) {
1258: return null;
1259: }
1260: }
1261:
1262: /**
1263: * Gets the extension identified by the given ObjectIdentifier
1264: *
1265: * @param oid the Object Identifier value for the extension.
1266: * @return Extension or null if certificate does not contain this
1267: * extension
1268: */
1269: public Extension getExtension(ObjectIdentifier oid) {
1270: if (info == null) {
1271: return null;
1272: }
1273: try {
1274: CertificateExtensions extensions = null;
1275: try {
1276: extensions = (CertificateExtensions) info
1277: .get(CertificateExtensions.NAME);
1278: } catch (CertificateException ce) {
1279: return null;
1280: }
1281: if (extensions == null) {
1282: return null;
1283: } else {
1284: Extension ex = null;
1285: for (Enumeration e = extensions.getElements(); e
1286: .hasMoreElements();) {
1287: ex = (Extension) e.nextElement();
1288: if (ex.getExtensionId().equals(oid))
1289: //NOTE: May want to consider cloning this
1290: return ex;
1291: }
1292: /* no such extension in this certificate */
1293: return null;
1294: }
1295: } catch (IOException ioe) {
1296: return null;
1297: }
1298: }
1299:
1300: /**
1301: * Gets the DER encoded extension identified by the given
1302: * oid String.
1303: *
1304: * @param oid the Object Identifier value for the extension.
1305: */
1306: public byte[] getExtensionValue(String oid) {
1307: try {
1308: ObjectIdentifier findOID = new ObjectIdentifier(oid);
1309: String extAlias = OIDMap.getName(findOID);
1310: Extension certExt = null;
1311:
1312: if (extAlias == null) { // may be unknown
1313: // get the extensions, search thru' for this oid
1314: CertificateExtensions exts = (CertificateExtensions) info
1315: .get(CertificateExtensions.NAME);
1316: if (exts == null)
1317: return null;
1318:
1319: Extension ex = null;
1320: ;
1321: ObjectIdentifier inCertOID;
1322: for (Enumeration e = exts.getElements(); e
1323: .hasMoreElements();) {
1324: ex = (Extension) e.nextElement();
1325: inCertOID = ex.getExtensionId();
1326: if (inCertOID.equals(findOID)) {
1327: certExt = ex;
1328: break;
1329: }
1330: }
1331: } else { // there's sub-class that can handle this extension
1332: certExt = (Extension) this .get(extAlias);
1333: }
1334: if (certExt == null)
1335: return null;
1336: byte[] extData = certExt.getExtensionValue();
1337: if (extData == null)
1338: return null;
1339:
1340: DerOutputStream out = new DerOutputStream();
1341: out.putOctetString(extData);
1342: return out.toByteArray();
1343: } catch (Exception e) {
1344: return null;
1345: }
1346: }
1347:
1348: /**
1349: * Get a boolean array representing the bits of the KeyUsage extension,
1350: * (oid = 2.5.29.15).
1351: * @return the bit values of this extension as an array of booleans.
1352: */
1353: public boolean[] getKeyUsage() {
1354: try {
1355: String extAlias = OIDMap
1356: .getName(PKIXExtensions.KeyUsage_Id);
1357: if (extAlias == null)
1358: return null;
1359:
1360: KeyUsageExtension certExt = (KeyUsageExtension) this
1361: .get(extAlias);
1362: if (certExt == null)
1363: return null;
1364:
1365: boolean[] ret = certExt.getBits();
1366: if (ret.length < NUM_STANDARD_KEY_USAGE) {
1367: boolean[] usageBits = new boolean[NUM_STANDARD_KEY_USAGE];
1368: System.arraycopy(ret, 0, usageBits, 0, ret.length);
1369: ret = usageBits;
1370: }
1371: return ret;
1372: } catch (Exception e) {
1373: return null;
1374: }
1375: }
1376:
1377: /**
1378: * This method are the overridden implementation of
1379: * getExtendedKeyUsage method in X509Certificate in the Sun
1380: * provider. It is better performance-wise since it returns cached
1381: * values.
1382: */
1383: public synchronized List getExtendedKeyUsage()
1384: throws CertificateParsingException {
1385: if (readOnly && extKeyUsage != null) {
1386: return extKeyUsage;
1387: } else {
1388: ExtendedKeyUsageExtension ext = getExtendedKeyUsageExtension();
1389: if (ext == null) {
1390: return null;
1391: }
1392: extKeyUsage = Collections.unmodifiableList(ext
1393: .getExtendedKeyUsage());
1394: return extKeyUsage;
1395: }
1396: }
1397:
1398: /**
1399: * This static method is the default implementation of the
1400: * getExtendedKeyUsage method in X509Certificate. A
1401: * X509Certificate provider generally should overwrite this to
1402: * provide among other things caching for better performance.
1403: */
1404: public static List getExtendedKeyUsage(X509Certificate cert)
1405: throws CertificateParsingException {
1406: try {
1407: byte[] ext = cert.getExtensionValue(EXTENDED_KEY_USAGE_OID);
1408: if (ext == null)
1409: return null;
1410: DerValue val = new DerValue(ext);
1411: byte[] data = val.getOctetString();
1412:
1413: ExtendedKeyUsageExtension ekuExt = new ExtendedKeyUsageExtension(
1414: Boolean.FALSE, data);
1415: return Collections.unmodifiableList(ekuExt
1416: .getExtendedKeyUsage());
1417: } catch (IOException ioe) {
1418: CertificateParsingException cpe = new CertificateParsingException();
1419: cpe.initCause(ioe);
1420: throw cpe;
1421: }
1422: }
1423:
1424: /**
1425: * Get the certificate constraints path length from the
1426: * the critical BasicConstraints extension, (oid = 2.5.29.19).
1427: * @return the length of the constraint.
1428: */
1429: public int getBasicConstraints() {
1430: try {
1431: String extAlias = OIDMap
1432: .getName(PKIXExtensions.BasicConstraints_Id);
1433: if (extAlias == null)
1434: return -1;
1435: BasicConstraintsExtension certExt = (BasicConstraintsExtension) this
1436: .get(extAlias);
1437: if (certExt == null)
1438: return -1;
1439:
1440: if (((Boolean) certExt.get(BasicConstraintsExtension.IS_CA))
1441: .booleanValue() == true)
1442: return ((Integer) certExt
1443: .get(BasicConstraintsExtension.PATH_LEN))
1444: .intValue();
1445: else
1446: return -1;
1447: } catch (Exception e) {
1448: return -1;
1449: }
1450: }
1451:
1452: /**
1453: * Converts a GeneralNames structure into an immutable Collection of
1454: * alternative names (subject or issuer) in the form required by
1455: * {@link #getSubjectAlternativeNames} or
1456: * {@link #getIssuerAlternativeNames}.
1457: *
1458: * @param names the GeneralNames to be converted
1459: * @return an immutable Collection of alternative names
1460: */
1461: private static Collection makeAltNames(GeneralNames names) {
1462: if (names.isEmpty())
1463: return Collections.EMPTY_SET;
1464:
1465: HashSet newNames = new HashSet(names.size());
1466: Iterator i = names.iterator();
1467: while (i.hasNext()) {
1468: GeneralName gname = (GeneralName) i.next();
1469: GeneralNameInterface name = gname.getName();
1470: ArrayList nameEntry = new ArrayList(2);
1471: nameEntry.add(new Integer(name.getType()));
1472: switch (name.getType()) {
1473: case GeneralNameInterface.NAME_RFC822:
1474: nameEntry.add(((RFC822Name) name).getName());
1475: break;
1476: case GeneralNameInterface.NAME_DNS:
1477: nameEntry.add(((DNSName) name).getName());
1478: break;
1479: case GeneralNameInterface.NAME_DIRECTORY:
1480: nameEntry.add(((X500Name) name).getRFC2253Name());
1481: break;
1482: case GeneralNameInterface.NAME_URI:
1483: nameEntry.add(((URIName) name).getName());
1484: break;
1485: case GeneralNameInterface.NAME_IP:
1486: try {
1487: nameEntry.add(((IPAddressName) name).getName());
1488: } catch (IOException ioe) {
1489: // IPAddressName in cert is bogus
1490: throw new RuntimeException(
1491: "IPAddress cannot be parsed", ioe);
1492: }
1493: break;
1494: case GeneralNameInterface.NAME_OID:
1495: nameEntry.add(((OIDName) name).getOID().toString());
1496: break;
1497: default:
1498: // add DER encoded form
1499: DerOutputStream derOut = new DerOutputStream();
1500: try {
1501: name.encode(derOut);
1502: } catch (IOException ioe) {
1503: // should not occur since name has already been decoded
1504: // from cert (this would indicate a bug in our code)
1505: throw new RuntimeException(
1506: "name cannot be encoded", ioe);
1507: }
1508: nameEntry.add(derOut.toByteArray());
1509: break;
1510: }
1511: newNames.add(Collections.unmodifiableList(nameEntry));
1512: }
1513: return Collections.unmodifiableCollection(newNames);
1514: }
1515:
1516: /**
1517: * Checks a Collection of altNames and clones any name entries of type
1518: * byte [].
1519: */
1520: private static Collection cloneAltNames(Collection altNames) {
1521: boolean mustClone = false;
1522: Iterator i = altNames.iterator();
1523: while (i.hasNext() && !mustClone) {
1524: List nameEntry = (List) i.next();
1525: if (nameEntry.get(1) instanceof byte[]) {
1526: // must clone names
1527: mustClone = true;
1528: }
1529: }
1530: if (mustClone) {
1531: HashSet namesCopy = new HashSet(altNames.size());
1532: i = altNames.iterator();
1533: while (i.hasNext()) {
1534: List nameEntry = (List) i.next();
1535: Object nameObject = nameEntry.get(1);
1536: if (nameObject instanceof byte[]) {
1537: ArrayList nameEntryCopy = new ArrayList(
1538: (List) nameEntry);
1539: nameEntryCopy.set(1, ((byte[]) nameObject).clone());
1540: namesCopy.add(Collections
1541: .unmodifiableList(nameEntryCopy));
1542: } else
1543: namesCopy.add(nameEntry);
1544: }
1545: return Collections.unmodifiableCollection(namesCopy);
1546: } else
1547: return altNames;
1548: }
1549:
1550: /**
1551: * This method are the overridden implementation of
1552: * getSubjectAlternativeNames method in X509Certificate in the Sun
1553: * provider. It is better performance-wise since it returns cached
1554: * values.
1555: */
1556: public synchronized Collection getSubjectAlternativeNames()
1557: throws CertificateParsingException {
1558: // return cached value if we can
1559: if (readOnly && subjectAlternativeNames != null)
1560: return cloneAltNames(subjectAlternativeNames);
1561:
1562: SubjectAlternativeNameExtension subjectAltNameExt = getSubjectAlternativeNameExtension();
1563: if (subjectAltNameExt == null)
1564: return null;
1565:
1566: GeneralNames names;
1567: try {
1568: names = (GeneralNames) subjectAltNameExt
1569: .get(SubjectAlternativeNameExtension.SUBJECT_NAME);
1570: } catch (IOException ioe) {
1571: // should not occur
1572: return Collections.EMPTY_SET;
1573: }
1574: subjectAlternativeNames = makeAltNames(names);
1575: return subjectAlternativeNames;
1576: }
1577:
1578: /**
1579: * This static method is the default implementation of the
1580: * getSubjectAlternaitveNames method in X509Certificate. A
1581: * X509Certificate provider generally should overwrite this to
1582: * provide among other things caching for better performance.
1583: */
1584: public static Collection getSubjectAlternativeNames(
1585: X509Certificate cert) throws CertificateParsingException {
1586: try {
1587: byte[] ext = cert.getExtensionValue(SUBJECT_ALT_NAME_OID);
1588: if (ext == null) {
1589: return null;
1590: }
1591: DerValue val = new DerValue(ext);
1592: byte[] data = val.getOctetString();
1593:
1594: SubjectAlternativeNameExtension subjectAltNameExt = new SubjectAlternativeNameExtension(
1595: Boolean.FALSE, data);
1596:
1597: GeneralNames names;
1598: try {
1599: names = (GeneralNames) subjectAltNameExt
1600: .get(SubjectAlternativeNameExtension.SUBJECT_NAME);
1601: } catch (IOException ioe) {
1602: // should not occur
1603: return Collections.EMPTY_SET;
1604: }
1605: return makeAltNames(names);
1606: } catch (IOException ioe) {
1607: CertificateParsingException cpe = new CertificateParsingException();
1608: cpe.initCause(ioe);
1609: throw cpe;
1610: }
1611: }
1612:
1613: /**
1614: * This method are the overridden implementation of
1615: * getIssuerAlternativeNames method in X509Certificate in the Sun
1616: * provider. It is better performance-wise since it returns cached
1617: * values.
1618: */
1619: public synchronized Collection getIssuerAlternativeNames()
1620: throws CertificateParsingException {
1621: // return cached value if we can
1622: if (readOnly && issuerAlternativeNames != null)
1623: return cloneAltNames(issuerAlternativeNames);
1624:
1625: IssuerAlternativeNameExtension issuerAltNameExt = getIssuerAlternativeNameExtension();
1626: if (issuerAltNameExt == null)
1627: return null;
1628:
1629: GeneralNames names;
1630: try {
1631: names = (GeneralNames) issuerAltNameExt
1632: .get(IssuerAlternativeNameExtension.ISSUER_NAME);
1633: } catch (IOException ioe) {
1634: // should not occur
1635: return Collections.EMPTY_SET;
1636: }
1637: issuerAlternativeNames = makeAltNames(names);
1638: return issuerAlternativeNames;
1639: }
1640:
1641: /**
1642: * This static method is the default implementation of the
1643: * getIssuerAlternaitveNames method in X509Certificate. A
1644: * X509Certificate provider generally should overwrite this to
1645: * provide among other things caching for better performance.
1646: */
1647: public static Collection getIssuerAlternativeNames(
1648: X509Certificate cert) throws CertificateParsingException {
1649: try {
1650: byte[] ext = cert.getExtensionValue(ISSUER_ALT_NAME_OID);
1651: if (ext == null) {
1652: return null;
1653: }
1654:
1655: DerValue val = new DerValue(ext);
1656: byte[] data = val.getOctetString();
1657:
1658: IssuerAlternativeNameExtension issuerAltNameExt = new IssuerAlternativeNameExtension(
1659: Boolean.FALSE, data);
1660: GeneralNames names;
1661: try {
1662: names = (GeneralNames) issuerAltNameExt
1663: .get(IssuerAlternativeNameExtension.ISSUER_NAME);
1664: } catch (IOException ioe) {
1665: // should not occur
1666: return Collections.EMPTY_SET;
1667: }
1668: return makeAltNames(names);
1669: } catch (IOException ioe) {
1670: CertificateParsingException cpe = new CertificateParsingException();
1671: cpe.initCause(ioe);
1672: throw cpe;
1673: }
1674: }
1675:
1676: /************************************************************/
1677:
1678: /*
1679: * Cert is a SIGNED ASN.1 macro, a three elment sequence:
1680: *
1681: * - Data to be signed (ToBeSigned) -- the "raw" cert
1682: * - Signature algorithm (SigAlgId)
1683: * - The signature bits
1684: *
1685: * This routine unmarshals the certificate, saving the signature
1686: * parts away for later verification.
1687: */
1688: private void parse(DerValue val) throws CertificateException,
1689: IOException {
1690: // check if can over write the certificate
1691: if (readOnly)
1692: throw new CertificateParsingException(
1693: "cannot over-write existing certificate");
1694:
1695: if (val.data == null)
1696: throw new CertificateParsingException(
1697: "invalid DER-encoded certificate data");
1698:
1699: signedCert = val.toByteArray();
1700: DerValue[] seq = new DerValue[3];
1701:
1702: seq[0] = val.data.getDerValue();
1703: seq[1] = val.data.getDerValue();
1704: seq[2] = val.data.getDerValue();
1705:
1706: if (val.data.available() != 0) {
1707: throw new CertificateParsingException(
1708: "signed overrun, bytes = " + val.data.available());
1709: }
1710: if (seq[0].tag != DerValue.tag_Sequence) {
1711: throw new CertificateParsingException(
1712: "signed fields invalid");
1713: }
1714:
1715: algId = AlgorithmId.parse(seq[1]);
1716: signature = seq[2].getBitString();
1717:
1718: if (seq[1].data.available() != 0) {
1719: throw new CertificateParsingException("algid field overrun");
1720: }
1721: if (seq[2].data.available() != 0)
1722: throw new CertificateParsingException(
1723: "signed fields overrun");
1724:
1725: // The CertificateInfo
1726: info = new X509CertInfo(seq[0]);
1727:
1728: // the "inner" and "outer" signature algorithms must match
1729: AlgorithmId infoSigAlg = (AlgorithmId) info
1730: .get(CertificateAlgorithmId.NAME + DOT
1731: + CertificateAlgorithmId.ALGORITHM);
1732: if (!algId.equals(infoSigAlg))
1733: throw new CertificateException(
1734: "Signature algorithm mismatch");
1735: readOnly = true;
1736: }
1737:
1738: /**
1739: * Extract the subject or issuer X500Principal from an X509Certificate.
1740: * Parses the encoded form of the cert to preserve the principal's
1741: * ASN.1 encoding.
1742: */
1743: private static X500Principal getX500Principal(X509Certificate cert,
1744: boolean getIssuer) throws Exception {
1745: byte[] encoded = cert.getEncoded();
1746: DerInputStream derIn = new DerInputStream(encoded);
1747: DerValue tbsCert = derIn.getSequence(3)[0];
1748: DerInputStream tbsIn = tbsCert.data;
1749: DerValue tmp;
1750: tmp = tbsIn.getDerValue();
1751: // skip version number if present
1752: if (tmp.isContextSpecific((byte) 0)) {
1753: tmp = tbsIn.getDerValue();
1754: }
1755: // tmp always contains serial number now
1756: tmp = tbsIn.getDerValue(); // skip signature
1757: tmp = tbsIn.getDerValue(); // issuer
1758: if (getIssuer == false) {
1759: tmp = tbsIn.getDerValue(); // skip validity
1760: tmp = tbsIn.getDerValue(); // subject
1761: }
1762: byte[] principalBytes = tmp.toByteArray();
1763: return new X500Principal(principalBytes);
1764: }
1765:
1766: /**
1767: * Extract the subject X500Principal from an X509Certificate.
1768: * Called from java.security.cert.X509Certificate.getSubjectX500Principal().
1769: */
1770: public static X500Principal getSubjectX500Principal(
1771: X509Certificate cert) {
1772: try {
1773: return getX500Principal(cert, false);
1774: } catch (Exception e) {
1775: throw new RuntimeException("Could not parse subject", e);
1776: }
1777: }
1778:
1779: /**
1780: * Extract the issuer X500Principal from an X509Certificate.
1781: * Called from java.security.cert.X509Certificate.getIssuerX500Principal().
1782: */
1783: public static X500Principal getIssuerX500Principal(
1784: X509Certificate cert) {
1785: try {
1786: return getX500Principal(cert, true);
1787: } catch (Exception e) {
1788: throw new RuntimeException("Could not parse issuer", e);
1789: }
1790: }
1791:
1792: /**
1793: * Returned the encoding of the given certificate for internal use.
1794: * Callers must guarantee that they neither modify it nor expose it
1795: * to untrusted code. Uses getEncodedInternal() if the certificate
1796: * is instance of X509CertImpl, getEncoded() otherwise.
1797: */
1798: public static byte[] getEncodedInternal(Certificate cert)
1799: throws CertificateEncodingException {
1800: if (cert instanceof X509CertImpl) {
1801: return ((X509CertImpl) cert).getEncodedInternal();
1802: } else {
1803: return cert.getEncoded();
1804: }
1805: }
1806:
1807: /**
1808: * Utility method to convert an arbitrary instance of X509Certificate
1809: * to a X509CertImpl. Does a cast if possible, otherwise reparses
1810: * the encoding.
1811: */
1812: public static X509CertImpl toImpl(X509Certificate cert)
1813: throws CertificateException {
1814: if (cert instanceof X509CertImpl) {
1815: return (X509CertImpl) cert;
1816: } else {
1817: return X509Factory.intern(cert);
1818: }
1819: }
1820:
1821: /**
1822: * Utility method to test if a certificate is self-issued. This is
1823: * the case iff the subject and issuer X500Principals are equal.
1824: * New API subsetted out in CDC/FP and cannot be invoked here. It
1825: * appears to be invoked only certpath code & exists in the
1826: * security optional package version of this class.
1827: public static boolean isSelfIssued(X509Certificate cert) {
1828: X500Principal subject = cert.getSubjectX500Principal();
1829: X500Principal issuer = cert.getIssuerX500Principal();
1830: return subject.equals(issuer);
1831: }
1832: */
1833:
1834: }
|