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 }