111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root/*
211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * Copyright (C) 2013 The Android Open Source Project
311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root *
411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * Licensed under the Apache License, Version 2.0 (the "License");
511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * you may not use this file except in compliance with the License.
611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * You may obtain a copy of the License at
711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root *
811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root *      http://www.apache.org/licenses/LICENSE-2.0
911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root *
1011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * Unless required by applicable law or agreed to in writing, software
1111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * distributed under the License is distributed on an "AS IS" BASIS,
1211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * See the License for the specific language governing permissions and
1411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * limitations under the License.
1511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root */
1611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt;
1811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
1911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.math.BigInteger;
2011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.InvalidKeyException;
2111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.Key;
2211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.KeyFactorySpi;
2311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.PrivateKey;
2411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.PublicKey;
2511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.interfaces.ECPrivateKey;
2611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.interfaces.ECPublicKey;
2711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.ECParameterSpec;
2811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.ECPoint;
2911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.ECPrivateKeySpec;
3011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.ECPublicKeySpec;
3111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.InvalidKeySpecException;
3211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.KeySpec;
3311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.PKCS8EncodedKeySpec;
3411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.X509EncodedKeySpec;
3511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
365070bdfc6277af136b7eb5fe5d0d72ad2ff6a2ebKenny Root/**
3729916ef38dc9cb4e4c6e3fdb87d4e921546d3ef4Nathan Mittler * An implementation of a {@link KeyFactorySpi} for EC keys based on BoringSSL.
385070bdfc6277af136b7eb5fe5d0d72ad2ff6a2ebKenny Root *
395070bdfc6277af136b7eb5fe5d0d72ad2ff6a2ebKenny Root * @hide
405070bdfc6277af136b7eb5fe5d0d72ad2ff6a2ebKenny Root */
41dbe082cb70a1ffbe1a693bd583a06ecad585f46dNathan Mittler@Internal
4229916ef38dc9cb4e4c6e3fdb87d4e921546d3ef4Nathan Mittlerpublic final class OpenSSLECKeyFactory extends KeyFactorySpi {
4311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
4411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root    @Override
4511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root    protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException {
46d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root        if (keySpec == null) {
47d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            throw new InvalidKeySpecException("keySpec == null");
48d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root        }
4911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
50d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root        if (keySpec instanceof ECPublicKeySpec) {
51d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            return new OpenSSLECPublicKey((ECPublicKeySpec) keySpec);
5211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        } else if (keySpec instanceof X509EncodedKeySpec) {
53f79c90d56464e254ce8645f886ec0ca47573ced1Adam Langley            return OpenSSLKey.getPublicKey((X509EncodedKeySpec) keySpec, NativeConstants.EVP_PKEY_EC);
5411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        }
5511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        throw new InvalidKeySpecException("Must use ECPublicKeySpec or X509EncodedKeySpec; was "
5611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root                + keySpec.getClass().getName());
5711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root    }
5811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
5911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root    @Override
6011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root    protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException {
61d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root        if (keySpec == null) {
62d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            throw new InvalidKeySpecException("keySpec == null");
63d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root        }
6411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
65d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root        if (keySpec instanceof ECPrivateKeySpec) {
66d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            return new OpenSSLECPrivateKey((ECPrivateKeySpec) keySpec);
6711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        } else if (keySpec instanceof PKCS8EncodedKeySpec) {
68d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            return OpenSSLKey.getPrivateKey((PKCS8EncodedKeySpec) keySpec,
69f79c90d56464e254ce8645f886ec0ca47573ced1Adam Langley                    NativeConstants.EVP_PKEY_EC);
7011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        }
719414cebabcf332fcca1f40fa629cc471cfbbc21cKenny Root        throw new InvalidKeySpecException("Must use ECPrivateKeySpec or PKCS8EncodedKeySpec; was "
7211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root                + keySpec.getClass().getName());
7311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root    }
7411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
7511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root    @Override
7611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root    protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
7711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            throws InvalidKeySpecException {
7811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        if (key == null) {
7911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            throw new InvalidKeySpecException("key == null");
8011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        }
8111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
8211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        if (keySpec == null) {
8311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            throw new InvalidKeySpecException("keySpec == null");
8411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        }
8511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
86d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root        if (!"EC".equals(key.getAlgorithm())) {
87d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            throw new InvalidKeySpecException("Key must be an EC key");
88d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root        }
8911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
90d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root        if (key instanceof ECPublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
91d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            ECPublicKey ecKey = (ECPublicKey) key;
92d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            @SuppressWarnings("unchecked")
93d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            T result = (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
94d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            return result;
95d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root        } else if (key instanceof PublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
96d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            final byte[] encoded = key.getEncoded();
97d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            if (!"X.509".equals(key.getFormat()) || encoded == null) {
98d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root                throw new InvalidKeySpecException("Not a valid X.509 encoding");
9911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            }
100d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            ECPublicKey ecKey = (ECPublicKey) engineGeneratePublic(new X509EncodedKeySpec(encoded));
101d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            @SuppressWarnings("unchecked")
102d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            T result = (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
103d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            return result;
104d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root        } else if (key instanceof ECPrivateKey
105d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root                && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
10611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            ECPrivateKey ecKey = (ECPrivateKey) key;
107d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            @SuppressWarnings("unchecked")
108d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            T result = (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams());
109d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            return result;
110d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root        } else if (key instanceof PrivateKey && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
111d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            final byte[] encoded = key.getEncoded();
112d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            if (!"PKCS#8".equals(key.getFormat()) || encoded == null) {
113d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root                throw new InvalidKeySpecException("Not a valid PKCS#8 encoding");
114d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            }
115d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            ECPrivateKey ecKey =
116d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root                    (ECPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
117d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            @SuppressWarnings("unchecked")
118d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            T result = (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams());
119d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            return result;
120d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root        } else if (key instanceof PrivateKey
121d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root                && PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {
122d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            final byte[] encoded = key.getEncoded();
123d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            if (!"PKCS#8".equals(key.getFormat())) {
124d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root                throw new InvalidKeySpecException("Encoding type must be PKCS#8; was "
125d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root                        + key.getFormat());
126d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            } else if (encoded == null) {
127d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root                throw new InvalidKeySpecException("Key is not encodable");
128d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            }
129d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            @SuppressWarnings("unchecked") T result = (T) new PKCS8EncodedKeySpec(encoded);
130d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            return result;
131d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root        } else if (key instanceof PublicKey && X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {
132d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            final byte[] encoded = key.getEncoded();
133d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            if (!"X.509".equals(key.getFormat())) {
134d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root                throw new InvalidKeySpecException("Encoding type must be X.509; was "
135d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root                        + key.getFormat());
136d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            } else if (encoded == null) {
137d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root                throw new InvalidKeySpecException("Key is not encodable");
13811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            }
139d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            @SuppressWarnings("unchecked") T result = (T) new X509EncodedKeySpec(encoded);
140d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root            return result;
14111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        } else {
142d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            throw new InvalidKeySpecException("Unsupported key type and key spec combination; key="
143d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root                    + key.getClass().getName() + ", keySpec=" + keySpec.getName());
14411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        }
14511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root    }
14611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
14711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root    @Override
14811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root    protected Key engineTranslateKey(Key key) throws InvalidKeyException {
14911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        if (key == null) {
15011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            throw new InvalidKeyException("key == null");
15111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        }
1520c1d455738a5d4b054b85d72d2c9f216b4f57291Alex Klyubin        if ((key instanceof OpenSSLECPublicKey) || (key instanceof OpenSSLECPrivateKey)) {
1530c1d455738a5d4b054b85d72d2c9f216b4f57291Alex Klyubin            return key;
1540c1d455738a5d4b054b85d72d2c9f216b4f57291Alex Klyubin        } else if (key instanceof ECPublicKey) {
15511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            ECPublicKey ecKey = (ECPublicKey) key;
15611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
15711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            ECPoint w = ecKey.getW();
15811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
15911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            ECParameterSpec params = ecKey.getParams();
16011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
16111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            try {
16211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root                return engineGeneratePublic(new ECPublicKeySpec(w, params));
16311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            } catch (InvalidKeySpecException e) {
16411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root                throw new InvalidKeyException(e);
16511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            }
16611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        } else if (key instanceof ECPrivateKey) {
16711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            ECPrivateKey ecKey = (ECPrivateKey) key;
16811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
16911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            BigInteger s = ecKey.getS();
17011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
17111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            ECParameterSpec params = ecKey.getParams();
17211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root
17311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            try {
1749414cebabcf332fcca1f40fa629cc471cfbbc21cKenny Root                return engineGeneratePrivate(new ECPrivateKeySpec(s, params));
17511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            } catch (InvalidKeySpecException e) {
17611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root                throw new InvalidKeyException(e);
17711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root            }
178724f18f3f9fdc2501bc21d05959f7bb774b7774dAlex Klyubin        } else if ((key instanceof PrivateKey) && ("PKCS#8".equals(key.getFormat()))) {
1791d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin            byte[] encoded = key.getEncoded();
1801d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin            if (encoded == null) {
1811d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin                throw new InvalidKeyException("Key does not support encoding");
1821d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin            }
183d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            try {
1841d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin                return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
185d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            } catch (InvalidKeySpecException e) {
186d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root                throw new InvalidKeyException(e);
187d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            }
188724f18f3f9fdc2501bc21d05959f7bb774b7774dAlex Klyubin        } else if ((key instanceof PublicKey) && ("X.509".equals(key.getFormat()))) {
1891d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin            byte[] encoded = key.getEncoded();
1901d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin            if (encoded == null) {
1911d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin                throw new InvalidKeyException("Key does not support encoding");
1921d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin            }
193d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            try {
1941d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin                return engineGeneratePublic(new X509EncodedKeySpec(encoded));
195d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            } catch (InvalidKeySpecException e) {
196d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root                throw new InvalidKeyException(e);
197d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            }
19811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        } else {
199d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root            throw new InvalidKeyException("Key must be EC public or private key; was "
200cb4e73b4fffb5c5608f320f0af1004ebcfad71c0Kenny Root                    + key.getClass().getName());
20111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root        }
20211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root    }
20311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root}
204