From: Arran Cudbard-Bell Date: Wed, 25 Aug 2021 02:11:57 +0000 (-0500) Subject: Verify certificates are valid X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d94fe9070c1645758fdb635d0ab95c30f508d671;p=thirdparty%2Ffreeradius-server.git Verify certificates are valid Check certificate validity periods explicitly for lib/tls users and rlm_cipher Add %(_certificate:notBefore) and %(_certificate:notAfter) --- diff --git a/raddb/mods-available/cipher b/raddb/mods-available/cipher index acf86f28d89..c2d4b1dafa5 100644 --- a/raddb/mods-available/cipher +++ b/raddb/mods-available/cipher @@ -19,6 +19,10 @@ # | `%{_decrypt:...}` | Decrypts ciphertext using `private_key_file` # | `%{_sign:...}` | Signs plaintext using `private_key_file` # | `%{<inst>_verify:<signature> <plaintext>...}` | Validates a signature using `certificate_file` +# | `%(<inst>_certificate:serial)` | Returns the serial of `certificate_file` +# | `%(<inst>_certificate:fingerprint <hash>)` | Produces a fingerprint of `certificate_file` using the specified hash. +# | `%(<inst>_certificate:not_before)` | Retrieves the notBefore time from `certificate_file`. +# | `%(<inst>_certificate:not_after)` | Retrieves the notAfter time from `certificate_file`. # |=== # # NOTE: `<ciphertext>` and `<signature>` are ingested and excreted to in their raw form. @@ -84,6 +88,26 @@ cipher { # certificate_file = ${certdir}/rsa/server.pem + # + # verify_mode:: How we verify certificate_file on startup + # + # After reading the certificate file from disk and parsing it we can + # apply other checks to ensure it is valid. Currently we check + # the `notBefore` and `notAfter` fields to ensure the certificate is + # temporally valid. Key use checks may be added in future. + # + # [options="header,autowidth"] + # |=== + # | Error | Description + # | hard | Error out if the certificate is not yet valid or has expired. + # | soft | Warn if the certificate is not yet valid or has expired. + # | none | Stay silent if the certificate is not yet valid. + # |=== + # + # The default is `hard`. + # +# verify_mode = "hard" + # # oaep { ... }:: # diff --git a/src/lib/server/module.h b/src/lib/server/module.h index c540b61f48f..79a0a51f59a 100644 --- a/src/lib/server/module.h +++ b/src/lib/server/module.h @@ -259,8 +259,9 @@ typedef struct { * */ struct module_ctx_s { - void *instance; //!< Global instance data for the module. - void *thread; //!< Thread specific instance data. + void *instance; //!< Global instance data for the module. + void *thread; //!< Thread specific instance data. + void *rctx; //!< Resume ctx that a module previously set. }; /** @name Convenience wrappers around other internal APIs to make them easier to instantiate with modules diff --git a/src/lib/tls/all.mk b/src/lib/tls/all.mk index 00c6497b76b..d90834ca48d 100644 --- a/src/lib/tls/all.mk +++ b/src/lib/tls/all.mk @@ -8,6 +8,7 @@ SOURCES := \ base.c \ bio.c \ cache.c \ + cert.c \ conf.c \ ctx.c \ engine.c \ diff --git a/src/lib/tls/cert.c b/src/lib/tls/cert.c new file mode 100644 index 00000000000..ff5a40752df --- /dev/null +++ b/src/lib/tls/cert.c @@ -0,0 +1,93 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * $Id$ + * + * @file tls/cert.c + * @brief Functions to work with certificates. + * + * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org) + */ +RCSID("$Id$") +USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ + +#ifdef WITH_TLS +#define LOG_PREFIX "tls - " + +#include <openssl/ssl.h> + +#include <freeradius-devel/util/strerror.h> + +#include "cert.h" +#include "utils.h" + +/** Check if a certificate is currently valid + * + * @param[out] not_before_p Where to write the not before time. May be NULL. + * @param[out] not_after_p Where to write the not after time. May be NULL. + * @parma[in] cert The Certificate to validate. + * @return + * - -1 if we can't parse the notBefore or notAfter values in the cert. + * - -2 if the cert has expired (not_before_p, not_after_p still populated). + * - -3 if the cert is not yet valid (not_before_p, not_after_t still populated). + */ +int fr_tls_cert_is_valid(fr_unix_time_t *not_before_p, fr_unix_time_t *not_after_p, X509 *cert) +{ + fr_time_t now = fr_time(); + time_t not_before, not_after; + + /* + * If the cert has a mangled notAfter or + * notBefore timestamps then always fail, + * no matter what the verify mode. + */ + if (fr_tls_utils_asn1time_to_epoch(&not_after, X509_get0_notAfter(cert)) < 0) { + fr_strerror_const_push("Failed parsing notAfter time in certificate"); + return -1; + } + if (fr_tls_utils_asn1time_to_epoch(&not_before, X509_get0_notBefore(cert)) < 0) { + fr_strerror_const_push("Failed parsing notBefore time in certificate"); + return -1; + } + + if (not_before_p) *not_before_p = fr_unix_time_from_sec(not_before); + if (not_after_p) *not_after_p = fr_unix_time_from_sec(not_after); + + /* + * Check the cert hasn't expired + */ + if (fr_time_from_sec(not_after) < now) { + fr_strerror_printf("Certificate has expired. " + "Validity period (notAfter) ends %pV, current time is %pV", + fr_box_date(fr_unix_time_from_sec(not_before)), fr_box_date(now)); + return -2; + } + + /* + * Check the cert's validity period + * has started. + */ + if (fr_time_from_sec(not_before) > now) { + fr_strerror_printf("Certificate is not yet valid. " + "Validity period (notBefore) starts %pV, current time is %pV", + fr_box_date(fr_unix_time_from_sec(not_before)), fr_box_date(now)); + return -3; + } + + return 0; +} +#endif diff --git a/src/lib/tls/cert.h b/src/lib/tls/cert.h new file mode 100644 index 00000000000..dd57b68182e --- /dev/null +++ b/src/lib/tls/cert.h @@ -0,0 +1,42 @@ +#pragma once +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifdef WITH_TLS +/** + * $Id$ + * + * @file lib/tls/cert.h + * @brief Functions to work with certificates. + * + * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org) + */ +RCSIDH(cert_h, "$Id$") + +#include <openssl/ssl.h> +#include <openssl/err.h> + +#include <freeradius-devel/util/time.h> + +#ifdef __cplusplus +extern "C" { +#endif + +int fr_tls_cert_is_valid(fr_unix_time_t *not_before_p, fr_unix_time_t *not_after_p, X509 *cert); + +#ifdef __cplusplus +} +#endif +#endif /* WITH_TLS */ diff --git a/src/lib/tls/conf-h b/src/lib/tls/conf-h index 8cc90f71e70..bd0d46029b6 100644 --- a/src/lib/tls/conf-h +++ b/src/lib/tls/conf-h @@ -72,6 +72,8 @@ typedef struct { fr_tls_chain_verify_mode_t verify_mode; //!< How hard we try to build up a complete certificate ///< chain. bool include_root_ca; //!< Include the root ca in the chain we built. + + fr_unix_time_t valid_until; //!< The certificate in the chain which expires the earliest. } fr_tls_chain_conf_t; /** Control what types of session resumption we allow diff --git a/src/lib/tls/ctx.c b/src/lib/tls/ctx.c index 47a8f6e66df..a71b601f5a4 100644 --- a/src/lib/tls/ctx.c +++ b/src/lib/tls/ctx.c @@ -41,6 +41,7 @@ USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */ #include "base.h" #include "log.h" +#include "cert.h" #ifndef OPENSSL_NO_ECDH static int ctx_ecdh_curve_set(SSL_CTX *ctx, char const *ecdh_curve, bool disable_single_dh_use) @@ -116,7 +117,7 @@ static int ctx_dh_params_load(SSL_CTX *ctx, char *file) return 0; } -static int tls_ctx_load_cert_chain(SSL_CTX *ctx, fr_tls_chain_conf_t const *chain) +static int tls_ctx_load_cert_chain(SSL_CTX *ctx, fr_tls_chain_conf_t *chain) { char *password; @@ -224,6 +225,72 @@ static int tls_ctx_load_cert_chain(SSL_CTX *ctx, fr_tls_chain_conf_t const *chai return -1; } + /* + * Loop over the certificates checking validity periods. + * SSL_CTX_build_cert_chain does this too, but we can + * produce significantly better errors here. + * + * After looping over all the certs we figure out when + * the chain will next need refreshing. + */ + { + fr_unix_time_t expires_first = 0; + int ret; + + for (ret = SSL_CTX_set_current_cert(ctx, SSL_CERT_SET_FIRST); + ret == 1; + ret = SSL_CTX_set_current_cert(ctx, SSL_CERT_SET_NEXT)) { + fr_unix_time_t not_after; + STACK_OF(X509) *our_chain; + X509 *our_cert; + + our_cert = SSL_CTX_get0_certificate(ctx); + if (!SSL_CTX_get0_chain_certs(ctx, &our_chain)) { + fr_tls_log_error(NULL, "Failed retrieving chain certificates"); + return -1; + } + + switch (fr_tls_cert_is_valid(NULL, &not_after, our_cert)) { + case -1: + fr_tls_log_certificate_chain(NULL, L_ERR, our_chain, our_cert); + PERROR("Malformed certificate"); + return -1; + + case -2: + case -3: + switch (chain->verify_mode) { + case FR_TLS_CHAIN_VERIFY_SOFT: + fr_tls_log_certificate_chain(NULL, L_WARN, our_chain, our_cert); + PWARN("Certificate validation failed"); + break; + + case FR_TLS_CHAIN_VERIFY_HARD: + fr_tls_log_certificate_chain(NULL, L_ERR, our_chain, our_cert); + PERROR("Certificate validation failed"); + return -1; + + default: + break; + } + + } + + /* + * Record the time the first certificate in + * the chain expires so we can use it for + * runtime checks. + */ + if ((expires_first == 0) || (expires_first > not_after)) expires_first = not_after; + } + + /* + * Record this as a unix timestamp as + * internal time might not progress at + * the same rate as wallclock time. + */ + chain->valid_until = expires_first; + } + { int mode = SSL_BUILD_CHAIN_FLAG_CHECK; @@ -265,6 +332,7 @@ static int tls_ctx_load_cert_chain(SSL_CTX *ctx, fr_tls_chain_conf_t const *chai break; } } + return 0; } @@ -667,7 +735,7 @@ SSL_CTX *fr_tls_ctx_alloc(fr_tls_conf_t const *conf, bool client) goto error; } - if (DEBUG_ENABLED3) fr_tls_log_certificate_chain(NULL, our_chain, our_cert); + if (DEBUG_ENABLED3) fr_tls_log_certificate_chain(NULL, L_DBG, our_chain, our_cert); } (void)SSL_CTX_set_current_cert(ctx, SSL_CERT_SET_FIRST); /* Reset */ } diff --git a/src/lib/tls/log.c b/src/lib/tls/log.c index ace13a2043f..61a38f73419 100644 --- a/src/lib/tls/log.c +++ b/src/lib/tls/log.c @@ -75,7 +75,7 @@ static _Thread_local fr_tls_log_bio_t *request_log_bio; static _Thread_local fr_tls_log_bio_t *global_log_bio; static void _tls_ctx_print_cert_line(char const *file, int line, - request_t *request, int index, X509 *cert) + request_t *request, fr_log_type_t log_type, int idx, X509 *cert) { char subject[1024]; @@ -83,11 +83,11 @@ static void _tls_ctx_print_cert_line(char const *file, int line, subject[sizeof(subject) - 1] = '\0'; if (request) { - log_request(L_DBG, fr_debug_lvl, request, file, line, - "[%i] %s %s", index, fr_tls_utils_x509_pkey_type(cert), subject); + log_request(log_type, fr_debug_lvl, request, file, line, + "[%i] %s %s", idx, fr_tls_utils_x509_pkey_type(cert), subject); } else { - fr_log(LOG_DST, fr_debug_lvl, file, line, - "[%i] %s %s", index, fr_tls_utils_x509_pkey_type(cert), subject); + fr_log(LOG_DST, log_type, file, line, + "[%i] %s %s", idx, fr_tls_utils_x509_pkey_type(cert), subject); } } @@ -98,18 +98,19 @@ DIAG_OFF(used-but-marked-unused) /* fix spurious warnings for sk macros */ * @param[in] file File where this function is being called. * @param[in] line Line where this function is being called. * @param[in] request Current request, may be NULL. + * @param[in] log_type The type of log message to produce L_INFO, L_ERR, L_DBG etc... * @param[in] chain The certificate chain. * @param[in] cert The leaf certificate. */ void _fr_tls_log_certificate_chain(char const *file, int line, - request_t *request, STACK_OF(X509) *chain, X509 *cert) + request_t *request, fr_log_type_t log_type, STACK_OF(X509) *chain, X509 *cert) { int i; for (i = sk_X509_num(chain); i > 0 ; i--) { - _tls_ctx_print_cert_line(file, line, request, i, sk_X509_value(chain, i - 1)); + _tls_ctx_print_cert_line(file, line, request, log_type, i, sk_X509_value(chain, i - 1)); } - _tls_ctx_print_cert_line(file, line, request, i, cert); + _tls_ctx_print_cert_line(file, line, request, log_type, i, cert); } DIAG_ON(used-but-marked-unused) DIAG_ON(DIAG_UNKNOWN_PRAGMAS) diff --git a/src/lib/tls/log.h b/src/lib/tls/log.h index dc6efbd84b7..93e83a2ed4f 100644 --- a/src/lib/tls/log.h +++ b/src/lib/tls/log.h @@ -34,10 +34,10 @@ RCSIDH(tls_log_h, "$Id$") #include "base.h" -#define fr_tls_log_certificate_chain(_request, _chain, _cert) \ - _fr_tls_log_certificate_chain( __FILE__, __LINE__, _request, _chain, _cert) +#define fr_tls_log_certificate_chain(_request, _log_type, _chain, _cert) \ + _fr_tls_log_certificate_chain( __FILE__, __LINE__, _request, _log_type, _chain, _cert) void _fr_tls_log_certificate_chain(char const *file, int line, - request_t *request, STACK_OF(X509) *chain, X509 *cert); + request_t *request, fr_log_type_t log_type, STACK_OF(X509) *chain, X509 *cert); int fr_tls_log_io_error(request_t *request, fr_tls_session_t *session, int ret, char const *msg, ...) CC_HINT(format (printf, 4, 5)); diff --git a/src/modules/rlm_cipher/rlm_cipher.c b/src/modules/rlm_cipher/rlm_cipher.c index 1bf93d63f70..c55da0bd3bb 100644 --- a/src/modules/rlm_cipher/rlm_cipher.c +++ b/src/modules/rlm_cipher/rlm_cipher.c @@ -31,6 +31,7 @@ RCSID("$Id$") #include <freeradius-devel/server/module.h> #include <freeradius-devel/tls/base.h> #include <freeradius-devel/tls/log.h> +#include <freeradius-devel/tls/cert.h> #include <freeradius-devel/util/debug.h> #include <openssl/crypto.h> @@ -56,6 +57,26 @@ typedef enum { RLM_CIPHER_TYPE_RSA = 1, } cipher_type_t; +/** Certificate validation modes + * + */ +typedef enum { + CIPHER_CERT_VERIFY_INVALID = 0, + + CIPHER_CERT_VERIFY_HARD, //!< Fail if the certificate isn't valid. + CIPHER_CERT_VERIFY_SOFT, //!< Warn if the certificate isn't valid. + CIPHER_CERT_VERIFY_NONE //!< Don't check to see if the we're between + ///< notBefore or notAfter. +} cipher_cert_verify_mode_t; + +typedef enum { + CIPHER_CERT_ATTR_UNKNOWN = 0, //!< Unrecognised attribute. + CIPHER_CERT_ATTR_SERIAL, //!< Certificate's serial number. + CIPHER_CERT_ATTR_FINGERPRINT, //!< Dynamically calculated fingerprint. + CIPHER_CERT_ATTR_NOT_BEFORE, //!< Time the certificate becomes valid. + CIPHER_CERT_ATTR_NOT_AFTER //!< Time the certificate expires. +} cipher_cert_attributes_t; + /** Public key types * */ @@ -84,6 +105,24 @@ static fr_table_num_sorted_t const cipher_type[] = { }; static size_t cipher_type_len = NUM_ELEMENTS(cipher_type); +static fr_table_num_sorted_t const cipher_cert_verify_mode_table[] = { + { L("hard"), CIPHER_CERT_VERIFY_HARD }, + { L("none"), CIPHER_CERT_VERIFY_SOFT }, + { L("soft"), CIPHER_CERT_VERIFY_NONE } +}; +static size_t cipher_cert_verify_mode_table_len = NUM_ELEMENTS(cipher_cert_verify_mode_table); + +/** Public key types + * + */ +static fr_table_num_sorted_t const cert_attributes[] = { + { L("fingerprint"), CIPHER_CERT_ATTR_FINGERPRINT }, + { L("notAfter"), CIPHER_CERT_ATTR_NOT_AFTER }, + { L("notBefore"), CIPHER_CERT_ATTR_NOT_BEFORE }, + { L("serial"), CIPHER_CERT_ATTR_SERIAL }, +}; +static size_t cert_attributes_len = NUM_ELEMENTS(cert_attributes); + typedef struct { EVP_PKEY_CTX *evp_encrypt_ctx; //!< Pre-allocated evp_pkey_ctx. EVP_PKEY_CTX *evp_sign_ctx; //!< Pre-allocated evp_pkey_ctx. @@ -104,6 +143,8 @@ typedef struct { char const *label; //!< Additional input to the hashing function. } cipher_rsa_oaep_t; + + /** Configuration for RSA encryption/decryption/signing * */ @@ -116,6 +157,10 @@ typedef struct { EVP_PKEY *certificate_file; //!< Public (certificate) file. X509 *x509_certificate_file; //!< Needed for extracting certificate attributes. + cipher_cert_verify_mode_t verify_mode; //!< How hard we try to verify the certificate. + fr_unix_time_t not_before; //!< Certificate isn't valid before this time. + fr_unix_time_t not_after; //!< Certificate isn't valid after this time. + int padding; //!< Type of padding to apply to the plaintext ///< or ciphertext before feeding it to RSA crypto ///< functions. @@ -159,6 +204,14 @@ static const CONF_PARSER rsa_config[] = { { FR_CONF_OFFSET("private_key_file", FR_TYPE_VOID | FR_TYPE_NOT_EMPTY, cipher_rsa_t, private_key_file), .func = cipher_rsa_private_key_file_load }, { FR_CONF_OFFSET("certificate_file", FR_TYPE_VOID | FR_TYPE_NOT_EMPTY, cipher_rsa_t, certificate_file), .func = cipher_rsa_certificate_file_load }, + { FR_CONF_OFFSET("verify_mode", FR_TYPE_VOID, cipher_rsa_t, verify_mode), + .func = cf_table_parse_int, + .uctx = &(cf_table_parse_ctx_t){ + .table = cipher_cert_verify_mode_table, + .len = &cipher_cert_verify_mode_table_len + }, + .dflt = "hard" }, + { FR_CONF_OFFSET("random_file", FR_TYPE_STRING, cipher_rsa_t, random_file) }, { FR_CONF_OFFSET("signature_digest", FR_TYPE_VOID | FR_TYPE_NOT_EMPTY, cipher_rsa_t, sig_digest), .func = digest_type_parse, .dflt = "sha256" }, @@ -459,11 +512,36 @@ static int cipher_rsa_certificate_file_load(TALLOC_CTX *ctx, void *out, void *pa cf_log_err(ci, "Expected certificate to contain %s public key, got %s public key", fr_table_str_by_value(pkey_types, EVP_PKEY_RSA, "?Unknown?"), fr_table_str_by_value(pkey_types, pkey_type, "?Unknown?")); - + error: EVP_PKEY_free(pkey); return -1; } + /* + * Certificate validity checks + */ + switch (fr_tls_cert_is_valid(&rsa_inst->not_before, &rsa_inst->not_after, cert)) { + case -1: + + cf_log_perr(ci, "Malformed certificate"); + return -1; + + case -2: + case -3: + switch (rsa_inst->verify_mode) { + case CIPHER_CERT_VERIFY_SOFT: + cf_log_pwarn(ci, "Certificate validation failed"); + break; + + case CIPHER_CERT_VERIFY_HARD: + cf_log_perr(ci, "Certificate validation failed"); + goto error; + + default: + break; + } + } + talloc_set_type(pkey, EVP_PKEY); (void)talloc_steal(cert, pkey); /* Bind lifetime to config */ talloc_set_destructor(pkey, _evp_pkey_free); /* Free pkey correctly on chunk free */ @@ -795,8 +873,9 @@ static xlat_action_t cipher_rsa_verify_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, return XLAT_ACTION_DONE; } -static xlat_arg_parser_t const cipher_fingerprint_xlat_args[] = { +static xlat_arg_parser_t const cipher_certificate_xlat_args[] = { { .required = true, .concat = false, .single = true, .variadic = false, .type = FR_TYPE_STRING }, + { .required = false, .concat = false, .single = true, .variadic = false, .type = FR_TYPE_STRING }, /* Optional hash for fingerprint mode */ XLAT_ARG_PARSER_TERMINATOR }; @@ -805,7 +884,7 @@ static xlat_arg_parser_t const cipher_fingerprint_xlat_args[] = { * Arguments are @verbatim(<digest>)@endverbatim * @verbatim -%(<inst>_fingerprint:<digest>) +%(<inst>_certificate:fingerprint <digest>) @endverbatim * * @ingroup xlat_functions @@ -815,12 +894,21 @@ static xlat_action_t cipher_fingerprint_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, fr_value_box_list_t *in) { rlm_cipher_t const *inst = talloc_get_type_abort_const(*((void const * const *)xlat_inst), rlm_cipher_t); - char const *md_name = ((fr_value_box_t *)fr_dlist_head(in))->vb_strvalue; + char const *md_name; EVP_MD const *md; size_t md_len; fr_value_box_t *vb; uint8_t *digest; + if (!fr_dlist_next(in, fr_dlist_head(in))) { + REDEBUG("Missing digest argument"); + return XLAT_ACTION_FAIL; + } + + /* + * Second arg... + */ + md_name = ((fr_value_box_t *)fr_dlist_next(in, fr_dlist_head(in)))->vb_strvalue; md = EVP_get_digestbyname(md_name); if (!md) { REDEBUG("Specified digest \"%s\" is not a valid digest type", md_name); @@ -842,14 +930,10 @@ static xlat_action_t cipher_fingerprint_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, return XLAT_ACTION_DONE; } -static xlat_arg_parser_t const cipher_serial_xlat_args[] = { - XLAT_ARG_PARSER_TERMINATOR -}; - /** Return the serial of the public certificate * @verbatim -%(<inst>_serial:) +%(<inst>_certificate:serial) @endverbatim * * @ingroup xlat_functions @@ -898,6 +982,39 @@ static xlat_action_t cipher_serial_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, return XLAT_ACTION_DONE; } +static xlat_action_t cipher_certificate_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, + request_t *request, void const *xlat_inst, void *xlat_thread_inst, + fr_value_box_list_t *in) +{ + rlm_cipher_t const *inst = talloc_get_type_abort_const(*((void const * const *)xlat_inst), rlm_cipher_t); + char const *attribute = ((fr_value_box_t *)fr_dlist_head(in))->vb_strvalue; + fr_value_box_t *vb; + + switch (fr_table_value_by_str(cert_attributes, attribute, CIPHER_CERT_ATTR_UNKNOWN)) { + default: + REDEBUG("Unknown certificate attribute \"%s\"", attribute); + return XLAT_ACTION_FAIL; + + case CIPHER_CERT_ATTR_FINGERPRINT: + return cipher_fingerprint_xlat(ctx, out, request, xlat_inst, xlat_thread_inst, in); + + case CIPHER_CERT_ATTR_SERIAL: + return cipher_serial_xlat(ctx, out, request, xlat_inst, xlat_thread_inst, in); + + case CIPHER_CERT_ATTR_NOT_BEFORE: + MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_DATE, NULL, true)); + vb->vb_date = inst->rsa->not_before; + fr_dcursor_append(out, vb); + return XLAT_ACTION_DONE; + + case CIPHER_CERT_ATTR_NOT_AFTER: + MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_DATE, NULL, true)); + vb->vb_date = inst->rsa->not_after; + fr_dcursor_append(out, vb); + return XLAT_ACTION_DONE; + } +} + /** Talloc destructor for freeing an EVP_PKEY_CTX * * @param[in] evp_pkey_ctx to free. @@ -1308,23 +1425,9 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf) inst); talloc_free(xlat_name); - xlat_name = talloc_asprintf(inst, "%s_fingerprint", inst->xlat_name); - xlat = xlat_register(inst, xlat_name, cipher_fingerprint_xlat, false); - xlat_func_args(xlat, cipher_fingerprint_xlat_args); - xlat_async_instantiate_set(xlat, cipher_xlat_instantiate, - rlm_cipher_t *, - NULL, - inst); - xlat_async_thread_instantiate_set(xlat, - cipher_xlat_thread_instantiate, - rlm_cipher_rsa_thread_inst_t *, - NULL, - inst); - talloc_free(xlat_name); - - xlat_name = talloc_asprintf(inst, "%s_serial", inst->xlat_name); - xlat = xlat_register(inst, xlat_name, cipher_serial_xlat, false); - xlat_func_args(xlat, cipher_serial_xlat_args); + xlat_name = talloc_asprintf(inst, "%s_certificate", inst->xlat_name); + xlat = xlat_register(inst, xlat_name, cipher_certificate_xlat, false); + xlat_func_args(xlat, cipher_certificate_xlat_args); xlat_async_instantiate_set(xlat, cipher_xlat_instantiate, rlm_cipher_t *, NULL, diff --git a/src/modules/rlm_ocsp/ocsp.c b/src/modules/rlm_ocsp/ocsp.c index 3ea59bbfd09..633b1dce974 100644 --- a/src/modules/rlm_ocsp/ocsp.c +++ b/src/modules/rlm_ocsp/ocsp.c @@ -234,7 +234,7 @@ int fr_tls_ocsp_staple_cb(SSL *ssl, void *data) if (RDEBUG_ENABLED3) { RDEBUG3("Current SSL session cert store contents"); RINDENT(); - fr_tls_log_certificate_chain(request, our_chain, cert); + fr_tls_log_certificate_chain(request, L_DBG, our_chain, cert); REXDENT(); } diff --git a/src/tests/modules/cipher/fingerprint.unlang b/src/tests/modules/cipher/fingerprint.unlang index c09b48f966d..1c55906b3df 100644 --- a/src/tests/modules/cipher/fingerprint.unlang +++ b/src/tests/modules/cipher/fingerprint.unlang @@ -3,7 +3,7 @@ # but we can test the digest length, and for smoke... # update request { - &Tmp-Octets-0 := "%(cipher_rsa_fingerprint:sha1)" + &Tmp-Octets-0 := "%(cipher_rsa_certificate:fingerprint sha1)" } if ("%(length:%{Tmp-Octets-0})" != 20) { @@ -13,7 +13,7 @@ if ("%(length:%{Tmp-Octets-0})" != 20) { } update request { - &Tmp-Octets-0 := "%(cipher_rsa_fingerprint:sha256)" + &Tmp-Octets-0 := "%(cipher_rsa_certificate:fingerprint sha256)" } if ("%(length:%{Tmp-Octets-0})" != 32) { diff --git a/src/tests/modules/cipher/serial.unlang b/src/tests/modules/cipher/serial.unlang index 085213b830c..1168ed117d0 100644 --- a/src/tests/modules/cipher/serial.unlang +++ b/src/tests/modules/cipher/serial.unlang @@ -1,5 +1,5 @@ update request { - &Tmp-Octets-0 := "%(cipher_rsa_serial:)" + &Tmp-Octets-0 := "%(cipher_rsa_certificate:serial)" } if ("%(length:%{Tmp-Octets-0})" != 1) { diff --git a/src/tests/modules/cipher/valid.unlang b/src/tests/modules/cipher/valid.unlang new file mode 100644 index 00000000000..5b44a75b9ac --- /dev/null +++ b/src/tests/modules/cipher/valid.unlang @@ -0,0 +1,11 @@ +update request { + &Tmp-Date-0 := "%(cipher_rsa_certificate:notBefore)" + &Tmp-Date-1 := "%(cipher_rsa_certificate:notAfter)" +} + +# Check the cert validity period is 60 days +if (<uint32>"%{expr:%(integer:%{Tmp-Date-1}) - %(integer:%{Tmp-Date-0})}" != <uint32>"%{expr:86400 * 60}") { + test_fail +} else { + test_pass +}