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