1 /*
   2  * Copyright (c) 2019, 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 package sun.security.ssl;
  26 
  27 import java.io.IOException;
  28 import java.math.BigInteger;
  29 import java.security.*;
  30 import java.security.interfaces.XECPublicKey;
  31 import java.security.spec.*;
  32 import sun.security.ssl.NamedGroup.NamedGroupType;
  33 import sun.security.util.*;
  34 
  35 /**
  36  * Specifics for XEC/XDH Keys/Exchanges
  37  */
  38 final class XDHKeyExchange {
  39 
  40     static final SSLKeyAgreementGenerator xdheKAGenerator
  41             = new XDHEKAGenerator();
  42 
  43     static final class XDHECredentials implements NamedGroupCredentials {
  44 
  45         final XECPublicKey popPublicKey;
  46         final NamedGroup namedGroup;
  47 
  48         XDHECredentials(XECPublicKey popPublicKey, NamedGroup namedGroup) {
  49             this.popPublicKey = popPublicKey;
  50             this.namedGroup = namedGroup;
  51         }
  52 
  53         @Override
  54         public PublicKey getPublicKey() {
  55             return popPublicKey;
  56         }
  57 
  58         @Override
  59         public NamedGroup getNamedGroup() {
  60             return namedGroup;
  61         }
  62 
  63         /**
  64          * Parse the encoded Point into the XDHECredentials using the
  65          * namedGroup.
  66          */
  67         static XDHECredentials valueOf(NamedGroup namedGroup,
  68                 byte[] encodedPoint) throws IOException,
  69                 GeneralSecurityException {
  70 
  71             if (namedGroup.type != NamedGroupType.NAMED_GROUP_XDH) {
  72                 throw new RuntimeException(
  73                         "Credentials decoding:  Not XDH named group");
  74             }
  75 
  76             if (encodedPoint == null || encodedPoint.length == 0) {
  77                 return null;
  78             }
  79 
  80             byte[] uBytes = encodedPoint.clone();
  81             Utilities.reverseBytes(uBytes);
  82             BigInteger u = new BigInteger(1, uBytes);
  83 
  84             XECPublicKeySpec xecPublicKeySpec = new XECPublicKeySpec(
  85                     new NamedParameterSpec(namedGroup.name), u);
  86             KeyFactory factory = KeyFactory.getInstance(namedGroup.algorithm);
  87             XECPublicKey publicKey = (XECPublicKey) factory.generatePublic(
  88                     xecPublicKeySpec);
  89 
  90             return new XDHECredentials(publicKey, namedGroup);
  91         }
  92     }
  93 
  94     static final class XDHEPossession implements NamedGroupPossession {
  95 
  96         final PrivateKey privateKey;
  97         final XECPublicKey publicKey;
  98         final NamedGroup namedGroup;
  99 
 100         XDHEPossession(NamedGroup namedGroup, SecureRandom random) {
 101             try {
 102                 KeyPairGenerator kpg
 103                         = KeyPairGenerator.getInstance(namedGroup.algorithm);
 104                 AlgorithmParameterSpec params = namedGroup.getParameterSpec();
 105                 kpg.initialize(params, random);
 106                 KeyPair kp = kpg.generateKeyPair();
 107                 privateKey = kp.getPrivate();
 108                 publicKey = (XECPublicKey) kp.getPublic();
 109             } catch (GeneralSecurityException e) {
 110                 throw new RuntimeException(
 111                         "Could not generate XDH keypair", e);
 112             }
 113 
 114             this.namedGroup = namedGroup;
 115         }
 116 
 117         @Override
 118         public byte[] encode() {
 119 
 120             byte[] uBytes = ECUtil.trimZeroes(publicKey.getU().toByteArray());
 121 
 122             int expLength;
 123             switch (namedGroup) {
 124                 case X25519:
 125                     expLength = 32;
 126                     break;
 127                 case X448:
 128                     expLength = 56;
 129                     break;
 130                 default:
 131                     throw new RuntimeException("Invalid XDH group");
 132             }
 133 
 134             if (uBytes.length > expLength) {
 135                 throw new RuntimeException("Encoded XDH key too large");
 136             }
 137 
 138             if (uBytes.length != expLength) {
 139                 byte[] tmp = new byte[expLength];
 140                 System.arraycopy(uBytes, 0, tmp,
 141                         expLength - uBytes.length, uBytes.length);
 142                 uBytes = tmp;
 143             }
 144 
 145             Utilities.reverseBytes(uBytes);
 146             return (uBytes);
 147         }
 148 
 149         @Override
 150         public PublicKey getPublicKey() {
 151             return publicKey;
 152         }
 153 
 154         @Override
 155         public NamedGroup getNamedGroup() {
 156             return namedGroup;
 157         }
 158 
 159         @Override
 160         public PrivateKey getPrivateKey() {
 161             return privateKey;
 162         }
 163     }
 164 
 165     private static final class XDHEKAGenerator
 166             implements SSLKeyAgreementGenerator {
 167 
 168         // Prevent instantiation of this class.
 169         private XDHEKAGenerator() {
 170             // blank
 171         }
 172 
 173         @Override
 174         public SSLKeyDerivation createKeyDerivation(
 175                 HandshakeContext context) throws IOException {
 176             XDHEPossession xdhePossession = null;
 177             XDHECredentials xdheCredentials = null;
 178             for (SSLPossession poss : context.handshakePossessions) {
 179                 if (!(poss instanceof XDHEPossession)) {
 180                     continue;
 181                 }
 182 
 183                 NamedGroup ng = ((XDHEPossession) poss).namedGroup;
 184                 for (SSLCredentials cred : context.handshakeCredentials) {
 185                     if (!(cred instanceof XDHECredentials)) {
 186                         continue;
 187                     }
 188                     if (ng.equals(((XDHECredentials) cred).namedGroup)) {
 189                         xdheCredentials = (XDHECredentials) cred;
 190                         break;
 191                     }
 192                 }
 193 
 194                 if (xdheCredentials != null) {
 195                     xdhePossession = (XDHEPossession) poss;
 196                     break;
 197                 }
 198             }
 199 
 200             if (xdhePossession == null || xdheCredentials == null) {
 201                 context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
 202                         "No sufficient XDHE key agreement "
 203                         + "parameters negotiated");
 204             }
 205 
 206             return new KAKeyDerivation("XDH", context,
 207                     xdhePossession.privateKey, xdheCredentials.popPublicKey);
 208         }
 209     }
 210 }