10669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin/* 20669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin * Copyright (C) 2013 The Android Open Source Project 30669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin * 40669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin * Licensed under the Apache License, Version 2.0 (the "License"); 50669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin * you may not use this file except in compliance with the License. 60669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin * You may obtain a copy of the License at 70669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin * 80669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin * http://www.apache.org/licenses/LICENSE-2.0 90669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin * 100669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin * Unless required by applicable law or agreed to in writing, software 110669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin * distributed under the License is distributed on an "AS IS" BASIS, 120669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin * See the License for the specific language governing permissions and 140669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin * limitations under the License. 150669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin */ 160669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin 170669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubinpackage libcore.javax.net.ssl; 180669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin 190669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubinimport junit.framework.Assert; 200669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubinimport java.security.GeneralSecurityException; 210669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubinimport java.security.KeyFactory; 220669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubinimport java.security.KeyPairGenerator; 230669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubinimport java.security.PrivateKey; 240669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubinimport java.security.spec.DSAParameterSpec; 250669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubinimport java.security.spec.DSAPrivateKeySpec; 260669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubinimport java.security.spec.RSAPrivateKeySpec; 270669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubinimport java.util.HashMap; 280669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubinimport java.util.Map; 290669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubinimport javax.net.ssl.X509ExtendedKeyManager; 300669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin 310669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin/** 320669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin * {@link X509ExtendedKeyManager} which forwards all calls to a delegate while substituting 330669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin * the returned private key with its own randomly generated keys of the same type (and parameters). 340669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin */ 350669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubinpublic class RandomPrivateKeyX509ExtendedKeyManager extends ForwardingX509ExtendedKeyManager { 360669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin 370669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin private final Map<String, PrivateKey> cachedKeys = new HashMap<String, PrivateKey>(); 380669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin 390669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin public RandomPrivateKeyX509ExtendedKeyManager(X509ExtendedKeyManager delegate) { 400669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin super(delegate); 410669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin } 420669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin 430669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin @Override 440669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin public PrivateKey getPrivateKey(String alias) { 450669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin PrivateKey originalPrivateKey = super.getPrivateKey(alias); 460669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin if (originalPrivateKey == null) { 470669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin return null; 480669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin } 490669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin 500669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin PrivateKey result; 510669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin String keyAlgorithm = originalPrivateKey.getAlgorithm(); 520669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin try { 530669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm); 540669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin if ("RSA".equals(keyAlgorithm)) { 550669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin RSAPrivateKeySpec originalKeySpec = 560669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin keyFactory.getKeySpec(originalPrivateKey, RSAPrivateKeySpec.class); 570669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin int keyLengthBits = originalKeySpec.getModulus().bitLength(); 580669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin // Use a cache because RSA key generation is slow. 590669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin String cacheKey = keyAlgorithm + "-" + keyLengthBits; 600669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin result = cachedKeys.get(cacheKey); 610669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin if (result == null) { 620669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyAlgorithm); 630669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin keyPairGenerator.initialize(keyLengthBits); 640669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin result = keyPairGenerator.generateKeyPair().getPrivate(); 650669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin cachedKeys.put(cacheKey, result); 660669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin } 670669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin } else if ("DSA".equals(keyAlgorithm)) { 680669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin DSAPrivateKeySpec originalKeySpec = 690669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin keyFactory.getKeySpec(originalPrivateKey, DSAPrivateKeySpec.class); 700669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyAlgorithm); 710669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin keyPairGenerator.initialize(new DSAParameterSpec( 720669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin originalKeySpec.getP(), originalKeySpec.getQ(), originalKeySpec.getG())); 730669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin result = keyPairGenerator.generateKeyPair().getPrivate(); 740669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin } else { 750669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin Assert.fail("Unsupported key algorithm: " + originalPrivateKey.getAlgorithm()); 760669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin result = null; 770669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin } 780669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin } catch (GeneralSecurityException e) { 790669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin Assert.fail("Failed to generate private key: " + e); 800669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin result = null; 810669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin } 820669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin 830669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin return result; 840669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin } 850669a8cf8b08b2d66a7ff758e5e3dbd456855495Alex Klyubin} 86