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