OpenVPN
ssl_verify_mbedtls.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2002-2024 OpenVPN Inc <sales@openvpn.net>
9 * Copyright (C) 2010-2021 Fox Crypto B.V. <openvpn@foxcrypto.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2
13 * as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 */
24
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#include "syshead.h"
35
36#if defined(ENABLE_CRYPTO_MBEDTLS)
37
38#include "crypto_mbedtls.h"
39#include "mbedtls_compat.h"
40#include "ssl_verify.h"
41#include <mbedtls/asn1.h>
42#include <mbedtls/error.h>
43#include <mbedtls/bignum.h>
44#include <mbedtls/oid.h>
45#include <mbedtls/sha1.h>
46
47#define MAX_SUBJECT_LENGTH 256
48
49int
50verify_callback(void *session_obj, mbedtls_x509_crt *cert, int cert_depth,
51 uint32_t *flags)
52{
53 struct tls_session *session = (struct tls_session *) session_obj;
54 struct gc_arena gc = gc_new();
55
56 ASSERT(cert);
58
59 session->verified = false;
60
61 /* Remember certificate hash */
64
65 if (session->opt->verify_hash_no_ca)
66 {
67 /*
68 * If we decide to verify the peer certificate based on the fingerprint
69 * we ignore wrong dates and the certificate not being trusted.
70 * Any other problem with the certificate (wrong key, bad cert,...)
71 * will still trigger an error.
72 * Clearing these flags relies on verify_cert will later rejecting a
73 * certificate that has no matching fingerprint.
74 */
78 *flags = *flags & ~flags_ignore;
79 }
80
81 /* did peer present cert which was signed by our root cert? */
82 if (*flags != 0)
83 {
84 int ret = 0;
85 char errstr[512] = { 0 };
86 char *subject = x509_get_subject(cert, &gc);
87 char *serial = backend_x509_get_serial(cert, &gc);
88
89 ret = mbedtls_x509_crt_verify_info(errstr, sizeof(errstr)-1, "", *flags);
90 if (ret <= 0 && !snprintf(errstr, sizeof(errstr),
91 "Could not retrieve error string, flags=%" PRIx32, *flags))
92 {
93 errstr[0] = '\0';
94 }
95 else
96 {
98 }
99
100 if (subject)
101 {
102 msg(D_TLS_ERRORS, "VERIFY ERROR: depth=%d, subject=%s, serial=%s: %s",
103 cert_depth, subject, serial ? serial : "<not available>", errstr);
104 }
105 else
106 {
107 msg(D_TLS_ERRORS, "VERIFY ERROR: depth=%d, (could not extract X509 "
108 "subject string from certificate): %s", cert_depth, errstr);
109 }
110
111 /* Leave flags set to non-zero to indicate that the cert is not ok */
112 }
113 else if (SUCCESS != verify_cert(session, cert, cert_depth))
114 {
116 }
117
118 gc_free(&gc);
119
120 /*
121 * PolarSSL/mbed TLS-1.2.0+ expects 0 on anything except fatal errors.
122 */
123 return 0;
124}
125
126#ifdef ENABLE_X509ALTUSERNAME
127#warning "X509 alt user name not yet supported for mbed TLS"
128#endif
129
132 char *x509_username_field, mbedtls_x509_crt *cert)
133{
134 mbedtls_x509_name *name;
135
136 ASSERT( cn != NULL );
137
138 name = &cert->subject;
139
140 /* Find common name */
141 while (name != NULL)
142 {
143 if (0 == memcmp(name->oid.p, MBEDTLS_OID_AT_CN,
145 {
146 break;
147 }
148
149 name = name->next;
150 }
151
152 /* Not found, return an error if this is the peer's certificate */
153 if (name == NULL)
154 {
155 return FAILURE;
156 }
157
158 /* Found, extract CN */
159 if (cn_len > name->val.len)
160 {
161 memcpy( cn, name->val.p, name->val.len );
162 cn[name->val.len] = '\0';
163 }
164 else
165 {
166 memcpy( cn, name->val.p, cn_len);
167 cn[cn_len-1] = '\0';
168 }
169
170 return SUCCESS;
171}
172
173char *
175{
176 char *buf = NULL;
177 size_t buflen = 0;
178 mbedtls_mpi serial_mpi = { 0 };
179
180 /* Transform asn1 integer serial into mbed TLS MPI */
182 if (!mbed_ok(mbedtls_mpi_read_binary(&serial_mpi, cert->serial.p,
183 cert->serial.len)))
184 {
185 msg(M_WARN, "Failed to retrieve serial from certificate.");
186 goto end;
187 }
188
189 /* Determine decimal representation length, allocate buffer */
191 buf = gc_malloc(buflen, true, gc);
192
193 /* Write MPI serial as decimal string into buffer */
195 {
196 msg(M_WARN, "Failed to write serial to string.");
197 buf = NULL;
198 goto end;
199 }
200
201end:
203 return buf;
204}
205
206char *
208{
209 char *buf = NULL;
210 size_t len = cert->serial.len * 3 + 1;
211
212 buf = gc_malloc(len, true, gc);
213
214 if (mbedtls_x509_serial_gets(buf, len-1, &cert->serial) < 0)
215 {
216 buf = NULL;
217 }
218
219 return buf;
220}
221
223backend_x509_write_pem(openvpn_x509_cert_t *cert, const char *filename)
224{
225 /* mbed TLS does not make it easy to write a certificate in PEM format.
226 * The only way is to directly access the DER encoded raw certificate
227 * and PEM encode it ourselves */
228
229 struct gc_arena gc = gc_new();
230 /* just do a very loose upper bound for the base64 based PEM encoding
231 * using 3 times the space for the base64 and 100 bytes for the
232 * headers and footer */
233 struct buffer pem = alloc_buf_gc(cert->raw.len * 3 + 100, &gc);
234
235 struct buffer der = {};
236 buf_set_read(&der, cert->raw.p, cert->raw.len);
237
238 if (!crypto_pem_encode("CERTIFICATE", &pem, &der, &gc))
239 {
240 goto err;
241 }
242
243 if (!buffer_write_file(filename, &pem))
244 {
245 goto err;
246 }
247
248 gc_free(&gc);
249 return SUCCESS;
250err:
251 msg(D_TLS_DEBUG_LOW, "Error writing X509 certificate to file %s",
252 filename);
253 gc_free(&gc);
254 return FAILURE;
255}
256
257static struct buffer
259 struct gc_arena *gc)
260{
261 const size_t md_size = mbedtls_md_get_size(md_info);
263 mbedtls_md(md_info, cert->raw.p, cert->raw.len, BPTR(&fingerprint));
265 return fingerprint;
266}
267
268struct buffer
270{
271 return x509_get_fingerprint(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1),
272 cert, gc);
273}
274
275struct buffer
277{
278 return x509_get_fingerprint(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
279 cert, gc);
280}
281
282char *
283x509_get_subject(mbedtls_x509_crt *cert, struct gc_arena *gc)
284{
285 char tmp_subject[MAX_SUBJECT_LENGTH] = {0};
286 char *subject = NULL;
287
288 int ret = 0;
289
290 ret = mbedtls_x509_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, &cert->subject );
291 if (ret > 0)
292 {
293 /* Allocate the required space for the subject */
294 subject = string_alloc(tmp_subject, gc);
295 }
296
297 return subject;
298}
299
300static void
301do_setenv_x509(struct env_set *es, const char *name, char *value, int depth)
302{
303 char *name_expand;
304 size_t name_expand_size;
305
306 string_mod(value, CC_ANY, CC_CRLF, '?');
307 msg(D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth);
308 name_expand_size = 64 + strlen(name);
309 name_expand = (char *) malloc(name_expand_size);
310 check_malloc_return(name_expand);
311 snprintf(name_expand, name_expand_size, "X509_%d_%s", depth, name);
312 setenv_str(es, name_expand, value);
313 free(name_expand);
314}
315
316static char *
317asn1_buf_to_c_string(const mbedtls_asn1_buf *orig, struct gc_arena *gc)
318{
319 size_t i;
320 char *val;
321
322 if (!(orig->tag == MBEDTLS_ASN1_UTF8_STRING
323 || orig->tag == MBEDTLS_ASN1_PRINTABLE_STRING
324 || orig->tag == MBEDTLS_ASN1_IA5_STRING))
325 {
326 /* Only support C-string compatible types */
327 return string_alloc("ERROR: unsupported ASN.1 string type", gc);
328 }
329
330 for (i = 0; i < orig->len; ++i)
331 {
332 if (orig->p[i] == '\0')
333 {
334 return string_alloc("ERROR: embedded null value", gc);
335 }
336 }
337 val = gc_malloc(orig->len+1, false, gc);
338 memcpy(val, orig->p, orig->len);
339 val[orig->len] = '\0';
340 return val;
341}
342
343static void
344do_setenv_name(struct env_set *es, const struct x509_track *xt,
345 const mbedtls_x509_crt *cert, int depth, struct gc_arena *gc)
346{
347 const mbedtls_x509_name *xn;
348 for (xn = &cert->subject; xn != NULL; xn = xn->next)
349 {
350 const char *xn_short_name = NULL;
351 if (0 == mbedtls_oid_get_attr_short_name(&xn->oid, &xn_short_name)
352 && 0 == strcmp(xt->name, xn_short_name))
353 {
354 char *val_str = asn1_buf_to_c_string(&xn->val, gc);
355 do_setenv_x509(es, xt->name, val_str, depth);
356 }
357 }
358}
359
360void
361x509_track_add(const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc)
362{
363 struct x509_track *xt;
364 ALLOC_OBJ_CLEAR_GC(xt, struct x509_track, gc);
365 if (*name == '+')
366 {
367 xt->flags |= XT_FULL_CHAIN;
368 ++name;
369 }
370 xt->name = name;
371 xt->next = *ll_head;
372 *ll_head = xt;
373}
374
375void
376x509_setenv_track(const struct x509_track *xt, struct env_set *es,
377 const int depth, mbedtls_x509_crt *cert)
378{
379 struct gc_arena gc = gc_new();
380 while (xt)
381 {
382 if (depth == 0 || (xt->flags & XT_FULL_CHAIN))
383 {
384 if (0 == strcmp(xt->name, "SHA1") || 0 == strcmp(xt->name, "SHA256"))
385 {
386 /* Fingerprint is not part of X509 structure */
387 struct buffer cert_hash;
388 char *fingerprint;
389
390 if (0 == strcmp(xt->name, "SHA1"))
391 {
393 }
394 else
395 {
397 }
398
400 BLEN(&cert_hash), 0, 1 | FHE_CAPS, ":", &gc);
402 }
403 else
404 {
405 do_setenv_name(es, xt, cert, depth, &gc);
406 }
407 }
408 xt = xt->next;
409 }
410 gc_free(&gc);
411}
412
413/*
414 * Save X509 fields to environment, using the naming convention:
415 *
416 * X509_{cert_depth}_{name}={value}
417 */
418void
420{
421 int i;
422 unsigned char c;
423 const mbedtls_x509_name *name;
424 char s[128] = { 0 };
425
426 name = &cert->subject;
427
428 while (name != NULL)
429 {
430 char name_expand[64+8];
431 const char *shortname;
432
433 if (0 == mbedtls_oid_get_attr_short_name(&name->oid, &shortname) )
434 {
435 snprintf(name_expand, sizeof(name_expand), "X509_%d_%s",
437 }
438 else
439 {
440 snprintf(name_expand, sizeof(name_expand), "X509_%d_\?\?",
441 cert_depth);
442 }
443
444 for (i = 0; i < name->val.len; i++)
445 {
446 if (i >= (int) sizeof( s ) - 1)
447 {
448 break;
449 }
450
451 c = name->val.p[i];
452 if (c < 32 || c == 127 || ( c > 128 && c < 160 ) )
453 {
454 s[i] = '?';
455 }
456 else
457 {
458 s[i] = c;
459 }
460 }
461 s[i] = '\0';
462
463 /* Check both strings, set environment variable */
465 string_mod((char *)s, CC_PRINT, CC_CRLF, '_');
466 setenv_str_incr(es, name_expand, (char *)s);
467
468 name = name->next;
469 }
470}
471
472/* Dummy function because Netscape certificate types are not supported in OpenVPN with mbedtls.
473 * Returns SUCCESS if usage is NS_CERT_CHECK_NONE, FAILURE otherwise. */
476{
478 {
479 return SUCCESS;
480 }
481
482 return FAILURE;
483}
484
486x509_verify_cert_ku(mbedtls_x509_crt *cert, const unsigned *const expected_ku,
487 int expected_len)
488{
489 msg(D_HANDSHAKE, "Validating certificate key usage");
490
492 {
494 "ERROR: Certificate does not have key usage extension");
495 return FAILURE;
496 }
497
499 {
500 /* Extension required, value checked by TLS library */
501 return SUCCESS;
502 }
503
505 for (size_t i = 0; SUCCESS != fFound && i<expected_len; i++)
506 {
507 if (expected_ku[i] != 0
509 {
510 fFound = SUCCESS;
511 }
512 }
513
514 if (fFound != SUCCESS)
515 {
516 msg(D_TLS_ERRORS, "ERROR: Certificate has invalid key usage, expected one of:");
517 for (size_t i = 0; i < expected_len && expected_ku[i]; i++)
518 {
519 msg(D_TLS_ERRORS, " * %04x", expected_ku[i]);
520 }
521 }
522
523 return fFound;
524}
525
527x509_verify_cert_eku(mbedtls_x509_crt *cert, const char *const expected_oid)
528{
530
532 {
533 msg(D_HANDSHAKE, "Certificate does not have extended key usage extension");
534 }
535 else
536 {
537 mbedtls_x509_sequence *oid_seq = &(cert->ext_key_usage);
538
539 msg(D_HANDSHAKE, "Validating certificate extended key usage");
540 while (oid_seq != NULL)
541 {
543 char oid_num_str[1024];
544 const char *oid_str;
545
547 {
548 msg(D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s",
551 {
552 fFound = SUCCESS;
553 break;
554 }
555 }
556
558 sizeof(oid_num_str), oid))
559 {
560 msg(D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s",
563 {
564 fFound = SUCCESS;
565 break;
566 }
567 }
568 oid_seq = oid_seq->next;
569 }
570 }
571
572 return fFound;
573}
574
575bool
576tls_verify_crl_missing(const struct tls_options *opt)
577{
578 if (opt->crl_file && !(opt->ssl_flags & SSLF_CRL_VERIFY_DIR)
579 && (opt->ssl_ctx.crl == NULL || opt->ssl_ctx.crl->version == 0))
580 {
581 return true;
582 }
583 return false;
584}
585
586#endif /* #if defined(ENABLE_CRYPTO_MBEDTLS) */
bool buffer_write_file(const char *filename, const struct buffer *buf)
Write buffer contents to file.
Definition buffer.c:300
char * format_hex_ex(const uint8_t *data, int size, int maxoutput, unsigned int space_break_flags, const char *separator, struct gc_arena *gc)
Definition buffer.c:483
void chomp(char *str)
Definition buffer.c:614
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition buffer.c:336
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:88
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...
Definition buffer.c:1041
char * string_alloc(const char *str, struct gc_arena *gc)
Definition buffer.c:649
#define CC_ANY
any character
Definition buffer.h:883
#define BPTR(buf)
Definition buffer.h:124
static bool buf_inc_len(struct buffer *buf, int inc)
Definition buffer.h:590
#define CC_CRLF
carriage return or newline
Definition buffer.h:920
static void buf_set_read(struct buffer *buf, const uint8_t *data, size_t size)
Definition buffer.h:348
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
Definition buffer.h:1097
#define BLEN(buf)
Definition buffer.h:127
static void check_malloc_return(void *p)
Definition buffer.h:1103
static void gc_free(struct gc_arena *a)
Definition buffer.h:1033
#define CC_PRINT
printable (>= 32, != 127)
Definition buffer.h:891
#define FHE_CAPS
Definition buffer.h:498
static struct gc_arena gc_new(void)
Definition buffer.h:1025
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 mbed TLS-specific backend interface.
#define mbed_ok(errval)
Check errval and log on error.
void setenv_str(struct env_set *es, const char *name, const char *value)
Definition env_set.c:283
void setenv_str_incr(struct env_set *es, const char *name, const char *value)
Store the supplied name value pair in the env_set.
Definition env_set.c:305
#define D_TLS_DEBUG_LOW
Definition errlevel.h:77
#define D_X509_ATTR
Definition errlevel.h:103
#define D_HANDSHAKE
Definition errlevel.h:72
#define D_TLS_ERRORS
Definition errlevel.h:59
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.
static int mbedtls_x509_crt_has_ext_type(const mbedtls_x509_crt *ctx, int ext_type)
#define msg(flags,...)
Definition error.h:144
#define ASSERT(x)
Definition error.h:195
#define M_WARN
Definition error.h:91
static void usage(void)
Definition options.c:4934
#define SSLF_CRL_VERIFY_DIR
Definition ssl_common.h:420
result_t verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_depth)
Definition ssl_verify.c:590
void cert_hash_remember(struct tls_session *session, const int error_depth, const struct buffer *cert_hash)
Definition ssl_verify.c:197
Control Channel Verification Module.
#define OPENVPN_KU_REQUIRED
Require keyUsage to be present in cert (0xFFFF is an invalid KU value)
Definition ssl_verify.h:235
#define XT_FULL_CHAIN
Definition ssl_verify.h:219
#define NS_CERT_CHECK_NONE
Do not perform Netscape certificate type verification.
Definition ssl_verify.h:228
struct buffer x509_get_sha256_fingerprint(openvpn_x509_cert_t *cert, struct gc_arena *gc)
Retrieve the certificate's SHA256 fingerprint.
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 usage)
result_t backend_x509_get_username(char *common_name, int cn_len, char *x509_username_field, openvpn_x509_cert_t *peer_cert)
char * backend_x509_get_serial_hex(openvpn_x509_cert_t *cert, struct gc_arena *gc)
result_t x509_verify_cert_ku(openvpn_x509_cert_t *x509, const unsigned *const expected_ku, int expected_len)
struct buffer x509_get_sha1_fingerprint(openvpn_x509_cert_t *cert, struct gc_arena *gc)
Retrieve the certificate's SHA1 fingerprint.
char * x509_get_subject(openvpn_x509_cert_t *cert, struct gc_arena *gc)
Definition test_pkcs11.c:69
char * backend_x509_get_serial(openvpn_x509_cert_t *cert, struct gc_arena *gc)
void x509_track_add(const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc)
result_t
Result of verification function.
@ FAILURE
@ SUCCESS
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.
Definition buffer.h:61
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
Structure containing the hash for a single certificate.
Definition ssl_verify.h:55
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
struct tls_root_ctx ssl_ctx
Definition ssl_common.h:300
unsigned int ssl_flags
Definition ssl_common.h:426
const char * crl_file
Definition ssl_common.h:345
mbedtls_x509_crl * crl
Certificate Revocation List.
Security parameter state of a single session within a VPN tunnel.
Definition ssl_common.h:480
unsigned int flags
Definition ssl_verify.h:220
const struct x509_track * next
Definition ssl_verify.h:217
const char * name
Definition ssl_verify.h:218
struct env_set * es
struct gc_arena gc
Definition test_ssl.c:155