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 }