1 /*
   2  * Copyright (c) 2018, 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 
  26 package sun.security.ssl;
  27 
  28 import java.security.PrivateKey;
  29 import java.security.PublicKey;
  30 import java.security.cert.X509Certificate;
  31 import java.security.interfaces.ECKey;
  32 import java.security.interfaces.ECPublicKey;
  33 import java.security.interfaces.XECKey;
  34 import java.security.spec.AlgorithmParameterSpec;
  35 import java.security.spec.ECParameterSpec;
  36 import java.security.spec.NamedParameterSpec;
  37 import java.util.AbstractMap.SimpleImmutableEntry;
  38 import java.util.Map;
  39 import javax.net.ssl.SSLEngine;
  40 import javax.net.ssl.SSLSocket;
  41 import javax.net.ssl.X509ExtendedKeyManager;
  42 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
  43 
  44 enum X509Authentication implements SSLAuthentication {
  45     // Require rsaEncryption public key
  46     RSA         ("RSA",         new X509PossessionGenerator(
  47                                     new String[]{"RSA"})),
  48 
  49     // Require RSASSA-PSS public key
  50     RSASSA_PSS  ("RSASSA-PSS",  new X509PossessionGenerator(
  51                                     new String[] {"RSASSA-PSS"})),
  52 
  53     // Require rsaEncryption or RSASSA-PSS public key
  54     //
  55     // Note that this is a specifical scheme for TLS 1.2. (EC)DHE_RSA cipher
  56     // suites of TLS 1.2 can use either rsaEncryption or RSASSA-PSS public
  57     // key for authentication and handshake.
  58     RSA_OR_PSS  ("RSA_OR_PSS",  new X509PossessionGenerator(
  59                                     new String[] {"RSA", "RSASSA-PSS"})),
  60 
  61     // Require DSA public key
  62     DSA         ("DSA",         new X509PossessionGenerator(
  63                                     new String[] {"DSA"})),
  64 
  65     // Require EC public key
  66     EC          ("EC",          new X509PossessionGenerator(
  67                                     new String[] {"EC"}));
  68 
  69     final String keyType;
  70     final SSLPossessionGenerator possessionGenerator;
  71 
  72     X509Authentication(String keyType,
  73             SSLPossessionGenerator possessionGenerator) {
  74         this.keyType = keyType;
  75         this.possessionGenerator = possessionGenerator;
  76     }
  77 
  78     static X509Authentication valueOf(SignatureScheme signatureScheme) {
  79         for (X509Authentication au : X509Authentication.values()) {
  80             if (au.keyType.equals(signatureScheme.keyAlgorithm)) {
  81                 return au;
  82             }
  83         }
  84 
  85         return null;
  86     }
  87 
  88     @Override
  89     public SSLPossession createPossession(HandshakeContext handshakeContext) {
  90         return possessionGenerator.createPossession(handshakeContext);
  91     }
  92 
  93     @Override
  94     public SSLHandshake[] getRelatedHandshakers(
  95             HandshakeContext handshakeContext) {
  96         if (!handshakeContext.negotiatedProtocol.useTLS13PlusSpec()) {
  97             return new SSLHandshake[] {
  98                     SSLHandshake.CERTIFICATE,
  99                     SSLHandshake.CERTIFICATE_REQUEST
 100                 };
 101         }   // Otherwise, TLS 1.3 does not use this method.
 102 
 103         return new SSLHandshake[0];
 104     }
 105 
 106     @SuppressWarnings({"unchecked", "rawtypes"})
 107     @Override
 108     public Map.Entry<Byte, HandshakeProducer>[] getHandshakeProducers(
 109             HandshakeContext handshakeContext) {
 110         if (!handshakeContext.negotiatedProtocol.useTLS13PlusSpec()) {
 111             return (Map.Entry<Byte, HandshakeProducer>[])(new Map.Entry[] {
 112                     new SimpleImmutableEntry<Byte, HandshakeProducer>(
 113                         SSLHandshake.CERTIFICATE.id,
 114                         SSLHandshake.CERTIFICATE
 115                     )
 116                 });
 117         }   // Otherwise, TLS 1.3 does not use this method.
 118 
 119         return (Map.Entry<Byte, HandshakeProducer>[])(new Map.Entry[0]);
 120     }
 121 
 122     static final class X509Possession implements SSLPossession {
 123         // Proof of possession of the private key corresponding to the public
 124         // key for which a certificate is being provided for authentication.
 125         final X509Certificate[]   popCerts;
 126         final PrivateKey          popPrivateKey;
 127 
 128         X509Possession(PrivateKey popPrivateKey,
 129                 X509Certificate[] popCerts) {
 130             this.popCerts = popCerts;
 131             this.popPrivateKey = popPrivateKey;
 132         }
 133 
 134         ECParameterSpec getECParameterSpec() {
 135             if (popPrivateKey == null ||
 136                     !"EC".equals(popPrivateKey.getAlgorithm())) {
 137                 return null;
 138             }
 139 
 140             if (popPrivateKey instanceof ECKey) {
 141                 return ((ECKey)popPrivateKey).getParams();
 142             } else if (popCerts != null && popCerts.length != 0) {
 143                 // The private key not extractable, get the parameters from
 144                 // the X.509 certificate.
 145                 PublicKey publicKey = popCerts[0].getPublicKey();
 146                 if (publicKey instanceof ECKey) {
 147                     return ((ECKey)publicKey).getParams();
 148                 }
 149             }
 150 
 151             return null;
 152         }
 153 
 154         // Similar to above, but for XEC.
 155         NamedParameterSpec getXECParameterSpec() {
 156             if (popPrivateKey == null ||
 157                     !"XEC".equals(popPrivateKey.getAlgorithm())) {
 158                 return null;
 159             }
 160 
 161             if (popPrivateKey instanceof XECKey) {
 162                 AlgorithmParameterSpec params =
 163                         ((XECKey)popPrivateKey).getParams();
 164                 if (params instanceof NamedParameterSpec){
 165                     return (NamedParameterSpec)params;
 166                 }
 167             } else if (popCerts != null && popCerts.length != 0) {
 168                 // The private key not extractable, get the parameters from
 169                 // the X.509 certificate.
 170                 PublicKey publicKey = popCerts[0].getPublicKey();
 171                 if (publicKey instanceof XECKey) {
 172                     AlgorithmParameterSpec params =
 173                             ((XECKey)publicKey).getParams();
 174                     if (params instanceof NamedParameterSpec){
 175                         return (NamedParameterSpec)params;
 176                     }
 177                 }
 178             }
 179 
 180             return null;
 181         }
 182     }
 183 
 184     static final class X509Credentials implements SSLCredentials {
 185         final X509Certificate[]   popCerts;
 186         final PublicKey           popPublicKey;
 187 
 188         X509Credentials(PublicKey popPublicKey, X509Certificate[] popCerts) {
 189             this.popCerts = popCerts;
 190             this.popPublicKey = popPublicKey;
 191         }
 192     }
 193 
 194     private static final
 195             class X509PossessionGenerator implements SSLPossessionGenerator {
 196         private final String[] keyTypes;
 197 
 198         private X509PossessionGenerator(String[] keyTypes) {
 199             this.keyTypes = keyTypes;
 200         }
 201 
 202         @Override
 203         public SSLPossession createPossession(HandshakeContext context) {
 204             if (context.sslConfig.isClientMode) {
 205                 for (String keyType : keyTypes) {
 206                     SSLPossession poss = createClientPossession(
 207                             (ClientHandshakeContext)context, keyType);
 208                     if (poss != null) {
 209                         return poss;
 210                     }
 211                 }
 212             } else {
 213                 for (String keyType : keyTypes) {
 214                     SSLPossession poss = createServerPossession(
 215                             (ServerHandshakeContext)context, keyType);
 216                     if (poss != null) {
 217                         return poss;
 218                     }
 219                 }
 220             }
 221 
 222             return null;
 223         }
 224 
 225         // Used by TLS 1.2 and TLS 1.3.
 226         private SSLPossession createClientPossession(
 227                 ClientHandshakeContext chc, String keyType) {
 228             X509ExtendedKeyManager km = chc.sslContext.getX509KeyManager();
 229             String clientAlias = null;
 230             if (chc.conContext.transport instanceof SSLSocketImpl) {
 231                 clientAlias = km.chooseClientAlias(
 232                         new String[] { keyType },
 233                         chc.peerSupportedAuthorities,
 234                         (SSLSocket)chc.conContext.transport);
 235             } else if (chc.conContext.transport instanceof SSLEngineImpl) {
 236                 clientAlias = km.chooseEngineClientAlias(
 237                         new String[] { keyType },
 238                         chc.peerSupportedAuthorities,
 239                         (SSLEngine)chc.conContext.transport);
 240             }
 241 
 242             if (clientAlias == null) {
 243                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 244                     SSLLogger.finest("No X.509 cert selected for " + keyType);
 245                 }
 246                 return null;
 247             }
 248 
 249             PrivateKey clientPrivateKey = km.getPrivateKey(clientAlias);
 250             if (clientPrivateKey == null) {
 251                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 252                     SSLLogger.finest(
 253                             clientAlias + " is not a private key entry");
 254                 }
 255                 return null;
 256             }
 257 
 258             X509Certificate[] clientCerts = km.getCertificateChain(clientAlias);
 259             if ((clientCerts == null) || (clientCerts.length == 0)) {
 260                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 261                     SSLLogger.finest(clientAlias +
 262                         " is a private key entry with no cert chain stored");
 263                 }
 264                 return null;
 265             }
 266 
 267             PublicKey clientPublicKey = clientCerts[0].getPublicKey();
 268             if ((!clientPrivateKey.getAlgorithm().equals(keyType))
 269                     || (!clientPublicKey.getAlgorithm().equals(keyType))) {
 270                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 271                     SSLLogger.fine(
 272                             clientAlias + " private or public key is not of " +
 273                             keyType + " algorithm");
 274                 }
 275                 return null;
 276             }
 277 
 278             return new X509Possession(clientPrivateKey, clientCerts);
 279         }
 280 
 281         private SSLPossession createServerPossession(
 282                 ServerHandshakeContext shc, String keyType) {
 283             X509ExtendedKeyManager km = shc.sslContext.getX509KeyManager();
 284             String serverAlias = null;
 285             if (shc.conContext.transport instanceof SSLSocketImpl) {
 286                 serverAlias = km.chooseServerAlias(keyType,
 287                         null, (SSLSocket)shc.conContext.transport);
 288             } else if (shc.conContext.transport instanceof SSLEngineImpl) {
 289                 serverAlias = km.chooseEngineServerAlias(keyType,
 290                         null, (SSLEngine)shc.conContext.transport);
 291             }
 292 
 293             if (serverAlias == null) {
 294                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 295                     SSLLogger.finest("No X.509 cert selected for " + keyType);
 296                 }
 297                 return null;
 298             }
 299 
 300             PrivateKey serverPrivateKey = km.getPrivateKey(serverAlias);
 301             if (serverPrivateKey == null) {
 302                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 303                     SSLLogger.finest(
 304                             serverAlias + " is not a private key entry");
 305                 }
 306                 return null;
 307             }
 308 
 309             X509Certificate[] serverCerts = km.getCertificateChain(serverAlias);
 310             if ((serverCerts == null) || (serverCerts.length == 0)) {
 311                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 312                     SSLLogger.finest(
 313                             serverAlias + " is not a certificate entry");
 314                 }
 315                 return null;
 316             }
 317 
 318             PublicKey serverPublicKey = serverCerts[0].getPublicKey();
 319             if ((!serverPrivateKey.getAlgorithm().equals(keyType))
 320                     || (!serverPublicKey.getAlgorithm().equals(keyType))) {
 321                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 322                     SSLLogger.fine(
 323                             serverAlias + " private or public key is not of " +
 324                             keyType + " algorithm");
 325                 }
 326                 return null;
 327             }
 328 
 329             // For ECC certs, check whether we support the EC domain
 330             // parameters.  If the client sent a SupportedEllipticCurves
 331             // ClientHello extension, check against that too.
 332             if (keyType.equals("EC")) {
 333                 if (!(serverPublicKey instanceof ECPublicKey)) {
 334                     if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 335                         SSLLogger.warning(serverAlias +
 336                             " public key is not an instance of ECPublicKey");
 337                     }
 338                     return null;
 339                 }
 340 
 341                 // For ECC certs, check whether we support the EC domain
 342                 // parameters. If the client sent a SupportedEllipticCurves
 343                 // ClientHello extension, check against that too.
 344                 ECParameterSpec params =
 345                         ((ECPublicKey)serverPublicKey).getParams();
 346                 NamedGroup namedGroup = NamedGroup.valueOf(params);
 347                 if ((namedGroup == null) ||
 348                         (!SupportedGroups.isSupported(namedGroup)) ||
 349                         ((shc.clientRequestedNamedGroups != null) &&
 350                         !shc.clientRequestedNamedGroups.contains(namedGroup))) {
 351 
 352                     if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 353                         SSLLogger.warning(
 354                             "Unsupported named group (" + namedGroup +
 355                             ") used in the " + serverAlias + " certificate");
 356                     }
 357 
 358                     return null;
 359                 }
 360             }
 361 
 362             return new X509Possession(serverPrivateKey, serverCerts);
 363         }
 364     }
 365 }