OpenSSLECKeyFactory.java revision 28a47ccf41ba39f227f0b075dd31cde42b7a5f49
1/*
2 * Copyright (C) 2013 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.apache.harmony.xnet.provider.jsse;
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.interfaces.ECPrivateKey;
26import java.security.interfaces.ECPublicKey;
27import java.security.spec.ECParameterSpec;
28import java.security.spec.ECPoint;
29import java.security.spec.ECPrivateKeySpec;
30import java.security.spec.ECPublicKeySpec;
31import java.security.spec.InvalidKeySpecException;
32import java.security.spec.KeySpec;
33import java.security.spec.PKCS8EncodedKeySpec;
34import java.security.spec.X509EncodedKeySpec;
35
36public class OpenSSLECKeyFactory 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 ECPublicKeySpec) {
45            return new OpenSSLECPublicKey((ECPublicKeySpec) keySpec);
46        } else if (keySpec instanceof X509EncodedKeySpec) {
47            return OpenSSLKey.getPublicKey((X509EncodedKeySpec) keySpec, NativeCrypto.EVP_PKEY_EC);
48        }
49        throw new InvalidKeySpecException("Must use ECPublicKeySpec 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 ECPrivateKeySpec) {
60            return new OpenSSLECPrivateKey((ECPrivateKeySpec) keySpec);
61        } else if (keySpec instanceof PKCS8EncodedKeySpec) {
62            return OpenSSLKey.getPrivateKey((PKCS8EncodedKeySpec) keySpec,
63                    NativeCrypto.EVP_PKEY_EC);
64        }
65        throw new InvalidKeySpecException("Must use ECPrivateKeySpec 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 (!"EC".equals(key.getAlgorithm())) {
81            throw new InvalidKeySpecException("Key must be an EC key");
82        }
83
84        if (key instanceof ECPublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
85            ECPublicKey ecKey = (ECPublicKey) key;
86            return (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
87        } else if (key instanceof PublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
88            final byte[] encoded = key.getEncoded();
89            if (!"X.509".equals(key.getFormat()) || encoded == null) {
90                throw new InvalidKeySpecException("Not a valid X.509 encoding");
91            }
92            ECPublicKey ecKey = (ECPublicKey) engineGeneratePublic(new X509EncodedKeySpec(encoded));
93            return (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
94        } else if (key instanceof ECPrivateKey
95                && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
96            ECPrivateKey ecKey = (ECPrivateKey) key;
97            return (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams());
98        } else if (key instanceof PrivateKey && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
99            final byte[] encoded = key.getEncoded();
100            if (!"PKCS#8".equals(key.getFormat()) || encoded == null) {
101                throw new InvalidKeySpecException("Not a valid PKCS#8 encoding");
102            }
103            ECPrivateKey ecKey =
104                    (ECPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
105            return (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams());
106        } else if (key instanceof PrivateKey
107                && PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {
108            final byte[] encoded = key.getEncoded();
109            if (!"PKCS#8".equals(key.getFormat())) {
110                throw new InvalidKeySpecException("Encoding type must be PKCS#8; was "
111                        + key.getFormat());
112            } else if (encoded == null) {
113                throw new InvalidKeySpecException("Key is not encodable");
114            }
115            return (T) new PKCS8EncodedKeySpec(encoded);
116        } else if (key instanceof PublicKey && X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {
117            final byte[] encoded = key.getEncoded();
118            if (!"X.509".equals(key.getFormat())) {
119                throw new InvalidKeySpecException("Encoding type must be X.509; was "
120                        + key.getFormat());
121            } else if (encoded == null) {
122                throw new InvalidKeySpecException("Key is not encodable");
123            }
124            return (T) new X509EncodedKeySpec(encoded);
125        } else {
126            throw new InvalidKeySpecException("Unsupported key type and key spec combination; key="
127                    + key.getClass().getName() + ", keySpec=" + keySpec.getName());
128        }
129    }
130
131    @Override
132    protected Key engineTranslateKey(Key key) throws InvalidKeyException {
133        if (key == null) {
134            throw new InvalidKeyException("key == null");
135        }
136
137        if (key instanceof ECPublicKey) {
138            ECPublicKey ecKey = (ECPublicKey) key;
139
140            ECPoint w = ecKey.getW();
141
142            ECParameterSpec params = ecKey.getParams();
143
144            try {
145                return engineGeneratePublic(new ECPublicKeySpec(w, params));
146            } catch (InvalidKeySpecException e) {
147                throw new InvalidKeyException(e);
148            }
149        } else if (key instanceof ECPrivateKey) {
150            ECPrivateKey ecKey = (ECPrivateKey) key;
151
152            BigInteger s = ecKey.getS();
153
154            ECParameterSpec params = ecKey.getParams();
155
156            try {
157                return engineGeneratePrivate(new ECPrivateKeySpec(s, params));
158            } catch (InvalidKeySpecException e) {
159                throw new InvalidKeyException(e);
160            }
161        } else if ((key instanceof PrivateKey) && ("PKCS#8".equals(key.getFormat()))) {
162            byte[] encoded = key.getEncoded();
163            if (encoded == null) {
164                throw new InvalidKeyException("Key does not support encoding");
165            }
166            try {
167                return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
168            } catch (InvalidKeySpecException e) {
169                throw new InvalidKeyException(e);
170            }
171        } else if ((key instanceof PublicKey) && ("X.509".equals(key.getFormat()))) {
172            byte[] encoded = key.getEncoded();
173            if (encoded == null) {
174                throw new InvalidKeyException("Key does not support encoding");
175            }
176            try {
177                return engineGeneratePublic(new X509EncodedKeySpec(encoded));
178            } catch (InvalidKeySpecException e) {
179                throw new InvalidKeyException(e);
180            }
181        } else {
182            throw new InvalidKeyException("Key must be EC public or private key; was "
183                    + key.getClass().getName());
184        }
185    }
186
187}
188