1746a236e2be5dee62c482e27f4c682496d071d8bKenny Root/* 2746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * Copyright (C) 2012 The Android Open Source Project 3746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * 4746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * Licensed under the Apache License, Version 2.0 (the "License"); 5746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * you may not use this file except in compliance with the License. 6746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * You may obtain a copy of the License at 7746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * 8746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * http://www.apache.org/licenses/LICENSE-2.0 9746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * 10746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * Unless required by applicable law or agreed to in writing, software 11746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * distributed under the License is distributed on an "AS IS" BASIS, 12746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * See the License for the specific language governing permissions and 14746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * limitations under the License. 15746a236e2be5dee62c482e27f4c682496d071d8bKenny Root */ 16746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 1738375a4d0b3d34e2babbd2f6a013976c7c439696Kenny Rootpackage org.conscrypt; 18746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 19746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.math.BigInteger; 20746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.InvalidKeyException; 21746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.Key; 22746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.KeyFactorySpi; 23746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.PrivateKey; 24746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.PublicKey; 25746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.interfaces.DSAParams; 26746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.interfaces.DSAPrivateKey; 27746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.interfaces.DSAPublicKey; 28746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.spec.DSAPrivateKeySpec; 29746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.spec.DSAPublicKeySpec; 30746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.spec.InvalidKeySpecException; 31746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.spec.KeySpec; 32746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.spec.PKCS8EncodedKeySpec; 33746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.spec.X509EncodedKeySpec; 34746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 35746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootpublic class OpenSSLDSAKeyFactory extends KeyFactorySpi { 36746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 37746a236e2be5dee62c482e27f4c682496d071d8bKenny Root @Override 38746a236e2be5dee62c482e27f4c682496d071d8bKenny Root protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException { 397885a9c6c62c6162a308913272447153b6a2e809Kenny Root if (keySpec == null) { 407885a9c6c62c6162a308913272447153b6a2e809Kenny Root throw new InvalidKeySpecException("keySpec == null"); 417885a9c6c62c6162a308913272447153b6a2e809Kenny Root } 42746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 437885a9c6c62c6162a308913272447153b6a2e809Kenny Root if (keySpec instanceof DSAPublicKeySpec) { 447885a9c6c62c6162a308913272447153b6a2e809Kenny Root return new OpenSSLDSAPublicKey((DSAPublicKeySpec) keySpec); 45746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } else if (keySpec instanceof X509EncodedKeySpec) { 467885a9c6c62c6162a308913272447153b6a2e809Kenny Root return OpenSSLKey.getPublicKey((X509EncodedKeySpec) keySpec, NativeCrypto.EVP_PKEY_DSA); 47746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 48746a236e2be5dee62c482e27f4c682496d071d8bKenny Root throw new InvalidKeySpecException("Must use DSAPublicKeySpec or X509EncodedKeySpec; was " 49746a236e2be5dee62c482e27f4c682496d071d8bKenny Root + keySpec.getClass().getName()); 50746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 51746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 52746a236e2be5dee62c482e27f4c682496d071d8bKenny Root @Override 53746a236e2be5dee62c482e27f4c682496d071d8bKenny Root protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException { 547885a9c6c62c6162a308913272447153b6a2e809Kenny Root if (keySpec == null) { 557885a9c6c62c6162a308913272447153b6a2e809Kenny Root throw new InvalidKeySpecException("keySpec == null"); 567885a9c6c62c6162a308913272447153b6a2e809Kenny Root } 57746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 587885a9c6c62c6162a308913272447153b6a2e809Kenny Root if (keySpec instanceof DSAPrivateKeySpec) { 597885a9c6c62c6162a308913272447153b6a2e809Kenny Root return new OpenSSLDSAPrivateKey((DSAPrivateKeySpec) keySpec); 60746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } else if (keySpec instanceof PKCS8EncodedKeySpec) { 617885a9c6c62c6162a308913272447153b6a2e809Kenny Root return OpenSSLKey.getPrivateKey((PKCS8EncodedKeySpec) keySpec, 627885a9c6c62c6162a308913272447153b6a2e809Kenny Root NativeCrypto.EVP_PKEY_DSA); 63746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 648c4b6ac9b5a3346af8b474949c501fbb2d464c50Kenny Root throw new InvalidKeySpecException("Must use DSAPrivateKeySpec or PKCS8EncodedKeySpec; was " 65746a236e2be5dee62c482e27f4c682496d071d8bKenny Root + keySpec.getClass().getName()); 66746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 67746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 68746a236e2be5dee62c482e27f4c682496d071d8bKenny Root @Override 69746a236e2be5dee62c482e27f4c682496d071d8bKenny Root protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec) 70746a236e2be5dee62c482e27f4c682496d071d8bKenny Root throws InvalidKeySpecException { 71746a236e2be5dee62c482e27f4c682496d071d8bKenny Root if (key == null) { 72746a236e2be5dee62c482e27f4c682496d071d8bKenny Root throw new InvalidKeySpecException("key == null"); 73746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 74746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 75746a236e2be5dee62c482e27f4c682496d071d8bKenny Root if (keySpec == null) { 76746a236e2be5dee62c482e27f4c682496d071d8bKenny Root throw new InvalidKeySpecException("keySpec == null"); 77746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 78746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 797885a9c6c62c6162a308913272447153b6a2e809Kenny Root if (!"DSA".equals(key.getAlgorithm())) { 807885a9c6c62c6162a308913272447153b6a2e809Kenny Root throw new InvalidKeySpecException("Key must be a DSA key"); 817885a9c6c62c6162a308913272447153b6a2e809Kenny Root } 82746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 837885a9c6c62c6162a308913272447153b6a2e809Kenny Root if (key instanceof DSAPublicKey && DSAPublicKeySpec.class.isAssignableFrom(keySpec)) { 847885a9c6c62c6162a308913272447153b6a2e809Kenny Root DSAPublicKey dsaKey = (DSAPublicKey) key; 857885a9c6c62c6162a308913272447153b6a2e809Kenny Root DSAParams params = dsaKey.getParams(); 867885a9c6c62c6162a308913272447153b6a2e809Kenny Root return (T) new DSAPublicKeySpec(dsaKey.getY(), params.getP(), params.getQ(), 877885a9c6c62c6162a308913272447153b6a2e809Kenny Root params.getG()); 887885a9c6c62c6162a308913272447153b6a2e809Kenny Root } else if (key instanceof PublicKey && DSAPublicKeySpec.class.isAssignableFrom(keySpec)) { 897885a9c6c62c6162a308913272447153b6a2e809Kenny Root final byte[] encoded = key.getEncoded(); 907885a9c6c62c6162a308913272447153b6a2e809Kenny Root if (!"X.509".equals(key.getFormat()) || encoded == null) { 917885a9c6c62c6162a308913272447153b6a2e809Kenny Root throw new InvalidKeySpecException("Not a valid X.509 encoding"); 92746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 937885a9c6c62c6162a308913272447153b6a2e809Kenny Root DSAPublicKey dsaKey = 947885a9c6c62c6162a308913272447153b6a2e809Kenny Root (DSAPublicKey) engineGeneratePublic(new X509EncodedKeySpec(encoded)); 957885a9c6c62c6162a308913272447153b6a2e809Kenny Root DSAParams params = dsaKey.getParams(); 967885a9c6c62c6162a308913272447153b6a2e809Kenny Root return (T) new DSAPublicKeySpec(dsaKey.getY(), params.getP(), params.getQ(), 977885a9c6c62c6162a308913272447153b6a2e809Kenny Root params.getG()); 987885a9c6c62c6162a308913272447153b6a2e809Kenny Root } else if (key instanceof DSAPrivateKey 997885a9c6c62c6162a308913272447153b6a2e809Kenny Root && DSAPrivateKeySpec.class.isAssignableFrom(keySpec)) { 100746a236e2be5dee62c482e27f4c682496d071d8bKenny Root DSAPrivateKey dsaKey = (DSAPrivateKey) key; 1017885a9c6c62c6162a308913272447153b6a2e809Kenny Root DSAParams params = dsaKey.getParams(); 1027885a9c6c62c6162a308913272447153b6a2e809Kenny Root return (T) new DSAPrivateKeySpec(dsaKey.getX(), params.getP(), params.getQ(), 1037885a9c6c62c6162a308913272447153b6a2e809Kenny Root params.getG()); 1047885a9c6c62c6162a308913272447153b6a2e809Kenny Root } else if (key instanceof PrivateKey && DSAPrivateKeySpec.class.isAssignableFrom(keySpec)) { 1057885a9c6c62c6162a308913272447153b6a2e809Kenny Root final byte[] encoded = key.getEncoded(); 1067885a9c6c62c6162a308913272447153b6a2e809Kenny Root if (!"PKCS#8".equals(key.getFormat()) || encoded == null) { 1077885a9c6c62c6162a308913272447153b6a2e809Kenny Root throw new InvalidKeySpecException("Not a valid PKCS#8 encoding"); 1087885a9c6c62c6162a308913272447153b6a2e809Kenny Root } 1097885a9c6c62c6162a308913272447153b6a2e809Kenny Root DSAPrivateKey dsaKey = 1107885a9c6c62c6162a308913272447153b6a2e809Kenny Root (DSAPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded)); 1117885a9c6c62c6162a308913272447153b6a2e809Kenny Root DSAParams params = dsaKey.getParams(); 1127885a9c6c62c6162a308913272447153b6a2e809Kenny Root return (T) new DSAPrivateKeySpec(dsaKey.getX(), params.getP(), params.getQ(), 1137885a9c6c62c6162a308913272447153b6a2e809Kenny Root params.getG()); 1147885a9c6c62c6162a308913272447153b6a2e809Kenny Root } else if (key instanceof PrivateKey 1157885a9c6c62c6162a308913272447153b6a2e809Kenny Root && PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) { 1167885a9c6c62c6162a308913272447153b6a2e809Kenny Root final byte[] encoded = key.getEncoded(); 1177885a9c6c62c6162a308913272447153b6a2e809Kenny Root if (!"PKCS#8".equals(key.getFormat())) { 1187885a9c6c62c6162a308913272447153b6a2e809Kenny Root throw new InvalidKeySpecException("Encoding type must be PKCS#8; was " 1197885a9c6c62c6162a308913272447153b6a2e809Kenny Root + key.getFormat()); 1207885a9c6c62c6162a308913272447153b6a2e809Kenny Root } else if (encoded == null) { 1217885a9c6c62c6162a308913272447153b6a2e809Kenny Root throw new InvalidKeySpecException("Key is not encodable"); 1227885a9c6c62c6162a308913272447153b6a2e809Kenny Root } 1237885a9c6c62c6162a308913272447153b6a2e809Kenny Root return (T) new PKCS8EncodedKeySpec(encoded); 1247885a9c6c62c6162a308913272447153b6a2e809Kenny Root } else if (key instanceof PublicKey && X509EncodedKeySpec.class.isAssignableFrom(keySpec)) { 1257885a9c6c62c6162a308913272447153b6a2e809Kenny Root final byte[] encoded = key.getEncoded(); 1267885a9c6c62c6162a308913272447153b6a2e809Kenny Root if (!"X.509".equals(key.getFormat())) { 1277885a9c6c62c6162a308913272447153b6a2e809Kenny Root throw new InvalidKeySpecException("Encoding type must be X.509; was " 1287885a9c6c62c6162a308913272447153b6a2e809Kenny Root + key.getFormat()); 1297885a9c6c62c6162a308913272447153b6a2e809Kenny Root } else if (encoded == null) { 1307885a9c6c62c6162a308913272447153b6a2e809Kenny Root throw new InvalidKeySpecException("Key is not encodable"); 131746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 1327885a9c6c62c6162a308913272447153b6a2e809Kenny Root return (T) new X509EncodedKeySpec(encoded); 133746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } else { 1347885a9c6c62c6162a308913272447153b6a2e809Kenny Root throw new InvalidKeySpecException("Unsupported key type and key spec combination; key=" 1357885a9c6c62c6162a308913272447153b6a2e809Kenny Root + key.getClass().getName() + ", keySpec=" + keySpec.getName()); 136746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 137746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 138746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 139746a236e2be5dee62c482e27f4c682496d071d8bKenny Root @Override 140746a236e2be5dee62c482e27f4c682496d071d8bKenny Root protected Key engineTranslateKey(Key key) throws InvalidKeyException { 141746a236e2be5dee62c482e27f4c682496d071d8bKenny Root if (key == null) { 142746a236e2be5dee62c482e27f4c682496d071d8bKenny Root throw new InvalidKeyException("key == null"); 143746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 1443fb32505a22a01c95ff82435ac7f4d6da001c11cAlex Klyubin if ((key instanceof OpenSSLDSAPublicKey) || (key instanceof OpenSSLDSAPrivateKey)) { 1453fb32505a22a01c95ff82435ac7f4d6da001c11cAlex Klyubin return key; 1463fb32505a22a01c95ff82435ac7f4d6da001c11cAlex Klyubin } else if (key instanceof DSAPublicKey) { 147746a236e2be5dee62c482e27f4c682496d071d8bKenny Root DSAPublicKey dsaKey = (DSAPublicKey) key; 148746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 149746a236e2be5dee62c482e27f4c682496d071d8bKenny Root BigInteger y = dsaKey.getY(); 150746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 151746a236e2be5dee62c482e27f4c682496d071d8bKenny Root DSAParams params = dsaKey.getParams(); 152746a236e2be5dee62c482e27f4c682496d071d8bKenny Root BigInteger p = params.getP(); 153746a236e2be5dee62c482e27f4c682496d071d8bKenny Root BigInteger q = params.getQ(); 154746a236e2be5dee62c482e27f4c682496d071d8bKenny Root BigInteger g = params.getG(); 155746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 156746a236e2be5dee62c482e27f4c682496d071d8bKenny Root try { 157746a236e2be5dee62c482e27f4c682496d071d8bKenny Root return engineGeneratePublic(new DSAPublicKeySpec(y, p, q, g)); 158746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } catch (InvalidKeySpecException e) { 159746a236e2be5dee62c482e27f4c682496d071d8bKenny Root throw new InvalidKeyException(e); 160746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 161746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } else if (key instanceof DSAPrivateKey) { 162746a236e2be5dee62c482e27f4c682496d071d8bKenny Root DSAPrivateKey dsaKey = (DSAPrivateKey) key; 163746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 164746a236e2be5dee62c482e27f4c682496d071d8bKenny Root BigInteger x = dsaKey.getX(); 165746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 166746a236e2be5dee62c482e27f4c682496d071d8bKenny Root DSAParams params = dsaKey.getParams(); 167746a236e2be5dee62c482e27f4c682496d071d8bKenny Root BigInteger p = params.getP(); 168746a236e2be5dee62c482e27f4c682496d071d8bKenny Root BigInteger q = params.getQ(); 169746a236e2be5dee62c482e27f4c682496d071d8bKenny Root BigInteger g = params.getG(); 170746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 171746a236e2be5dee62c482e27f4c682496d071d8bKenny Root try { 1728c4b6ac9b5a3346af8b474949c501fbb2d464c50Kenny Root return engineGeneratePrivate(new DSAPrivateKeySpec(x, p, q, g)); 173746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } catch (InvalidKeySpecException e) { 174746a236e2be5dee62c482e27f4c682496d071d8bKenny Root throw new InvalidKeyException(e); 175746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 176ddee4ef28dcce942e25fd7a24f27239cd74807faAlex Klyubin } else if ((key instanceof PrivateKey) && ("PKCS#8".equals(key.getFormat()))) { 177ed7441ebfbc69821598a5bc060518b5c82ffb5c8Alex Klyubin byte[] encoded = key.getEncoded(); 178ed7441ebfbc69821598a5bc060518b5c82ffb5c8Alex Klyubin if (encoded == null) { 179ed7441ebfbc69821598a5bc060518b5c82ffb5c8Alex Klyubin throw new InvalidKeyException("Key does not support encoding"); 180ed7441ebfbc69821598a5bc060518b5c82ffb5c8Alex Klyubin } 1817885a9c6c62c6162a308913272447153b6a2e809Kenny Root try { 182ed7441ebfbc69821598a5bc060518b5c82ffb5c8Alex Klyubin return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded)); 1837885a9c6c62c6162a308913272447153b6a2e809Kenny Root } catch (InvalidKeySpecException e) { 1847885a9c6c62c6162a308913272447153b6a2e809Kenny Root throw new InvalidKeyException(e); 1857885a9c6c62c6162a308913272447153b6a2e809Kenny Root } 186ddee4ef28dcce942e25fd7a24f27239cd74807faAlex Klyubin } else if ((key instanceof PublicKey) && ("X.509".equals(key.getFormat()))) { 187ed7441ebfbc69821598a5bc060518b5c82ffb5c8Alex Klyubin byte[] encoded = key.getEncoded(); 188ed7441ebfbc69821598a5bc060518b5c82ffb5c8Alex Klyubin if (encoded == null) { 189ed7441ebfbc69821598a5bc060518b5c82ffb5c8Alex Klyubin throw new InvalidKeyException("Key does not support encoding"); 190ed7441ebfbc69821598a5bc060518b5c82ffb5c8Alex Klyubin } 1917885a9c6c62c6162a308913272447153b6a2e809Kenny Root try { 192ed7441ebfbc69821598a5bc060518b5c82ffb5c8Alex Klyubin return engineGeneratePublic(new X509EncodedKeySpec(encoded)); 1937885a9c6c62c6162a308913272447153b6a2e809Kenny Root } catch (InvalidKeySpecException e) { 1947885a9c6c62c6162a308913272447153b6a2e809Kenny Root throw new InvalidKeyException(e); 1957885a9c6c62c6162a308913272447153b6a2e809Kenny Root } 196746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } else { 1977885a9c6c62c6162a308913272447153b6a2e809Kenny Root throw new InvalidKeyException("Key must be DSA public or private key; was " 198a812f61dc1102c8089c1acd48c24b36829ce2482Kenny Root + key.getClass().getName()); 199746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 200746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 201746a236e2be5dee62c482e27f4c682496d071d8bKenny Root} 202