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.security.PrivateKey;
  29 import java.security.PublicKey;
  30 import java.security.cert.X509Certificate;
  31 import java.security.interfaces.ECPublicKey;
  32 import java.security.spec.ECParameterSpec;
  33 import java.util.AbstractMap.SimpleImmutableEntry;
  34 import java.util.Map;
  35 import javax.net.ssl.SSLEngine;
  36 import javax.net.ssl.SSLSocket;
  37 import javax.net.ssl.X509ExtendedKeyManager;
  38 import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
  39 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
  40 
  41 enum X509Authentication implements SSLAuthentication {
  42     RSA     ("RSA",        new X509PossessionGenerator("RSA")),
  43     RSA_PSS ("RSASSA-PSS", new X509PossessionGenerator("RSASSA-PSS")),
  44     DSA     ("DSA",        new X509PossessionGenerator("DSA")),
  45     EC      ("EC",         new X509PossessionGenerator("EC"));
  46 
  47     final String keyType;
  48     final SSLPossessionGenerator possessionGenerator;
  49 
  50     X509Authentication(String keyType,
  51             SSLPossessionGenerator possessionGenerator) {
  52         this.keyType = keyType;
  53         this.possessionGenerator = possessionGenerator;
  54     }
  55 
  56     static X509Authentication nameOf(String keyType) {
  57         for (X509Authentication au: X509Authentication.values()) {
  58             if (au.keyType.equals(keyType)) {
  59                 return au;
  60             }
  61         }
  62 
  63         return null;
  64     }
  65 
  66     @Override
  67     public SSLPossession createPossession(HandshakeContext handshakeContext) {
  68         return possessionGenerator.createPossession(handshakeContext);
  69     }
  70 
  71     @Override
  72     public SSLHandshake[] getRelatedHandshakers(
  73             HandshakeContext handshakeContext) {
  74         if (!handshakeContext.negotiatedProtocol.useTLS13PlusSpec()) {
  75             return new SSLHandshake[] {
  76                     SSLHandshake.CERTIFICATE,
  77                     SSLHandshake.CERTIFICATE_REQUEST
  78                 };
  79         }   // Otherwise, TLS 1.3 does not use this method.
  80 
  81         return new SSLHandshake[0];
  82     }
  83 
  84     @SuppressWarnings({"unchecked", "rawtypes"})
  85     @Override
  86     public Map.Entry<Byte, HandshakeProducer>[] getHandshakeProducers(
  87             HandshakeContext handshakeContext) {
  88         if (!handshakeContext.negotiatedProtocol.useTLS13PlusSpec()) {
  89             return (Map.Entry<Byte, HandshakeProducer>[])(new Map.Entry[] {
  90                     new SimpleImmutableEntry<Byte, HandshakeProducer>(
  91                         SSLHandshake.CERTIFICATE.id,
  92                         SSLHandshake.CERTIFICATE
  93                     )
  94                 });
  95         }   // Otherwise, TLS 1.3 does not use this method.
  96 
  97         return (Map.Entry<Byte, HandshakeProducer>[])(new Map.Entry[0]);
  98     }
  99 
 100     static final class X509Possession implements SSLPossession {
 101         // Proof of possession of the private key corresponding to the public
 102         // key for which a certificate is being provided for authentication.
 103         final X509Certificate[]   popCerts;
 104         final PrivateKey          popPrivateKey;
 105 
 106         X509Possession(PrivateKey popPrivateKey,
 107                 X509Certificate[] popCerts) {
 108             this.popCerts = popCerts;
 109             this.popPrivateKey = popPrivateKey;
 110         }
 111     }
 112 
 113     static final class X509Credentials implements SSLCredentials {
 114         final X509Certificate[]   popCerts;
 115         final PublicKey           popPublicKey;
 116 
 117         X509Credentials(PublicKey popPublicKey, X509Certificate[] popCerts) {
 118             this.popCerts = popCerts;
 119             this.popPublicKey = popPublicKey;
 120         }
 121     }
 122 
 123     private static final
 124             class X509PossessionGenerator implements SSLPossessionGenerator {
 125         final String keyType;
 126 
 127         private X509PossessionGenerator(String keyType) {
 128             this.keyType = keyType;
 129         }
 130 
 131         @Override
 132         public SSLPossession createPossession(HandshakeContext context) {
 133             if (context.sslConfig.isClientMode) {
 134                 return createClientPossession((ClientHandshakeContext)context);
 135             } else {
 136                 return createServerPossession((ServerHandshakeContext)context);
 137             }
 138         }
 139 
 140         // Used by TLS 1.3 only.
 141         private SSLPossession createClientPossession(
 142                 ClientHandshakeContext chc) {
 143             X509ExtendedKeyManager km = chc.sslContext.getX509KeyManager();
 144             String clientAlias = null;
 145             if (chc.conContext.transport instanceof SSLSocketImpl) {
 146                 clientAlias = km.chooseClientAlias(
 147                         new String[] { keyType },
 148                         null, (SSLSocket)chc.conContext.transport);
 149             } else if (chc.conContext.transport instanceof SSLEngineImpl) {
 150                 clientAlias = km.chooseEngineClientAlias(
 151                         new String[] { keyType },
 152                         null, (SSLEngine)chc.conContext.transport);
 153             }
 154 
 155             if (clientAlias == null) {
 156                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 157                     SSLLogger.finest("No X.509 cert selected for " + keyType);
 158                 }
 159                 return null;
 160             }
 161 
 162             PrivateKey clientPrivateKey = km.getPrivateKey(clientAlias);
 163             if (clientPrivateKey == null) {
 164                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 165                     SSLLogger.finest(
 166                             clientAlias + " is not a private key entry");
 167                 }
 168                 return null;
 169             }
 170 
 171             X509Certificate[] clientCerts = km.getCertificateChain(clientAlias);
 172             if ((clientCerts == null) || (clientCerts.length == 0)) {
 173                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 174                     SSLLogger.finest(
 175                             clientAlias + " is not a certificate entry");
 176                 }
 177                 return null;
 178             }
 179 
 180             PublicKey clientPublicKey = clientCerts[0].getPublicKey();
 181             if ((!clientPrivateKey.getAlgorithm().equals(keyType))
 182                     || (!clientPublicKey.getAlgorithm().equals(keyType))) {
 183                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 184                     SSLLogger.fine(
 185                             clientAlias + " private or public key is not of " +
 186                             keyType + " algorithm");
 187                 }
 188                 return null;
 189             }
 190 
 191             return new X509Possession(clientPrivateKey, clientCerts);
 192         }
 193 
 194         private SSLPossession createServerPossession(
 195                 ServerHandshakeContext shc) {
 196             X509ExtendedKeyManager km = shc.sslContext.getX509KeyManager();
 197             String serverAlias = null;
 198             if (shc.conContext.transport instanceof SSLSocketImpl) {
 199                 serverAlias = km.chooseServerAlias(keyType,
 200                         null, (SSLSocket)shc.conContext.transport);
 201             } else if (shc.conContext.transport instanceof SSLEngineImpl) {
 202                 serverAlias = km.chooseEngineServerAlias(keyType,
 203                         null, (SSLEngine)shc.conContext.transport);
 204             }
 205 
 206             if (serverAlias == null) {
 207                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 208                     SSLLogger.finest("No X.509 cert selected for " + keyType);
 209                 }
 210                 return null;
 211             }
 212 
 213             PrivateKey serverPrivateKey = km.getPrivateKey(serverAlias);
 214             if (serverPrivateKey == null) {
 215                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 216                     SSLLogger.finest(
 217                             serverAlias + " is not a private key entry");
 218                 }
 219                 return null;
 220             }
 221 
 222             X509Certificate[] serverCerts = km.getCertificateChain(serverAlias);
 223             if ((serverCerts == null) || (serverCerts.length == 0)) {
 224                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 225                     SSLLogger.finest(
 226                             serverAlias + " is not a certificate entry");
 227                 }
 228                 return null;
 229             }
 230 
 231             PublicKey serverPublicKey = serverCerts[0].getPublicKey();
 232             if ((!serverPrivateKey.getAlgorithm().equals(keyType))
 233                     || (!serverPublicKey.getAlgorithm().equals(keyType))) {
 234                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 235                     SSLLogger.fine(
 236                             serverAlias + " private or public key is not of " +
 237                             keyType + " algorithm");
 238                 }
 239                 return null;
 240             }
 241 
 242             // For ECC certs, check whether we support the EC domain
 243             // parameters.  If the client sent a SupportedEllipticCurves
 244             // ClientHello extension, check against that too.
 245             if (keyType.equals("EC")) {
 246                 if (!(serverPublicKey instanceof ECPublicKey)) {
 247                     if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 248                         SSLLogger.warning(serverAlias +
 249                             " public key is not an instance of ECPublicKey");
 250                     }
 251                     return null;
 252                 }
 253 
 254                 // For ECC certs, check whether we support the EC domain
 255                 // parameters. If the client sent a SupportedEllipticCurves
 256                 // ClientHello extension, check against that too.
 257                 ECParameterSpec params =
 258                         ((ECPublicKey)serverPublicKey).getParams();
 259                 NamedGroup namedGroup = NamedGroup.valueOf(params);
 260                 if ((namedGroup == null) ||
 261                     (!SupportedGroups.isSupported(namedGroup)) ||
 262                     ((shc.clientRequestedNamedGroups != null) &&
 263                     !shc.clientRequestedNamedGroups.contains(namedGroup))) {
 264 
 265                     if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 266                         SSLLogger.warning(
 267                             "Unsupported named group (" + namedGroup +
 268                             ") used in the " + serverAlias + " certificate");
 269                     }
 270 
 271                     return null;
 272                 }
 273             }
 274 
 275             return new X509Possession(serverPrivateKey, serverCerts);
 276         }
 277     }
 278 }