From 075c048b99cefdce1245c13c4aa449b28ce8366c Mon Sep 17 00:00:00 2001 From: tb <> Date: Wed, 28 Aug 2024 07:15:04 +0000 Subject: Implement X509_get_signature_info() This is a slightly strange combination of OBJ_find_sigid_algs() and the security level API necessary because OBJ_find_sigid_algs() on its own isn't smart enough for the special needs of RSA-PSS and EdDSA. The API extracts the hash's NID and the pubkey's NID from the certificate's signatureAlgorithm and invokes special handlers for RSA-PSS and EdDSA for retrieving the corresponding information. This isn't entirely free for RSA-PSS, but for now we don't cache this information. The security bits calculation is a bit hand-wavy, but that's something that comes along with this sort of numerology. ok jsing --- src/lib/libcrypto/x509/x509.h | 10 ++- src/lib/libcrypto/x509/x509_siginfo.c | 113 ++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 src/lib/libcrypto/x509/x509_siginfo.c (limited to 'src/lib/libcrypto/x509') diff --git a/src/lib/libcrypto/x509/x509.h b/src/lib/libcrypto/x509/x509.h index 87bc6dbb33..856ad19ba4 100644 --- a/src/lib/libcrypto/x509/x509.h +++ b/src/lib/libcrypto/x509/x509.h @@ -1,4 +1,4 @@ -/* $OpenBSD: x509.h,v 1.112 2024/06/12 03:55:46 tb Exp $ */ +/* $OpenBSD: x509.h,v 1.113 2024/08/28 07:15:04 tb Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -622,6 +622,14 @@ X509 * d2i_X509_AUX(X509 **a,const unsigned char **pp,long length); int i2d_re_X509_tbs(X509 *x, unsigned char **pp); +#if defined(LIBRESSL_INTERNAL) || defined(LIBRESSL_NEXT_API) +/* Flags returned by X509_get_signature_info(): valid and suitable for TLS. */ +#define X509_SIG_INFO_VALID 1 +#define X509_SIG_INFO_TLS 2 +int X509_get_signature_info(X509 *x, int *mdnid, int *pknid, int *secbits, + uint32_t *flags); +#endif + void X509_get0_signature(const ASN1_BIT_STRING **psig, const X509_ALGOR **palg, const X509 *x); int X509_get_signature_nid(const X509 *x); diff --git a/src/lib/libcrypto/x509/x509_siginfo.c b/src/lib/libcrypto/x509/x509_siginfo.c new file mode 100644 index 0000000000..9bbb133216 --- /dev/null +++ b/src/lib/libcrypto/x509/x509_siginfo.c @@ -0,0 +1,113 @@ +/* $OpenBSD: x509_siginfo.c,v 1.1 2024/08/28 07:15:04 tb Exp $ */ + +/* + * Copyright (c) 2024 Theo Buehler + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "evp_local.h" + +#include "x509_internal.h" + +static int +x509_find_sigid_algs(const X509 *x509, int *out_md_nid, int *out_pkey_nid) +{ + const ASN1_OBJECT *aobj; + int nid; + + *out_md_nid = NID_undef; + *out_pkey_nid = NID_undef; + + X509_ALGOR_get0(&aobj, NULL, NULL, x509->sig_alg); + if ((nid = OBJ_obj2nid(aobj)) == NID_undef) + return 0; + + return OBJ_find_sigid_algs(nid, out_md_nid, out_pkey_nid); +} + +int +X509_get_signature_info(X509 *x509, int *out_md_nid, int *out_pkey_nid, + int *out_security_bits, uint32_t *out_flags) +{ + const EVP_MD *md; + int md_nid = NID_undef, pkey_nid = NID_undef, security_bits = -1; + uint32_t flags = 0; + + if (out_md_nid != NULL) + *out_md_nid = md_nid; + if (out_pkey_nid != NULL) + *out_pkey_nid = pkey_nid; + if (out_security_bits != NULL) + *out_security_bits = security_bits; + if (out_flags != NULL) + *out_flags = flags; + + if (!x509v3_cache_extensions(x509)) + goto err; + + if (!x509_find_sigid_algs(x509, &md_nid, &pkey_nid)) + goto err; + + /* + * If md_nid == NID_undef, this means we need to consult the ameth. + * Handlers are available for EdDSA and RSA-PSS. No other signature + * algorithm with NID_undef should appear in a certificate. + */ + if (md_nid == NID_undef) { + const EVP_PKEY_ASN1_METHOD *ameth; + + if ((ameth = EVP_PKEY_asn1_find(NULL, pkey_nid)) == NULL || + ameth->signature_info == NULL) + goto err; + + if (!ameth->signature_info(x509->sig_alg, &md_nid, &pkey_nid, + &security_bits, &flags)) + goto err; + + goto done; + } + + /* XXX - OpenSSL 3 special cases SHA-1 (63 bits) and MD5 (39 bits). */ + if ((md = EVP_get_digestbynid(md_nid)) == NULL) + goto err; + + /* Assume 4 bits of collision resistance per octet. */ + if ((security_bits = EVP_MD_size(md)) <= 0) + goto err; + security_bits *= 4; + + if (md_nid == NID_sha1 || md_nid == NID_sha256 || + md_nid == NID_sha384 || md_nid == NID_sha512) + flags |= X509_SIG_INFO_TLS; + + flags |= X509_SIG_INFO_VALID; + + done: + if (out_md_nid != NULL) + *out_md_nid = md_nid; + if (out_pkey_nid != NULL) + *out_pkey_nid = pkey_nid; + if (out_security_bits != NULL) + *out_security_bits = security_bits; + if (out_flags != NULL) + *out_flags = flags; + + err: + return (flags & X509_SIG_INFO_VALID) != 0; +} +LCRYPTO_ALIAS(X509_get_signature_info); -- cgit v1.2.3-55-g6feb