8263188: JSSE should fail fast if there isn't supported signature algorithm
Reviewed-by: xuelei
This commit is contained in:
parent
6678b01c57
commit
99b4bab366
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -689,13 +689,16 @@ final class CertificateRequest {
|
||||
chc.handshakeProducers.put(SSLHandshake.CERTIFICATE.id,
|
||||
SSLHandshake.CERTIFICATE);
|
||||
|
||||
List<SignatureScheme> sss = new LinkedList<>();
|
||||
for (int id : crm.algorithmIds) {
|
||||
SignatureScheme ss = SignatureScheme.valueOf(id);
|
||||
if (ss != null) {
|
||||
sss.add(ss);
|
||||
}
|
||||
List<SignatureScheme> sss =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
chc.sslConfig,
|
||||
chc.algorithmConstraints, chc.negotiatedProtocol,
|
||||
crm.algorithmIds);
|
||||
if (sss == null || sss.isEmpty()) {
|
||||
throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
|
||||
"No supported signature algorithm");
|
||||
}
|
||||
|
||||
chc.peerRequestedSignatureSchemes = sss;
|
||||
chc.peerRequestedCertSignSchemes = sss; // use the same schemes
|
||||
chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss);
|
||||
|
@ -279,6 +279,10 @@ final class SignatureAlgorithmsExtension {
|
||||
shc.sslConfig,
|
||||
shc.algorithmConstraints, shc.negotiatedProtocol,
|
||||
spec.signatureSchemes);
|
||||
if (sss == null || sss.isEmpty()) {
|
||||
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
|
||||
"No supported signature algorithm");
|
||||
}
|
||||
shc.peerRequestedSignatureSchemes = sss;
|
||||
|
||||
// If no "signature_algorithms_cert" extension is present, then
|
||||
@ -330,7 +334,7 @@ final class SignatureAlgorithmsExtension {
|
||||
if (shc.negotiatedProtocol.useTLS13PlusSpec()) {
|
||||
throw shc.conContext.fatal(Alert.MISSING_EXTENSION,
|
||||
"No mandatory signature_algorithms extension in the " +
|
||||
"received CertificateRequest handshake message");
|
||||
"received ClientHello handshake message");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -503,6 +507,10 @@ final class SignatureAlgorithmsExtension {
|
||||
chc.sslConfig,
|
||||
chc.algorithmConstraints, chc.negotiatedProtocol,
|
||||
spec.signatureSchemes);
|
||||
if (sss == null || sss.isEmpty()) {
|
||||
throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
|
||||
"No supported signature algorithm");
|
||||
}
|
||||
chc.peerRequestedSignatureSchemes = sss;
|
||||
|
||||
// If no "signature_algorithms_cert" extension is present, then
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -478,7 +478,7 @@ public interface SSLContextTemplate {
|
||||
/*
|
||||
* Create an instance of KeyManager with the specified key materials.
|
||||
*/
|
||||
private KeyManager createKeyManager(
|
||||
static KeyManager createKeyManager(
|
||||
String[] keyMaterialCerts,
|
||||
String[] keyMaterialKeys,
|
||||
String[] keyMaterialKeyAlgs,
|
||||
@ -534,7 +534,7 @@ public interface SSLContextTemplate {
|
||||
/*
|
||||
* Create an instance of TrustManager with the specified trust materials.
|
||||
*/
|
||||
private TrustManager createTrustManager(
|
||||
static TrustManager createTrustManager(
|
||||
String[] trustedMaterials,
|
||||
ContextParameters params) throws Exception {
|
||||
|
||||
|
@ -197,7 +197,7 @@ public class SSLEngineTemplate implements SSLContextTemplate {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isOpen(SSLEngine engine) {
|
||||
static boolean isOpen(SSLEngine engine) {
|
||||
return (!engine.isOutboundDone() || !engine.isInboundDone());
|
||||
}
|
||||
|
||||
@ -240,7 +240,7 @@ public class SSLEngineTemplate implements SSLContextTemplate {
|
||||
}
|
||||
|
||||
// Simple check to make sure everything came across as expected.
|
||||
private static void checkTransfer(ByteBuffer a, ByteBuffer b)
|
||||
static void checkTransfer(ByteBuffer a, ByteBuffer b)
|
||||
throws Exception {
|
||||
a.flip();
|
||||
b.flip();
|
||||
|
@ -0,0 +1,381 @@
|
||||
/*
|
||||
* Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test 8263188
|
||||
* @summary If TLS the server and client has no common signature algorithms,
|
||||
* the connection should fail fast with "No supported signature algorithm".
|
||||
* This test only covers TLS 1.2.
|
||||
*
|
||||
* @library /test/lib
|
||||
* /javax/net/ssl/templates
|
||||
*
|
||||
* @run main/othervm
|
||||
* -Djdk.tls.server.SignatureSchemes=ecdsa_secp384r1_sha384
|
||||
* -Djdk.tls.client.SignatureSchemes=ecdsa_secp256r1_sha256,ecdsa_secp384r1_sha384
|
||||
* -Dtest.clientAuth=false
|
||||
* -Dtest.expectFail=false
|
||||
* SigAlgosExtTestWithTLS12
|
||||
* @run main/othervm
|
||||
* -Djdk.tls.server.SignatureSchemes=ecdsa_secp384r1_sha384
|
||||
* -Djdk.tls.client.SignatureSchemes=ecdsa_secp256r1_sha256
|
||||
* -Dtest.clientAuth=false
|
||||
* -Dtest.expectFail=true
|
||||
* SigAlgosExtTestWithTLS12
|
||||
* @run main/othervm
|
||||
* -Djdk.tls.server.SignatureSchemes=ecdsa_secp256r1_sha256
|
||||
* -Djdk.tls.client.SignatureSchemes=ecdsa_secp256r1_sha256
|
||||
* -Dtest.clientAuth=true
|
||||
* -Dtest.expectFail=true
|
||||
* SigAlgosExtTestWithTLS12
|
||||
*/
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
|
||||
public class SigAlgosExtTestWithTLS12 extends SSLEngineTemplate {
|
||||
|
||||
private static final boolean CLIENT_AUTH
|
||||
= Boolean.getBoolean("test.clientAuth");
|
||||
private static final boolean EXPECT_FAIL
|
||||
= Boolean.getBoolean("test.expectFail");
|
||||
|
||||
private static final String[] CA_CERTS = new String[] {
|
||||
// SHA256withECDSA, curve secp256r1
|
||||
// Validity
|
||||
// Not Before: May 22 07:18:16 2018 GMT
|
||||
// Not After : May 17 07:18:16 2038 GMT
|
||||
// Subject Key Identifier:
|
||||
// 60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIIBvjCCAWOgAwIBAgIJAIvFG6GbTroCMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" +
|
||||
"AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
|
||||
"ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYTAlVT\n" +
|
||||
"MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTBZ\n" +
|
||||
"MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBz1WeVb6gM2mh85z3QlvaB/l11b5h0v\n" +
|
||||
"LIzmkC3DKlVukZT+ltH2Eq1oEkpXuf7QmbM0ibrUgtjsWH3mULfmcWmjUDBOMB0G\n" +
|
||||
"A1UdDgQWBBRgz71z//oaMNKk7NNJcUbvGjWghjAfBgNVHSMEGDAWgBRgz71z//oa\n" +
|
||||
"MNKk7NNJcUbvGjWghjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQCG\n" +
|
||||
"6wluh1r2/T6L31mZXRKf9JxeSf9pIzoLj+8xQeUChQIhAJ09wAi1kV8yePLh2FD9\n" +
|
||||
"2YEHlSQUAbwwqCDEVB5KxaqP\n" +
|
||||
"-----END CERTIFICATE-----",
|
||||
|
||||
// SHA384withECDSA, curve secp384r1
|
||||
// Validity
|
||||
// Not Before: Jun 24 08:15:06 2019 GMT
|
||||
// Not After : Jun 19 08:15:06 2039 GMT
|
||||
// Subject Key Identifier:
|
||||
// 0a:93:a9:a0:bf:e7:d5:48:9d:4f:89:15:c6:51:98:80:05:51:4e:4e
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIICCDCCAY6gAwIBAgIUCpOpoL/n1UidT4kVxlGYgAVRTk4wCgYIKoZIzj0EAwMw\n" +
|
||||
"OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" +
|
||||
"VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowOzEL\n" +
|
||||
"MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" +
|
||||
"dCBTZXJpdmNlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAENVQN1wXWFdgC6u/dDdiC\n" +
|
||||
"y+WtMTF66oL/0BSm+1ZqsogamzCryawOcHgiuXgWzx5CQ3LuOC+tDFyXpGfHuCvb\n" +
|
||||
"dkzxPrP5n9NrR8/uRPe5l1KOUbchviU8z9cTP+LZxnZDo1MwUTAdBgNVHQ4EFgQU\n" +
|
||||
"SktSFArR1p/5mXV0kyo0RxIVa/UwHwYDVR0jBBgwFoAUSktSFArR1p/5mXV0kyo0\n" +
|
||||
"RxIVa/UwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjBZvoNmq3/v\n" +
|
||||
"RD2gBTyvxjS9h0rsMRLHDnvul/KWngytwGPTOBo0Y8ixQXSjdKoc3rkCMQDkiNgx\n" +
|
||||
"IDxuHedmrLQKIPnVcthTmwv7//jHiqGoKofwChMo2a1P+DQdhszmeHD/ARQ=\n" +
|
||||
"-----END CERTIFICATE-----"
|
||||
};
|
||||
|
||||
private static final String[] EE_CERTS = new String[] {
|
||||
// SHA256withECDSA, curve secp256r1
|
||||
// Validity
|
||||
// Not Before: May 22 07:18:16 2018 GMT
|
||||
// Not After : May 17 07:18:16 2038 GMT
|
||||
// Authority Key Identifier:
|
||||
// 60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIIBqjCCAVCgAwIBAgIJAPLY8qZjgNRAMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" +
|
||||
"AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
|
||||
"ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYTAlVT\n" +
|
||||
"MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTEY\n" +
|
||||
"MBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n" +
|
||||
"QgAEb+9n05qfXnfHUb0xtQJNS4JeSi6IjOfW5NqchvKnfJey9VkJzR7QHLuOESdf\n" +
|
||||
"xlR7q8YIWgih3iWLGfB+wxHiOqMjMCEwHwYDVR0jBBgwFoAUYM+9c//6GjDSpOzT\n" +
|
||||
"SXFG7xo1oIYwCgYIKoZIzj0EAwIDSAAwRQIgWpRegWXMheiD3qFdd8kMdrkLxRbq\n" +
|
||||
"1zj8nQMEwFTUjjQCIQDRIrAjZX+YXHN9b0SoWWLPUq0HmiFIi8RwMnO//wJIGQ==\n" +
|
||||
"-----END CERTIFICATE-----",
|
||||
|
||||
// SHA384withECDSA, curve secp384r1
|
||||
// Validity
|
||||
// Not Before: Jun 24 08:15:06 2019 GMT
|
||||
// Not After : Jun 19 08:15:06 2039 GMT
|
||||
// Authority Key Identifier:
|
||||
// 40:2D:AA:EE:66:AA:33:27:AD:9B:5D:52:9B:60:67:6A:2B:AD:52:D2
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIICEjCCAZegAwIBAgIUS3F0AqAXWRg07CnbknJzxofyBQMwCgYIKoZIzj0EAwMw\n" +
|
||||
"OzELMAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0Ug\n" +
|
||||
"VGVzdCBTZXJpdmNlMB4XDTE5MDYyNDA4MTUwNloXDTM5MDYxOTA4MTUwNlowVTEL\n" +
|
||||
"MAkGA1UEBhMCVVMxDTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVz\n" +
|
||||
"dCBTZXJpdmNlMRgwFgYDVQQDDA9SZWdyZXNzaW9uIFRlc3QwdjAQBgcqhkjOPQIB\n" +
|
||||
"BgUrgQQAIgNiAARqElz8b6T07eyKomIinhztV3/3XBk9bKGtJ0W+JOltjuhMmP/w\n" +
|
||||
"G8ASSevpgqgpi6EzpBZaaJxE3zNfkNnxXOZmQi2Ypd1uK0zRdbEOKg0XOcTTZwEj\n" +
|
||||
"iLjYmt3O0pwpklijQjBAMB0GA1UdDgQWBBRALaruZqozJ62bXVKbYGdqK61S0jAf\n" +
|
||||
"BgNVHSMEGDAWgBRKS1IUCtHWn/mZdXSTKjRHEhVr9TAKBggqhkjOPQQDAwNpADBm\n" +
|
||||
"AjEArVDFKf48xijN6huVUJzKCOP0zlWB5Js+DItIkZmLQuhciPLhLIB/rChf3Y4C\n" +
|
||||
"xuP4AjEAmfLhQRI0O3pifpYzYSVh2G7/jHNG4eO+2dvgAcU+Lh2IIj/cpLaPFSvL\n" +
|
||||
"J8FXY9Nj\n" +
|
||||
"-----END CERTIFICATE-----"
|
||||
};
|
||||
|
||||
private static final String[] EE_KEYS = new String[] {
|
||||
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgn5K03bpTLjEtFQRa\n" +
|
||||
"JUtx22gtmGEvvSUSQdimhGthdtihRANCAARv72fTmp9ed8dRvTG1Ak1Lgl5KLoiM\n" +
|
||||
"59bk2pyG8qd8l7L1WQnNHtAcu44RJ1/GVHurxghaCKHeJYsZ8H7DEeI6",
|
||||
"MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDASuI9EtK29APXPipkc\n" +
|
||||
"qDA+qwlewMjv/OcjUJ77kP1Vz62oVF9iY9SRIyFIUju8wt+hZANiAARqElz8b6T0\n" +
|
||||
"7eyKomIinhztV3/3XBk9bKGtJ0W+JOltjuhMmP/wG8ASSevpgqgpi6EzpBZaaJxE\n" +
|
||||
"3zNfkNnxXOZmQi2Ypd1uK0zRdbEOKg0XOcTTZwEjiLjYmt3O0pwpklg="
|
||||
};
|
||||
|
||||
private static final String[] EE_ALGS = new String[] {
|
||||
"EC",
|
||||
"EC"
|
||||
};
|
||||
|
||||
private static final String[] EE_ALIASES = new String[] {
|
||||
"EC-SHA256",
|
||||
"EC-SHA384"
|
||||
};
|
||||
|
||||
private static final Map<Integer, String> SIG_SCHEMES_MAP = Map.of(
|
||||
0x0403, "ecdsa_secp256r1_sha256",
|
||||
0x0503, "ecdsa_secp384r1_sha384");
|
||||
|
||||
private static final int TLS_HS_CLI_HELLO = 1;
|
||||
private static final int TLS_HS_CERT_REQ = 13;
|
||||
private static final int HELLO_EXT_SIG_ALGS = 13;
|
||||
|
||||
public SigAlgosExtTestWithTLS12() throws Exception {
|
||||
super();
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an instance of KeyManager for client use.
|
||||
*/
|
||||
public KeyManager createClientKeyManager() throws Exception {
|
||||
return SSLContextTemplate.createKeyManager(
|
||||
EE_CERTS,
|
||||
EE_KEYS,
|
||||
EE_ALGS,
|
||||
EE_ALIASES,
|
||||
getServerContextParameters());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrustManager createClientTrustManager() throws Exception {
|
||||
return SSLContextTemplate.createTrustManager(
|
||||
CA_CERTS,
|
||||
getServerContextParameters());
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyManager createServerKeyManager() throws Exception {
|
||||
return SSLContextTemplate.createKeyManager(
|
||||
EE_CERTS,
|
||||
EE_KEYS,
|
||||
EE_ALGS,
|
||||
EE_ALIASES,
|
||||
getServerContextParameters());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrustManager createServerTrustManager() throws Exception {
|
||||
return SSLContextTemplate.createTrustManager(
|
||||
CA_CERTS,
|
||||
getServerContextParameters());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SSLEngine configureServerEngine(SSLEngine serverEngine) {
|
||||
serverEngine.setUseClientMode(false);
|
||||
serverEngine.setNeedClientAuth(CLIENT_AUTH);
|
||||
return serverEngine;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SSLEngine configureClientEngine(SSLEngine clientEngine) {
|
||||
clientEngine.setUseClientMode(true);
|
||||
clientEngine.setEnabledProtocols(new String[] { "TLSv1.2" });
|
||||
return clientEngine;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.setProperty("javax.net.debug", "ssl:handshake");
|
||||
|
||||
try {
|
||||
new SigAlgosExtTestWithTLS12().run();
|
||||
if (EXPECT_FAIL) {
|
||||
throw new RuntimeException(
|
||||
"Expected SSLHandshakeException wasn't thrown");
|
||||
}
|
||||
} catch (SSLHandshakeException e) {
|
||||
if (EXPECT_FAIL && e.getMessage().equals(
|
||||
"No supported signature algorithm")) {
|
||||
System.out.println("Expected SSLHandshakeException");
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void run() throws Exception {
|
||||
boolean dataDone = false;
|
||||
while (isOpen(clientEngine) || isOpen(serverEngine)) {
|
||||
clientEngine.wrap(clientOut, cTOs);
|
||||
cTOs.flip();
|
||||
|
||||
// Consume the ClientHello and get the server flight of handshake
|
||||
// messages. We expect that it will be one TLS record containing
|
||||
// multiple handshake messages, one of which is a CertificateRequest
|
||||
// when the client authentication is required.
|
||||
serverEngine.unwrap(cTOs, serverIn);
|
||||
runDelegatedTasks(serverEngine);
|
||||
|
||||
// Wrap the server flight
|
||||
serverEngine.wrap(serverOut, sTOc);
|
||||
sTOc.flip();
|
||||
|
||||
if (CLIENT_AUTH && EXPECT_FAIL) {
|
||||
twistCertReqMsg(sTOc);
|
||||
}
|
||||
|
||||
clientEngine.unwrap(sTOc, clientIn);
|
||||
runDelegatedTasks(clientEngine);
|
||||
|
||||
serverEngine.unwrap(cTOs, serverIn);
|
||||
runDelegatedTasks(serverEngine);
|
||||
|
||||
cTOs.compact();
|
||||
sTOc.compact();
|
||||
|
||||
if (!dataDone && (clientOut.limit() == serverIn.position()) &&
|
||||
(serverOut.limit() == clientIn.position())) {
|
||||
checkTransfer(serverOut, clientIn);
|
||||
checkTransfer(clientOut, serverIn);
|
||||
|
||||
clientEngine.closeOutbound();
|
||||
dataDone = true;
|
||||
serverEngine.closeOutbound();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Twists signature schemes in CertificateRequest message for negative
|
||||
* client authentication cases.
|
||||
*
|
||||
* @param tlsRecord a ByteBuffer containing a TLS record. It is assumed
|
||||
* that the position of the ByteBuffer is on the first byte of the TLS
|
||||
* record header.
|
||||
*
|
||||
* @throws SSLException if the incoming ByteBuffer does not contain a
|
||||
* well-formed TLS message.
|
||||
*/
|
||||
private static void twistCertReqMsg(
|
||||
ByteBuffer tlsRecord) throws SSLException {
|
||||
Objects.requireNonNull(tlsRecord);
|
||||
tlsRecord.mark();
|
||||
|
||||
// Process the TLS record header
|
||||
int type = Byte.toUnsignedInt(tlsRecord.get());
|
||||
int ver_major = Byte.toUnsignedInt(tlsRecord.get());
|
||||
int ver_minor = Byte.toUnsignedInt(tlsRecord.get());
|
||||
int recLen = Short.toUnsignedInt(tlsRecord.getShort());
|
||||
|
||||
// Simple sanity checks
|
||||
if (type != 22) {
|
||||
throw new SSLException("Not a handshake: Type = " + type);
|
||||
} else if (recLen > tlsRecord.remaining()) {
|
||||
throw new SSLException("Incomplete record in buffer: " +
|
||||
"Record length = " + recLen + ", Remaining = " +
|
||||
tlsRecord.remaining());
|
||||
}
|
||||
|
||||
while (tlsRecord.hasRemaining()) {
|
||||
// Grab the handshake message header.
|
||||
int msgHdr = tlsRecord.getInt();
|
||||
int msgType = (msgHdr >> 24) & 0x000000FF;
|
||||
int msgLen = msgHdr & 0x00FFFFFF;
|
||||
|
||||
if (msgType == TLS_HS_CERT_REQ) {
|
||||
// Slice the buffer such that it contains the entire
|
||||
// handshake message (less the handshake header).
|
||||
int bufPos = tlsRecord.position();
|
||||
ByteBuffer buf = tlsRecord.slice(bufPos, msgLen);
|
||||
|
||||
// Replace the signature scheme with an unknown value
|
||||
twistSigSchemesCertReq(buf, (short) 0x0000);
|
||||
byte[] bufBytes = new byte[buf.limit()];
|
||||
buf.get(bufBytes);
|
||||
tlsRecord.put(bufPos, bufBytes);
|
||||
|
||||
break;
|
||||
} else {
|
||||
// Skip to the next handshake message, if there is one
|
||||
tlsRecord.position(tlsRecord.position() + msgLen);
|
||||
}
|
||||
}
|
||||
|
||||
tlsRecord.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the signature schemes in CertificateRequest message with an
|
||||
* alternative value. It is assumed that the provided ByteBuffer has its
|
||||
* position set at the first byte of the CertificateRequest message body
|
||||
* (AFTER the handshake header) and contains the entire CR message. Upon
|
||||
* successful completion of this method the ByteBuffer will have its
|
||||
* position reset to the initial offset in the buffer.
|
||||
* If an exception is thrown the position at the time of the exception
|
||||
* will be preserved.
|
||||
*
|
||||
* @param data the ByteBuffer containing the CertificateRequest bytes
|
||||
* @param altSigScheme an alternative signature scheme
|
||||
*/
|
||||
private static void twistSigSchemesCertReq(ByteBuffer data,
|
||||
Short altSigScheme) {
|
||||
Objects.requireNonNull(data);
|
||||
data.mark();
|
||||
|
||||
// Jump past the certificate types
|
||||
int certTypeLen = Byte.toUnsignedInt(data.get());
|
||||
if (certTypeLen != 0) {
|
||||
data.position(data.position() + certTypeLen);
|
||||
}
|
||||
|
||||
int sigSchemeLen = Short.toUnsignedInt(data.getShort());
|
||||
for (int ssOff = 0; ssOff < sigSchemeLen; ssOff += 2) {
|
||||
System.err.println(
|
||||
"Use alternative signature scheme: " + altSigScheme);
|
||||
data.putShort(data.position(), altSigScheme);
|
||||
}
|
||||
|
||||
data.reset();
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test 8263188
|
||||
* @summary If TLS the server and client has no common signature algorithms,
|
||||
* the connection should fail fast with "No supported signature algorithm".
|
||||
* This test only covers TLS 1.3, but doesn't cover client authentication.
|
||||
*
|
||||
* @library /test/lib
|
||||
* /javax/net/ssl/templates
|
||||
*
|
||||
* @run main/othervm
|
||||
* -Djdk.tls.server.SignatureSchemes=ecdsa_secp384r1_sha384
|
||||
* -Djdk.tls.client.SignatureSchemes=ecdsa_secp256r1_sha256,ecdsa_secp384r1_sha384
|
||||
* -Dtest.expectFail=false
|
||||
* SigAlgosExtTestWithTLS13
|
||||
* @run main/othervm
|
||||
* -Djdk.tls.server.SignatureSchemes=ecdsa_secp384r1_sha384
|
||||
* -Djdk.tls.client.SignatureSchemes=ecdsa_secp256r1_sha256
|
||||
* -Dtest.expectFail=true
|
||||
* SigAlgosExtTestWithTLS13
|
||||
*/
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
public class SigAlgosExtTestWithTLS13 extends SSLSocketTemplate {
|
||||
|
||||
@Override
|
||||
protected SSLContext createServerSSLContext() throws Exception {
|
||||
return createSSLContext(
|
||||
new Cert[] { Cert.CA_ECDSA_SECP256R1, Cert.CA_ECDSA_SECP384R1 },
|
||||
new Cert[] { Cert.EE_ECDSA_SECP256R1, Cert.EE_ECDSA_SECP384R1 },
|
||||
getServerContextParameters());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SSLContext createClientSSLContext() throws Exception {
|
||||
return createSSLContext(
|
||||
new Cert[] { Cert.CA_ECDSA_SECP256R1, Cert.CA_ECDSA_SECP384R1 },
|
||||
new Cert[] { Cert.EE_ECDSA_SECP256R1, Cert.EE_ECDSA_SECP384R1 },
|
||||
getClientContextParameters());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureClientSocket(SSLSocket socket) {
|
||||
socket.setEnabledProtocols(new String[] { "TLSv1.3" });
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
boolean expectFail = Boolean.getBoolean("test.expectFail");
|
||||
try {
|
||||
new SigAlgosExtTestWithTLS13().run();
|
||||
if (expectFail) {
|
||||
throw new RuntimeException(
|
||||
"Expected SSLHandshakeException wasn't thrown");
|
||||
}
|
||||
} catch (SSLHandshakeException e) {
|
||||
if (expectFail && e.getMessage().equals(
|
||||
"No supported signature algorithm")) {
|
||||
System.out.println("Expected SSLHandshakeException");
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user