]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add function to get certificate serial
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 9 Apr 2021 11:56:10 +0000 (12:56 +0100)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 9 Apr 2021 11:56:46 +0000 (12:56 +0100)
src/modules/rlm_cipher/rlm_cipher.c
src/tests/modules/cipher/fingerprint.unlang [moved from src/tests/modules/cipher/cipher.unlang with 100% similarity]
src/tests/modules/cipher/serial.unlang [new file with mode: 0644]

index b9c295ed3457a02db26e8041909cb5859dc5eab5..7f782280405610f016b9789664d501c0f0cef3b7 100644 (file)
@@ -832,9 +832,61 @@ static xlat_action_t cipher_fingerprint_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
 
        if (X509_digest(inst->rsa->x509_certificate_file, md, digest, (unsigned int *)&md_len) != 1) {
                fr_tls_log_error(request, "Failed calculating certificate fingerprint");
+               talloc_free(vb);
+               return XLAT_ACTION_FAIL;
+       }
+
+       fr_dcursor_append(out, vb);
+
+       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:)
+@endverbatim
+ *
+ * @ingroup xlat_functions
+ */
+static xlat_action_t cipher_serial_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
+                                       request_t *request, void const *xlat_inst, UNUSED void *xlat_thread_inst,
+                                       UNUSED fr_value_box_list_t *in)
+{
+       rlm_cipher_t const      *inst = talloc_get_type_abort_const(*((void const * const *)xlat_inst), rlm_cipher_t);
+       ASN1_INTEGER const      *serial;
+       uint8_t                 *serial_bin;
+       BIGNUM                  *bn;
+       fr_value_box_t          *vb;
+       size_t                  bn_len;
+
+       serial = X509_get0_serialNumber(inst->rsa->x509_certificate_file);
+       if (!serial) {
+       error:
+               fr_tls_log_error(request, "Failed retrieving certificate serial");
                return XLAT_ACTION_FAIL;
        }
 
+       bn = ASN1_INTEGER_to_BN(serial, NULL);
+       if (!bn) goto error;
+
+       bn_len = BN_num_bytes(bn);
+
+       MEM(vb = fr_value_box_alloc_null(ctx));
+       MEM(fr_value_box_mem_alloc(vb, &serial_bin, vb, NULL, bn_len, true) == 0);
+
+       /*
+        *      Copy the serial number into an octets buffer
+        */
+       if (BN_bn2bin(bn, (unsigned char *)serial_bin) != 1) {
+               BN_free(bn);
+               talloc_free(vb);
+               goto error;
+       }
        fr_dcursor_append(out, vb);
 
        return XLAT_ACTION_DONE;
@@ -1160,15 +1212,14 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf)
                }
 
                if (inst->rsa->private_key_file) {
-                       char *decrypt_name;
-                       char *verify_name;
+                       char *xlat_name;
                        xlat_t *xlat;
 
                        /*
                         *      Register decrypt xlat
                         */
-                       decrypt_name = talloc_asprintf(inst, "%s_decrypt", inst->xlat_name);
-                       xlat = xlat_register(inst, decrypt_name, cipher_rsa_decrypt_xlat, false);
+                       xlat_name = talloc_asprintf(inst, "%s_decrypt", inst->xlat_name);
+                       xlat = xlat_register(inst, xlat_name, cipher_rsa_decrypt_xlat, false);
                        xlat_func_mono(xlat, &cipher_rsa_decrypt_xlat_arg);
                        xlat_async_instantiate_set(xlat, cipher_xlat_instantiate,
                                                   rlm_cipher_t *,
@@ -1179,13 +1230,13 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf)
                                                          rlm_cipher_rsa_thread_inst_t *,
                                                          NULL,
                                                          inst);
-                       talloc_free(decrypt_name);
+                       talloc_free(xlat_name);
 
                        /*
                         *      Verify sign xlat
                         */
-                       verify_name = talloc_asprintf(inst, "%s_verify", inst->xlat_name);
-                       xlat = xlat_register(inst, verify_name, cipher_rsa_verify_xlat, false);
+                       xlat_name = talloc_asprintf(inst, "%s_verify", inst->xlat_name);
+                       xlat = xlat_register(inst, xlat_name, cipher_rsa_verify_xlat, false);
                        xlat_func_args(xlat, cipher_rsa_verify_xlat_arg);
                        xlat_async_instantiate_set(xlat, cipher_xlat_instantiate,
                                                   rlm_cipher_t *,
@@ -1196,20 +1247,34 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf)
                                                          rlm_cipher_rsa_thread_inst_t *,
                                                          NULL,
                                                          inst);
-                       talloc_free(verify_name);
+                       talloc_free(xlat_name);
                }
 
                if (inst->rsa->certificate_file) {
-                       char *encrypt_name;
-                       char *sign_name;
-                       char *fingerprint_name;
+                       char *xlat_name;
                        xlat_t *xlat;
 
+                       /*
+                        *      If we have both public and private keys check they're
+                        *      part of the same keypair.  This isn't technically a requirement
+                        *      but it fixes some obscure errors where the user uses the serial
+                        *      xlat, expecting it to be the serial of the keypair containing
+                        *      the private key.
+                        */
+                       if (inst->rsa->private_key_file && inst->rsa->x509_certificate_file) {
+                               if (X509_check_private_key(inst->rsa->x509_certificate_file,
+                                                          inst->rsa->private_key_file) == 0) {
+                                       tls_strerror_printf(NULL);
+                                       cf_log_perr(conf, "Private key does not match the certificate public key");
+                                       return -1;
+                               }
+                       }
+
                        /*
                         *      Register encrypt xlat
                         */
-                       encrypt_name = talloc_asprintf(inst, "%s_encrypt", inst->xlat_name);
-                       xlat = xlat_register(inst, encrypt_name, cipher_rsa_encrypt_xlat, false);
+                       xlat_name = talloc_asprintf(inst, "%s_encrypt", inst->xlat_name);
+                       xlat = xlat_register(inst, xlat_name, cipher_rsa_encrypt_xlat, false);
                        xlat_func_mono(xlat, &cipher_rsa_encrypt_xlat_arg);
                        xlat_async_instantiate_set(xlat, cipher_xlat_instantiate,
                                                   rlm_cipher_t *,
@@ -1219,13 +1284,13 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf)
                                                          rlm_cipher_rsa_thread_inst_t *,
                                                          NULL,
                                                          inst);
-                       talloc_free(encrypt_name);
+                       talloc_free(xlat_name);
 
                        /*
                         *      Register sign xlat
                         */
-                       sign_name = talloc_asprintf(inst, "%s_sign", inst->xlat_name);
-                       xlat = xlat_register(inst, sign_name, cipher_rsa_sign_xlat, false);
+                       xlat_name = talloc_asprintf(inst, "%s_sign", inst->xlat_name);
+                       xlat = xlat_register(inst, xlat_name, cipher_rsa_sign_xlat, false);
                        xlat_func_mono(xlat, &cipher_rsa_sign_xlat_arg);
                        xlat_async_instantiate_set(xlat, cipher_xlat_instantiate,
                                                   rlm_cipher_t *,
@@ -1235,10 +1300,10 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf)
                                                          rlm_cipher_rsa_thread_inst_t *,
                                                          NULL,
                                                          inst);
-                       talloc_free(sign_name);
+                       talloc_free(xlat_name);
 
-                       fingerprint_name = talloc_asprintf(inst, "%s_fingerprint", inst->xlat_name);
-                       xlat = xlat_register(inst, fingerprint_name, cipher_fingerprint_xlat, false);
+                       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 *,
@@ -1249,23 +1314,21 @@ static int mod_bootstrap(void *instance, CONF_SECTION *conf)
                                                          rlm_cipher_rsa_thread_inst_t *,
                                                          NULL,
                                                          inst);
-                       talloc_free(fingerprint_name);
+                       talloc_free(xlat_name);
 
-                       /*
-                        *      If we have both public and private keys check they're
-                        *      part of the same keypair.  This isn't technically a requirement
-                        *      but it fixes some obscure errors where the user uses the serial
-                        *      xlat, expecting it to be the serial of the keypair containing
-                        *      the private key.
-                        */
-                       if (inst->rsa->private_key_file && inst->rsa->x509_certificate_file) {
-                               if (X509_check_private_key(inst->rsa->x509_certificate_file,
-                                                          inst->rsa->private_key_file) == 0) {
-                                       tls_strerror_printf(NULL);
-                                       cf_log_perr(conf, "Private key does not match the certificate public key");
-                                       return -1;
-                               }
-                       }
+                       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_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);
                }
                break;
 
diff --git a/src/tests/modules/cipher/serial.unlang b/src/tests/modules/cipher/serial.unlang
new file mode 100644 (file)
index 0000000..085213b
--- /dev/null
@@ -0,0 +1,15 @@
+update request {
+       &Tmp-Octets-0 := "%(cipher_rsa_serial:)"
+}
+
+if ("%(length:%{Tmp-Octets-0})" != 1) {
+       test_fail
+} else {
+       test_pass
+}
+
+if ("%{hex:%{Tmp-Octets-0}}" != "01") {
+       test_fail
+} else {
+       test_pass
+}