1 /*
2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.security.ec.ed;
27 
28 import java.security.KeyFactorySpi;
29 import java.security.Key;
30 import java.security.PublicKey;
31 import java.security.PrivateKey;
32 import java.security.InvalidKeyException;
33 import java.security.ProviderException;
34 import java.security.interfaces.*;
35 import java.security.spec.*;
36 import java.util.function.Function;
37 
38 public class EdDSAKeyFactory extends KeyFactorySpi {
39 
40     private EdDSAParameters lockedParams = null;
41 
EdDSAKeyFactory()42     public EdDSAKeyFactory() {
43         // do nothing
44     }
45 
EdDSAKeyFactory(NamedParameterSpec paramSpec)46     protected EdDSAKeyFactory(NamedParameterSpec paramSpec) {
47         lockedParams = EdDSAParameters.get(ProviderException::new, paramSpec);
48     }
49 
50     @Override
engineTranslateKey(Key key)51     protected Key engineTranslateKey(Key key) throws InvalidKeyException {
52 
53         if (key == null) {
54             throw new InvalidKeyException("Key must not be null");
55         }
56 
57         if (key instanceof EdECKey) {
58             EdECKey edKey = (EdECKey) key;
59             EdDSAParameters params = EdDSAParameters.get(
60                 InvalidKeyException::new, edKey.getParams());
61             checkLockedParams(InvalidKeyException::new, params);
62 
63             if (edKey instanceof EdECPublicKey) {
64                 EdECPublicKey publicKey = (EdECPublicKey) edKey;
65                 return new EdDSAPublicKeyImpl(params, publicKey.getPoint());
66             } else if (edKey instanceof EdECPrivateKey) {
67                 EdECPrivateKey privateKey = (EdECPrivateKey) edKey;
68                 byte[] privateKeyBytes = privateKey.getBytes().orElseThrow(
69                     () -> new InvalidKeyException("No private key data"));
70                 return new EdDSAPrivateKeyImpl(params, privateKeyBytes);
71             } else {
72                 throw new InvalidKeyException("Unsupported EdECKey subclass");
73             }
74         } else if (key instanceof PublicKey &&
75                    key.getFormat().equals("X.509")) {
76             EdDSAPublicKeyImpl result =
77                 new EdDSAPublicKeyImpl(key.getEncoded());
78             checkLockedParams(InvalidKeyException::new, result.getParams());
79             return result;
80         } else if (key instanceof PrivateKey &&
81                    key.getFormat().equals("PKCS#8")) {
82             EdDSAPrivateKeyImpl result =
83                 new EdDSAPrivateKeyImpl(key.getEncoded());
84             checkLockedParams(InvalidKeyException::new, result.getParams());
85             return result;
86         } else {
87             throw new InvalidKeyException("Unsupported key type or format");
88         }
89     }
90 
91     private
92     <T extends Throwable>
checkLockedParams(Function<String, T> exception, NamedParameterSpec spec)93     void checkLockedParams(Function<String, T> exception,
94                            NamedParameterSpec spec) throws T {
95 
96         EdDSAParameters params = EdDSAParameters.get(exception, spec);
97         checkLockedParams(exception, params);
98     }
99 
100     private
101     <T extends Throwable>
checkLockedParams(Function<String, T> exception, EdDSAParameters params)102     void checkLockedParams(Function<String, T> exception,
103                            EdDSAParameters params) throws T {
104 
105         if (lockedParams != null && lockedParams != params) {
106             throw exception.apply("Parameters must be " +
107                 lockedParams.getName());
108         }
109     }
110 
111     @Override
engineGeneratePublic(KeySpec keySpec)112     protected PublicKey engineGeneratePublic(KeySpec keySpec)
113         throws InvalidKeySpecException {
114 
115         try {
116              return generatePublicImpl(keySpec);
117         } catch (InvalidKeyException ex) {
118             throw new InvalidKeySpecException(ex);
119         }
120     }
121 
122     @Override
engineGeneratePrivate(KeySpec keySpec)123     protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
124         throws InvalidKeySpecException {
125 
126         try {
127             return generatePrivateImpl(keySpec);
128         } catch (InvalidKeyException ex) {
129             throw new InvalidKeySpecException(ex);
130         }
131     }
132 
133 
generatePublicImpl(KeySpec keySpec)134     private PublicKey generatePublicImpl(KeySpec keySpec)
135         throws InvalidKeyException, InvalidKeySpecException {
136 
137         if (keySpec instanceof X509EncodedKeySpec) {
138             X509EncodedKeySpec x509Spec = (X509EncodedKeySpec) keySpec;
139             EdDSAPublicKeyImpl result =
140                 new EdDSAPublicKeyImpl(x509Spec.getEncoded());
141             checkLockedParams(InvalidKeySpecException::new,
142                 result.getParams());
143             return result;
144         } else if (keySpec instanceof EdECPublicKeySpec) {
145             EdECPublicKeySpec publicKeySpec = (EdECPublicKeySpec) keySpec;
146             EdDSAParameters params = EdDSAParameters.get(
147                 InvalidKeySpecException::new, publicKeySpec.getParams());
148             checkLockedParams(InvalidKeySpecException::new, params);
149             return new EdDSAPublicKeyImpl(params, publicKeySpec.getPoint());
150         } else {
151             throw new InvalidKeySpecException(
152                 "Only X509EncodedKeySpec and EdECPublicKeySpec are supported");
153         }
154     }
155 
generatePrivateImpl(KeySpec keySpec)156     private PrivateKey generatePrivateImpl(KeySpec keySpec)
157         throws InvalidKeyException, InvalidKeySpecException {
158 
159         if (keySpec instanceof PKCS8EncodedKeySpec) {
160             PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec) keySpec;
161             EdDSAPrivateKeyImpl result =
162                 new EdDSAPrivateKeyImpl(pkcsSpec.getEncoded());
163             checkLockedParams(InvalidKeySpecException::new,
164                 result.getParams());
165             return result;
166         } else if (keySpec instanceof EdECPrivateKeySpec) {
167             EdECPrivateKeySpec privateKeySpec = (EdECPrivateKeySpec) keySpec;
168             EdDSAParameters params = EdDSAParameters.get(
169                 InvalidKeySpecException::new, privateKeySpec.getParams());
170             checkLockedParams(InvalidKeySpecException::new, params);
171             return new EdDSAPrivateKeyImpl(params, privateKeySpec.getBytes());
172         } else {
173             throw new InvalidKeySpecException(
174                 "Only PKCS8EncodedKeySpec and EdECPrivateKeySpec supported");
175         }
176     }
177 
engineGetKeySpec(Key key, Class<T> keySpec)178     protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
179             throws InvalidKeySpecException {
180 
181         if (key instanceof EdECPublicKey) {
182             checkLockedParams(InvalidKeySpecException::new,
183                 ((EdECPublicKey) key).getParams());
184 
185             if (X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {
186                 if (!key.getFormat().equals("X.509")) {
187                     throw new InvalidKeySpecException("Format is not X.509");
188                 }
189                 return keySpec.cast(new X509EncodedKeySpec(key.getEncoded()));
190             } else if (EdECPublicKeySpec.class.isAssignableFrom(keySpec)) {
191                 EdECPublicKey edKey = (EdECPublicKey) key;
192                 return keySpec.cast(
193                     new EdECPublicKeySpec(edKey.getParams(), edKey.getPoint()));
194             } else {
195                 throw new InvalidKeySpecException(
196                     "KeySpec must be X509EncodedKeySpec or EdECPublicKeySpec");
197             }
198         } else if (key instanceof EdECPrivateKey) {
199             checkLockedParams(InvalidKeySpecException::new,
200                 ((EdECPrivateKey) key).getParams());
201 
202             if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {
203                 if (!key.getFormat().equals("PKCS#8")) {
204                     throw new InvalidKeySpecException("Format is not PKCS#8");
205                 }
206                 return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));
207             } else if (EdECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
208                 EdECPrivateKey edKey = (EdECPrivateKey) key;
209                 byte[] scalar = edKey.getBytes().orElseThrow(
210                     () -> new InvalidKeySpecException("No private key value")
211                 );
212                 return keySpec.cast(
213                     new EdECPrivateKeySpec(edKey.getParams(), scalar));
214             } else {
215                 throw new InvalidKeySpecException
216                 ("KeySpec must be PKCS8EncodedKeySpec or EdECPrivateKeySpec");
217             }
218         } else {
219             throw new InvalidKeySpecException("Unsupported key type");
220         }
221     }
222 
223     public static class Ed25519 extends EdDSAKeyFactory {
224 
Ed25519()225         public Ed25519() {
226             super(NamedParameterSpec.ED25519);
227         }
228     }
229 
230     public static class Ed448 extends EdDSAKeyFactory {
231 
Ed448()232         public Ed448() {
233             super(NamedParameterSpec.ED448);
234         }
235     }
236 }
237