1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package org.conscrypt; 18 19import java.math.BigInteger; 20import java.security.InvalidKeyException; 21import java.security.Key; 22import java.security.KeyFactorySpi; 23import java.security.PrivateKey; 24import java.security.PublicKey; 25import java.security.spec.InvalidKeySpecException; 26import java.security.spec.KeySpec; 27import java.security.spec.PKCS8EncodedKeySpec; 28import java.security.spec.X509EncodedKeySpec; 29 30import javax.crypto.interfaces.DHPrivateKey; 31import javax.crypto.interfaces.DHPublicKey; 32import javax.crypto.spec.DHParameterSpec; 33import javax.crypto.spec.DHPrivateKeySpec; 34import javax.crypto.spec.DHPublicKeySpec; 35 36public class OpenSSLDHKeyFactory extends KeyFactorySpi { 37 38 @Override 39 protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException { 40 if (keySpec == null) { 41 throw new InvalidKeySpecException("keySpec == null"); 42 } 43 44 if (keySpec instanceof DHPublicKeySpec) { 45 return new OpenSSLDHPublicKey((DHPublicKeySpec) keySpec); 46 } else if (keySpec instanceof X509EncodedKeySpec) { 47 return OpenSSLKey.getPublicKey((X509EncodedKeySpec) keySpec, NativeCrypto.EVP_PKEY_DH); 48 } 49 throw new InvalidKeySpecException("Must use DHPublicKeySpec or X509EncodedKeySpec; was " 50 + keySpec.getClass().getName()); 51 } 52 53 @Override 54 protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException { 55 if (keySpec == null) { 56 throw new InvalidKeySpecException("keySpec == null"); 57 } 58 59 if (keySpec instanceof DHPrivateKeySpec) { 60 return new OpenSSLDHPrivateKey((DHPrivateKeySpec) keySpec); 61 } else if (keySpec instanceof PKCS8EncodedKeySpec) { 62 return OpenSSLKey.getPrivateKey((PKCS8EncodedKeySpec) keySpec, 63 NativeCrypto.EVP_PKEY_DH); 64 } 65 throw new InvalidKeySpecException("Must use DHPrivateKeySpec or PKCS8EncodedKeySpec; was " 66 + keySpec.getClass().getName()); 67 } 68 69 @Override 70 protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec) 71 throws InvalidKeySpecException { 72 if (key == null) { 73 throw new InvalidKeySpecException("key == null"); 74 } 75 76 if (keySpec == null) { 77 throw new InvalidKeySpecException("keySpec == null"); 78 } 79 80 if (!"DH".equals(key.getAlgorithm())) { 81 throw new InvalidKeySpecException("Key must be a DH key"); 82 } 83 84 if (key instanceof DHPublicKey && DHPublicKeySpec.class.isAssignableFrom(keySpec)) { 85 DHPublicKey dhKey = (DHPublicKey) key; 86 DHParameterSpec params = dhKey.getParams(); 87 return (T) new DHPublicKeySpec(dhKey.getY(), params.getP(), params.getG()); 88 } else if (key instanceof PublicKey && DHPublicKeySpec.class.isAssignableFrom(keySpec)) { 89 final byte[] encoded = key.getEncoded(); 90 if (!"X.509".equals(key.getFormat()) || encoded == null) { 91 throw new InvalidKeySpecException("Not a valid X.509 encoding"); 92 } 93 DHPublicKey dhKey = (DHPublicKey) engineGeneratePublic(new X509EncodedKeySpec(encoded)); 94 DHParameterSpec params = dhKey.getParams(); 95 return (T) new DHPublicKeySpec(dhKey.getY(), params.getP(), params.getG()); 96 } else if (key instanceof DHPrivateKey && DHPrivateKeySpec.class.isAssignableFrom(keySpec)) { 97 DHPrivateKey dhKey = (DHPrivateKey) key; 98 DHParameterSpec params = dhKey.getParams(); 99 return (T) new DHPrivateKeySpec(dhKey.getX(), params.getP(), params.getG()); 100 } else if (key instanceof PrivateKey && DHPrivateKeySpec.class.isAssignableFrom(keySpec)) { 101 final byte[] encoded = key.getEncoded(); 102 if (!"PKCS#8".equals(key.getFormat()) || encoded == null) { 103 throw new InvalidKeySpecException("Not a valid PKCS#8 encoding"); 104 } 105 DHPrivateKey dhKey = (DHPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec( 106 encoded)); 107 DHParameterSpec params = dhKey.getParams(); 108 return (T) new DHPrivateKeySpec(dhKey.getX(), params.getP(), params.getG()); 109 } else if (key instanceof PrivateKey 110 && PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) { 111 final byte[] encoded = key.getEncoded(); 112 if (!"PKCS#8".equals(key.getFormat())) { 113 throw new InvalidKeySpecException("Encoding type must be PKCS#8; was " 114 + key.getFormat()); 115 } else if (encoded == null) { 116 throw new InvalidKeySpecException("Key is not encodable"); 117 } 118 return (T) new PKCS8EncodedKeySpec(encoded); 119 } else if (key instanceof PublicKey && X509EncodedKeySpec.class.isAssignableFrom(keySpec)) { 120 final byte[] encoded = key.getEncoded(); 121 if (!"X.509".equals(key.getFormat())) { 122 throw new InvalidKeySpecException("Encoding type must be X.509; was " 123 + key.getFormat()); 124 } else if (encoded == null) { 125 throw new InvalidKeySpecException("Key is not encodable"); 126 } 127 return (T) new X509EncodedKeySpec(encoded); 128 } else { 129 throw new InvalidKeySpecException("Unsupported key type and key spec combination; key=" 130 + key.getClass().getName() + ", keySpec=" + keySpec.getName()); 131 } 132 } 133 134 @Override 135 protected Key engineTranslateKey(Key key) throws InvalidKeyException { 136 if (key == null) { 137 throw new InvalidKeyException("key == null"); 138 } 139 if ((key instanceof OpenSSLDHPublicKey) || (key instanceof OpenSSLDHPrivateKey)) { 140 return key; 141 } else if (key instanceof DHPublicKey) { 142 DHPublicKey dhKey = (DHPublicKey) key; 143 144 BigInteger y = dhKey.getY(); 145 146 DHParameterSpec params = dhKey.getParams(); 147 BigInteger p = params.getP(); 148 BigInteger g = params.getG(); 149 150 try { 151 return engineGeneratePublic(new DHPublicKeySpec(y, p, g)); 152 } catch (InvalidKeySpecException e) { 153 throw new InvalidKeyException(e); 154 } 155 } else if (key instanceof DHPrivateKey) { 156 DHPrivateKey dhKey = (DHPrivateKey) key; 157 158 BigInteger x = dhKey.getX(); 159 160 DHParameterSpec params = dhKey.getParams(); 161 BigInteger p = params.getP(); 162 BigInteger g = params.getG(); 163 164 try { 165 return engineGeneratePrivate(new DHPrivateKeySpec(x, p, g)); 166 } catch (InvalidKeySpecException e) { 167 throw new InvalidKeyException(e); 168 } 169 } else if ((key instanceof PrivateKey) && ("PKCS#8".equals(key.getFormat()))) { 170 byte[] encoded = key.getEncoded(); 171 if (encoded == null) { 172 throw new InvalidKeyException("Key does not support encoding"); 173 } 174 try { 175 return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded)); 176 } catch (InvalidKeySpecException e) { 177 throw new InvalidKeyException(e); 178 } 179 } else if ((key instanceof PublicKey) && ("X.509".equals(key.getFormat()))) { 180 byte[] encoded = key.getEncoded(); 181 if (encoded == null) { 182 throw new InvalidKeyException("Key does not support encoding"); 183 } 184 try { 185 return engineGeneratePublic(new X509EncodedKeySpec(encoded)); 186 } catch (InvalidKeySpecException e) { 187 throw new InvalidKeyException(e); 188 } 189 } else { 190 throw new InvalidKeyException("Key must be DH public or private key; was " 191 + key.getClass().getName()); 192 } 193 } 194} 195