]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Optionally decode certificates using the DER decoder
authorNick Porter <nick@portercomputing.co.uk>
Mon, 15 Sep 2025 08:28:20 +0000 (09:28 +0100)
committerNick Porter <nick@portercomputing.co.uk>
Mon, 15 Sep 2025 15:47:36 +0000 (16:47 +0100)
This requires OpenSSL >= 3.4 where the custom stack allocator callback
is available.
The default stack size allocated by previous versions is too small and
the recursive calls involved in certificate decoding require a larger
stack.

src/lib/tls/all.mk
src/lib/tls/attrs.h
src/lib/tls/base.c
src/lib/tls/conf-h
src/lib/tls/conf.c
src/lib/tls/pairs.c
src/lib/tls/session.h
src/lib/tls/verify.c

index 0cc957b742ef82d422dd3dfc37c7e5ac5b84918f..ba9e565f50da5cbcc4203ea68709db94b2afbfdb 100644 (file)
@@ -21,7 +21,7 @@ SOURCES       := \
        version.c \
        virtual_server.c
 
-TGT_PREREQS := libfreeradius-internal$(L) libfreeradius-util$(L)
+TGT_PREREQS := libfreeradius-internal$(L) libfreeradius-util$(L) libfreeradius-der$(L)
 
 # This lets the linker determine which version of the SSLeay functions to use.
 TGT_LDLIBS  := $(LIBS) $(OPENSSL_LIBS) $(GPERFTOOLS_LIBS)
index f651e32187acd921aea49b4a676b180d54ed6588..aeb7de6ed45007f0e20015bf9f41030775d9e67e 100644 (file)
@@ -29,6 +29,7 @@ RCSIDH(tls_attrs_h, "$Id$")
 extern HIDDEN fr_dict_t const *dict_freeradius;
 extern HIDDEN fr_dict_t const *dict_radius;
 extern HIDDEN fr_dict_t const *dict_tls;
+extern HIDDEN fr_dict_t const *dict_der;
 
 extern HIDDEN fr_dict_attr_t const *attr_allow_session_resumption;
 extern HIDDEN fr_dict_attr_t const *attr_session_resumed;
@@ -72,6 +73,8 @@ extern HIDDEN fr_dict_attr_t const *attr_tls_session_id;
 extern HIDDEN fr_dict_attr_t const *attr_tls_session_resumed;
 extern HIDDEN fr_dict_attr_t const *attr_tls_session_ttl;
 
+extern HIDDEN fr_dict_attr_t const *attr_der_certificate;
+
 extern fr_value_box_t const *enum_tls_session_resumed_stateful;
 extern fr_value_box_t const *enum_tls_session_resumed_stateless;
 
index f7f774a183e2a7ba5e52cefa3c60a2516b763361..b6d004f11ada4ecd520649d0e374f4d3d2c03b53 100644 (file)
@@ -75,11 +75,13 @@ static uint32_t tls_instance_count = 0;
 fr_dict_t const *dict_freeradius;
 fr_dict_t const *dict_radius;
 fr_dict_t const *dict_tls;
+fr_dict_t const        *dict_der;
 
 extern fr_dict_autoload_t tls_dict[];
 fr_dict_autoload_t tls_dict[] = {
        { .out = &dict_freeradius, .proto = "freeradius" },
        { .out = &dict_tls, .proto = "tls" },
+       { .out = &dict_der, .proto = "der" },
        { NULL }
 };
 
@@ -128,6 +130,8 @@ fr_dict_attr_t const *attr_tls_session_id;
 fr_dict_attr_t const *attr_tls_session_resumed;
 fr_dict_attr_t const *attr_tls_session_ttl;
 
+fr_dict_attr_t const *attr_der_certificate;
+
 extern fr_dict_attr_autoload_t tls_dict_attr[];
 fr_dict_attr_autoload_t tls_dict_attr[] = {
        { .out = &attr_allow_session_resumption, .name = "Allow-Session-Resumption", .type = FR_TYPE_BOOL, .dict = &dict_freeradius },
@@ -177,6 +181,9 @@ fr_dict_attr_autoload_t tls_dict_attr[] = {
        { .out = &attr_tls_session_id, .name = "Session-Id", .type = FR_TYPE_OCTETS, .dict = &dict_tls },
        { .out = &attr_tls_session_resumed, .name = "Session-Resumed", .type = FR_TYPE_BOOL, .dict = &dict_tls },
        { .out = &attr_tls_session_ttl, .name = "Session-TTL", .type = FR_TYPE_TIME_DELTA, .dict = &dict_tls },
+
+       { .out = &attr_der_certificate, .name = "Certificate", .type = FR_TYPE_TLV, .dict = &dict_der },
+
        { NULL }
 };
 
index e54b47cea78dc477848de34aa3ad4913a4e88926..3e881c33ae1d70e2d4acb947ea685b6d062f97db 100644 (file)
@@ -126,6 +126,8 @@ typedef struct {
        bool            check_crl;                      //!< Check certificate revocation lists.
        bool            allow_expired_crl;              //!< Don't error out if CRL is expired.
        bool            allow_not_yet_valid_crl;        //!< Don't error out if CRL is not-yet-valid.
+
+       bool            der_decode;                     //!< Should certificates be passed to the DER decoder.
 } fr_tls_verify_conf_t;
 
 /* configured values goes right here */
index bb190214c501c9f062dc9f78145e7a8c0de6c8d3..a658fa21ecc062a7546b2940af7e9714f1f2dcb7 100644 (file)
@@ -151,6 +151,7 @@ static conf_parser_t tls_verify_config[] = {
        { FR_CONF_OFFSET("check_crl", fr_tls_verify_conf_t, check_crl), .dflt = "no" },
        { FR_CONF_OFFSET("allow_expired_crl", fr_tls_verify_conf_t, allow_expired_crl) },
        { FR_CONF_OFFSET("allow_not_yet_valid_crl", fr_tls_verify_conf_t, allow_not_yet_valid_crl) },
+       { FR_CONF_OFFSET("der_decode", fr_tls_verify_conf_t, der_decode) },
        CONF_PARSER_TERMINATOR
 };
 
index 96d1505c7ed6fa18c2f020a80654ba63bdd60511..98a9b2c74954ced9fb4ffed45d3237ff55bfba8e 100644 (file)
@@ -32,6 +32,7 @@ USES_APPLE_DEPRECATED_API     /* OpenSSL API has been deprecated by Apple */
 #include <freeradius-devel/util/pair.h>
 #include <freeradius-devel/server/request.h>
 #include <freeradius-devel/server/pair.h>
+#include <freeradius-devel/der/der.h>
 
 #include "attrs.h"
 #include "bio.h"
@@ -154,12 +155,19 @@ static bool tls_session_pairs_from_crl(fr_pair_list_t *pair_list, TALLOC_CTX *ct
  * @param[in] ctx              to allocate attributes in.
  * @param[in] request          the current request.
  * @param[in] cert             to validate.
+ * @param[in] der_decode       should the certificate be parsed with the DER decoder.
  * @return
  *     - 1 already exists.
  *     - 0 on success.
  *     - < 0 on failure.
  */
-int fr_tls_session_pairs_from_x509_cert(fr_pair_list_t *pair_list, TALLOC_CTX *ctx, request_t *request, X509 *cert)
+int fr_tls_session_pairs_from_x509_cert(fr_pair_list_t *pair_list, TALLOC_CTX *ctx, request_t *request, X509 *cert,
+#if OPENSSL_VERSION_NUMBER >= 0x30400000L
+                                       bool der_decode
+#else
+                                       UNUSED bool der_decode
+#endif
+                               )
 {
        int             loc;
        char            buff[1024];
@@ -173,6 +181,35 @@ int fr_tls_session_pairs_from_x509_cert(fr_pair_list_t *pair_list, TALLOC_CTX *c
        ssize_t         slen;
        bool            san_found = false, crl_found = false;
 
+       /*
+        *      We require OpenSSL >= 3.4 to call the DER decoder due to the stack size
+        *      needed to handle the recursive calls involved in certificate decoding.
+        */
+#if OPENSSL_VERSION_NUMBER >= 0x30400000L
+       if (der_decode) {
+               uint8_t                 *cert_der;
+               uint8_t                 *cd;
+               int                     der_len;
+               fr_der_decode_ctx_t     der_ctx;
+
+               der_len = i2d_X509(cert, NULL);
+               if (der_len < 0) {
+                       fr_tls_log(request, "Failed retrieving certificate");
+                       return -1;
+               }
+               der_ctx.tmp_ctx = talloc_new(ctx);
+               cert_der = cd = talloc_array(der_ctx.tmp_ctx, uint8_t, der_len);
+               i2d_X509(cert, &cd);
+               slen = fr_der_decode_pair_dbuff(request->session_state_ctx, &request->session_state_pairs,
+                                               attr_der_certificate, &FR_DBUFF_TMP(cert_der, (size_t)der_len), &der_ctx);
+               talloc_free(der_ctx.tmp_ctx);
+               if (slen < 0) {
+                       fr_tls_log(request, "Failed decoding certificate");
+                       return -1;
+               }
+       }
+#endif
+
        /*
         *      Subject
         */
index 277a1ac71a28333148b59422ed7ab40b9dc3bc19..0e82c7b2ef8c54c5ffcad31901f5c4d13cf9a307 100644 (file)
@@ -303,7 +303,7 @@ void                fr_tls_session_msg_cb(int write_p, int msg_version, int content_type,
 void           fr_tls_session_keylog_cb(const SSL *ssl, const char *line);
 
 int            fr_tls_session_pairs_from_x509_cert(fr_pair_list_t *pair_list, TALLOC_CTX *ctx,
-                                                   request_t *request, X509 *cert) CC_HINT(nonnull);
+                                                   request_t *request, X509 *cert, bool der_decode) CC_HINT(nonnull);
 
 int            fr_tls_session_recv(request_t *request, fr_tls_session_t *tls_session);
 
index e026e8974f0bad7ec051e2603432cc41854ec462..d8948f6e1d90c681ee2a3ad68cd660507442ad35 100644 (file)
@@ -266,7 +266,7 @@ int fr_tls_verify_cert_cb(int ok, X509_STORE_CTX *x509_ctx)
                 *      and cause validation to fail.
                 */
                if (fr_tls_session_pairs_from_x509_cert(&container->vp_group, container,
-                                                       request, cert) < 0) {
+                                                       request, cert, conf->verify.der_decode) < 0) {
                        fr_pair_delete_by_da(&request->session_state_pairs, attr_tls_certificate);
                        my_ok = 0;
                        goto done;