### Changes between 3.6 and 4.0 [xx XXX xxxx]
+ * New `SSL_get0_sigalg()` and `SSL_get0_shared_sigalg()` functions report the
+ TLS signature algorithm name and codepoint for the peer advertised and shared
+ algorithms respectively. These supersede the existing `SSL_get_sigalgs()` and
+ `SSL_get_shared_sigalgs()` functions which are only a good fit for TLS 1.2.
+ The names reported are the IANA names, and are expected to consistently match
+ the names expected in `SignatureAlgorithms` configuration settings, see
+ `SSL_CONF_cmd(3)` for details. Previously reported names were not always directly
+ usable or configurations, and were mostly OpenSSL-specific aliases that
+ rarely matched the official IANA codepoint names.
+
+ There is an associated change in how signature algorithms are reported by the
+ `openssl-s_client(1)` and `openssl-s_server(1)` command-line tools. They
+ now use the new functions and report the IANA registered names of each
+ signature scheme. Example new output:
+
+ ```
+ Signature Algorithms: mldsa65:mldsa87:mldsa44:ecdsa_secp256r1_sha256:ecdsa_secp384r1_sha384:ecdsa_secp521r1_sha512:ed25519:ed448:ecdsa_brainpoolP256r1tls13_sha256:ecdsa_brainpoolP384r1tls13_sha384:ecdsa_brainpoolP512r1tls13_sha512:rsa_pss_pss_sha256:rsa_pss_pss_sha384:rsa_pss_pss_sha512:rsa_pss_rsae_sha256:rsa_pss_rsae_sha384:rsa_pss_rsae_sha512:rsa_pkcs1_sha256:rsa_pkcs1_sha384:rsa_pkcs1_sha512:ecdsa_sha224:rsa_pkcs1_sha224:dsa_sha224:dsa_sha256:dsa_sha384:dsa_sha512
+ ```
+
+ *Viktor Dukhovni*
+
* Updated the default group list to append `SecP256r1MKEM768` and
`curveSM2MLKEM768` to the first tuple in that order after `*X25519MLKEM768`.
Also inserted a penultimate tuple with `curveSM2` (just before the `FFDHE`
client = SSL_is_server(s) ? 0 : 1;
if (shared)
- nsig = SSL_get_shared_sigalgs(s, 0, NULL, NULL, NULL, NULL, NULL);
+ nsig = SSL_get0_shared_sigalg(s, -1, NULL, NULL);
else
- nsig = SSL_get_sigalgs(s, -1, NULL, NULL, NULL, NULL, NULL);
+ nsig = SSL_get0_sigalg(s, -1, NULL, NULL);
if (nsig == 0)
return 1;
BIO_puts(out, "Requested ");
BIO_puts(out, "Signature Algorithms: ");
for (i = 0; i < nsig; i++) {
- int hash_nid, sign_nid;
- unsigned char rhash, rsign;
- const char *sstr = NULL;
+ const char *name = NULL;
+ unsigned int codepoint;
+
if (shared)
- SSL_get_shared_sigalgs(s, i, &sign_nid, &hash_nid, NULL,
- &rsign, &rhash);
+ SSL_get0_shared_sigalg(s, i, &codepoint, &name);
else
- SSL_get_sigalgs(s, i, &sign_nid, &hash_nid, NULL, &rsign, &rhash);
- if (i)
+ SSL_get0_sigalg(s, i, &codepoint, &name);
+ if (i > 0)
BIO_puts(out, ":");
- switch (rsign | rhash << 8) {
- case 0x0809:
- BIO_puts(out, "rsa_pss_pss_sha256");
- continue;
- case 0x080a:
- BIO_puts(out, "rsa_pss_pss_sha384");
- continue;
- case 0x080b:
- BIO_puts(out, "rsa_pss_pss_sha512");
- continue;
- case 0x081a:
- BIO_puts(out, "ecdsa_brainpoolP256r1_sha256");
- continue;
- case 0x081b:
- BIO_puts(out, "ecdsa_brainpoolP384r1_sha384");
- continue;
- case 0x081c:
- BIO_puts(out, "ecdsa_brainpoolP512r1_sha512");
- continue;
- }
- sstr = get_sigtype(sign_nid);
- if (sstr)
- BIO_puts(out, sstr);
+ if (name != NULL)
+ BIO_puts(out, name);
else
- BIO_printf(out, "0x%02X", (int)rsign);
- if (hash_nid != NID_undef)
- BIO_printf(out, "+%s", OBJ_nid2sn(hash_nid));
- else if (sstr == NULL)
- BIO_printf(out, "+0x%02X", (int)rhash);
+ BIO_printf(out, "0x%04X", codepoint);
}
BIO_puts(out, "\n");
return 1;
const SSL_CIPHER *c;
X509 *peer = SSL_get0_peer_certificate(s);
EVP_PKEY *peer_rpk = SSL_get0_peer_rpk(s);
+ const char *local_sigalg = NULL;
int nid;
BIO_printf(bio_err, "Protocol version: %s\n", SSL_get_version(s));
c = SSL_get_current_cipher(s);
BIO_printf(bio_err, "Ciphersuite: %s\n", SSL_CIPHER_get_name(c));
do_print_sigalgs(bio_err, s, 0);
+ if (SSL_get0_signature_name(s, &local_sigalg) > 0
+ && local_sigalg != NULL)
+ BIO_printf(bio_err, "Own signature type: %s\n", local_sigalg);
if (peer != NULL) {
BIO_puts(bio_err, "Peer certificate: ");
X509_NAME_print_ex(bio_err, X509_get_subject_name(peer),
=head1 NAME
-SSL_get_shared_sigalgs, SSL_get_sigalgs - get supported signature algorithms
+SSL_get0_shared_sigalg, SSL_get0_sigalg,
+SSL_get_shared_sigalgs, SSL_get_sigalgs -
+get shared or peer signature algorithms
=head1 SYNOPSIS
#include <openssl/ssl.h>
+ int SSL_get0_sigalg(SSL *s, int idx, unsigned int *codepoint,
+ const char **name);
+
+ int SSL_get0_shared_sigalg(SSL *s, int idx, unsigned int *codepoint,
+ const char **name);
+
int SSL_get_shared_sigalgs(SSL *s, int idx,
int *psign, int *phash, int *psignhash,
unsigned char *rsig, unsigned char *rhash);
=head1 DESCRIPTION
-SSL_get_shared_sigalgs() returns information about the shared signature
-algorithms supported by peer B<s>. The parameter B<idx> indicates the index
-of the shared signature algorithm to return starting from zero. The signature
-algorithm NID is written to B<*psign>, the hash NID to B<*phash> and the
-sign and hash NID to B<*psignhash>. The raw signature and hash values
-are written to B<*rsig> and B<*rhash>.
+SSL_get0_shared_sigalg() returns the names and codepoints of signature
+algorithms shared with the peer in the SSL connection I<s>.
+When I<idx> is negative, the number of algorithms is returned, and the output
+parameters remain unmodified.
+Otherwise, when I<idx> is nonnegative, it is the index of the shared
+signature algorithm to return starting from zero.
+The signature algorithm name is written to I<*name> (if I<name>) is not NULL).
+The name reported is the IANA registered name for that algorithm, and is
+expected to work verbatim if used in a B<SignatureAlgorithms> configuration
+setting (see L<SSL_CONF_cmd(3)>).
+The signature algorithm codepoint is written to I<*codepoint> (if I<codepoint>
+is not NULL).
+This function is better suited for inspecting TLS 1.3 signature algorithms than
+the older SSL_get_shared_sigalgs().
+
+SSL_get0_sigalg() returns the names and codepoints of signature
+algorithms advertised by the peer in the SSL connection I<s>.
+When I<idx> is negative, the number of algorithms is returned, and the output
+parameters remain unmodified.
+Otherwise, when I<idx> is nonnegative, it is the index of the peer
+signature algorithm to return starting from zero.
+For signature algorithms that are locally known, the name reported is the IANA
+registered name for that algorithm, and is expected to work verbatim if used in
+a B<SignatureAlgorithms> configuration setting (see L<SSL_CONF_cmd(3)>).
+The signature algorithm codepoint is written to I<*codepoint> (if I<codepoint>
+is not NULL).
+If the signature algorithm is known, its name is written to I<*name> (if
+I<name>) is not NULL).
+This function is better suited for inspecting TLS 1.3 signature algorithms than
+the older SSL_get_sigalgs().
+
+SSL_get_shared_sigalgs() returns information about the supported signature
+algorithms shared with the peer in the SSL connection I<s>.
+When I<idx> is negative, the number of shared algorithms is returned, and
+the output parameters remain unmodified.
+Otherwise, when I<idx> is nonnegative, it is the index of the shared
+signature algorithm to return starting from zero.
+The signature algorithm NID is written to I<*psign>, the hash NID to I<*phash>
+and the sign and hash NID to I<*psignhash>.
+As of TLS 1.3 signature algorithms are not always a pairing of of a separate
+public key algorithm and a digest algorithm, and so I<*phash> and I<*psignhash>
+may not always be meaningful.
+The raw B<hash> and B<signature> bytes of the signature algorithm codepoint are
+written to I<*rhash> and I<*rsig>.
+For example, the B<rsa_pkcs1_sha256> signature algorithm, with codepoint B<0x0401>,
+gives B<0x04> for I<*rhash> and B<0x01> for I<*rsig>.
SSL_get_sigalgs() is similar to SSL_get_shared_sigalgs() except it returns
-information about all signature algorithms supported by B<s> in the order
+information about all signature algorithms advertised by the peer in the order
they were sent by the peer.
=head1 RETURN VALUES
-SSL_get_shared_sigalgs() and SSL_get_sigalgs() return the number of
-signature algorithms or B<0> if the B<idx> parameter is out of range.
+SSL_get0_sigalg(), SSL_get0_shared_sigalg(), SSL_get_shared_sigalgs() and
+SSL_get_sigalgs() return the number of signature algorithms or B<0> if the
+I<idx> parameter is out of range (too large).
=head1 NOTES
signature algorithm it can just set B<idx> to zero.
Any or all of the parameters B<psign>, B<phash>, B<psignhash>, B<rsig> or
-B<rhash> can be set to B<NULL> if the value is not required. By setting
-them all to B<NULL> and setting B<idx> to zero the total number of
+B<rhash> can be set to NULL if the value is not required. By setting
+them all to NULL and setting B<idx> to zero the total number of
signature algorithms can be determined: which can be zero.
These functions must be called after the peer has sent a list of supported
L<SSL_CTX_set_cert_cb(3)>,
L<ssl(7)>
+=head1 HISTORY
+
+Prior to OpenSSL 4.0 SSL_get_shared_sigalgs() treated negative I<idx> values
+the same way as out-of-range (too large positive) values, and returned 0.
+
+SSL_get0_shared_sigalg() and SSL_get0_sigalg() were added in OpenSSL
+4.0.
+
=head1 COPYRIGHT
Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved.
int SSL_get_peer_signature_type_nid(const SSL *s, int *pnid);
int SSL_get_signature_type_nid(const SSL *s, int *pnid);
+int SSL_get0_sigalg(SSL *s, int idx, unsigned int *codepoint,
+ const char **name);
+int SSL_get0_shared_sigalg(SSL *s, int idx, unsigned int *codepoint,
+ const char **name);
+
int SSL_get_sigalgs(SSL *s, int idx,
int *psign, int *phash, int *psignandhash,
unsigned char *rsig, unsigned char *rhash);
return retval;
}
-/* Lookup TLS signature algorithm */
-static const SIGALG_LOOKUP *tls1_lookup_sigalg(const SSL_CTX *ctx,
+/* Find known TLS signature algorithm */
+static const SIGALG_LOOKUP *tls1_find_sigalg(const SSL_CTX *ctx,
uint16_t sigalg)
{
- size_t i;
const SIGALG_LOOKUP *lu = ctx->sigalg_lookup_cache;
- for (i = 0; i < ctx->sigalg_lookup_cache_len; lu++, i++) {
- if (lu->sigalg == sigalg) {
- if (!lu->available)
- return NULL;
+ for (size_t i = 0; i < ctx->sigalg_lookup_cache_len; lu++, i++)
+ if (lu->sigalg == sigalg)
return lu;
- }
- }
return NULL;
}
+/* Look up available TLS signature algorithm */
+static const SIGALG_LOOKUP *tls1_lookup_sigalg(const SSL_CTX *ctx,
+ uint16_t sigalg)
+{
+ const SIGALG_LOOKUP *lu = tls1_find_sigalg(ctx, sigalg);
+
+ return (lu != NULL && lu->available) ? lu : NULL;
+}
+
/* Lookup hash: return 0 if invalid or not enabled */
int tls1_lookup_md(SSL_CTX *ctx, const SIGALG_LOOKUP *lu, const EVP_MD **pmd)
{
unsigned char *rsig, unsigned char *rhash)
{
uint16_t *psig;
- size_t numsigalgs;
+ int numsigalgs;
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
if (sc == NULL)
return 0;
- psig = sc->s3.tmp.peer_sigalgs;
- numsigalgs = sc->s3.tmp.peer_sigalgslen;
-
- if (psig == NULL || numsigalgs > INT_MAX)
+ /* A TLS peer can't propose more sigalgs than would fit in an int. */
+ numsigalgs = (int)sc->s3.tmp.peer_sigalgslen;
+ if (idx >= numsigalgs || (psig = sc->s3.tmp.peer_sigalgs) == NULL)
return 0;
+
if (idx >= 0) {
const SIGALG_LOOKUP *lu;
- if (idx >= (int)numsigalgs)
- return 0;
psig += idx;
if (rhash != NULL)
*rhash = (unsigned char)((*psig >> 8) & 0xff);
return (int)sc->shared_sigalgslen;
}
+int SSL_get0_sigalg(SSL *s, int idx, unsigned int *codepoint,
+ const char **name)
+{
+ SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+ const SIGALG_LOOKUP *lu;
+ uint16_t *psig;
+ int numsigalgs;
+
+ if (sc == NULL)
+ return 0;
+
+ /* A TLS peer can't propose more sigalgs than would fit in an int. */
+ numsigalgs = (int)sc->s3.tmp.peer_sigalgslen;
+ if (idx >= numsigalgs || (psig = sc->s3.tmp.peer_sigalgs) == NULL)
+ return 0;
+
+ if (idx >= 0) {
+ if (codepoint != NULL)
+ *codepoint = psig[idx];
+ lu = tls1_find_sigalg(SSL_CONNECTION_GET_CTX(sc), psig[idx]);
+ if (name != NULL)
+ *name = lu == NULL ? NULL : lu->name;
+ }
+ return numsigalgs;
+}
+
+int SSL_get0_shared_sigalg(SSL *s, int idx, unsigned int *codepoint,
+ const char **name)
+{
+ SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+ const SIGALG_LOOKUP *lu;
+ int numsigalgs;
+
+ if (sc == NULL)
+ return 0;
+
+ /* A TLS peer can't propose more sigalgs than would fit in an int. */
+ numsigalgs = (int)sc->shared_sigalgslen;
+ if (idx >= numsigalgs || sc->shared_sigalgs == NULL)
+ return 0;
+
+ if (idx >= 0) {
+ lu = sc->shared_sigalgs[idx];
+ if (codepoint != NULL)
+ *codepoint = lu->sigalg;
+ if (name != NULL)
+ *name = lu->name;
+ }
+ return numsigalgs;
+}
+
/* Maximum possible number of unique entries in sigalgs array */
#define TLS_MAX_SIGALGCNT (OSSL_NELEM(sigalg_lookup_tbl) * 2)
OSSL_LIB_CTX *clientctx = libctx, *serverctx = libctx;
OSSL_PROVIDER *filterprov = NULL;
int sig, hash, numshared, numshared_expected, hash_expected, sig_expected;
- const char *sigalg_name, *signame_expected;
+ unsigned char rsig, rhash;
+ unsigned int sigalg, csigalg_expected;
+ const char *sigalg_name, *signame_expected, *csigname_expected;
if (!TEST_ptr(tmpctx))
goto end;
/* For tests 0 and 3 we expect 2 shared sigalgs, otherwise exactly 1 */
numshared = SSL_get_shared_sigalgs(serverssl, 0, &sig, &hash,
- NULL, NULL, NULL);
+ NULL, &rsig, &rhash);
numshared_expected = 1;
hash_expected = NID_sha256;
sig_expected = NID_rsassaPss;
signame_expected = "rsa_pss_rsae_sha256";
+ csigname_expected = "rsa_pss_rsae_sha256";
+ csigalg_expected = 0x0804;
switch (idx) {
case 0:
- hash_expected = NID_sha384;
signame_expected = "rsa_pss_rsae_sha384";
+ hash_expected = NID_sha384;
+ numshared_expected = 2;
/* FALLTHROUGH */
+ case 2:
+ csigname_expected = "rsa_pss_rsae_sha384";
+ csigalg_expected = 0x0805;
+ break;
case 3:
numshared_expected = 2;
break;
case 4:
+ csigname_expected = "ecdsa_secp256r1_sha256";
+ csigalg_expected = 0x0403;
case 5:
sig_expected = EVP_PKEY_EC;
signame_expected = "ecdsa_secp256r1_sha256";
|| !TEST_int_eq(sig, sig_expected)
|| !TEST_true(SSL_get0_peer_signature_name(clientssl, &sigalg_name))
|| !TEST_ptr(sigalg_name)
- || !TEST_str_eq(sigalg_name, signame_expected))
+ || !TEST_str_eq(sigalg_name, signame_expected)
+ || !TEST_int_gt(SSL_get0_shared_sigalg(serverssl, 0, &sigalg, &sigalg_name), 0)
+ || !TEST_int_eq(sigalg, (((int)rhash) << 8) | rsig)
+ || !TEST_str_eq(sigalg_name, signame_expected)
+ || !TEST_int_gt(SSL_get0_sigalg(serverssl, 0, &sigalg, &sigalg_name), 0)
+ || !TEST_int_eq(sigalg, csigalg_expected)
+ || !TEST_str_eq(sigalg_name, csigname_expected))
goto end;
testresult = filter_provider_check_clean_finish();
SSL_ech_get1_retry_config ? 4_0_0 EXIST::FUNCTION:ECH
SSL_CTX_ech_set1_outer_alpn_protos ? 4_0_0 EXIST::FUNCTION:ECH
SSL_set1_ech_config_list ? 4_0_0 EXIST::FUNCTION:ECH
+SSL_get0_sigalg ? 4_0_0 EXIST::FUNCTION:
+SSL_get0_shared_sigalg ? 4_0_0 EXIST::FUNCTION: