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