Support SLH-DSA server keys

This commit adds support for server certificates that have SLH-DSA public keys. The code points come from https://datatracker.ietf.org/doc/draft-reddy-tls-slhdsa/. These code points were added to OpenSSL 4.1.0-dev by https://github.com/openssl/openssl/pull/31248.
This commit is contained in:
David
2025-04-28 08:52:01 -07:00
parent 06adbdccc5
commit b662a0f746
2 changed files with 49 additions and 11 deletions
+1
View File
@@ -15,6 +15,7 @@
* Provide an FAQ * Provide an FAQ
* Security fix: HTML-escape URLs in the HTML report to prevent stored XSS from a server-controlled `Location:` header (#3090) * Security fix: HTML-escape URLs in the HTML report to prevent stored XSS from a server-controlled `Location:` header (#3090)
* Detect short-lived certificates (validity period <= `DAYS_VALID_SHORTLIVED`, default 10 days) and no longer flag them red merely for their short lifespan; warn only when less than 24h is left (#3097) * Detect short-lived certificates (validity period <= `DAYS_VALID_SHORTLIVED`, default 10 days) and no longer flag them red merely for their short lifespan; warn only when less than 24h is left (#3097)
* Check for SLH-DSA signatures (draft-reddy-tls-slhdsa)
### Features implemented / improvements in 3.2 ### Features implemented / improvements in 3.2
+48 -11
View File
@@ -1223,6 +1223,10 @@ set_key_str_score() {
if [[ $size -lt 4032 ]] && [[ $KEY_EXCH_SCORE -ge 90 ]]; then if [[ $size -lt 4032 ]] && [[ $KEY_EXCH_SCORE -ge 90 ]]; then
KEY_EXCH_SCORE=90 KEY_EXCH_SCORE=90
fi fi
elif [[ $type == SLH-DSA ]]; then
if [[ $size -lt 48 ]] && [[ $KEY_EXCH_SCORE -ge 90 ]]; then
KEY_EXCH_SCORE=90
fi
fi fi
return 0 return 0
} }
@@ -8700,7 +8704,7 @@ get_server_certificate() {
# For TLS 1.3, the way to indicate what type of certificate the server should use is through the signature_algorithms/-cert extension. # For TLS 1.3, the way to indicate what type of certificate the server should use is through the signature_algorithms/-cert extension.
# So, for TLS 1.3 connections, the -sigalgs option is used with $OPENSSL and an appropriate signature_algorithms (0x0d) extension # So, for TLS 1.3 connections, the -sigalgs option is used with $OPENSSL and an appropriate signature_algorithms (0x0d) extension
# is provided to tls_sockets(). # is provided to tls_sockets().
# The return 1 if $1 is neither tls_1_3_RSA nor tls_1_3_ECDSA is unnecessary. That would only happen if there were a bug in the # The return 1 if $1 is not one of the listed values is unnecessary. That would only happen if there were a bug in the
# code. For example, if someone added another certificate type (e.g., FN-DSA) to run_server_defaults(), but forgot to add corresponding # code. For example, if someone added another certificate type (e.g., FN-DSA) to run_server_defaults(), but forgot to add corresponding
# code to get_server_certificate(). # code to get_server_certificate().
@@ -8742,6 +8746,8 @@ get_server_certificate() {
tls_sockets "04" "$TLS13_CIPHER" "all+" "00,12,00,00, 00,05,00,05,01,00,00,00,00, 00,0d,00,08,00,06,09,04,09,05,09,06" tls_sockets "04" "$TLS13_CIPHER" "all+" "00,12,00,00, 00,05,00,05,01,00,00,00,00, 00,0d,00,08,00,06,09,04,09,05,09,06"
elif [[ "$1" =~ tls1_3_SM2 ]]; then elif [[ "$1" =~ tls1_3_SM2 ]]; then
tls_sockets "04" "$TLS13_CIPHER" "all+" "00,12,00,00, 00,05,00,05,01,00,00,00,00, 00,0d,00,04,00,02,07,08" tls_sockets "04" "$TLS13_CIPHER" "all+" "00,12,00,00, 00,05,00,05,01,00,00,00,00, 00,0d,00,04,00,02,07,08"
elif [[ "$1" =~ tls1_3_SLHDSA ]]; then
tls_sockets "04" "$TLS13_CIPHER" "all+" "00,12,00,00, 00,05,00,05,01,00,00,00,00, 00,0d,00,1a,00,18,09,11,09,12,09,13,09,14,09,15,09,16,09,17,09,18,09,19,09,1a,09,1b,09,1c"
else else
return 1 return 1
fi fi
@@ -9436,6 +9442,8 @@ certificate_transparency() {
extra_extns=", 00,0d,00,06,00,04,08,07,08,08" extra_extns=", 00,0d,00,06,00,04,08,07,08,08"
elif [[ "$cipher" == tls1_3_MLDSA ]]; then elif [[ "$cipher" == tls1_3_MLDSA ]]; then
extra_extns=", 00,0d,00,08,00,06,09,04,09,05,09,06" extra_extns=", 00,0d,00,08,00,06,09,04,09,05,09,06"
elif [[ "$cipher" == tls1_3_SLHDSA ]]; then
extra_extns=", 00,0d,00,1a,00,18,09,11,09,12,09,13,09,14,09,15,09,16,09,17,09,18,09,19,09,1a,09,1b,09,1c"
else else
return 1 return 1
fi fi
@@ -9648,6 +9656,18 @@ certificate_info() {
2.16.840.1.101.3.4.3.17|ML-DSA-44) cert_key_algo="ML-DSA-44"; cert_keysize=2560 ;; 2.16.840.1.101.3.4.3.17|ML-DSA-44) cert_key_algo="ML-DSA-44"; cert_keysize=2560 ;;
2.16.840.1.101.3.4.3.18|ML-DSA-65) cert_key_algo="ML-DSA-65"; cert_keysize=4032 ;; 2.16.840.1.101.3.4.3.18|ML-DSA-65) cert_key_algo="ML-DSA-65"; cert_keysize=4032 ;;
2.16.840.1.101.3.4.3.19|ML-DSA-87) cert_key_algo="ML-DSA-87"; cert_keysize=4896 ;; 2.16.840.1.101.3.4.3.19|ML-DSA-87) cert_key_algo="ML-DSA-87"; cert_keysize=4896 ;;
2.16.840.1.101.3.4.3.20|SLH-DSA-SHA2-128s) cert_key_algo="SLH-DSA-SHA2-128s"; cert_keysize=32 ;;
2.16.840.1.101.3.4.3.21|SLH-DSA-SHA2-128f) cert_key_algo="SLH-DSA-SHA2-128f"; cert_keysize=32 ;;
2.16.840.1.101.3.4.3.22|SLH-DSA-SHA2-192s) cert_key_algo="SLH-DSA-SHA2-192s"; cert_keysize=48 ;;
2.16.840.1.101.3.4.3.23|SLH-DSA-SHA2-192f) cert_key_algo="SLH-DSA-SHA2-192f"; cert_keysize=48 ;;
2.16.840.1.101.3.4.3.24|SLH-DSA-SHA2-256s) cert_key_algo="SLH-DSA-SHA2-256s"; cert_keysize=64 ;;
2.16.840.1.101.3.4.3.25|SLH-DSA-SHA2-256f) cert_key_algo="SLH-DSA-SHAKE-256f"; cert_keysize=64 ;;
2.16.840.1.101.3.4.3.26|SLH-DSA-SHAKE-128s) cert_key_algo="SLH-DSA-SHAKE-128s"; cert_keysize=32 ;;
2.16.840.1.101.3.4.3.27|SLH-DSA-SHAKE-128f) cert_key_algo="SLH-DSA-SHAKE-128f"; cert_keysize=32 ;;
2.16.840.1.101.3.4.3.28|SLH-DSA-SHAKE-192s) cert_key_algo="SLH-DSA-SHAKE-192s"; cert_keysize=48 ;;
2.16.840.1.101.3.4.3.29|SLH-DSA-SHAKE-192f) cert_key_algo="SLH-DSA-SHAKE-192f"; cert_keysize=48 ;;
2.16.840.1.101.3.4.3.30|SLH-DSA-SHAKE-256s) cert_key_algo="SLH-DSA-SHAKE-256s"; cert_keysize=64 ;;
2.16.840.1.101.3.4.3.31|SLH-DSA-SHAKE-256f) cert_key_algo="SLH-DSA-SHAKE-256f"; cert_keysize=64 ;;
esac esac
out "$indent" ; pr_bold " Signature Algorithm " out "$indent" ; pr_bold " Signature Algorithm "
@@ -9793,7 +9813,7 @@ certificate_info() {
*) pr_fixme "don't know $cert_key_algo " *) pr_fixme "don't know $cert_key_algo "
((ret++)) ;; ((ret++)) ;;
esac esac
if [[ $short_keyAlgo != EdDSA ]] && [[ $short_keyAlgo != ML-DSA ]]; then if [[ $short_keyAlgo != EdDSA ]] && [[ $short_keyAlgo != ML-DSA ]] && [[ $short_keyAlgo != SLH-DSA ]]; then
out "$short_keyAlgo " out "$short_keyAlgo "
fi fi
# https://tools.ietf.org/html/rfc4492, https://www.keylength.com/en/compare/ # https://tools.ietf.org/html/rfc4492, https://www.keylength.com/en/compare/
@@ -9852,7 +9872,7 @@ certificate_info() {
fi fi
set_key_str_score "$short_keyAlgo" "$cert_keysize" set_key_str_score "$short_keyAlgo" "$cert_keysize"
elif [[ $cert_key_algo == Ed* ]] || [[ $cert_key_algo == ML-DSA* ]]; then elif [[ $cert_key_algo == Ed* ]] || [[ $cert_key_algo == ML-DSA* ]] || [[ $cert_key_algo == SLH-DSA* ]]; then
pr_svrty_good "$cert_key_algo" pr_svrty_good "$cert_key_algo"
json_rating="OK"; json_msg="$short_keyAlgo $cert_key_algo" json_rating="OK"; json_msg="$short_keyAlgo $cert_key_algo"
set_key_str_score "$short_keyAlgo" "$cert_keysize" set_key_str_score "$short_keyAlgo" "$cert_keysize"
@@ -10723,13 +10743,15 @@ run_server_defaults() {
ciphers_to_test[10]="tls1_3_EdDSA" ciphers_to_test[10]="tls1_3_EdDSA"
ciphers_to_test[11]="tls1_3_MLDSA" ciphers_to_test[11]="tls1_3_MLDSA"
ciphers_to_test[12]="tls1_3_SM2" ciphers_to_test[12]="tls1_3_SM2"
ciphers_to_test[13]="tls1_3_SLHDSA"
certificate_type[1]="" ; certificate_type[2]="" certificate_type[1]="" ; certificate_type[2]=""
certificate_type[3]=""; certificate_type[4]="" certificate_type[3]=""; certificate_type[4]=""
certificate_type[5]="" ; certificate_type[6]="" certificate_type[5]="" ; certificate_type[6]=""
certificate_type[7]="" ; certificate_type[8]="RSASig" certificate_type[7]="" ; certificate_type[8]="RSASig"
certificate_type[9]="ECDSA" ; certificate_type[10]="EdDSA" certificate_type[9]="ECDSA" ; certificate_type[10]="EdDSA"
certificate_type[11]="MLDSA" ; certificate_type[12]="SM2" certificate_type[11]="MLDSA" ; certificate_type[12]="SM2"
nr_cert_types=12 certificate_type[13]="SLHDSA"
local -i nr_cert_types=13
if "$SERVER_SIZE_LIMIT_BUG"; then if "$SERVER_SIZE_LIMIT_BUG"; then
ciphers_to_test[3]="aDSS:aDH:aECDH" ciphers_to_test[3]="aDSS:aDH:aECDH"
@@ -11263,10 +11285,10 @@ run_fs() {
local -a ffdhe_groups_hex=("01,00" "01,01" "01,02" "01,03" "01,04") local -a ffdhe_groups_hex=("01,00" "01,01" "01,02" "01,03" "01,04")
local -a ffdhe_groups_output=("ffdhe2048" "ffdhe3072" "ffdhe4096" "ffdhe6144" "ffdhe8192") local -a ffdhe_groups_output=("ffdhe2048" "ffdhe3072" "ffdhe4096" "ffdhe6144" "ffdhe8192")
local -a supported_curve local -a supported_curve
local -a sigalgs_hex=("01,01" "01,02" "01,03" "02,01" "02,02" "02,03" "03,01" "03,02" "03,03" "04,01" "04,02" "04,03" "04,20" "05,01" "05,02" "05,03" "05,20" "06,01" "06,02" "06,03" "06,20" "07,08" "08,04" "08,05" "08,06" "08,07" "08,08" "08,09" "08,0a" "08,0b" "08,1a" "08,1b" "08,1c" "09,04" "09,05" "09,06") local -a sigalgs_hex=("01,01" "01,02" "01,03" "02,01" "02,02" "02,03" "03,01" "03,02" "03,03" "04,01" "04,02" "04,03" "04,20" "05,01" "05,02" "05,03" "05,20" "06,01" "06,02" "06,03" "06,20" "07,08" "08,04" "08,05" "08,06" "08,07" "08,08" "08,09" "08,0a" "08,0b" "08,1a" "08,1b" "08,1c" "09,04" "09,05" "09,06" "09,11" "09,12" "09,13" "09,14" "09,15" "09,16" "09,17" "09,18" "09,19" "09,1a" "09,1b" "09,1c" )
local -a sigalgs_strings=("RSA+MD5" "DSA+MD5" "ECDSA+MD5" "RSA+SHA1" "DSA+SHA1" "ECDSA+SHA1" "RSA+SHA224" "DSA+SHA224" "ECDSA+SHA224" "RSA+SHA256" "DSA+SHA256" "ECDSA+SHA256" "RSA+SHA256" "RSA+SHA384" "DSA+SHA384" "ECDSA+SHA384" "RSA+SHA384" "RSA+SHA512" "DSA+SHA512" "ECDSA+SHA512" "RSA+SHA512" "sm2sig_sm3" "RSA-PSS-RSAE+SHA256" "RSA-PSS-RSAE+SHA384" "RSA-PSS-RSAE+SHA512" "Ed25519" "Ed448" "RSA-PSS-PSS+SHA256" "RSA-PSS-PSS+SHA384" "RSA-PSS-PSS+SHA512" "ECDSA-BRAINPOOL+SHA256" "ECDSA-BRAINPOOL+SHA384" "ECDSA-BRAINPOOL+SHA512" "ML-DSA-44" "ML-DSA-65" "ML-DSA-87") local -a sigalgs_strings=("RSA+MD5" "DSA+MD5" "ECDSA+MD5" "RSA+SHA1" "DSA+SHA1" "ECDSA+SHA1" "RSA+SHA224" "DSA+SHA224" "ECDSA+SHA224" "RSA+SHA256" "DSA+SHA256" "ECDSA+SHA256" "RSA+SHA256" "RSA+SHA384" "DSA+SHA384" "ECDSA+SHA384" "RSA+SHA384" "RSA+SHA512" "DSA+SHA512" "ECDSA+SHA512" "RSA+SHA512" "sm2sig_sm3" "RSA-PSS-RSAE+SHA256" "RSA-PSS-RSAE+SHA384" "RSA-PSS-RSAE+SHA512" "Ed25519" "Ed448" "RSA-PSS-PSS+SHA256" "RSA-PSS-PSS+SHA384" "RSA-PSS-PSS+SHA512" "ECDSA-BRAINPOOL+SHA256" "ECDSA-BRAINPOOL+SHA384" "ECDSA-BRAINPOOL+SHA512" "ML-DSA-44" "ML-DSA-65" "ML-DSA-87" "SLH-DSA-SHA2-128s" "SLH-DSA-SHA2-128f" "SLH-DSA-SHA2-192s" "SLH-DSA-SHA2-192f" "SLH-DSA-SHA2-256s" "SLH-DSA-SHA2-256f" "SLH-DSA-SHAKE-128s" "SLH-DSA-SHAKE-128f" "SLH-DSA-SHAKE-192s" "SLH-DSA-SHAKE-192f" "SLH-DSA-SHAKE-256s" "SLH-DSA-SHAKE-256f")
local -a tls13_supported_sigalgs=("false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false") local -a tls13_supported_sigalgs=("false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false")
local -a tls12_supported_sigalgs=("false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false") local -a tls12_supported_sigalgs=("false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false" "false")
local rsa_cipher="" ecdsa_cipher="" dss_cipher="" local rsa_cipher="" ecdsa_cipher="" dss_cipher=""
local sigalgs_to_test tls12_supported_sigalg_list="" tls13_supported_sigalg_list="" local sigalgs_to_test tls12_supported_sigalg_list="" tls13_supported_sigalg_list=""
local -i nr_supported_ciphers=0 nr_curves=0 nr_ossl_curves=0 i j low high local -i nr_supported_ciphers=0 nr_curves=0 nr_ossl_curves=0 i j low high
@@ -16375,11 +16397,24 @@ parse_tls_serverhello() {
echo "Peer signature type: $peer_signature_type" >> $TMPFILE echo "Peer signature type: $peer_signature_type" >> $TMPFILE
[[ $DEBUG -ge 3 ]] && echo -e " Peer signature type: $peer_signature_type\n" [[ $DEBUG -ge 3 ]] && echo -e " Peer signature type: $peer_signature_type\n"
elif [[ 0x$peering_signing_digest -eq 9 ]] && \ elif [[ 0x$peering_signing_digest -eq 9 ]] && \
[[ 0x$peer_signature_type -ge 4 ]] && [[ 0x$peer_signature_type -le 6 ]]; then { [[ 0x$peer_signature_type -ge 4 && 0x$peer_signature_type -le 6 ]] ||
[[ 0x$peer_signature_type -ge 17 && 0x$peer_signature_type -le 28 ]]; }; then
case $peer_signature_type in case $peer_signature_type in
04) peering_signing_digest=""; peer_signature_type="ML-DSA-44" ;; 04) peering_signing_digest=""; peer_signature_type="ML-DSA-44" ;;
05) peering_signing_digest=""; peer_signature_type="ML-DSA-65" ;; 05) peering_signing_digest=""; peer_signature_type="ML-DSA-65" ;;
06) peering_signing_digest=""; peer_signature_type="ML-DSA-87" ;; 06) peering_signing_digest=""; peer_signature_type="ML-DSA-87" ;;
11) peering_signing_digest=""; peer_signature_type="SLH-DSA-SHA2-128s" ;;
12) peering_signing_digest=""; peer_signature_type="SLH-DSA-SHA2-128f" ;;
13) peering_signing_digest=""; peer_signature_type="SLH-DSA-SHA2-192s" ;;
14) peering_signing_digest=""; peer_signature_type="SLH-DSA-SHA2-192f" ;;
15) peering_signing_digest=""; peer_signature_type="SLH-DSA-SHA2-256s" ;;
16) peering_signing_digest=""; peer_signature_type="SLH-DSA-SHA2-256f" ;;
17) peering_signing_digest=""; peer_signature_type="SLH-DSA-SHAKE-128s" ;;
18) peering_signing_digest=""; peer_signature_type="SLH-DSA-SHAKE-128f" ;;
19) peering_signing_digest=""; peer_signature_type="SLH-DSA-SHAKE-192s" ;;
1A) peering_signing_digest=""; peer_signature_type="SLH-DSA-SHAKE-192f" ;;
1B) peering_signing_digest=""; peer_signature_type="SLH-DSA-SHAKE-256s" ;;
1C) peering_signing_digest=""; peer_signature_type="SLH-DSA-SHAKE-256f" ;;
esac esac
echo "Peer signature type: $peer_signature_type" >> $TMPFILE echo "Peer signature type: $peer_signature_type" >> $TMPFILE
[[ $DEBUG -ge 3 ]] && echo -e " Peer signature type: $peer_signature_type\n" [[ $DEBUG -ge 3 ]] && echo -e " Peer signature type: $peer_signature_type\n"
@@ -16715,10 +16750,12 @@ prepare_tls_clienthello() {
else else
extension_signature_algorithms=" extension_signature_algorithms="
00, 0d, # Type: signature_algorithms , see RFC 8446 00, 0d, # Type: signature_algorithms , see RFC 8446
00, 30, 00, 2e, # lengths 00, 48, 00, 46, # lengths
04,03, 05,03, 06,03, 08,04, 08,05, 08,06, 04,01, 05,01, 04,03, 05,03, 06,03, 08,04, 08,05, 08,06, 04,01, 05,01,
06,01, 08,09, 08,0a, 08,0b, 08,07, 08,08, 02,01, 02,03, 06,01, 08,09, 08,0a, 08,0b, 08,07, 08,08, 02,01, 02,03,
07,08, 09,04, 09,05, 09,06, 08,1a, 08,1b, 08,1c" 07,08, 09,04, 09,05, 09,06, 08,1a, 08,1b, 08,1c, 09,11,
09,12, 09,13, 09,14, 09,15, 09,16, 09,17, 09,18, 09,19,
09,1a, 09,1b, 09,1c"
fi fi
extension_heartbeat=" extension_heartbeat="