src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java
branchdatagramsocketimpl-branch
changeset 58678 9cf78a70fa4f
parent 54417 f87041131515
child 58679 9c3209ff7550
equal deleted inserted replaced
58677:13588c901957 58678:9cf78a70fa4f
    34 import java.security.KeyPairGenerator;
    34 import java.security.KeyPairGenerator;
    35 import java.security.PrivateKey;
    35 import java.security.PrivateKey;
    36 import java.security.PublicKey;
    36 import java.security.PublicKey;
    37 import java.security.SecureRandom;
    37 import java.security.SecureRandom;
    38 import java.security.interfaces.ECPublicKey;
    38 import java.security.interfaces.ECPublicKey;
    39 import java.security.spec.AlgorithmParameterSpec;
       
    40 import java.security.spec.ECGenParameterSpec;
       
    41 import java.security.spec.ECParameterSpec;
    39 import java.security.spec.ECParameterSpec;
    42 import java.security.spec.ECPoint;
    40 import java.security.spec.ECPoint;
    43 import java.security.spec.ECPublicKeySpec;
    41 import java.security.spec.ECPublicKeySpec;
    44 import java.util.EnumSet;
    42 import java.util.EnumSet;
    45 import javax.crypto.KeyAgreement;
    43 import javax.crypto.KeyAgreement;
    46 import javax.crypto.SecretKey;
    44 import javax.crypto.SecretKey;
    47 import javax.crypto.spec.SecretKeySpec;
       
    48 import javax.net.ssl.SSLHandshakeException;
    45 import javax.net.ssl.SSLHandshakeException;
    49 import sun.security.ssl.CipherSuite.HashAlg;
    46 import sun.security.ssl.NamedGroup.NamedGroupSpec;
    50 import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
       
    51 import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
       
    52 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
    47 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
    53 import sun.security.ssl.X509Authentication.X509Credentials;
    48 import sun.security.ssl.X509Authentication.X509Credentials;
    54 import sun.security.ssl.X509Authentication.X509Possession;
    49 import sun.security.ssl.X509Authentication.X509Possession;
       
    50 import sun.security.ssl.XDHKeyExchange.XDHECredentials;
       
    51 import sun.security.ssl.XDHKeyExchange.XDHEPossession;
    55 import sun.security.util.ECUtil;
    52 import sun.security.util.ECUtil;
    56 
    53 
    57 final class ECDHKeyExchange {
    54 final class ECDHKeyExchange {
    58     static final SSLPossessionGenerator poGenerator =
    55     static final SSLPossessionGenerator poGenerator =
    59             new ECDHEPossessionGenerator();
    56             new ECDHEPossessionGenerator();
       
    57     static final SSLKeyAgreementGenerator ecdhKAGenerator =
       
    58             new ECDHKAGenerator();
       
    59 
       
    60     // TLSv1.3
    60     static final SSLKeyAgreementGenerator ecdheKAGenerator =
    61     static final SSLKeyAgreementGenerator ecdheKAGenerator =
    61             new ECDHEKAGenerator();
    62             new ECDHEKAGenerator();
    62     static final SSLKeyAgreementGenerator ecdhKAGenerator =
    63 
    63             new ECDHKAGenerator();
    64     // TLSv1-1.2, the KA gets more difficult with EC/XEC keys
    64 
    65     static final SSLKeyAgreementGenerator ecdheXdhKAGenerator =
    65     static final class ECDHECredentials implements SSLCredentials {
    66             new ECDHEXDHKAGenerator();
       
    67 
       
    68     static final class ECDHECredentials implements NamedGroupCredentials {
    66         final ECPublicKey popPublicKey;
    69         final ECPublicKey popPublicKey;
    67         final NamedGroup namedGroup;
    70         final NamedGroup namedGroup;
    68 
    71 
    69         ECDHECredentials(ECPublicKey popPublicKey, NamedGroup namedGroup) {
    72         ECDHECredentials(ECPublicKey popPublicKey, NamedGroup namedGroup) {
    70             this.popPublicKey = popPublicKey;
    73             this.popPublicKey = popPublicKey;
    71             this.namedGroup = namedGroup;
    74             this.namedGroup = namedGroup;
    72         }
    75         }
    73 
    76 
       
    77         @Override
       
    78         public PublicKey getPublicKey() {
       
    79             return popPublicKey;
       
    80         }
       
    81 
       
    82         @Override
       
    83         public NamedGroup getNamedGroup() {
       
    84             return namedGroup;
       
    85         }
       
    86 
    74         static ECDHECredentials valueOf(NamedGroup namedGroup,
    87         static ECDHECredentials valueOf(NamedGroup namedGroup,
    75             byte[] encodedPoint) throws IOException, GeneralSecurityException {
    88             byte[] encodedPoint) throws IOException, GeneralSecurityException {
    76 
    89 
    77             if (namedGroup.type != NamedGroupType.NAMED_GROUP_ECDHE) {
    90             if (namedGroup.spec != NamedGroupSpec.NAMED_GROUP_ECDHE) {
    78                 throw new RuntimeException(
    91                 throw new RuntimeException(
    79                     "Credentials decoding:  Not ECDHE named group");
    92                     "Credentials decoding:  Not ECDHE named group");
    80             }
    93             }
    81 
    94 
    82             if (encodedPoint == null || encodedPoint.length == 0) {
    95             if (encodedPoint == null || encodedPoint.length == 0) {
    83                 return null;
    96                 return null;
    84             }
    97             }
    85 
    98 
    86             ECParameterSpec parameters =
    99             ECParameterSpec parameters =
    87                     ECUtil.getECParameterSpec(null, namedGroup.oid);
   100                     (ECParameterSpec)namedGroup.keAlgParamSpec;
    88             if (parameters == null) {
       
    89                 return null;
       
    90             }
       
    91 
       
    92             ECPoint point = ECUtil.decodePoint(
   101             ECPoint point = ECUtil.decodePoint(
    93                     encodedPoint, parameters.getCurve());
   102                     encodedPoint, parameters.getCurve());
    94             KeyFactory factory = KeyFactory.getInstance("EC");
   103             KeyFactory factory = KeyFactory.getInstance("EC");
    95             ECPublicKey publicKey = (ECPublicKey)factory.generatePublic(
   104             ECPublicKey publicKey = (ECPublicKey)factory.generatePublic(
    96                     new ECPublicKeySpec(point, parameters));
   105                     new ECPublicKeySpec(point, parameters));
    97             return new ECDHECredentials(publicKey, namedGroup);
   106             return new ECDHECredentials(publicKey, namedGroup);
    98         }
   107         }
    99     }
   108     }
   100 
   109 
   101     static final class ECDHEPossession implements SSLPossession {
   110     static final class ECDHEPossession implements NamedGroupPossession {
   102         final PrivateKey privateKey;
   111         final PrivateKey privateKey;
   103         final ECPublicKey publicKey;
   112         final ECPublicKey publicKey;
   104         final NamedGroup namedGroup;
   113         final NamedGroup namedGroup;
   105 
   114 
   106         ECDHEPossession(NamedGroup namedGroup, SecureRandom random) {
   115         ECDHEPossession(NamedGroup namedGroup, SecureRandom random) {
   107             try {
   116             try {
   108                 KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
   117                 KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
   109                 ECGenParameterSpec params =
   118                 kpg.initialize(namedGroup.keAlgParamSpec, random);
   110                         (ECGenParameterSpec)namedGroup.getParameterSpec();
       
   111                 kpg.initialize(params, random);
       
   112                 KeyPair kp = kpg.generateKeyPair();
   119                 KeyPair kp = kpg.generateKeyPair();
   113                 privateKey = kp.getPrivate();
   120                 privateKey = kp.getPrivate();
   114                 publicKey = (ECPublicKey)kp.getPublic();
   121                 publicKey = (ECPublicKey)kp.getPublic();
   115             } catch (GeneralSecurityException e) {
   122             } catch (GeneralSecurityException e) {
   116                 throw new RuntimeException(
   123                 throw new RuntimeException(
   197             } catch (GeneralSecurityException | java.io.IOException e) {
   204             } catch (GeneralSecurityException | java.io.IOException e) {
   198                 throw (SSLHandshakeException) new SSLHandshakeException(
   205                 throw (SSLHandshakeException) new SSLHandshakeException(
   199                         "Could not generate ECPublicKey").initCause(e);
   206                         "Could not generate ECPublicKey").initCause(e);
   200             }
   207             }
   201         }
   208         }
       
   209 
       
   210         @Override
       
   211         public PublicKey getPublicKey() {
       
   212             return publicKey;
       
   213         }
       
   214 
       
   215         @Override
       
   216         public NamedGroup getNamedGroup() {
       
   217             return namedGroup;
       
   218         }
       
   219 
       
   220         @Override
       
   221         public PrivateKey getPrivateKey() {
       
   222             return privateKey;
       
   223         }
   202     }
   224     }
   203 
   225 
   204     private static final
   226     private static final
   205             class ECDHEPossessionGenerator implements SSLPossessionGenerator {
   227             class ECDHEPossessionGenerator implements SSLPossessionGenerator {
   206         // Prevent instantiation of this class.
   228         // Prevent instantiation of this class.
   208             // blank
   230             // blank
   209         }
   231         }
   210 
   232 
   211         @Override
   233         @Override
   212         public SSLPossession createPossession(HandshakeContext context) {
   234         public SSLPossession createPossession(HandshakeContext context) {
   213             NamedGroup preferableNamedGroup = null;
   235 
       
   236             NamedGroup preferableNamedGroup;
       
   237 
       
   238             // Find most preferred EC or XEC groups
   214             if ((context.clientRequestedNamedGroups != null) &&
   239             if ((context.clientRequestedNamedGroups != null) &&
   215                     (!context.clientRequestedNamedGroups.isEmpty())) {
   240                     (!context.clientRequestedNamedGroups.isEmpty())) {
   216                 preferableNamedGroup = SupportedGroups.getPreferredGroup(
   241                 preferableNamedGroup = SupportedGroups.getPreferredGroup(
   217                         context.negotiatedProtocol,
   242                         context.negotiatedProtocol,
   218                         context.algorithmConstraints,
   243                         context.algorithmConstraints,
   219                         NamedGroupType.NAMED_GROUP_ECDHE,
   244                         new NamedGroupSpec[] {
       
   245                             NamedGroupSpec.NAMED_GROUP_ECDHE,
       
   246                             NamedGroupSpec.NAMED_GROUP_XDH },
   220                         context.clientRequestedNamedGroups);
   247                         context.clientRequestedNamedGroups);
   221             } else {
   248             } else {
   222                 preferableNamedGroup = SupportedGroups.getPreferredGroup(
   249                 preferableNamedGroup = SupportedGroups.getPreferredGroup(
   223                         context.negotiatedProtocol,
   250                         context.negotiatedProtocol,
   224                         context.algorithmConstraints,
   251                         context.algorithmConstraints,
   225                         NamedGroupType.NAMED_GROUP_ECDHE);
   252                         new NamedGroupSpec[] {
       
   253                             NamedGroupSpec.NAMED_GROUP_ECDHE,
       
   254                             NamedGroupSpec.NAMED_GROUP_XDH });
   226             }
   255             }
   227 
   256 
   228             if (preferableNamedGroup != null) {
   257             if (preferableNamedGroup != null) {
   229                 return new ECDHEPossession(preferableNamedGroup,
   258                 return preferableNamedGroup.createPossession(
   230                             context.sslContext.getSecureRandom());
   259                     context.sslContext.getSecureRandom());
   231             }
   260             }
   232 
   261 
   233             // no match found, cannot use this cipher suite.
   262             // no match found, cannot use this cipher suite.
   234             //
   263             //
   235             return null;
   264             return null;
   270                     continue;
   299                     continue;
   271                 }
   300                 }
   272 
   301 
   273                 NamedGroup ng = NamedGroup.valueOf(params);
   302                 NamedGroup ng = NamedGroup.valueOf(params);
   274                 if (ng == null) {
   303                 if (ng == null) {
   275                     // unlikely, have been checked during cipher suite negotiation.
   304                     // unlikely, have been checked during cipher suite
       
   305                     // negotiation.
   276                     throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
   306                     throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
   277                         "Unsupported EC server cert for ECDH key exchange");
   307                         "Unsupported EC server cert for ECDH key exchange");
   278                 }
   308                 }
   279 
   309 
   280                 for (SSLCredentials cred : shc.handshakeCredentials) {
   310                 for (SSLCredentials cred : shc.handshakeCredentials) {
   296             if (x509Possession == null || ecdheCredentials == null) {
   326             if (x509Possession == null || ecdheCredentials == null) {
   297                 throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
   327                 throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
   298                     "No sufficient ECDHE key agreement parameters negotiated");
   328                     "No sufficient ECDHE key agreement parameters negotiated");
   299             }
   329             }
   300 
   330 
   301             return new ECDHEKAKeyDerivation(shc,
   331             return new KAKeyDerivation("ECDH", shc,
   302                 x509Possession.popPrivateKey, ecdheCredentials.popPublicKey);
   332                 x509Possession.popPrivateKey, ecdheCredentials.popPublicKey);
   303         }
   333         }
   304 
   334 
   305         private SSLKeyDerivation createClientKeyDerivation(
   335         private SSLKeyDerivation createClientKeyDerivation(
   306                 ClientHandshakeContext chc) throws IOException {
   336                 ClientHandshakeContext chc) throws IOException {
   345             if (ecdhePossession == null || x509Credentials == null) {
   375             if (ecdhePossession == null || x509Credentials == null) {
   346                 throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
   376                 throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
   347                     "No sufficient ECDH key agreement parameters negotiated");
   377                     "No sufficient ECDH key agreement parameters negotiated");
   348             }
   378             }
   349 
   379 
   350             return new ECDHEKAKeyDerivation(chc,
   380             return new KAKeyDerivation("ECDH", chc,
   351                 ecdhePossession.privateKey, x509Credentials.popPublicKey);
   381                 ecdhePossession.privateKey, x509Credentials.popPublicKey);
   352         }
   382         }
   353     }
   383     }
   354 
   384 
   355     private static final
   385     private static final
   389             if (ecdhePossession == null || ecdheCredentials == null) {
   419             if (ecdhePossession == null || ecdheCredentials == null) {
   390                 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
   420                 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
   391                     "No sufficient ECDHE key agreement parameters negotiated");
   421                     "No sufficient ECDHE key agreement parameters negotiated");
   392             }
   422             }
   393 
   423 
   394             return new ECDHEKAKeyDerivation(context,
   424             return new KAKeyDerivation("ECDH", context,
   395                 ecdhePossession.privateKey, ecdheCredentials.popPublicKey);
   425                 ecdhePossession.privateKey, ecdheCredentials.popPublicKey);
   396         }
   426         }
   397     }
   427     }
   398 
   428 
       
   429     /*
       
   430      * A Generator for TLSv1-1.2 to create a ECDHE or a XDH KeyDerivation
       
   431      * object depending on the negotiated group.
       
   432      */
   399     private static final
   433     private static final
   400             class ECDHEKAKeyDerivation implements SSLKeyDerivation {
   434             class ECDHEXDHKAGenerator implements SSLKeyAgreementGenerator {
   401         private final HandshakeContext context;
   435         // Prevent instantiation of this class.
   402         private final PrivateKey localPrivateKey;
   436         private ECDHEXDHKAGenerator() {
   403         private final PublicKey peerPublicKey;
   437             // blank
   404 
   438         }
   405         ECDHEKAKeyDerivation(HandshakeContext context,
   439 
   406                 PrivateKey localPrivateKey,
   440         @Override
   407                 PublicKey peerPublicKey) {
   441         public SSLKeyDerivation createKeyDerivation(
   408             this.context = context;
   442                 HandshakeContext context) throws IOException {
   409             this.localPrivateKey = localPrivateKey;
   443 
   410             this.peerPublicKey = peerPublicKey;
   444             NamedGroupPossession namedGroupPossession = null;
   411         }
   445             NamedGroupCredentials namedGroupCredentials = null;
   412 
   446             NamedGroup namedGroup = null;
   413         @Override
   447 
   414         public SecretKey deriveKey(String algorithm,
   448             // Find a possession/credential combo using the same named group
   415                 AlgorithmParameterSpec params) throws IOException {
   449             search:
   416             if (!context.negotiatedProtocol.useTLS13PlusSpec()) {
   450             for (SSLPossession poss : context.handshakePossessions) {
   417                 return t12DeriveKey(algorithm, params);
   451                 for (SSLCredentials cred : context.handshakeCredentials) {
   418             } else {
   452                     if (((poss instanceof ECDHEPossession) &&
   419                 return t13DeriveKey(algorithm, params);
   453                             (cred instanceof ECDHECredentials)) ||
   420             }
   454                             (((poss instanceof XDHEPossession) &&
   421         }
   455                             (cred instanceof XDHECredentials)))) {
   422 
   456                         NamedGroupPossession p = (NamedGroupPossession)poss;
   423         private SecretKey t12DeriveKey(String algorithm,
   457                         NamedGroupCredentials c = (NamedGroupCredentials)cred;
   424                 AlgorithmParameterSpec params) throws IOException {
   458                         if (p.getNamedGroup() != c.getNamedGroup()) {
   425             try {
   459                             continue;
   426                 KeyAgreement ka = KeyAgreement.getInstance("ECDH");
   460                         } else {
   427                 ka.init(localPrivateKey);
   461                             namedGroup = p.getNamedGroup();
   428                 ka.doPhase(peerPublicKey, true);
   462                         }
   429                 SecretKey preMasterSecret =
   463                         namedGroupPossession = p;
   430                         ka.generateSecret("TlsPremasterSecret");
   464                         namedGroupCredentials = c;
   431 
   465                         break search;
   432                 SSLMasterKeyDerivation mskd =
   466                     }
   433                         SSLMasterKeyDerivation.valueOf(
   467                 }
   434                                 context.negotiatedProtocol);
   468             }
   435                 if (mskd == null) {
   469 
   436                     // unlikely
   470             if (namedGroupPossession == null || namedGroupCredentials == null) {
   437                     throw new SSLHandshakeException(
   471                 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
   438                             "No expected master key derivation for protocol: " +
   472                     "No sufficient ECDHE/XDH key agreement " +
   439                             context.negotiatedProtocol.name);
   473                             "parameters negotiated");
   440                 }
   474             }
   441                 SSLKeyDerivation kd = mskd.createKeyDerivation(
   475 
   442                         context, preMasterSecret);
   476             String alg;
   443                 return kd.deriveKey("MasterSecret", params);
   477             switch (namedGroup.spec) {
   444             } catch (GeneralSecurityException gse) {
   478                 case NAMED_GROUP_ECDHE:
   445                 throw (SSLHandshakeException) new SSLHandshakeException(
   479                     alg = "ECDH";
   446                     "Could not generate secret").initCause(gse);
   480                     break;
   447             }
   481                 case NAMED_GROUP_XDH:
   448         }
   482                     alg = "XDH";
   449 
   483                     break;
   450         private SecretKey t13DeriveKey(String algorithm,
   484                 default:
   451                 AlgorithmParameterSpec params) throws IOException {
   485                     throw new RuntimeException("Unexpected named group type");
   452             try {
   486             }
   453                 KeyAgreement ka = KeyAgreement.getInstance("ECDH");
   487 
   454                 ka.init(localPrivateKey);
   488             return new KAKeyDerivation(alg, context,
   455                 ka.doPhase(peerPublicKey, true);
   489                     namedGroupPossession.getPrivateKey(),
   456                 SecretKey sharedSecret =
   490                     namedGroupCredentials.getPublicKey());
   457                         ka.generateSecret("TlsPremasterSecret");
       
   458 
       
   459                 HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg;
       
   460                 SSLKeyDerivation kd = context.handshakeKeyDerivation;
       
   461                 HKDF hkdf = new HKDF(hashAlg.name);
       
   462                 if (kd == null) {   // No PSK is in use.
       
   463                     // If PSK is not in use Early Secret will still be
       
   464                     // HKDF-Extract(0, 0).
       
   465                     byte[] zeros = new byte[hashAlg.hashLength];
       
   466                     SecretKeySpec ikm =
       
   467                             new SecretKeySpec(zeros, "TlsPreSharedSecret");
       
   468                     SecretKey earlySecret =
       
   469                             hkdf.extract(zeros, ikm, "TlsEarlySecret");
       
   470                     kd = new SSLSecretDerivation(context, earlySecret);
       
   471                 }
       
   472 
       
   473                 // derive salt secret
       
   474                 SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
       
   475 
       
   476                 // derive handshake secret
       
   477                 return hkdf.extract(saltSecret, sharedSecret, algorithm);
       
   478             } catch (GeneralSecurityException gse) {
       
   479                 throw (SSLHandshakeException) new SSLHandshakeException(
       
   480                     "Could not generate secret").initCause(gse);
       
   481             }
       
   482         }
   491         }
   483     }
   492     }
   484 }
   493 }