1 /* 2 * Copyright (c) 2018, 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.ssl; 27 28 import java.io.IOException; 29 import java.security.GeneralSecurityException; 30 import java.security.KeyFactory; 31 import java.security.KeyPair; 32 import java.security.KeyPairGenerator; 33 import java.security.PrivateKey; 34 import java.security.PublicKey; 35 import java.security.SecureRandom; 36 import java.security.interfaces.XECPublicKey; 37 import java.security.spec.*; 38 import sun.security.ssl.SupportedGroupsExtension.NamedGroup; 39 import sun.security.ssl.SupportedGroupsExtension.NamedGroupType; 40 import sun.security.util.ECUtil; 41 42 final class XDHKeyExchange { 43 static final SSLKeyAgreementGenerator xdheKAGenerator = 44 new XDHEKAGenerator(); 45 46 static final class XDHECredentials implements SSLKeyAgreementCredentials { 47 final XECPublicKey popPublicKey; 48 final NamedGroup namedGroup; 49 50 XDHECredentials(XECPublicKey popPublicKey, NamedGroup namedGroup) { 51 this.popPublicKey = popPublicKey; 52 this.namedGroup = namedGroup; 53 } 54 55 @Override 56 public PublicKey getPublicKey() { 57 return popPublicKey; 58 } 59 60 static XDHECredentials valueOf(NamedGroup namedGroup, 61 byte[] encodedPoint) throws IOException, GeneralSecurityException { 62 63 if (namedGroup.type != NamedGroupType.NAMED_GROUP_XDH) { 64 throw new RuntimeException( 65 "Credentials decoding: Not XDH named group"); 66 } 67 68 if (encodedPoint == null || encodedPoint.length == 0) { 69 return null; 70 } 71 72 NamedParameterSpec namedSpec = 73 new NamedParameterSpec(namedGroup.algorithm); 74 XECPublicKeySpec xecKeySpec = 75 ECUtil.decodeXecPublicKey(encodedPoint, namedSpec); 76 KeyFactory factory = JsseJce.getKeyFactory(namedGroup.algorithm); 77 78 XECPublicKey publicKey = 79 (XECPublicKey) factory.generatePublic(xecKeySpec); 80 return new XDHECredentials(publicKey, namedGroup); 81 } 82 } 83 84 static final class XDHEPossession implements SSLPossession { 85 final PrivateKey privateKey; 86 final XECPublicKey publicKey; 87 final NamedGroup namedGroup; 88 89 XDHEPossession(NamedGroup namedGroup, SecureRandom random) { 90 try { 91 KeyPairGenerator kpg = 92 JsseJce.getKeyPairGenerator(namedGroup.algorithm); 93 AlgorithmParameterSpec params = namedGroup.getParameterSpec(); 94 kpg.initialize(params, random); 95 KeyPair kp = kpg.generateKeyPair(); 96 privateKey = kp.getPrivate(); 97 publicKey = (XECPublicKey) kp.getPublic(); 98 } catch (GeneralSecurityException e) { 99 throw new RuntimeException( 100 "Could not generate XDH keypair", e); 101 } 102 103 this.namedGroup = namedGroup; 104 } 105 106 @Override 107 public byte[] encode() { 108 try { 109 return ECUtil.encodeXecPublicKey(publicKey.getU(), 110 publicKey.getParams()); 111 } catch (InvalidParameterSpecException ex) { 112 throw new RuntimeException(ex); 113 } 114 } 115 } 116 117 private static final 118 class XDHEKAGenerator implements SSLKeyAgreementGenerator { 119 // Prevent instantiation of this class. 120 private XDHEKAGenerator() { 121 // blank 122 } 123 124 @Override 125 public SSLKeyDerivation createKeyDerivation( 126 HandshakeContext context) throws IOException { 127 XDHEPossession xdhePossession = null; 128 XDHECredentials xdheCredentials = null; 129 for (SSLPossession poss : context.handshakePossessions) { 130 if (!(poss instanceof XDHEPossession)) { 131 continue; 132 } 133 134 NamedGroup ng = ((XDHEPossession) poss).namedGroup; 135 for (SSLCredentials cred : context.handshakeCredentials) { 136 if (!(cred instanceof XDHECredentials)) { 137 continue; 138 } 139 if (ng.equals(((XDHECredentials) cred).namedGroup)) { 140 xdheCredentials = (XDHECredentials) cred; 141 break; 142 } 143 } 144 145 if (xdheCredentials != null) { 146 xdhePossession = (XDHEPossession) poss; 147 break; 148 } 149 } 150 151 if (xdhePossession == null || xdheCredentials == null) { 152 context.conContext.fatal(Alert.HANDSHAKE_FAILURE, 153 "No sufficient XDHE key agreement parameters negotiated"); 154 } 155 156 return new KAKeyDerivation("XDH", context, 157 xdhePossession.privateKey, xdheCredentials.popPublicKey); 158 } 159 } 160 161 }