001: package org.bouncycastle.tsp;
002:
003: import org.bouncycastle.asn1.ASN1InputStream;
004: import org.bouncycastle.asn1.ASN1OctetString;
005: import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
006: import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
007: import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
008: import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
009: import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
010: import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
011: import org.bouncycastle.asn1.x509.KeyPurposeId;
012: import org.bouncycastle.asn1.x509.X509Extensions;
013:
014: import java.io.ByteArrayInputStream;
015: import java.io.IOException;
016: import java.security.MessageDigest;
017: import java.security.NoSuchAlgorithmException;
018: import java.security.NoSuchProviderException;
019: import java.security.cert.X509Certificate;
020: import java.util.HashMap;
021: import java.util.Map;
022:
023: public class TSPUtil {
024: private static final Map digestLengths = new HashMap();
025: private static final Map digestNames = new HashMap();
026:
027: static {
028: digestLengths.put(PKCSObjectIdentifiers.md5.getId(),
029: new Integer(16));
030: digestLengths.put(OIWObjectIdentifiers.idSHA1.getId(),
031: new Integer(20));
032: digestLengths.put(NISTObjectIdentifiers.id_sha224.getId(),
033: new Integer(28));
034: digestLengths.put(NISTObjectIdentifiers.id_sha256.getId(),
035: new Integer(32));
036: digestLengths.put(NISTObjectIdentifiers.id_sha384.getId(),
037: new Integer(48));
038: digestLengths.put(NISTObjectIdentifiers.id_sha512.getId(),
039: new Integer(64));
040:
041: digestNames.put(PKCSObjectIdentifiers.md5.getId(), "MD5");
042: digestNames.put(OIWObjectIdentifiers.idSHA1.getId(), "SHA1");
043: digestNames.put(NISTObjectIdentifiers.id_sha224.getId(),
044: "SHA224");
045: digestNames.put(NISTObjectIdentifiers.id_sha256.getId(),
046: "SHA256");
047: digestNames.put(NISTObjectIdentifiers.id_sha384.getId(),
048: "SHA384");
049: digestNames.put(NISTObjectIdentifiers.id_sha512.getId(),
050: "SHA512");
051: digestNames.put(PKCSObjectIdentifiers.sha1WithRSAEncryption
052: .getId(), "SHA1");
053: digestNames.put(PKCSObjectIdentifiers.sha224WithRSAEncryption
054: .getId(), "SHA224");
055: digestNames.put(PKCSObjectIdentifiers.sha256WithRSAEncryption
056: .getId(), "SHA256");
057: digestNames.put(PKCSObjectIdentifiers.sha384WithRSAEncryption
058: .getId(), "SHA384");
059: digestNames.put(PKCSObjectIdentifiers.sha512WithRSAEncryption
060: .getId(), "SHA512");
061: digestNames.put(TeleTrusTObjectIdentifiers.ripemd128.getId(),
062: "RIPEMD128");
063: digestNames.put(TeleTrusTObjectIdentifiers.ripemd160.getId(),
064: "RIPEMD160");
065: digestNames.put(TeleTrusTObjectIdentifiers.ripemd256.getId(),
066: "RIPEMD256");
067: digestNames.put(CryptoProObjectIdentifiers.gostR3411.getId(),
068: "GOST3411");
069: }
070:
071: /**
072: * Validate the passed in certificate as being of the correct type to be used
073: * for time stamping. To be valid it must have an ExtendedKeyUsage extension
074: * which has a key purpose identifier of id-kp-timeStamping.
075: *
076: * @param cert the certificate of interest.
077: * @throws TSPValidationException if the certicate fails on one of the check points.
078: */
079: public static void validateCertificate(X509Certificate cert)
080: throws TSPValidationException {
081: if (cert.getVersion() != 3) {
082: throw new IllegalArgumentException(
083: "Certificate must have an ExtendedKeyUsage extension.");
084: }
085:
086: byte[] ext = cert
087: .getExtensionValue(X509Extensions.ExtendedKeyUsage
088: .getId());
089: if (ext == null) {
090: throw new TSPValidationException(
091: "Certificate must have an ExtendedKeyUsage extension.");
092: }
093:
094: if (!cert.getCriticalExtensionOIDs().contains(
095: X509Extensions.ExtendedKeyUsage.getId())) {
096: throw new TSPValidationException(
097: "Certificate must have an ExtendedKeyUsage extension marked as critical.");
098: }
099:
100: ASN1InputStream aIn = new ASN1InputStream(
101: new ByteArrayInputStream(ext));
102:
103: try {
104: aIn = new ASN1InputStream(new ByteArrayInputStream(
105: ((ASN1OctetString) aIn.readObject()).getOctets()));
106:
107: ExtendedKeyUsage extKey = ExtendedKeyUsage.getInstance(aIn
108: .readObject());
109:
110: if (!extKey
111: .hasKeyPurposeId(KeyPurposeId.id_kp_timeStamping)
112: || extKey.size() != 1) {
113: throw new TSPValidationException(
114: "ExtendedKeyUsage not solely time stamping.");
115: }
116: } catch (IOException e) {
117: throw new TSPValidationException(
118: "cannot process ExtendedKeyUsage extension");
119: }
120: }
121:
122: /*
123: * Return the digest algorithm using one of the standard JCA string
124: * representations rather than the algorithm identifier (if possible).
125: */
126: static String getDigestAlgName(String digestAlgOID) {
127: String digestName = (String) digestNames.get(digestAlgOID);
128:
129: if (digestName != null) {
130: return digestName;
131: }
132:
133: return digestAlgOID;
134: }
135:
136: static int getDigestLength(String digestAlgOID, String provider)
137: throws NoSuchProviderException, TSPException {
138: String digestName = TSPUtil.getDigestAlgName(digestAlgOID);
139:
140: try {
141: Integer length = (Integer) digestLengths.get(digestAlgOID);
142:
143: if (length != null) {
144: return length.intValue();
145: }
146:
147: return MessageDigest.getInstance(digestName, provider)
148: .getDigestLength();
149: } catch (NoSuchAlgorithmException e) {
150: try {
151: return MessageDigest.getInstance(digestName)
152: .getDigestLength();
153: } catch (NoSuchAlgorithmException ex) {
154: throw new TSPException(
155: "digest algorithm cannot be found.", ex);
156: }
157: }
158: }
159: }
|