• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package org.conscrypt;
18 
19 import java.math.BigInteger;
20 import java.security.InvalidKeyException;
21 import java.security.Key;
22 import java.security.KeyFactorySpi;
23 import java.security.PrivateKey;
24 import java.security.PublicKey;
25 import java.security.interfaces.ECPrivateKey;
26 import java.security.interfaces.ECPublicKey;
27 import java.security.spec.ECParameterSpec;
28 import java.security.spec.ECPoint;
29 import java.security.spec.ECPrivateKeySpec;
30 import java.security.spec.ECPublicKeySpec;
31 import java.security.spec.InvalidKeySpecException;
32 import java.security.spec.KeySpec;
33 import java.security.spec.PKCS8EncodedKeySpec;
34 import java.security.spec.X509EncodedKeySpec;
35 
36 /**
37  * An implementation of a {@link KeyFactorySpi} for EC keys based on BoringSSL.
38  */
39 @Internal
40 public final class OpenSSLECKeyFactory extends KeyFactorySpi {
41 
OpenSSLECKeyFactory()42     public OpenSSLECKeyFactory() {}
43 
44     @Override
engineGeneratePublic(KeySpec keySpec)45     protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException {
46         if (keySpec == null) {
47             throw new InvalidKeySpecException("keySpec == null");
48         }
49 
50         if (keySpec instanceof ECPublicKeySpec) {
51             return new OpenSSLECPublicKey((ECPublicKeySpec) keySpec);
52         } else if (keySpec instanceof X509EncodedKeySpec) {
53             return OpenSSLKey.getPublicKey((X509EncodedKeySpec) keySpec, NativeConstants.EVP_PKEY_EC);
54         }
55         throw new InvalidKeySpecException("Must use ECPublicKeySpec or X509EncodedKeySpec; was "
56                 + keySpec.getClass().getName());
57     }
58 
59     @Override
engineGeneratePrivate(KeySpec keySpec)60     protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException {
61         if (keySpec == null) {
62             throw new InvalidKeySpecException("keySpec == null");
63         }
64 
65         if (keySpec instanceof ECPrivateKeySpec) {
66             return new OpenSSLECPrivateKey((ECPrivateKeySpec) keySpec);
67         } else if (keySpec instanceof PKCS8EncodedKeySpec) {
68             return OpenSSLKey.getPrivateKey((PKCS8EncodedKeySpec) keySpec,
69                     NativeConstants.EVP_PKEY_EC);
70         }
71         throw new InvalidKeySpecException("Must use ECPrivateKeySpec or PKCS8EncodedKeySpec; was "
72                 + keySpec.getClass().getName());
73     }
74 
75     @Override
engineGetKeySpec(Key key, Class<T> keySpec)76     protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
77             throws InvalidKeySpecException {
78         if (key == null) {
79             throw new InvalidKeySpecException("key == null");
80         }
81 
82         if (keySpec == null) {
83             throw new InvalidKeySpecException("keySpec == null");
84         }
85 
86         if (!"EC".equals(key.getAlgorithm())) {
87             throw new InvalidKeySpecException("Key must be an EC key");
88         }
89 
90         if (key instanceof ECPublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
91             ECPublicKey ecKey = (ECPublicKey) key;
92             @SuppressWarnings("unchecked")
93             T result = (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
94             return result;
95         } else if (key instanceof PublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
96             final byte[] encoded = key.getEncoded();
97             if (!"X.509".equals(key.getFormat()) || encoded == null) {
98                 throw new InvalidKeySpecException("Not a valid X.509 encoding");
99             }
100             ECPublicKey ecKey = (ECPublicKey) engineGeneratePublic(new X509EncodedKeySpec(encoded));
101             @SuppressWarnings("unchecked")
102             T result = (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
103             return result;
104         } else if (key instanceof ECPrivateKey
105                 && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
106             ECPrivateKey ecKey = (ECPrivateKey) key;
107             @SuppressWarnings("unchecked")
108             T result = (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams());
109             return result;
110         } else if (key instanceof PrivateKey && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
111             final byte[] encoded = key.getEncoded();
112             if (!"PKCS#8".equals(key.getFormat()) || encoded == null) {
113                 throw new InvalidKeySpecException("Not a valid PKCS#8 encoding");
114             }
115             ECPrivateKey ecKey =
116                     (ECPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
117             @SuppressWarnings("unchecked")
118             T result = (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams());
119             return result;
120         } else if (key instanceof PrivateKey
121                 && PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {
122             final byte[] encoded = key.getEncoded();
123             if (!"PKCS#8".equals(key.getFormat())) {
124                 throw new InvalidKeySpecException("Encoding type must be PKCS#8; was "
125                         + key.getFormat());
126             } else if (encoded == null) {
127                 throw new InvalidKeySpecException("Key is not encodable");
128             }
129             @SuppressWarnings("unchecked") T result = (T) new PKCS8EncodedKeySpec(encoded);
130             return result;
131         } else if (key instanceof PublicKey && X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {
132             final byte[] encoded = key.getEncoded();
133             if (!"X.509".equals(key.getFormat())) {
134                 throw new InvalidKeySpecException("Encoding type must be X.509; was "
135                         + key.getFormat());
136             } else if (encoded == null) {
137                 throw new InvalidKeySpecException("Key is not encodable");
138             }
139             @SuppressWarnings("unchecked") T result = (T) new X509EncodedKeySpec(encoded);
140             return result;
141         } else {
142             throw new InvalidKeySpecException("Unsupported key type and key spec combination; key="
143                     + key.getClass().getName() + ", keySpec=" + keySpec.getName());
144         }
145     }
146 
147     @Override
engineTranslateKey(Key key)148     protected Key engineTranslateKey(Key key) throws InvalidKeyException {
149         if (key == null) {
150             throw new InvalidKeyException("key == null");
151         }
152         if ((key instanceof OpenSSLECPublicKey) || (key instanceof OpenSSLECPrivateKey)) {
153             return key;
154         } else if (key instanceof ECPublicKey) {
155             ECPublicKey ecKey = (ECPublicKey) key;
156 
157             ECPoint w = ecKey.getW();
158 
159             ECParameterSpec params = ecKey.getParams();
160 
161             try {
162                 return engineGeneratePublic(new ECPublicKeySpec(w, params));
163             } catch (InvalidKeySpecException e) {
164                 throw new InvalidKeyException(e);
165             }
166         } else if (key instanceof ECPrivateKey) {
167             ECPrivateKey ecKey = (ECPrivateKey) key;
168 
169             BigInteger s = ecKey.getS();
170 
171             ECParameterSpec params = ecKey.getParams();
172 
173             try {
174                 return engineGeneratePrivate(new ECPrivateKeySpec(s, params));
175             } catch (InvalidKeySpecException e) {
176                 throw new InvalidKeyException(e);
177             }
178         } else if ((key instanceof PrivateKey) && "PKCS#8".equals(key.getFormat())) {
179             byte[] encoded = key.getEncoded();
180             if (encoded == null) {
181                 throw new InvalidKeyException("Key does not support encoding");
182             }
183             try {
184                 return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded));
185             } catch (InvalidKeySpecException e) {
186                 throw new InvalidKeyException(e);
187             }
188         } else if ((key instanceof PublicKey) && "X.509".equals(key.getFormat())) {
189             byte[] encoded = key.getEncoded();
190             if (encoded == null) {
191                 throw new InvalidKeyException("Key does not support encoding");
192             }
193             try {
194                 return engineGeneratePublic(new X509EncodedKeySpec(encoded));
195             } catch (InvalidKeySpecException e) {
196                 throw new InvalidKeyException(e);
197             }
198         } else {
199             throw new InvalidKeyException("Key must be EC public or private key; was "
200                     + key.getClass().getName());
201         }
202     }
203 }
204