java-topology/test/jdk/sun/security/ssl/SignatureScheme/AbstractCheckSignatureSchemes.java
russell@unturf.com 0a580b313d undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
2026-03-26 17:11:57 -04:00

246 lines
9.7 KiB
Java

/*
* Copyright (c) 2021, 2025, 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
* 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.
*/
import java.nio.ByteBuffer;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
/**
* This is not a test. Actual tests are implemented by concrete subclasses.
* The abstract class AbstractCheckSignatureSchemes provides a base framework
* for checking TLS signature schemes.
*/
public abstract class AbstractCheckSignatureSchemes extends SSLEngineTemplate {
// Helper map to correlate integral SignatureScheme identifiers to
// their IANA string name counterparts.
protected static final Map<Integer, String> sigSchemeMap = Map.ofEntries(
new SimpleImmutableEntry(0x0401, "rsa_pkcs1_sha256"),
new SimpleImmutableEntry(0x0501, "rsa_pkcs1_sha384"),
new SimpleImmutableEntry(0x0601, "rsa_pkcs1_sha512"),
new SimpleImmutableEntry(0x0403, "ecdsa_secp256r1_sha256"),
new SimpleImmutableEntry(0x0503, "ecdsa_secp384r1_sha384"),
new SimpleImmutableEntry(0x0603, "ecdsa_secp521r1_sha512"),
new SimpleImmutableEntry(0x0804, "rsa_pss_rsae_sha256"),
new SimpleImmutableEntry(0x0805, "rsa_pss_rsae_sha384"),
new SimpleImmutableEntry(0x0806, "rsa_pss_rsae_sha512"),
new SimpleImmutableEntry(0x0807, "ed25519"),
new SimpleImmutableEntry(0x0808, "ed448"),
new SimpleImmutableEntry(0x0809, "rsa_pss_pss_sha256"),
new SimpleImmutableEntry(0x080a, "rsa_pss_pss_sha384"),
new SimpleImmutableEntry(0x080b, "rsa_pss_pss_sha512"),
new SimpleImmutableEntry(0x0101, "rsa_md5"),
new SimpleImmutableEntry(0x0201, "rsa_pkcs1_sha1"),
new SimpleImmutableEntry(0x0202, "dsa_sha1"),
new SimpleImmutableEntry(0x0203, "ecdsa_sha1"),
new SimpleImmutableEntry(0x0301, "rsa_sha224"),
new SimpleImmutableEntry(0x0302, "dsa_sha224"),
new SimpleImmutableEntry(0x0303, "ecdsa_sha224"),
new SimpleImmutableEntry(0x0402, "rsa_pkcs1_sha256"));
// Other useful TLS definitions for these tests
protected static final int TLS_HS_CLI_HELLO = 1;
protected static final int TLS_HS_CERT_REQ = 13;
protected static final int SIG_ALGS_EXT = 13;
protected static final int SIG_ALGS_CERT_EXT = 50;
protected AbstractCheckSignatureSchemes() throws Exception {
super();
}
// Returns the protocol for test to use.
abstract String getProtocol();
protected boolean isDtls() {
return getProtocol().startsWith("DTLS");
}
@Override
protected SSLEngine configureClientEngine(SSLEngine clientEngine) {
clientEngine.setUseClientMode(true);
clientEngine.setEnabledProtocols(new String[]{getProtocol()});
return clientEngine;
}
@Override
protected SSLEngine configureServerEngine(SSLEngine serverEngine) {
serverEngine.setUseClientMode(false);
serverEngine.setWantClientAuth(true);
serverEngine.setEnabledProtocols(new String[]{getProtocol()});
return serverEngine;
}
@Override
protected ContextParameters getServerContextParameters() {
return new ContextParameters(getProtocol(), "PKIX", "NewSunX509");
}
@Override
protected ContextParameters getClientContextParameters() {
return new ContextParameters(getProtocol(), "PKIX", "NewSunX509");
}
protected ByteBuffer extractHandshakeMsg(ByteBuffer tlsRecord, int hsMsgId)
throws SSLException {
return extractHandshakeMsg(tlsRecord, hsMsgId, isDtls());
}
/**
* Parses the ClientHello message and extracts from it a list of
* SignatureScheme values in string form. It is assumed that the provided
* ByteBuffer has its position set at the first byte of the ClientHello
* message body (AFTER the handshake header) and contains the entire
* hello 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 ClientHello bytes.
* @param extCode Code of the TLS extension from which to extract
* signature schemes.
* @return A List of the signature schemes in string form.
*/
protected List<String> getSigSchemesCliHello(
ByteBuffer data, int extCode) {
Objects.requireNonNull(data);
data.mark();
// Skip over the protocol version and client random
data.position(data.position() + 34);
// Jump past the session ID (if there is one)
int sessLen = Byte.toUnsignedInt(data.get());
if (sessLen != 0) {
data.position(data.position() + sessLen);
}
// Skip DTLS-specific opaque cookie if any
if (isDtls()) {
int cookieLen = Byte.toUnsignedInt(data.get());
if (cookieLen != 0) {
data.position(data.position() + cookieLen);
}
}
// Jump past the cipher suites
int csLen = Short.toUnsignedInt(data.getShort());
if (csLen != 0) {
data.position(data.position() + csLen);
}
// ...and the compression
int compLen = Byte.toUnsignedInt(data.get());
if (compLen != 0) {
data.position(data.position() + compLen);
}
// Now for the fun part. Go through the extensions and look
// for the two status request exts.
List<String> extSigAlgs = getSigSchemesFromExt(data, extCode);
// We should be at the end of the ClientHello
data.reset();
return extSigAlgs;
}
/**
* Parses the CertificateRequest message and extracts from it a list of
* SignatureScheme values in string form. 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
*
* @return A List of the signature schemes in string form. If no
* signature_algorithms extension is present in the CertificateRequest
* then an empty list will be returned.
*/
protected List<String> getSigSchemesCertReq(ByteBuffer data) {
Objects.requireNonNull(data);
data.mark();
// Jump past the certificate types
int certTypeLen = Byte.toUnsignedInt(data.get());
if (certTypeLen != 0) {
data.position(data.position() + certTypeLen);
}
// Collect the SignatureAndHashAlgorithms
List<String> extSigAlgs = new ArrayList();
int sigSchemeLen = Short.toUnsignedInt(data.getShort());
for (int ssOff = 0; ssOff < sigSchemeLen; ssOff += 2) {
String schemeName = sigSchemeMap.get(
Short.toUnsignedInt(data.getShort()));
if (schemeName != null) {
extSigAlgs.add(schemeName);
}
}
data.reset();
return extSigAlgs;
}
/**
* Gets signatures schemes from the given TLS extension.
* The buffer should be positioned at the start of the extension.
*/
protected List<String> getSigSchemesFromExt(
ByteBuffer data, int extCode) {
List<String> extSigAlgs = new ArrayList<>();
data.getShort(); // read length
while (data.hasRemaining()) {
int extType = Short.toUnsignedInt(data.getShort());
int extLen = Short.toUnsignedInt(data.getShort());
if (extType == extCode) {
// Start processing signature algorithms
int sigSchemeLen = Short.toUnsignedInt(data.getShort());
for (int ssOff = 0; ssOff < sigSchemeLen; ssOff += 2) {
String schemeName = sigSchemeMap.get(
Short.toUnsignedInt(data.getShort()));
if (schemeName != null) {
extSigAlgs.add(schemeName);
}
}
} else {
// Not the extension we're looking for. Skip past the
// extension data
data.position(data.position() + extLen);
}
}
return extSigAlgs;
}
}