0001: package org.bouncycastle.jce.provider;
0002:
0003: import org.bouncycastle.asn1.ASN1EncodableVector;
0004: import org.bouncycastle.asn1.ASN1InputStream;
0005: import org.bouncycastle.asn1.ASN1Object;
0006: import org.bouncycastle.asn1.ASN1OctetString;
0007: import org.bouncycastle.asn1.ASN1Sequence;
0008: import org.bouncycastle.asn1.ASN1Set;
0009: import org.bouncycastle.asn1.BERConstructedOctetString;
0010: import org.bouncycastle.asn1.BEROutputStream;
0011: import org.bouncycastle.asn1.DERBMPString;
0012: import org.bouncycastle.asn1.DERNull;
0013: import org.bouncycastle.asn1.DERObject;
0014: import org.bouncycastle.asn1.DERObjectIdentifier;
0015: import org.bouncycastle.asn1.DEROctetString;
0016: import org.bouncycastle.asn1.DERSequence;
0017: import org.bouncycastle.asn1.DERSet;
0018: import org.bouncycastle.asn1.pkcs.AuthenticatedSafe;
0019: import org.bouncycastle.asn1.pkcs.CertBag;
0020: import org.bouncycastle.asn1.pkcs.ContentInfo;
0021: import org.bouncycastle.asn1.pkcs.EncryptedData;
0022: import org.bouncycastle.asn1.pkcs.MacData;
0023: import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
0024: import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
0025: import org.bouncycastle.asn1.pkcs.Pfx;
0026: import org.bouncycastle.asn1.pkcs.SafeBag;
0027: import org.bouncycastle.asn1.util.ASN1Dump;
0028: import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
0029: import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
0030: import org.bouncycastle.asn1.x509.DigestInfo;
0031: import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
0032: import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
0033: import org.bouncycastle.asn1.x509.X509Extensions;
0034: import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
0035: import org.bouncycastle.jce.interfaces.BCKeyStore;
0036: import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
0037: import org.bouncycastle.util.Arrays;
0038: import org.bouncycastle.util.Strings;
0039: import org.bouncycastle.util.encoders.Hex;
0040:
0041: import java.io.BufferedInputStream;
0042: import java.io.ByteArrayInputStream;
0043: import java.io.ByteArrayOutputStream;
0044: import java.io.IOException;
0045: import java.io.InputStream;
0046: import java.io.OutputStream;
0047: import java.security.Key;
0048: import java.security.KeyStoreException;
0049: import java.security.KeyStoreSpi;
0050: import java.security.NoSuchAlgorithmException;
0051: import java.security.Principal;
0052: import java.security.PrivateKey;
0053: import java.security.PublicKey;
0054: import java.security.SecureRandom;
0055: import java.security.UnrecoverableKeyException;
0056: import java.security.cert.Certificate;
0057: import java.security.cert.CertificateEncodingException;
0058: import java.security.cert.CertificateFactory;
0059: import java.security.cert.X509Certificate;
0060: import java.util.Date;
0061: import java.util.Enumeration;
0062: import java.util.Hashtable;
0063: import java.util.Vector;
0064:
0065: import javax.crypto.Cipher;
0066: import javax.crypto.Mac;
0067: import javax.crypto.SecretKey;
0068: import javax.crypto.SecretKeyFactory;
0069: import javax.crypto.spec.PBEKeySpec;
0070: import javax.crypto.spec.PBEParameterSpec;
0071:
0072: public class JDKPKCS12KeyStore extends KeyStoreSpi implements
0073: PKCSObjectIdentifiers, X509ObjectIdentifiers, BCKeyStore {
0074: private static final int SALT_SIZE = 20;
0075: private static final int MIN_ITERATIONS = 1024;
0076:
0077: //
0078: // SHA-1 and 3-key-triple DES.
0079: //
0080: private static final DERObjectIdentifier KEY_ALGORITHM = pbeWithSHAAnd3_KeyTripleDES_CBC;
0081:
0082: //
0083: // SHA-1 and 40 bit RC2.
0084: //
0085: private static final DERObjectIdentifier CERT_ALGORITHM = pbewithSHAAnd40BitRC2_CBC;
0086:
0087: private IgnoresCaseHashtable keys = new IgnoresCaseHashtable();
0088: private Hashtable localIds = new Hashtable();
0089: private IgnoresCaseHashtable certs = new IgnoresCaseHashtable();
0090: private Hashtable chainCerts = new Hashtable();
0091: private Hashtable keyCerts = new Hashtable();
0092:
0093: //
0094: // generic object types
0095: //
0096: static final int NULL = 0;
0097: static final int CERTIFICATE = 1;
0098: static final int KEY = 2;
0099: static final int SECRET = 3;
0100: static final int SEALED = 4;
0101:
0102: //
0103: // key types
0104: //
0105: static final int KEY_PRIVATE = 0;
0106: static final int KEY_PUBLIC = 1;
0107: static final int KEY_SECRET = 2;
0108:
0109: protected SecureRandom random = new SecureRandom();
0110:
0111: private CertificateFactory certFact = null;
0112:
0113: private class CertId {
0114: byte[] id;
0115:
0116: CertId(PublicKey key) {
0117: this .id = createSubjectKeyId(key).getKeyIdentifier();
0118: }
0119:
0120: CertId(byte[] id) {
0121: this .id = id;
0122: }
0123:
0124: public int hashCode() {
0125: int hash = id[0] & 0xff;
0126:
0127: for (int i = 1; i != id.length - 4; i++) {
0128: hash ^= ((id[i] & 0xff) << 24)
0129: | ((id[i + 1] & 0xff) << 16)
0130: | ((id[i + 2] & 0xff) << 8)
0131: | (id[i + 3] & 0xff);
0132: }
0133:
0134: return hash;
0135: }
0136:
0137: public boolean equals(Object o) {
0138: if (!(o instanceof CertId)) {
0139: return false;
0140: }
0141:
0142: CertId cId = (CertId) o;
0143:
0144: if (cId.id.length != id.length) {
0145: return false;
0146: }
0147:
0148: for (int i = 0; i != id.length; i++) {
0149: if (cId.id[i] != id[i]) {
0150: return false;
0151: }
0152: }
0153:
0154: return true;
0155: }
0156: }
0157:
0158: public JDKPKCS12KeyStore(String provider) {
0159: try {
0160: if (provider != null) {
0161: certFact = CertificateFactory.getInstance("X.509",
0162: provider);
0163: } else {
0164: certFact = CertificateFactory.getInstance("X.509");
0165: }
0166: } catch (Exception e) {
0167: throw new IllegalArgumentException(
0168: "can't create cert factory - " + e.toString());
0169: }
0170: }
0171:
0172: private SubjectKeyIdentifier createSubjectKeyId(PublicKey pubKey) {
0173: try {
0174: SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
0175: (ASN1Sequence) new ASN1InputStream(pubKey
0176: .getEncoded()).readObject());
0177:
0178: return new SubjectKeyIdentifier(info);
0179: } catch (Exception e) {
0180: throw new RuntimeException("error creating key");
0181: }
0182: }
0183:
0184: public void setRandom(SecureRandom rand) {
0185: this .random = rand;
0186: }
0187:
0188: public Enumeration engineAliases() {
0189: Hashtable tab = new Hashtable();
0190:
0191: Enumeration e = certs.keys();
0192: while (e.hasMoreElements()) {
0193: tab.put(e.nextElement(), "cert");
0194: }
0195:
0196: e = keys.keys();
0197: while (e.hasMoreElements()) {
0198: String a = (String) e.nextElement();
0199: if (tab.get(a) == null) {
0200: tab.put(a, "key");
0201: }
0202: }
0203:
0204: return tab.keys();
0205: }
0206:
0207: public boolean engineContainsAlias(String alias) {
0208: return (certs.get(alias) != null || keys.get(alias) != null);
0209: }
0210:
0211: /**
0212: * this is quite complete - we should follow up on the chain, a bit
0213: * tricky if a certificate appears in more than one chain...
0214: */
0215: public void engineDeleteEntry(String alias)
0216: throws KeyStoreException {
0217: Key k = (Key) keys.remove(alias);
0218:
0219: Certificate c = (Certificate) certs.remove(alias);
0220:
0221: if (c != null) {
0222: chainCerts.remove(new CertId(c.getPublicKey()));
0223: }
0224:
0225: if (k != null) {
0226: String id = (String) localIds.remove(alias);
0227: if (id != null) {
0228: c = (Certificate) keyCerts.remove(id);
0229: }
0230: if (c != null) {
0231: chainCerts.remove(new CertId(c.getPublicKey()));
0232: }
0233: }
0234:
0235: if (c == null && k == null) {
0236: throw new KeyStoreException("no such entry as " + alias);
0237: }
0238: }
0239:
0240: /**
0241: * simply return the cert for the private key
0242: */
0243: public Certificate engineGetCertificate(String alias) {
0244: if (alias == null) {
0245: throw new IllegalArgumentException(
0246: "null alias passed to getCertificate.");
0247: }
0248:
0249: Certificate c = (Certificate) certs.get(alias);
0250:
0251: //
0252: // look up the key table - and try the local key id
0253: //
0254: if (c == null) {
0255: String id = (String) localIds.get(alias);
0256: if (id != null) {
0257: c = (Certificate) keyCerts.get(id);
0258: } else {
0259: c = (Certificate) keyCerts.get(alias);
0260: }
0261: }
0262:
0263: return c;
0264: }
0265:
0266: public String engineGetCertificateAlias(Certificate cert) {
0267: Enumeration c = certs.elements();
0268: Enumeration k = certs.keys();
0269:
0270: while (c.hasMoreElements()) {
0271: Certificate tc = (Certificate) c.nextElement();
0272: String ta = (String) k.nextElement();
0273:
0274: if (tc.equals(cert)) {
0275: return ta;
0276: }
0277: }
0278:
0279: c = keyCerts.elements();
0280: k = keyCerts.keys();
0281:
0282: while (c.hasMoreElements()) {
0283: Certificate tc = (Certificate) c.nextElement();
0284: String ta = (String) k.nextElement();
0285:
0286: if (tc.equals(cert)) {
0287: return ta;
0288: }
0289: }
0290:
0291: return null;
0292: }
0293:
0294: public Certificate[] engineGetCertificateChain(String alias) {
0295: if (alias == null) {
0296: throw new IllegalArgumentException(
0297: "null alias passed to getCertificateChain.");
0298: }
0299:
0300: if (!engineIsKeyEntry(alias)) {
0301: return null;
0302: }
0303:
0304: Certificate c = engineGetCertificate(alias);
0305:
0306: if (c != null) {
0307: Vector cs = new Vector();
0308:
0309: while (c != null) {
0310: X509Certificate x509c = (X509Certificate) c;
0311: Certificate nextC = null;
0312:
0313: byte[] bytes = x509c
0314: .getExtensionValue(X509Extensions.AuthorityKeyIdentifier
0315: .getId());
0316: if (bytes != null) {
0317: try {
0318: ASN1InputStream aIn = new ASN1InputStream(bytes);
0319:
0320: byte[] authBytes = ((ASN1OctetString) aIn
0321: .readObject()).getOctets();
0322: aIn = new ASN1InputStream(authBytes);
0323:
0324: AuthorityKeyIdentifier id = new AuthorityKeyIdentifier(
0325: (ASN1Sequence) aIn.readObject());
0326: if (id.getKeyIdentifier() != null) {
0327: nextC = (Certificate) chainCerts
0328: .get(new CertId(id
0329: .getKeyIdentifier()));
0330: }
0331:
0332: } catch (IOException e) {
0333: throw new RuntimeException(e.toString());
0334: }
0335: }
0336:
0337: if (nextC == null) {
0338: //
0339: // no authority key id, try the Issuer DN
0340: //
0341: Principal i = x509c.getIssuerDN();
0342: Principal s = x509c.getSubjectDN();
0343:
0344: if (!i.equals(s)) {
0345: Enumeration e = chainCerts.keys();
0346:
0347: while (e.hasMoreElements()) {
0348: X509Certificate crt = (X509Certificate) chainCerts
0349: .get(e.nextElement());
0350: Principal sub = crt.getSubjectDN();
0351: if (sub.equals(i)) {
0352: try {
0353: x509c.verify(crt.getPublicKey());
0354: nextC = crt;
0355: break;
0356: } catch (Exception ex) {
0357: // continue
0358: }
0359: }
0360: }
0361: }
0362: }
0363:
0364: cs.addElement(c);
0365: if (nextC != c) // self signed - end of the chain
0366: {
0367: c = nextC;
0368: } else {
0369: c = null;
0370: }
0371: }
0372:
0373: Certificate[] certChain = new Certificate[cs.size()];
0374:
0375: for (int i = 0; i != certChain.length; i++) {
0376: certChain[i] = (Certificate) cs.elementAt(i);
0377: }
0378:
0379: return certChain;
0380: }
0381:
0382: return null;
0383: }
0384:
0385: public Date engineGetCreationDate(String alias) {
0386: return new Date();
0387: }
0388:
0389: public Key engineGetKey(String alias, char[] password)
0390: throws NoSuchAlgorithmException, UnrecoverableKeyException {
0391: if (alias == null) {
0392: throw new IllegalArgumentException(
0393: "null alias passed to getKey.");
0394: }
0395:
0396: return (Key) keys.get(alias);
0397: }
0398:
0399: public boolean engineIsCertificateEntry(String alias) {
0400: return (certs.get(alias) != null && keys.get(alias) == null);
0401: }
0402:
0403: public boolean engineIsKeyEntry(String alias) {
0404: return (keys.get(alias) != null);
0405: }
0406:
0407: public void engineSetCertificateEntry(String alias, Certificate cert)
0408: throws KeyStoreException {
0409: if (keys.get(alias) != null) {
0410: throw new KeyStoreException(
0411: "There is a key entry with the name " + alias + ".");
0412: }
0413:
0414: certs.put(alias, cert);
0415: chainCerts.put(new CertId(cert.getPublicKey()), cert);
0416: }
0417:
0418: public void engineSetKeyEntry(String alias, byte[] key,
0419: Certificate[] chain) throws KeyStoreException {
0420: throw new RuntimeException("operation not supported");
0421: }
0422:
0423: public void engineSetKeyEntry(String alias, Key key,
0424: char[] password, Certificate[] chain)
0425: throws KeyStoreException {
0426: if ((key instanceof PrivateKey) && (chain == null)) {
0427: throw new KeyStoreException(
0428: "no certificate chain for private key");
0429: }
0430:
0431: if (keys.get(alias) != null) {
0432: engineDeleteEntry(alias);
0433: }
0434:
0435: keys.put(alias, key);
0436: certs.put(alias, chain[0]);
0437:
0438: for (int i = 0; i != chain.length; i++) {
0439: chainCerts.put(new CertId(chain[i].getPublicKey()),
0440: chain[i]);
0441: }
0442: }
0443:
0444: public int engineSize() {
0445: Hashtable tab = new Hashtable();
0446:
0447: Enumeration e = certs.keys();
0448: while (e.hasMoreElements()) {
0449: tab.put(e.nextElement(), "cert");
0450: }
0451:
0452: e = keys.keys();
0453: while (e.hasMoreElements()) {
0454: String a = (String) e.nextElement();
0455: if (tab.get(a) == null) {
0456: tab.put(a, "key");
0457: }
0458: }
0459:
0460: return tab.size();
0461: }
0462:
0463: protected PrivateKey unwrapKey(AlgorithmIdentifier algId,
0464: byte[] data, char[] password, boolean wrongPKCS12Zero)
0465: throws IOException {
0466: String algorithm = algId.getObjectId().getId();
0467: PKCS12PBEParams pbeParams = new PKCS12PBEParams(
0468: (ASN1Sequence) algId.getParameters());
0469:
0470: PBEKeySpec pbeSpec = new PBEKeySpec(password);
0471: PrivateKey out;
0472:
0473: try {
0474: SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
0475: algorithm, "BC");
0476: PBEParameterSpec defParams = new PBEParameterSpec(pbeParams
0477: .getIV(), pbeParams.getIterations().intValue());
0478:
0479: SecretKey k = keyFact.generateSecret(pbeSpec);
0480:
0481: ((JCEPBEKey) k).setTryWrongPKCS12Zero(wrongPKCS12Zero);
0482:
0483: Cipher cipher = Cipher.getInstance(algorithm, "BC");
0484:
0485: cipher.init(Cipher.UNWRAP_MODE, k, defParams);
0486:
0487: // we pass "" as the key algorithm type as it is unknown at this point
0488: out = (PrivateKey) cipher.unwrap(data, "",
0489: Cipher.PRIVATE_KEY);
0490: } catch (Exception e) {
0491: throw new IOException("exception unwrapping private key - "
0492: + e.toString());
0493: }
0494:
0495: return out;
0496: }
0497:
0498: protected byte[] wrapKey(String algorithm, Key key,
0499: PKCS12PBEParams pbeParams, char[] password)
0500: throws IOException {
0501: PBEKeySpec pbeSpec = new PBEKeySpec(password);
0502: byte[] out;
0503:
0504: try {
0505: SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
0506: algorithm, "BC");
0507: PBEParameterSpec defParams = new PBEParameterSpec(pbeParams
0508: .getIV(), pbeParams.getIterations().intValue());
0509:
0510: Cipher cipher = Cipher.getInstance(algorithm, "BC");
0511:
0512: cipher.init(Cipher.WRAP_MODE, keyFact
0513: .generateSecret(pbeSpec), defParams);
0514:
0515: out = cipher.wrap(key);
0516: } catch (Exception e) {
0517: throw new IOException("exception encrypting data - "
0518: + e.toString());
0519: }
0520:
0521: return out;
0522: }
0523:
0524: protected byte[] cryptData(boolean forEncryption,
0525: AlgorithmIdentifier algId, char[] password,
0526: boolean wrongPKCS12Zero, byte[] data) throws IOException {
0527: String algorithm = algId.getObjectId().getId();
0528: PKCS12PBEParams pbeParams = new PKCS12PBEParams(
0529: (ASN1Sequence) algId.getParameters());
0530: PBEKeySpec pbeSpec = new PBEKeySpec(password);
0531:
0532: try {
0533: SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
0534: algorithm, "BC");
0535: PBEParameterSpec defParams = new PBEParameterSpec(pbeParams
0536: .getIV(), pbeParams.getIterations().intValue());
0537: JCEPBEKey key = (JCEPBEKey) keyFact.generateSecret(pbeSpec);
0538:
0539: key.setTryWrongPKCS12Zero(wrongPKCS12Zero);
0540:
0541: Cipher cipher = Cipher.getInstance(algorithm, "BC");
0542: int mode = forEncryption ? Cipher.ENCRYPT_MODE
0543: : Cipher.DECRYPT_MODE;
0544: cipher.init(mode, key, defParams);
0545: return cipher.doFinal(data);
0546: } catch (Exception e) {
0547: throw new IOException("exception decrypting data - "
0548: + e.toString());
0549: }
0550: }
0551:
0552: public void engineLoad(InputStream stream, char[] password)
0553: throws IOException {
0554: if (stream == null) // just initialising
0555: {
0556: return;
0557: }
0558:
0559: if (password == null) {
0560: throw new NullPointerException(
0561: "No password supplied for PKCS#12 KeyStore.");
0562: }
0563:
0564: BufferedInputStream bufIn = new BufferedInputStream(stream);
0565:
0566: bufIn.mark(10);
0567:
0568: int head = bufIn.read();
0569:
0570: if (head != 0x30) {
0571: throw new IOException(
0572: "stream does not represent a PKCS12 key store");
0573: }
0574:
0575: bufIn.reset();
0576:
0577: ASN1InputStream bIn = new ASN1InputStream(bufIn);
0578: ASN1Sequence obj = (ASN1Sequence) bIn.readObject();
0579: Pfx bag = new Pfx(obj);
0580: ContentInfo info = bag.getAuthSafe();
0581: Vector chain = new Vector();
0582: boolean unmarkedKey = false;
0583: boolean wrongPKCS12Zero = false;
0584:
0585: if (bag.getMacData() != null) // check the mac code
0586: {
0587: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
0588: BEROutputStream berOut = new BEROutputStream(bOut);
0589: MacData mData = bag.getMacData();
0590: DigestInfo dInfo = mData.getMac();
0591: AlgorithmIdentifier algId = dInfo.getAlgorithmId();
0592: byte[] salt = mData.getSalt();
0593: int itCount = mData.getIterationCount().intValue();
0594:
0595: berOut.writeObject(info);
0596:
0597: byte[] data = ((ASN1OctetString) info.getContent())
0598: .getOctets();
0599:
0600: try {
0601: byte[] res = calculatePbeMac(algId.getObjectId(), salt,
0602: itCount, password, false, data);
0603: byte[] dig = dInfo.getDigest();
0604:
0605: if (!Arrays.areEqual(res, dig)) {
0606: if (password.length > 0) {
0607: throw new IOException(
0608: "PKCS12 key store mac invalid - wrong password or corrupted file.");
0609: }
0610:
0611: // Try with incorrect zero length password
0612: res = calculatePbeMac(algId.getObjectId(), salt,
0613: itCount, password, true, data);
0614:
0615: if (!Arrays.areEqual(res, dig)) {
0616: throw new IOException(
0617: "PKCS12 key store mac invalid - wrong password or corrupted file.");
0618: }
0619:
0620: wrongPKCS12Zero = true;
0621: }
0622: } catch (IOException e) {
0623: throw e;
0624: } catch (Exception e) {
0625: throw new IOException("error constructing MAC: "
0626: + e.toString());
0627: }
0628: }
0629:
0630: keys = new IgnoresCaseHashtable();
0631: localIds = new Hashtable();
0632:
0633: if (info.getContentType().equals(data)) {
0634: bIn = new ASN1InputStream(((ASN1OctetString) info
0635: .getContent()).getOctets());
0636:
0637: AuthenticatedSafe authSafe = new AuthenticatedSafe(
0638: (ASN1Sequence) bIn.readObject());
0639: ContentInfo[] c = authSafe.getContentInfo();
0640:
0641: for (int i = 0; i != c.length; i++) {
0642: if (c[i].getContentType().equals(data)) {
0643: ASN1InputStream dIn = new ASN1InputStream(
0644: ((ASN1OctetString) c[i].getContent())
0645: .getOctets());
0646: ASN1Sequence seq = (ASN1Sequence) dIn.readObject();
0647:
0648: for (int j = 0; j != seq.size(); j++) {
0649: SafeBag b = new SafeBag((ASN1Sequence) seq
0650: .getObjectAt(j));
0651: if (b.getBagId().equals(pkcs8ShroudedKeyBag)) {
0652: org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo(
0653: (ASN1Sequence) b.getBagValue());
0654: PrivateKey privKey = unwrapKey(eIn
0655: .getEncryptionAlgorithm(), eIn
0656: .getEncryptedData(), password,
0657: wrongPKCS12Zero);
0658:
0659: //
0660: // set the attributes on the key
0661: //
0662: PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier) privKey;
0663: String alias = null;
0664: ASN1OctetString localId = null;
0665:
0666: if (b.getBagAttributes() != null) {
0667: Enumeration e = b.getBagAttributes()
0668: .getObjects();
0669: while (e.hasMoreElements()) {
0670: ASN1Sequence sq = (ASN1Sequence) e
0671: .nextElement();
0672: DERObjectIdentifier aOid = (DERObjectIdentifier) sq
0673: .getObjectAt(0);
0674: ASN1Set attrSet = (ASN1Set) sq
0675: .getObjectAt(1);
0676: DERObject attr = null;
0677:
0678: if (attrSet.size() > 0) {
0679: attr = (DERObject) attrSet
0680: .getObjectAt(0);
0681:
0682: bagAttr.setBagAttribute(aOid,
0683: attr);
0684: }
0685:
0686: if (aOid
0687: .equals(pkcs_9_at_friendlyName)) {
0688: alias = ((DERBMPString) attr)
0689: .getString();
0690: keys.put(alias, privKey);
0691: } else if (aOid
0692: .equals(pkcs_9_at_localKeyId)) {
0693: localId = (ASN1OctetString) attr;
0694: }
0695: }
0696: }
0697:
0698: if (localId != null) {
0699: String name = new String(Hex
0700: .encode(localId.getOctets()));
0701:
0702: if (alias == null) {
0703: keys.put(name, privKey);
0704: } else {
0705: localIds.put(alias, name);
0706: }
0707: } else {
0708: unmarkedKey = true;
0709: keys.put("unmarked", privKey);
0710: }
0711: } else if (b.getBagId().equals(certBag)) {
0712: chain.addElement(b);
0713: } else {
0714: System.out.println("extra in data "
0715: + b.getBagId());
0716: System.out
0717: .println(ASN1Dump.dumpAsString(b));
0718: }
0719: }
0720: } else if (c[i].getContentType().equals(encryptedData)) {
0721: EncryptedData d = new EncryptedData(
0722: (ASN1Sequence) c[i].getContent());
0723: byte[] octets = cryptData(false, d
0724: .getEncryptionAlgorithm(), password,
0725: wrongPKCS12Zero, d.getContent().getOctets());
0726: ASN1Sequence seq = (ASN1Sequence) ASN1Object
0727: .fromByteArray(octets);
0728:
0729: for (int j = 0; j != seq.size(); j++) {
0730: SafeBag b = new SafeBag((ASN1Sequence) seq
0731: .getObjectAt(j));
0732:
0733: if (b.getBagId().equals(certBag)) {
0734: chain.addElement(b);
0735: } else if (b.getBagId().equals(
0736: pkcs8ShroudedKeyBag)) {
0737: org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo(
0738: (ASN1Sequence) b.getBagValue());
0739: PrivateKey privKey = unwrapKey(eIn
0740: .getEncryptionAlgorithm(), eIn
0741: .getEncryptedData(), password,
0742: wrongPKCS12Zero);
0743:
0744: //
0745: // set the attributes on the key
0746: //
0747: PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier) privKey;
0748: String alias = null;
0749: ASN1OctetString localId = null;
0750:
0751: Enumeration e = b.getBagAttributes()
0752: .getObjects();
0753: while (e.hasMoreElements()) {
0754: ASN1Sequence sq = (ASN1Sequence) e
0755: .nextElement();
0756: DERObjectIdentifier aOid = (DERObjectIdentifier) sq
0757: .getObjectAt(0);
0758: ASN1Set attrSet = (ASN1Set) sq
0759: .getObjectAt(1);
0760: DERObject attr = null;
0761:
0762: if (attrSet.size() > 0) {
0763: attr = (DERObject) attrSet
0764: .getObjectAt(0);
0765:
0766: bagAttr.setBagAttribute(aOid, attr);
0767: }
0768:
0769: if (aOid.equals(pkcs_9_at_friendlyName)) {
0770: alias = ((DERBMPString) attr)
0771: .getString();
0772: keys.put(alias, privKey);
0773: } else if (aOid
0774: .equals(pkcs_9_at_localKeyId)) {
0775: localId = (ASN1OctetString) attr;
0776: }
0777: }
0778:
0779: String name = new String(Hex.encode(localId
0780: .getOctets()));
0781:
0782: if (alias == null) {
0783: keys.put(name, privKey);
0784: } else {
0785: localIds.put(alias, name);
0786: }
0787: } else if (b.getBagId().equals(keyBag)) {
0788: org.bouncycastle.asn1.pkcs.PrivateKeyInfo pIn = new org.bouncycastle.asn1.pkcs.PrivateKeyInfo(
0789: (ASN1Sequence) b.getBagValue());
0790: PrivateKey privKey = JDKKeyFactory
0791: .createPrivateKeyFromPrivateKeyInfo(pIn);
0792:
0793: //
0794: // set the attributes on the key
0795: //
0796: PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier) privKey;
0797: String alias = null;
0798: ASN1OctetString localId = null;
0799:
0800: Enumeration e = b.getBagAttributes()
0801: .getObjects();
0802: while (e.hasMoreElements()) {
0803: ASN1Sequence sq = (ASN1Sequence) e
0804: .nextElement();
0805: DERObjectIdentifier aOid = (DERObjectIdentifier) sq
0806: .getObjectAt(0);
0807: ASN1Set attrSet = (ASN1Set) sq
0808: .getObjectAt(1);
0809: DERObject attr = null;
0810:
0811: if (attrSet.size() > 0) {
0812: attr = (DERObject) attrSet
0813: .getObjectAt(0);
0814:
0815: bagAttr.setBagAttribute(aOid, attr);
0816: }
0817:
0818: if (aOid.equals(pkcs_9_at_friendlyName)) {
0819: alias = ((DERBMPString) attr)
0820: .getString();
0821: keys.put(alias, privKey);
0822: } else if (aOid
0823: .equals(pkcs_9_at_localKeyId)) {
0824: localId = (ASN1OctetString) attr;
0825: }
0826: }
0827:
0828: String name = new String(Hex.encode(localId
0829: .getOctets()));
0830:
0831: if (alias == null) {
0832: keys.put(name, privKey);
0833: } else {
0834: localIds.put(alias, name);
0835: }
0836: } else {
0837: System.out
0838: .println("extra in encryptedData "
0839: + b.getBagId());
0840: System.out
0841: .println(ASN1Dump.dumpAsString(b));
0842: }
0843: }
0844: } else {
0845: System.out.println("extra "
0846: + c[i].getContentType().getId());
0847: System.out.println("extra "
0848: + ASN1Dump.dumpAsString(c[i].getContent()));
0849: }
0850: }
0851: }
0852:
0853: certs = new IgnoresCaseHashtable();
0854: chainCerts = new Hashtable();
0855: keyCerts = new Hashtable();
0856:
0857: for (int i = 0; i != chain.size(); i++) {
0858: SafeBag b = (SafeBag) chain.elementAt(i);
0859: CertBag cb = new CertBag((ASN1Sequence) b.getBagValue());
0860:
0861: if (!cb.getCertId().equals(x509Certificate)) {
0862: throw new RuntimeException(
0863: "Unsupported certificate type: "
0864: + cb.getCertId());
0865: }
0866:
0867: Certificate cert;
0868:
0869: try {
0870: ByteArrayInputStream cIn = new ByteArrayInputStream(
0871: ((ASN1OctetString) cb.getCertValue())
0872: .getOctets());
0873: cert = certFact.generateCertificate(cIn);
0874: } catch (Exception e) {
0875: throw new RuntimeException(e.toString());
0876: }
0877:
0878: //
0879: // set the attributes
0880: //
0881: ASN1OctetString localId = null;
0882: String alias = null;
0883:
0884: if (b.getBagAttributes() != null) {
0885: Enumeration e = b.getBagAttributes().getObjects();
0886: while (e.hasMoreElements()) {
0887: ASN1Sequence sq = (ASN1Sequence) e.nextElement();
0888: DERObjectIdentifier oid = (DERObjectIdentifier) sq
0889: .getObjectAt(0);
0890: DERObject attr = (DERObject) ((ASN1Set) sq
0891: .getObjectAt(1)).getObjectAt(0);
0892:
0893: if (cert instanceof PKCS12BagAttributeCarrier) {
0894: PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier) cert;
0895: bagAttr.setBagAttribute(oid, attr);
0896: }
0897:
0898: if (oid.equals(pkcs_9_at_friendlyName)) {
0899: alias = ((DERBMPString) attr).getString();
0900: } else if (oid.equals(pkcs_9_at_localKeyId)) {
0901: localId = (ASN1OctetString) attr;
0902: }
0903: }
0904: }
0905:
0906: chainCerts.put(new CertId(cert.getPublicKey()), cert);
0907:
0908: if (unmarkedKey) {
0909: if (keyCerts.isEmpty()) {
0910: String name = new String(Hex
0911: .encode(createSubjectKeyId(
0912: cert.getPublicKey())
0913: .getKeyIdentifier()));
0914:
0915: keyCerts.put(name, cert);
0916: keys.put(name, keys.remove("unmarked"));
0917: }
0918: } else {
0919: //
0920: // the local key id needs to override the friendly name
0921: //
0922: if (localId != null) {
0923: String name = new String(Hex.encode(localId
0924: .getOctets()));
0925:
0926: keyCerts.put(name, cert);
0927: }
0928: if (alias != null) {
0929: certs.put(alias, cert);
0930: }
0931: }
0932: }
0933: }
0934:
0935: public void engineStore(OutputStream stream, char[] password)
0936: throws IOException {
0937: if (password == null) {
0938: throw new NullPointerException(
0939: "No password supplied for PKCS#12 KeyStore.");
0940: }
0941:
0942: //
0943: // handle the key
0944: //
0945: ASN1EncodableVector keyS = new ASN1EncodableVector();
0946:
0947: Enumeration ks = keys.keys();
0948:
0949: while (ks.hasMoreElements()) {
0950: byte[] kSalt = new byte[SALT_SIZE];
0951:
0952: random.nextBytes(kSalt);
0953:
0954: String name = (String) ks.nextElement();
0955: PrivateKey privKey = (PrivateKey) keys.get(name);
0956: PKCS12PBEParams kParams = new PKCS12PBEParams(kSalt,
0957: MIN_ITERATIONS);
0958: byte[] kBytes = wrapKey(KEY_ALGORITHM.getId(), privKey,
0959: kParams, password);
0960: AlgorithmIdentifier kAlgId = new AlgorithmIdentifier(
0961: KEY_ALGORITHM, kParams.getDERObject());
0962: org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo kInfo = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo(
0963: kAlgId, kBytes);
0964: boolean attrSet = false;
0965: ASN1EncodableVector kName = new ASN1EncodableVector();
0966:
0967: if (privKey instanceof PKCS12BagAttributeCarrier) {
0968: PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier) privKey;
0969: //
0970: // make sure we are using the local alias on store
0971: //
0972: DERBMPString nm = (DERBMPString) bagAttrs
0973: .getBagAttribute(pkcs_9_at_friendlyName);
0974: if (nm == null || !nm.getString().equals(name)) {
0975: bagAttrs.setBagAttribute(pkcs_9_at_friendlyName,
0976: new DERBMPString(name));
0977: }
0978:
0979: //
0980: // make sure we have a local key-id
0981: //
0982: if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null) {
0983: Certificate ct = engineGetCertificate(name);
0984:
0985: bagAttrs.setBagAttribute(pkcs_9_at_localKeyId,
0986: createSubjectKeyId(ct.getPublicKey()));
0987: }
0988:
0989: Enumeration e = bagAttrs.getBagAttributeKeys();
0990:
0991: while (e.hasMoreElements()) {
0992: DERObjectIdentifier oid = (DERObjectIdentifier) e
0993: .nextElement();
0994: ASN1EncodableVector kSeq = new ASN1EncodableVector();
0995:
0996: kSeq.add(oid);
0997: kSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
0998:
0999: attrSet = true;
1000:
1001: kName.add(new DERSequence(kSeq));
1002: }
1003: }
1004:
1005: if (!attrSet) {
1006: //
1007: // set a default friendly name (from the key id) and local id
1008: //
1009: ASN1EncodableVector kSeq = new ASN1EncodableVector();
1010: Certificate ct = engineGetCertificate(name);
1011:
1012: kSeq.add(pkcs_9_at_localKeyId);
1013: kSeq.add(new DERSet(createSubjectKeyId(ct
1014: .getPublicKey())));
1015:
1016: kName.add(new DERSequence(kSeq));
1017:
1018: kSeq = new ASN1EncodableVector();
1019:
1020: kSeq.add(pkcs_9_at_friendlyName);
1021: kSeq.add(new DERSet(new DERBMPString(name)));
1022:
1023: kName.add(new DERSequence(kSeq));
1024: }
1025:
1026: SafeBag kBag = new SafeBag(pkcs8ShroudedKeyBag, kInfo
1027: .getDERObject(), new DERSet(kName));
1028: keyS.add(kBag);
1029: }
1030:
1031: byte[] keySEncoded = new DERSequence(keyS).getDEREncoded();
1032: BERConstructedOctetString keyString = new BERConstructedOctetString(
1033: keySEncoded);
1034:
1035: //
1036: // certficate processing
1037: //
1038: byte[] cSalt = new byte[SALT_SIZE];
1039:
1040: random.nextBytes(cSalt);
1041:
1042: ASN1EncodableVector certSeq = new ASN1EncodableVector();
1043: PKCS12PBEParams cParams = new PKCS12PBEParams(cSalt,
1044: MIN_ITERATIONS);
1045: AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(
1046: CERT_ALGORITHM, cParams.getDERObject());
1047: Hashtable doneCerts = new Hashtable();
1048:
1049: Enumeration cs = keys.keys();
1050: while (cs.hasMoreElements()) {
1051: try {
1052: String name = (String) cs.nextElement();
1053: Certificate cert = engineGetCertificate(name);
1054: boolean cAttrSet = false;
1055: CertBag cBag = new CertBag(x509Certificate,
1056: new DEROctetString(cert.getEncoded()));
1057: ASN1EncodableVector fName = new ASN1EncodableVector();
1058:
1059: if (cert instanceof PKCS12BagAttributeCarrier) {
1060: PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier) cert;
1061: //
1062: // make sure we are using the local alias on store
1063: //
1064: DERBMPString nm = (DERBMPString) bagAttrs
1065: .getBagAttribute(pkcs_9_at_friendlyName);
1066: if (nm == null || !nm.getString().equals(name)) {
1067: bagAttrs.setBagAttribute(
1068: pkcs_9_at_friendlyName,
1069: new DERBMPString(name));
1070: }
1071:
1072: //
1073: // make sure we have a local key-id
1074: //
1075: if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null) {
1076: bagAttrs
1077: .setBagAttribute(pkcs_9_at_localKeyId,
1078: createSubjectKeyId(cert
1079: .getPublicKey()));
1080: }
1081:
1082: Enumeration e = bagAttrs.getBagAttributeKeys();
1083:
1084: while (e.hasMoreElements()) {
1085: DERObjectIdentifier oid = (DERObjectIdentifier) e
1086: .nextElement();
1087: ASN1EncodableVector fSeq = new ASN1EncodableVector();
1088:
1089: fSeq.add(oid);
1090: fSeq.add(new DERSet(bagAttrs
1091: .getBagAttribute(oid)));
1092: fName.add(new DERSequence(fSeq));
1093:
1094: cAttrSet = true;
1095: }
1096: }
1097:
1098: if (!cAttrSet) {
1099: ASN1EncodableVector fSeq = new ASN1EncodableVector();
1100:
1101: fSeq.add(pkcs_9_at_localKeyId);
1102: fSeq.add(new DERSet(createSubjectKeyId(cert
1103: .getPublicKey())));
1104: fName.add(new DERSequence(fSeq));
1105:
1106: fSeq = new ASN1EncodableVector();
1107:
1108: fSeq.add(pkcs_9_at_friendlyName);
1109: fSeq.add(new DERSet(new DERBMPString(name)));
1110:
1111: fName.add(new DERSequence(fSeq));
1112: }
1113:
1114: SafeBag sBag = new SafeBag(certBag,
1115: cBag.getDERObject(), new DERSet(fName));
1116:
1117: certSeq.add(sBag);
1118:
1119: doneCerts.put(cert, cert);
1120: } catch (CertificateEncodingException e) {
1121: throw new IOException("Error encoding certificate: "
1122: + e.toString());
1123: }
1124: }
1125:
1126: cs = certs.keys();
1127: while (cs.hasMoreElements()) {
1128: try {
1129: String certId = (String) cs.nextElement();
1130: Certificate cert = (Certificate) certs.get(certId);
1131: boolean cAttrSet = false;
1132:
1133: if (keys.get(certId) != null) {
1134: continue;
1135: }
1136:
1137: CertBag cBag = new CertBag(x509Certificate,
1138: new DEROctetString(cert.getEncoded()));
1139: ASN1EncodableVector fName = new ASN1EncodableVector();
1140:
1141: if (cert instanceof PKCS12BagAttributeCarrier) {
1142: PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier) cert;
1143: //
1144: // make sure we are using the local alias on store
1145: //
1146: DERBMPString nm = (DERBMPString) bagAttrs
1147: .getBagAttribute(pkcs_9_at_friendlyName);
1148: if (nm == null || !nm.getString().equals(certId)) {
1149: bagAttrs.setBagAttribute(
1150: pkcs_9_at_friendlyName,
1151: new DERBMPString(certId));
1152: }
1153:
1154: Enumeration e = bagAttrs.getBagAttributeKeys();
1155:
1156: while (e.hasMoreElements()) {
1157: DERObjectIdentifier oid = (DERObjectIdentifier) e
1158: .nextElement();
1159: ASN1EncodableVector fSeq = new ASN1EncodableVector();
1160:
1161: fSeq.add(oid);
1162: fSeq.add(new DERSet(bagAttrs
1163: .getBagAttribute(oid)));
1164: fName.add(new DERSequence(fSeq));
1165:
1166: cAttrSet = true;
1167: }
1168: }
1169:
1170: if (!cAttrSet) {
1171: ASN1EncodableVector fSeq = new ASN1EncodableVector();
1172:
1173: fSeq.add(pkcs_9_at_friendlyName);
1174: fSeq.add(new DERSet(new DERBMPString(certId)));
1175:
1176: fName.add(new DERSequence(fSeq));
1177: }
1178:
1179: SafeBag sBag = new SafeBag(certBag,
1180: cBag.getDERObject(), new DERSet(fName));
1181:
1182: certSeq.add(sBag);
1183:
1184: doneCerts.put(cert, cert);
1185: } catch (CertificateEncodingException e) {
1186: throw new IOException("Error encoding certificate: "
1187: + e.toString());
1188: }
1189: }
1190:
1191: cs = chainCerts.keys();
1192: while (cs.hasMoreElements()) {
1193: try {
1194: CertId certId = (CertId) cs.nextElement();
1195: Certificate cert = (Certificate) chainCerts.get(certId);
1196:
1197: if (doneCerts.get(cert) != null) {
1198: continue;
1199: }
1200:
1201: CertBag cBag = new CertBag(x509Certificate,
1202: new DEROctetString(cert.getEncoded()));
1203: ASN1EncodableVector fName = new ASN1EncodableVector();
1204:
1205: if (cert instanceof PKCS12BagAttributeCarrier) {
1206: PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier) cert;
1207: Enumeration e = bagAttrs.getBagAttributeKeys();
1208:
1209: while (e.hasMoreElements()) {
1210: DERObjectIdentifier oid = (DERObjectIdentifier) e
1211: .nextElement();
1212: ASN1EncodableVector fSeq = new ASN1EncodableVector();
1213:
1214: fSeq.add(oid);
1215: fSeq.add(new DERSet(bagAttrs
1216: .getBagAttribute(oid)));
1217: fName.add(new DERSequence(fSeq));
1218: }
1219: }
1220:
1221: SafeBag sBag = new SafeBag(certBag,
1222: cBag.getDERObject(), new DERSet(fName));
1223:
1224: certSeq.add(sBag);
1225: } catch (CertificateEncodingException e) {
1226: throw new IOException("Error encoding certificate: "
1227: + e.toString());
1228: }
1229: }
1230:
1231: byte[] certSeqEncoded = new DERSequence(certSeq)
1232: .getDEREncoded();
1233: byte[] certBytes = cryptData(true, cAlgId, password, false,
1234: certSeqEncoded);
1235: EncryptedData cInfo = new EncryptedData(data, cAlgId,
1236: new BERConstructedOctetString(certBytes));
1237:
1238: ContentInfo[] info = new ContentInfo[] {
1239: new ContentInfo(data, keyString),
1240: new ContentInfo(encryptedData, cInfo.getDERObject()) };
1241:
1242: AuthenticatedSafe auth = new AuthenticatedSafe(info);
1243:
1244: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
1245: BEROutputStream berOut = new BEROutputStream(bOut);
1246:
1247: berOut.writeObject(auth);
1248:
1249: byte[] pkg = bOut.toByteArray();
1250:
1251: ContentInfo mainInfo = new ContentInfo(data,
1252: new BERConstructedOctetString(pkg));
1253:
1254: //
1255: // create the mac
1256: //
1257: byte[] mSalt = new byte[20];
1258: int itCount = MIN_ITERATIONS;
1259:
1260: random.nextBytes(mSalt);
1261:
1262: byte[] data = ((ASN1OctetString) mainInfo.getContent())
1263: .getOctets();
1264:
1265: MacData mData;
1266:
1267: try {
1268: byte[] res = calculatePbeMac(id_SHA1, mSalt, itCount,
1269: password, false, data);
1270:
1271: AlgorithmIdentifier algId = new AlgorithmIdentifier(
1272: id_SHA1, new DERNull());
1273: DigestInfo dInfo = new DigestInfo(algId, res);
1274:
1275: mData = new MacData(dInfo, mSalt, itCount);
1276: } catch (Exception e) {
1277: throw new IOException("error constructing MAC: "
1278: + e.toString());
1279: }
1280:
1281: //
1282: // output the Pfx
1283: //
1284: Pfx pfx = new Pfx(mainInfo, mData);
1285:
1286: berOut = new BEROutputStream(stream);
1287:
1288: berOut.writeObject(pfx);
1289: }
1290:
1291: private static byte[] calculatePbeMac(DERObjectIdentifier oid,
1292: byte[] salt, int itCount, char[] password,
1293: boolean wrongPkcs12Zero, byte[] data) throws Exception {
1294: SecretKeyFactory keyFact = SecretKeyFactory.getInstance(oid
1295: .getId(), "BC");
1296: PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
1297: PBEKeySpec pbeSpec = new PBEKeySpec(password);
1298: JCEPBEKey key = (JCEPBEKey) keyFact.generateSecret(pbeSpec);
1299: key.setTryWrongPKCS12Zero(wrongPkcs12Zero);
1300:
1301: Mac mac = Mac.getInstance(oid.getId(), "BC");
1302: mac.init(key, defParams);
1303: mac.update(data);
1304: return mac.doFinal();
1305: }
1306:
1307: public static class BCPKCS12KeyStore extends JDKPKCS12KeyStore {
1308: public BCPKCS12KeyStore() {
1309: super ("BC");
1310: }
1311: }
1312:
1313: public static class DefPKCS12KeyStore extends JDKPKCS12KeyStore {
1314: public DefPKCS12KeyStore() {
1315: super (null);
1316: }
1317: }
1318:
1319: private static class IgnoresCaseHashtable {
1320: private Hashtable orig = new Hashtable();
1321: private Hashtable keys = new Hashtable();
1322:
1323: public void put(String key, Object value) {
1324: String lower = Strings.toLowerCase(key);
1325: String k = (String) keys.get(lower);
1326: if (k != null) {
1327: orig.remove(k);
1328: }
1329:
1330: keys.put(lower, key);
1331: orig.put(key, value);
1332: }
1333:
1334: public Enumeration keys() {
1335: return orig.keys();
1336: }
1337:
1338: public Object remove(String alias) {
1339: String k = (String) keys.remove(Strings.toLowerCase(alias));
1340: if (k == null) {
1341: return null;
1342: }
1343:
1344: return orig.remove(k);
1345: }
1346:
1347: public Object get(String alias) {
1348: String k = (String) keys.get(Strings.toLowerCase(alias));
1349: if (k == null) {
1350: return null;
1351: }
1352:
1353: return orig.get(k);
1354: }
1355:
1356: public Enumeration elements() {
1357: return orig.elements();
1358: }
1359: }
1360: }
|