35#if defined(ENABLE_CRYPTO_MBEDTLS)
37#include <mbedtls/version.h>
39#if MBEDTLS_VERSION_NUMBER < 0x04000000
41#include <mbedtls/bignum.h>
42#include <mbedtls/sha1.h>
50#include <mbedtls/asn1.h>
51#include <mbedtls/error.h>
52#include <mbedtls/oid.h>
54#define MAX_SUBJECT_LENGTH 256
57verify_callback(
void *session_obj, mbedtls_x509_crt *cert,
int cert_depth, uint32_t *flags)
71 if (
session->opt->verify_hash_no_ca)
81 uint32_t flags_ignore = MBEDTLS_X509_BADCERT_NOT_TRUSTED | MBEDTLS_X509_BADCERT_EXPIRED
82 | MBEDTLS_X509_BADCERT_FUTURE;
83 *flags = *flags & ~flags_ignore;
90 char errstr[512] = { 0 };
94 ret = mbedtls_x509_crt_verify_info(errstr,
sizeof(errstr) - 1,
"", *flags);
96 && !
checked_snprintf(errstr,
sizeof(errstr),
"Could not retrieve error string, flags=%" PRIx32, *flags))
107 msg(
D_TLS_ERRORS,
"VERIFY ERROR: depth=%d, subject=%s, serial=%s: %s", cert_depth,
108 subject, serial ? serial :
"<not available>", errstr);
113 "VERIFY ERROR: depth=%d, (could not extract X509 "
114 "subject string from certificate): %s",
122 *flags |= MBEDTLS_X509_BADCERT_OTHER;
141fieldname_to_oid(
const char *fieldname)
143 if (strcmp(fieldname,
"C") == 0)
145 return MBEDTLS_OID_AT_COUNTRY;
147 else if (strcmp(fieldname,
"ST") == 0)
149 return MBEDTLS_OID_AT_STATE;
151 else if (strcmp(fieldname,
"LOCALITY") == 0)
153 return MBEDTLS_OID_AT_LOCALITY;
155 else if (strcmp(fieldname,
"O") == 0)
157 return MBEDTLS_OID_AT_ORGANIZATION;
159 else if (strcmp(fieldname,
"OU") == 0)
161 return MBEDTLS_OID_AT_ORG_UNIT;
163 else if (strcmp(fieldname,
"CN") == 0)
165 return MBEDTLS_OID_AT_CN;
167 else if (strcmp(fieldname,
"GN") == 0)
169 return MBEDTLS_OID_AT_GIVEN_NAME;
171 else if (strcmp(fieldname,
"SN") == 0)
173 return MBEDTLS_OID_AT_SUR_NAME;
175 else if (strcmp(fieldname,
"initials") == 0)
177 return MBEDTLS_OID_AT_INITIALS;
179 else if (strcmp(fieldname,
"pseudonym") == 0)
181 return MBEDTLS_OID_AT_PSEUDONYM;
183 else if (strcmp(fieldname,
"title") == 0)
185 return MBEDTLS_OID_AT_TITLE;
187 else if (strcmp(fieldname,
"generationQualifier") == 0)
189 return MBEDTLS_OID_AT_GENERATION_QUALIFIER;
191 else if (strcmp(fieldname,
"postalAddress") == 0)
193 return MBEDTLS_OID_AT_POSTAL_ADDRESS;
195 else if (strcmp(fieldname,
"postalCode") == 0)
197 return MBEDTLS_OID_AT_POSTAL_CODE;
199 else if (strcmp(fieldname,
"emailAddress") == 0)
201 return MBEDTLS_OID_PKCS9_EMAIL;
203 else if (strcmp(fieldname,
"uid") == 0)
205 return MBEDTLS_OID_AT_UNIQUE_IDENTIFIER;
207 else if (strcmp(fieldname,
"dnQualifier") == 0)
209 return MBEDTLS_OID_AT_DN_QUALIFIER;
218asn1_buf_is_cstr_compatible(
const mbedtls_asn1_buf *asn1_buf)
220 if (!(asn1_buf->tag == MBEDTLS_ASN1_UTF8_STRING || asn1_buf->tag == MBEDTLS_ASN1_PRINTABLE_STRING
221 || asn1_buf->tag == MBEDTLS_ASN1_IA5_STRING))
225 for (
size_t i = 0; i < asn1_buf->len; i++)
227 if (asn1_buf->p[i] ==
'\0')
238 ASSERT(cn != NULL && cn_len > 0 && cert != NULL);
240 if (x509_username_field == NULL)
245 if (strcmp(x509_username_field,
"serialNumber") == 0)
254 bool leading_zeros =
true;
255 for (
size_t i = 0; i < cert->serial.len; i++)
257 uint8_t serial_byte = cert->serial.p[i];
258 if (leading_zeros && serial_byte == 0)
262 leading_zeros =
false;
263 if (cn_index > cn_len - 3)
267 snprintf(&cn[cn_index], cn_len - cn_index,
"%02X", serial_byte);
273 const char *field_oid = fieldname_to_oid(x509_username_field);
274 if (field_oid == NULL)
280 mbedtls_x509_name *name = NULL;
281 mbedtls_x509_name *next = &cert->subject;
284 if (strlen(field_oid) == next->oid.len
285 && 0 == memcmp(next->oid.p, field_oid, next->oid.len))
299 if (!asn1_buf_is_cstr_compatible(&name->val))
305 if (cn_len <= name->val.len)
310 memcpy(cn, name->val.p, name->val.len);
311 cn[name->val.len] =
'\0';
320#if MBEDTLS_VERSION_NUMBER >= 0x04000000
325bignum_mod_10(
const uint8_t *bignum,
size_t bignum_length)
328 for (
size_t i = 0; i < bignum_length; i++)
330 result = (result * 256) % 10;
331 result = (result + bignum[i]) % 10;
338bignum_div_10(uint8_t *bignum,
size_t *bignum_length)
359 size_t new_length = 0;
361 for (
size_t i = 0; i < *bignum_length; i++)
363 uint8_t next_byte = (uint8_t)((bignum[i] + carry) / 10);
364 int remainder = (bignum[i] + carry) % 10;
365 carry = remainder * 256;
368 if (new_length != 0 || next_byte != 0)
370 bignum[new_length++] = next_byte;
373 *bignum_length = new_length;
380write_bignum(
char *out,
size_t out_size,
const uint8_t *bignum,
size_t bignum_length)
382 if (bignum_length == 0)
392 else if (out_size > 0)
400 uint8_t *bignum_copy = malloc(bignum_length);
401 if (bignum_copy == NULL)
405 memcpy(bignum_copy, bignum, bignum_length);
407 size_t bytes_needed = 0;
408 size_t bytes_written = 0;
409 while (bignum_length > 0)
412 char digit = bignum_mod_10(bignum_copy, bignum_length);
413 if (out != NULL && bytes_written < out_size - 1)
415 out[bytes_written++] =
'0' + (char)digit;
418 bignum_div_10(bignum_copy, &bignum_length);
423 if (bytes_written == bytes_needed)
426 for (
size_t i = 0; i < bytes_written / 2; i++)
429 out[i] = out[bytes_written - 1 - i];
430 out[bytes_written - 1 - i] = tmp;
432 out[bytes_written] =
'\0';
434 else if (out_size > 0)
452#if MBEDTLS_VERSION_NUMBER < 0x04000000
453 mbedtls_mpi serial_mpi = { 0 };
456 mbedtls_mpi_init(&serial_mpi);
457 if (!
mbed_ok(mbedtls_mpi_read_binary(&serial_mpi, cert->serial.p, cert->serial.len)))
459 msg(
M_WARN,
"Failed to retrieve serial from certificate.");
464 mbedtls_mpi_write_string(&serial_mpi, 10, NULL, 0, &buflen);
468 if (!
mbed_ok(mbedtls_mpi_write_string(&serial_mpi, 10, buf, buflen, &buflen)))
470 msg(
M_WARN,
"Failed to write serial to string.");
476 mbedtls_mpi_free(&serial_mpi);
479 buflen = write_bignum(NULL, 0, cert->serial.p, cert->serial.len);
482 msg(
M_WARN,
"Failed to write serial to string.");
486 if (write_bignum(buf, buflen, cert->serial.p, cert->serial.len) != buflen)
488 msg(
M_WARN,
"Failed to write serial to string.");
499 size_t len = cert->serial.len * 3 + 1;
503 if (mbedtls_x509_serial_gets(buf,
len - 1, &cert->serial) < 0)
524 struct buffer der = { 0 };
545#if defined(__GNUC__) || defined(__clang__)
546#pragma GCC diagnostic push
547#pragma GCC diagnostic ignored "-Wconversion"
551x509_get_fingerprint(const mbedtls_md_info_t *
md_info, mbedtls_x509_crt *cert,
struct gc_arena *
gc)
553 const size_t md_size = mbedtls_md_get_size(
md_info);
555 mbedtls_md(
md_info, cert->raw.p, cert->raw.len,
BPTR(&fingerprint));
560#if defined(__GNUC__) || defined(__clang__)
561#pragma GCC diagnostic pop
567 return x509_get_fingerprint(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), cert,
gc);
573 return x509_get_fingerprint(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), cert,
gc);
579 char tmp_subject[MAX_SUBJECT_LENGTH] = { 0 };
580 char *subject = NULL;
584 ret = mbedtls_x509_dn_gets(tmp_subject, MAX_SUBJECT_LENGTH - 1, &cert->subject);
598 size_t name_expand_size;
601 msg(
D_X509_ATTR,
"X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth);
602 name_expand_size = 64 + strlen(name);
603 name_expand = (
char *)malloc(name_expand_size);
605 snprintf(name_expand, name_expand_size,
"X509_%d_%s", depth, name);
611asn1_buf_to_c_string(
const mbedtls_asn1_buf *orig,
struct gc_arena *
gc)
615 if (!asn1_buf_is_cstr_compatible(orig))
617 return string_alloc(
"ERROR: Unsupported string type or embedded null bytes.",
gc);
620 memcpy(val, orig->p, orig->len);
621 val[orig->len] =
'\0';
626do_setenv_name(
struct env_set *es,
const struct x509_track *xt,
const mbedtls_x509_crt *cert,
629 const mbedtls_x509_name *xn;
630 for (xn = &cert->subject; xn != NULL; xn = xn->next)
632 const char *xn_short_name = NULL;
633 if (0 == mbedtls_oid_get_attr_short_name(&xn->oid, &xn_short_name)
634 && 0 == strcmp(xt->
name, xn_short_name))
636 char *val_str = asn1_buf_to_c_string(&xn->val,
gc);
660 mbedtls_x509_crt *cert)
667 if (0 == strcmp(xt->
name,
"SHA1") || 0 == strcmp(xt->
name,
"SHA256"))
673 if (0 == strcmp(xt->
name,
"SHA1"))
688 do_setenv_name(es, xt, cert, depth, &
gc);
705 const mbedtls_x509_name *name;
708 name = &cert->subject;
712 char name_expand[64 + 8];
713 const char *shortname;
715 if (0 == mbedtls_oid_get_attr_short_name(&name->oid, &shortname))
717 snprintf(name_expand,
sizeof(name_expand),
"X509_%d_%s", cert_depth, shortname);
721 snprintf(name_expand,
sizeof(name_expand),
"X509_%d_\?\?", cert_depth);
725 for (i = 0; i < name->val.len; i++)
727 if (i >=
sizeof(s) - 1)
733 if (c < 32 || c == 127 || (c > 128 && c < 160))
767x509_verify_cert_ku(mbedtls_x509_crt *cert,
const unsigned int *
const expected_ku,
size_t expected_len)
771 if (!mbedtls_x509_crt_has_ext_type(cert, MBEDTLS_X509_EXT_KEY_USAGE))
773 msg(
D_TLS_ERRORS,
"ERROR: Certificate does not have key usage extension");
784 for (
size_t i = 0;
SUCCESS != fFound && i < expected_len; i++)
786 if (expected_ku[i] != 0 && 0 == mbedtls_x509_crt_check_key_usage(cert, expected_ku[i]))
794 msg(
D_TLS_ERRORS,
"ERROR: Certificate has invalid key usage, expected one of:");
795 for (
size_t i = 0; i < expected_len && expected_ku[i]; i++)
809 if (!mbedtls_x509_crt_has_ext_type(cert, MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE))
811 msg(
D_HANDSHAKE,
"Certificate does not have extended key usage extension");
815 mbedtls_x509_sequence *oid_seq = &(cert->ext_key_usage);
818 while (oid_seq != NULL)
820 mbedtls_x509_buf *oid = &oid_seq->buf;
821 char oid_num_str[1024];
824 if (0 == mbedtls_oid_get_extended_key_usage(oid, &oid_str))
826 msg(
D_HANDSHAKE,
"++ Certificate has EKU (str) %s, expects %s", oid_str,
828 if (!strcmp(expected_oid, oid_str))
835 if (0 < mbedtls_oid_get_numeric_string(oid_num_str,
sizeof(oid_num_str), oid))
837 msg(
D_HANDSHAKE,
"++ Certificate has EKU (oid) %s, expects %s", oid_num_str,
839 if (!strcmp(expected_oid, oid_num_str))
845 oid_seq = oid_seq->next;
bool buffer_write_file(const char *filename, const struct buffer *buf)
Write buffer contents to file.
void chomp(char *str)
Remove trailing newline and carriage-return characters from a string.
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Allocate memory and, optionally, zero it.
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Allocate a buffer of the given size under garbage collection.
char * format_hex_ex(const uint8_t *data, size_t size, size_t maxoutput, unsigned int space_break_flags, const char *separator, struct gc_arena *gc)
Format a binary buffer as a hex string.
bool string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace)
Modifies a string in place by replacing certain classes of characters of it with a specified characte...
bool checked_snprintf(char *str, size_t size, const char *format,...)
Like snprintf() but returns an boolean.
char * string_alloc(const char *str, struct gc_arena *gc)
Duplicate a string, allocating memory under garbage collection.
#define CC_ANY
any character
#define BPTR(buf)
Return a pointer to the start of the buffer content.
static bool buf_inc_len(struct buffer *buf, int inc)
Increase or decrease the length of a buffer.
#define CC_CRLF
carriage return or newline
static void buf_set_read(struct buffer *buf, const uint8_t *data, size_t size)
Initialise a buffer with an externally provided read-only memory region.
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
Allocate and zero-initialise a garbage-collected object of the given type.
#define BLEN(buf)
Return the length of the buffer content in bytes.
static void check_malloc_return(void *p)
Abort if a memory allocation returned NULL.
static void gc_free(struct gc_arena *a)
Free all allocations in a garbage collection arena.
#define CC_PRINT
printable (>= 32, != 127)
#define FHE_CAPS
Flag for format_hex_ex(): output hex digits in upper case.
static struct gc_arena gc_new(void)
Allocate and return a new, empty garbage collection arena.
bool crypto_pem_encode(const char *name, struct buffer *dst, const struct buffer *src, struct gc_arena *gc)
Encode binary data as PEM.
Data Channel Cryptography backend interface using the TF-PSA-Crypto library part of Mbed TLS 4.
#define mbed_ok(errval)
Check errval and log on error.
Data Channel Cryptography mbed TLS-specific backend interface.
void setenv_str(struct env_set *es, const char *name, const char *value)
void setenv_str_incr(struct env_set *es, const char *name, const char *value)
Store the supplied name value pair in the env_set.
int verify_callback(void *session_obj, mbedtls_x509_crt *cert, int cert_depth, uint32_t *flags)
Verify that the remote OpenVPN peer's certificate allows setting up a VPN tunnel.
mbedtls compatibility stub.
#define SSLF_CRL_VERIFY_DIR
result_t verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_depth)
void cert_hash_remember(struct tls_session *session, const int error_depth, const struct buffer *cert_hash)
Control Channel Verification Module.
#define OPENVPN_KU_REQUIRED
Require keyUsage to be present in cert (0xFFFF is an invalid KU value).
#define NS_CERT_CHECK_NONE
Do not perform Netscape certificate type verification.
struct buffer x509_get_sha256_fingerprint(openvpn_x509_cert_t *cert, struct gc_arena *gc)
Retrieve the certificate's SHA256 fingerprint.
bool x509_username_field_ext_supported(const char *extname)
Return true iff the supplied extension field is supported by the –x509-username-field option.
void x509_setenv_track(const struct x509_track *xt, struct env_set *es, const int depth, openvpn_x509_cert_t *x509)
void x509_setenv(struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert)
bool tls_verify_crl_missing(const struct tls_options *opt)
Return true iff a CRL is configured, but is not loaded.
result_t backend_x509_write_pem(openvpn_x509_cert_t *cert, const char *filename)
result_t x509_verify_ns_cert_type(openvpn_x509_cert_t *cert, const int cert_type)
char * backend_x509_get_serial_hex(openvpn_x509_cert_t *cert, struct gc_arena *gc)
struct buffer x509_get_sha1_fingerprint(openvpn_x509_cert_t *cert, struct gc_arena *gc)
Retrieve the certificate's SHA1 fingerprint.
result_t x509_verify_cert_ku(openvpn_x509_cert_t *x509, const unsigned *const expected_ku, size_t expected_len)
char * x509_get_subject(openvpn_x509_cert_t *cert, struct gc_arena *gc)
char * backend_x509_get_serial(openvpn_x509_cert_t *cert, struct gc_arena *gc)
result_t backend_x509_get_username(char *common_name, size_t cn_len, char *x509_username_field, openvpn_x509_cert_t *peer_cert)
void x509_track_add(const struct x509_track **ll_head, const char *name, msglvl_t msglevel, struct gc_arena *gc)
result_t
Result of verification function.
result_t x509_verify_cert_eku(openvpn_x509_cert_t *x509, const char *const expected_oid)
mbedtls_x509_crt openvpn_x509_cert_t
static void do_setenv_x509(struct env_set *es, const char *name, char *value, int depth)
Wrapper structure for dynamically allocated memory.
int len
Length in bytes of the actual content within the allocated memory.
Structure containing the hash for a single certificate.
Garbage collection arena used to keep track of dynamically allocated memory.
struct tls_root_ctx * ssl_ctx
mbedtls_x509_crl * crl
Certificate Revocation List.
Security parameter state of a single session within a VPN tunnel.
const struct x509_track * next