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