From 607440e43ab60de5b766fe1c327fee120629c3e5 Mon Sep 17 00:00:00 2001 From: tb <> Date: Wed, 29 Jun 2022 21:10:20 +0000 Subject: Add functions that check security level in certs and cert chains. ok beck jsing --- src/lib/libssl/ssl_locl.h | 6 +- src/lib/libssl/ssl_seclevel.c | 143 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 147 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib/libssl/ssl_locl.h b/src/lib/libssl/ssl_locl.h index d979baf301..161a8407af 100644 --- a/src/lib/libssl/ssl_locl.h +++ b/src/lib/libssl/ssl_locl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_locl.h,v 1.403 2022/06/29 20:04:28 tb Exp $ */ +/* $OpenBSD: ssl_locl.h,v 1.404 2022/06/29 21:10:20 tb Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -1300,6 +1300,10 @@ int ssl_ctx_security(const SSL_CTX *ctx, int op, int bits, int nid, int ssl_security(const SSL *ssl, int op, int bits, int nid, void *other); int ssl_ctx_security_dh(const SSL_CTX *ctx, DH *dh); int ssl_security_dh(const SSL *ssl, DH *dh); +int ssl_security_cert(const SSL_CTX *ctx, const SSL *ssl, X509 *x509, + int is_peer, int *out_error); +int ssl_security_cert_chain(const SSL *ssl, STACK_OF(X509) *sk, + X509 *x509, int *out_error); int ssl_get_new_session(SSL *s, int session); int ssl_get_prev_session(SSL *s, CBS *session_id, CBS *ext_block, diff --git a/src/lib/libssl/ssl_seclevel.c b/src/lib/libssl/ssl_seclevel.c index 1db2a2dbcd..b24999498c 100644 --- a/src/lib/libssl/ssl_seclevel.c +++ b/src/lib/libssl/ssl_seclevel.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_seclevel.c,v 1.8 2022/06/29 11:59:23 tb Exp $ */ +/* $OpenBSD: ssl_seclevel.c,v 1.9 2022/06/29 21:10:20 tb Exp $ */ /* * Copyright (c) 2020 Theo Buehler * @@ -17,10 +17,15 @@ #include +#include #include +#include +#include +#include #include #include #include +#include #include "ssl_locl.h" @@ -247,3 +252,139 @@ ssl_security_dh(const SSL *ssl, DH *dh) return 1; #endif } + +#if defined(LIBRESSL_HAS_SECURITY_LEVEL) +static int +ssl_cert_pubkey_security_bits(const X509 *x509) +{ + EVP_PKEY *pkey; + + if ((pkey = X509_get0_pubkey(x509)) == NULL) + return -1; + + /* + * XXX: DSA_security_bits() returns -1 on keys without parameters and + * cause the default security callback to fail. + */ + + return EVP_PKEY_security_bits(pkey); +} + +static int +ssl_security_cert_key(const SSL_CTX *ctx, const SSL *ssl, X509 *x509, int op) +{ + int security_bits; + + security_bits = ssl_cert_pubkey_security_bits(x509); + + if (ssl != NULL) + return ssl_security(ssl, op, security_bits, 0, x509); + + return ssl_ctx_security(ctx, op, security_bits, 0, x509); +} + +static int +ssl_cert_signature_md_nid(const X509 *x509) +{ + int md_nid, signature_nid; + + if ((signature_nid = X509_get_signature_nid(x509)) == NID_undef) + return NID_undef; + + if (!OBJ_find_sigid_algs(signature_nid, &md_nid, NULL)) + return NID_undef; + + return md_nid; +} + +static int +ssl_cert_md_nid_security_bits(int md_nid) +{ + const EVP_MD *md; + + if (md_nid == NID_undef) + return -1; + + if ((md = EVP_get_digestbynid(md_nid)) == NULL) + return -1; + + /* Assume 4 bits of collision resistance for each hash octet. */ + return EVP_MD_size(md) * 4; +} + +static int +ssl_security_cert_sig(const SSL_CTX *ctx, const SSL *ssl, X509 *x509, int op) +{ + int md_nid, security_bits; + + md_nid = ssl_cert_signature_md_nid(x509); + security_bits = ssl_cert_md_nid_security_bits(md_nid); + + if (ssl != NULL) + return ssl_security(ssl, op, security_bits, md_nid, x509); + + return ssl_ctx_security(ctx, op, security_bits, md_nid, x509); +} +#endif + +int +ssl_security_cert(const SSL_CTX *ctx, const SSL *ssl, X509 *x509, + int is_ee, int *out_error) +{ +#if defined(LIBRESSL_HAS_SECURITY_LEVEL) + int key_error, operation; + + *out_error = 0; + + if (is_ee) { + operation = SSL_SECOP_EE_KEY; + key_error = SSL_R_EE_KEY_TOO_SMALL; + } else { + operation = SSL_SECOP_CA_KEY; + key_error = SSL_R_CA_KEY_TOO_SMALL; + } + + if (!ssl_security_cert_key(ctx, ssl, x509, operation)) { + *out_error = key_error; + return 0; + } + + if (!ssl_security_cert_sig(ctx, ssl, x509, SSL_SECOP_CA_MD)) { + *out_error = SSL_R_CA_MD_TOO_WEAK; + return 0; + } + +#endif + return 1; +} + +/* + * Check security of a chain. If |sk| includes the end entity certificate + * then |x509| must be NULL. + */ +int +ssl_security_cert_chain(const SSL *ssl, STACK_OF(X509) *sk, X509 *x509, + int *out_error) +{ + int start_idx = 0; + int is_ee; + int i; + + if (x509 == NULL) { + x509 = sk_X509_value(sk, 0); + start_idx = 1; + } + + if (!ssl_security_cert(NULL, ssl, x509, is_ee = 1, out_error)) + return 0; + + for (i = start_idx; i < sk_X509_num(sk); i++) { + x509 = sk_X509_value(sk, i); + + if (!ssl_security_cert(NULL, ssl, x509, is_ee = 0, + out_error)) + return 0; + } + + return 1; +} -- cgit v1.2.3-55-g6feb