package org.bouncycastle.jce.provider.test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.KeyStore; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Date; import java.util.Hashtable; import java.util.Vector; import org.bouncycastle.jce.X509Principal; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ECParameterSpec; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTest; import org.bouncycastle.x509.X509V3CertificateGenerator; /** * Exercise the various key stores, making sure we at least get back what we put in! * <p> * This tests both the BKS, and the UBER key store. */ public class KeyStoreTest extends SimpleTest { static char[] passwd = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' }; byte[] v1BKS = Base64.decode( "AAAAAQAAABTqZbNMyPjsFazhFplWWDMBLPRdRAAABcYEAAdhbmRyb2lkAAAB" + "NOifkPwAAAAAAAAAPAAAABTZOLhcyhB0gKyfoDvyQbpzftB7GgAABEYPrZP8" + "q20AJLETjDv0K9C5rIl1erpyvpv20bqcbghK6wD0b8OP5/XzOz/8knhxmqJZ" + "3yRJMw=="); byte[] v2BKS = Base64.decode( "AAAAAgAAABSkmTXz4VIznO1SSUqsIHdxWcxsuQAABFMEAAdhbmRyb2lkAAABN" + "OifkPwAAAAAAAAAPAAAABTZOLhcyhB0gKyfoDvyQbpzftB7GgAABEYPrZP8q2" + "0AJLETjDv0K9C5rIl1erpyvpv20bqcbghK6wBO59KOGPvSrmJpd32P6ZAh9qLZJw=="); byte[] v1UBER = Base64.decode( "AAAAAQAAABRP0F6p2p3FyQKqyJiJt3NbvdybiwAAB2znqrO779YIW5gMtbt+" + "NUs96VPPcfZiKJPg7RKH7Yu3CQB0/g9nYsvgFB0fQ05mHcW3KjntN2/31A6G" + "i00n4ZnUTjJL16puZnQrloeGXxFy58tjwkFuwJ7V7ELYgiZlls0beHSdDGQW" + "iyYECwWs1la/"); byte[] v2UBER = Base64.decode( "AAAAAgAAABQ/D9k3376OG/REg4Ams9Up332tLQAABujoVcsRcKWwhlo4mMg5" + "lF2vJfK+okIYecJGWCvdykF5r8kDn68llt52IDXDkpRXVXcNJ0/aD7sa7iZ0" + "SL0TAwcfp/9v4j/w8slj/qgO0i/76+zROrP0NGFIa5k/iOg5Z0Tj77muMaJf" + "n3vLlIHa4IsX"); byte[] negSaltBKS = Base64.decode( "AAAAAv////+WnyglO06djy6JgCxGiIemnZdcOwAAB2AEAAdhbmRyb2lkAAAB" + "NOifkPwAAAAAAAAAPAAAABTZOLhcyhB0gKyfoDvyQbpzftB7GgAABEYPrZP8" + "q20AJLETjDv0K9C5rIl1erpyvpv20bqcbghK6wDrg6gUHsh27wNjUwkR+REe" + "NeFYBg=="); char[] oldStorePass = "fredfred".toCharArray(); public void ecStoreTest( String storeName) throws Exception { ECCurve curve = new ECCurve.Fp( new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b ECParameterSpec ecSpec = new ECParameterSpec( curve, curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC"); g.initialize(ecSpec, new SecureRandom()); KeyPair keyPair = g.generateKeyPair(); PublicKey pubKey = keyPair.getPublic(); PrivateKey privKey = keyPair.getPrivate(); // // distinguished name table. // Hashtable attrs = new Hashtable(); Vector order = new Vector(); attrs.put(X509Principal.C, "AU"); attrs.put(X509Principal.O, "The Legion of the Bouncy Castle"); attrs.put(X509Principal.L, "Melbourne"); attrs.put(X509Principal.ST, "Victoria"); attrs.put(X509Principal.E, "feedback-crypto@bouncycastle.org"); order.addElement(X509Principal.C); order.addElement(X509Principal.O); order.addElement(X509Principal.L); order.addElement(X509Principal.ST); order.addElement(X509Principal.E); // // create the certificate - version 3 // X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); certGen.setSerialNumber(BigInteger.valueOf(1)); certGen.setIssuerDN(new X509Principal(order, attrs)); certGen.setNotBefore(new Date(System.currentTimeMillis() - 50000)); certGen.setNotAfter(new Date(System.currentTimeMillis() + 50000)); certGen.setSubjectDN(new X509Principal(order, attrs)); certGen.setPublicKey(pubKey); certGen.setSignatureAlgorithm("ECDSAwithSHA1"); Certificate[] chain = new Certificate[1]; try { X509Certificate cert = certGen.generate(privKey); cert.checkValidity(new Date()); cert.verify(pubKey); ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded()); CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC"); cert = (X509Certificate)fact.generateCertificate(bIn); chain[0] = cert; } catch (Exception e) { fail("error generating cert - " + e.toString()); } KeyStore store = KeyStore.getInstance(storeName, "BC"); store.load(null, null); store.setKeyEntry("private", privKey, passwd, chain); // // write out and read back store // ByteArrayOutputStream bOut = new ByteArrayOutputStream(); store.store(bOut, passwd); ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); // // start with a new key store // store = KeyStore.getInstance(storeName, "BC"); store.load(bIn, passwd); // // load the private key // privKey = (PrivateKey)store.getKey("private", passwd); // // double public key encoding test // byte[] pubEnc = pubKey.getEncoded(); KeyFactory keyFac = KeyFactory.getInstance(pubKey.getAlgorithm(), "BC"); X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); pubKey = (PublicKey)keyFac.generatePublic(pubX509); pubEnc = pubKey.getEncoded(); keyFac = KeyFactory.getInstance(pubKey.getAlgorithm(), "BC"); pubX509 = new X509EncodedKeySpec(pubEnc); pubKey = (PublicKey)keyFac.generatePublic(pubX509); // // double private key encoding test // byte[] privEnc = privKey.getEncoded(); keyFac = KeyFactory.getInstance(privKey.getAlgorithm(), "BC"); PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); privKey = (PrivateKey)keyFac.generatePrivate(privPKCS8); keyFac = KeyFactory.getInstance(privKey.getAlgorithm(), "BC"); privPKCS8 = new PKCS8EncodedKeySpec(privEnc); privKey = (PrivateKey)keyFac.generatePrivate(privPKCS8); } public void keyStoreTest( String storeName) throws Exception { KeyStore store = KeyStore.getInstance(storeName, "BC"); store.load(null, null); KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA", "BC"); gen.initialize(1024, new SecureRandom()); KeyPair pair = gen.generateKeyPair(); RSAPrivateKey privKey = (RSAPrivateKey)pair.getPrivate(); RSAPublicKey pubKey = (RSAPublicKey)pair.getPublic(); BigInteger modulus = privKey.getModulus(); BigInteger privateExponent = privKey.getPrivateExponent(); // // distinguished name table. // Hashtable attrs = new Hashtable(); Vector order = new Vector(); attrs.put(X509Principal.C, "AU"); attrs.put(X509Principal.O, "The Legion of the Bouncy Castle"); attrs.put(X509Principal.L, "Melbourne"); attrs.put(X509Principal.ST, "Victoria"); attrs.put(X509Principal.EmailAddress, "feedback-crypto@bouncycastle.org"); order.addElement(X509Principal.C); order.addElement(X509Principal.O); order.addElement(X509Principal.L); order.addElement(X509Principal.ST); order.addElement(X509Principal.EmailAddress); // // extensions // // // create the certificate. // X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); certGen.setSerialNumber(BigInteger.valueOf(1)); certGen.setIssuerDN(new X509Principal(order, attrs)); certGen.setNotBefore(new Date(System.currentTimeMillis() - 50000)); certGen.setNotAfter(new Date(System.currentTimeMillis() + 50000)); certGen.setSubjectDN(new X509Principal(order, attrs)); certGen.setPublicKey(pubKey); certGen.setSignatureAlgorithm("MD5WithRSAEncryption"); Certificate[] chain = new Certificate[1]; try { X509Certificate cert = certGen.generate(privKey); cert.checkValidity(new Date()); cert.verify(pubKey); ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded()); CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC"); cert = (X509Certificate)fact.generateCertificate(bIn); chain[0] = cert; } catch (Exception e) { fail("error generating cert - " + e.toString()); } store.setKeyEntry("private", privKey, passwd, chain); // // write out and read back store // ByteArrayOutputStream bOut = new ByteArrayOutputStream(); store.store(bOut, passwd); ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); // // start with a new key store // store = KeyStore.getInstance(storeName, "BC"); store.load(bIn, passwd); // // verify public key // privKey = (RSAPrivateKey)store.getKey("private", passwd); if (!privKey.getModulus().equals(modulus)) { fail("private key modulus wrong"); } else if (!privKey.getPrivateExponent().equals(privateExponent)) { fail("private key exponent wrong"); } // // verify certificate // Certificate cert = store.getCertificateChain("private")[0]; cert.verify(pubKey); } private void oldStoreTest() throws Exception { checkStore(KeyStore.getInstance("BKS", "BC"), v1BKS); checkStore(KeyStore.getInstance("BKS", "BC"), v2BKS); checkStore(KeyStore.getInstance("UBER", "BC"), v1UBER); checkStore(KeyStore.getInstance("UBER", "BC"), v2UBER); checkOldStore(KeyStore.getInstance("BKS-V1", "BC"), v1BKS); checkOldStore(KeyStore.getInstance("BKS-V1", "BC"), v2BKS); } private void checkStore(KeyStore ks, byte[] data) throws Exception { ks.load(new ByteArrayInputStream(data), oldStorePass); if (!ks.containsAlias("android")) { fail("cannot find alias"); } Key key = ks.getKey("android", oldStorePass); if (key == null) { fail("cannot find key"); } ByteArrayOutputStream bOut = new ByteArrayOutputStream(); ks.store(bOut, oldStorePass); } private void checkOldStore(KeyStore ks, byte[] data) throws Exception { ks.load(new ByteArrayInputStream(data), oldStorePass); if (!ks.containsAlias("android")) { fail("cannot find alias"); } Key key = ks.getKey("android", oldStorePass); if (key == null) { fail("cannot find key"); } ByteArrayOutputStream bOut = new ByteArrayOutputStream(); ks.store(bOut, oldStorePass); if (data.length != bOut.toByteArray().length) { fail("Old version key store write incorrect"); } } private void checkException() throws Exception { KeyStore ks = KeyStore.getInstance("BKS", "BC"); try { ks.load(new ByteArrayInputStream(negSaltBKS), oldStorePass); } catch (IOException e) { if (!e.getMessage().equals("Invalid salt detected")) { fail("negative salt length not detected"); } } } public String getName() { return "KeyStore"; } public void performTest() throws Exception { keyStoreTest("BKS"); keyStoreTest("UBER"); keyStoreTest("BKS-V1"); ecStoreTest("BKS"); oldStoreTest(); checkException(); } public static void main( String[] args) { Security.addProvider(new BouncyCastleProvider()); runTest(new KeyStoreTest()); } }