diff options
Diffstat (limited to 'src/openvpn/ssl_verify_openssl.c')
-rw-r--r-- | src/openvpn/ssl_verify_openssl.c | 936 |
1 files changed, 500 insertions, 436 deletions
diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 3d1c85e..e9692a0 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -48,117 +48,123 @@ #include <openssl/err.h> int -verify_callback (int preverify_ok, X509_STORE_CTX * ctx) +verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { - int ret = 0; - struct tls_session *session; - SSL *ssl; - struct gc_arena gc = gc_new(); - - /* get the tls_session pointer */ - ssl = X509_STORE_CTX_get_ex_data (ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); - ASSERT (ssl); - session = (struct tls_session *) SSL_get_ex_data (ssl, mydata_index); - ASSERT (session); - - struct buffer cert_hash = x509_get_sha256_fingerprint(ctx->current_cert, &gc); - cert_hash_remember (session, ctx->error_depth, &cert_hash); - - /* did peer present cert which was signed by our root cert? */ - if (!preverify_ok) + int ret = 0; + struct tls_session *session; + SSL *ssl; + struct gc_arena gc = gc_new(); + + /* get the tls_session pointer */ + ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); + ASSERT(ssl); + session = (struct tls_session *) SSL_get_ex_data(ssl, mydata_index); + ASSERT(session); + + struct buffer cert_hash = x509_get_sha256_fingerprint(ctx->current_cert, &gc); + cert_hash_remember(session, ctx->error_depth, &cert_hash); + + /* did peer present cert which was signed by our root cert? */ + if (!preverify_ok) { - /* get the X509 name */ - char *subject = x509_get_subject(ctx->current_cert, &gc); - - if (!subject) - { - subject = "(Failed to retrieve certificate subject)"; - } + /* get the X509 name */ + char *subject = x509_get_subject(ctx->current_cert, &gc); - /* Log and ignore missing CRL errors */ - if (ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL) - { - msg (D_TLS_DEBUG_LOW, "VERIFY WARNING: depth=%d, %s: %s", - ctx->error_depth, - X509_verify_cert_error_string (ctx->error), - subject); - ret = 1; - goto cleanup; - } - - /* Remote site specified a certificate, but it's not correct */ - msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, error=%s: %s", - ctx->error_depth, - X509_verify_cert_error_string (ctx->error), - subject); - - ERR_clear_error(); + if (!subject) + { + subject = "(Failed to retrieve certificate subject)"; + } - session->verified = false; - goto cleanup; + /* Log and ignore missing CRL errors */ + if (ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL) + { + msg(D_TLS_DEBUG_LOW, "VERIFY WARNING: depth=%d, %s: %s", + ctx->error_depth, + X509_verify_cert_error_string(ctx->error), + subject); + ret = 1; + goto cleanup; + } + + /* Remote site specified a certificate, but it's not correct */ + msg(D_TLS_ERRORS, "VERIFY ERROR: depth=%d, error=%s: %s", + ctx->error_depth, + X509_verify_cert_error_string(ctx->error), + subject); + + ERR_clear_error(); + + session->verified = false; + goto cleanup; } - if (SUCCESS != verify_cert(session, ctx->current_cert, ctx->error_depth)) - goto cleanup; + if (SUCCESS != verify_cert(session, ctx->current_cert, ctx->error_depth)) + { + goto cleanup; + } - ret = 1; + ret = 1; cleanup: - gc_free(&gc); + gc_free(&gc); - return ret; + return ret; } #ifdef ENABLE_X509ALTUSERNAME static -bool extract_x509_extension(X509 *cert, char *fieldname, char *out, int size) +bool +extract_x509_extension(X509 *cert, char *fieldname, char *out, int size) { - bool retval = false; - char *buf = 0; - GENERAL_NAMES *extensions; - int nid = OBJ_txt2nid(fieldname); + bool retval = false; + char *buf = 0; + GENERAL_NAMES *extensions; + int nid = OBJ_txt2nid(fieldname); - extensions = (GENERAL_NAMES *)X509_get_ext_d2i(cert, nid, NULL, NULL); - if ( extensions ) + extensions = (GENERAL_NAMES *)X509_get_ext_d2i(cert, nid, NULL, NULL); + if (extensions) { - int numalts; - int i; - /* get amount of alternatives, - * RFC2459 claims there MUST be at least - * one, but we don't depend on it... - */ + int numalts; + int i; + /* get amount of alternatives, + * RFC2459 claims there MUST be at least + * one, but we don't depend on it... + */ - numalts = sk_GENERAL_NAME_num(extensions); + numalts = sk_GENERAL_NAME_num(extensions); - /* loop through all alternatives */ - for (i=0; i<numalts; i++) + /* loop through all alternatives */ + for (i = 0; i<numalts; i++) { - /* get a handle to alternative name number i */ - const GENERAL_NAME *name = sk_GENERAL_NAME_value (extensions, i ); + /* get a handle to alternative name number i */ + const GENERAL_NAME *name = sk_GENERAL_NAME_value(extensions, i ); - switch (name->type) + switch (name->type) { - case GEN_EMAIL: - ASN1_STRING_to_UTF8((unsigned char**)&buf, name->d.ia5); - if ( strlen (buf) != name->d.ia5->length ) - { - msg (D_TLS_ERRORS, "ASN1 ERROR: string contained terminating zero"); - OPENSSL_free (buf); - } else { - strncpynt(out, buf, size); - OPENSSL_free(buf); - retval = true; - } - break; - default: - msg (D_TLS_DEBUG, "%s: ignoring general name field type %i", - __func__, name->type); - break; + case GEN_EMAIL: + ASN1_STRING_to_UTF8((unsigned char **)&buf, name->d.ia5); + if (strlen(buf) != name->d.ia5->length) + { + msg(D_TLS_ERRORS, "ASN1 ERROR: string contained terminating zero"); + OPENSSL_free(buf); + } + else + { + strncpynt(out, buf, size); + OPENSSL_free(buf); + retval = true; + } + break; + + default: + msg(D_TLS_DEBUG, "%s: ignoring general name field type %i", + __func__, name->type); + break; } - } - sk_GENERAL_NAME_free (extensions); + } + sk_GENERAL_NAME_free(extensions); } - return retval; + return retval; } #endif /* ENABLE_X509ALTUSERNAME */ @@ -175,154 +181,173 @@ bool extract_x509_extension(X509 *cert, char *fieldname, char *out, int size) * to contain result is grounds for error). */ static result_t -extract_x509_field_ssl (X509_NAME *x509, const char *field_name, char *out, - int size) +extract_x509_field_ssl(X509_NAME *x509, const char *field_name, char *out, + int size) { - int lastpos = -1; - int tmp = -1; - X509_NAME_ENTRY *x509ne = 0; - ASN1_STRING *asn1 = 0; - unsigned char *buf = NULL; - int nid = OBJ_txt2nid(field_name); - - ASSERT (size > 0); - *out = '\0'; - do { - lastpos = tmp; - tmp = X509_NAME_get_index_by_NID(x509, nid, lastpos); - } while (tmp > -1); - - /* Nothing found */ - if (lastpos == -1) - return FAILURE; + int lastpos = -1; + int tmp = -1; + X509_NAME_ENTRY *x509ne = 0; + ASN1_STRING *asn1 = 0; + unsigned char *buf = NULL; + int nid = OBJ_txt2nid(field_name); + + ASSERT(size > 0); + *out = '\0'; + do { + lastpos = tmp; + tmp = X509_NAME_get_index_by_NID(x509, nid, lastpos); + } while (tmp > -1); + + /* Nothing found */ + if (lastpos == -1) + { + return FAILURE; + } - x509ne = X509_NAME_get_entry(x509, lastpos); - if (!x509ne) - return FAILURE; + x509ne = X509_NAME_get_entry(x509, lastpos); + if (!x509ne) + { + return FAILURE; + } - asn1 = X509_NAME_ENTRY_get_data(x509ne); - if (!asn1) - return FAILURE; - tmp = ASN1_STRING_to_UTF8(&buf, asn1); - if (tmp <= 0) - return FAILURE; + asn1 = X509_NAME_ENTRY_get_data(x509ne); + if (!asn1) + { + return FAILURE; + } + tmp = ASN1_STRING_to_UTF8(&buf, asn1); + if (tmp <= 0) + { + return FAILURE; + } - strncpynt(out, (char *)buf, size); + strncpynt(out, (char *)buf, size); - { - const result_t ret = (strlen ((char *)buf) < size) ? SUCCESS: FAILURE; - OPENSSL_free (buf); - return ret; - } + { + const result_t ret = (strlen((char *)buf) < size) ? SUCCESS : FAILURE; + OPENSSL_free(buf); + return ret; + } } result_t -backend_x509_get_username (char *common_name, int cn_len, - char * x509_username_field, X509 *peer_cert) +backend_x509_get_username(char *common_name, int cn_len, + char *x509_username_field, X509 *peer_cert) { #ifdef ENABLE_X509ALTUSERNAME - if (strncmp("ext:",x509_username_field,4) == 0) + if (strncmp("ext:",x509_username_field,4) == 0) { - if (!extract_x509_extension (peer_cert, x509_username_field+4, common_name, cn_len)) - return FAILURE; - } else + if (!extract_x509_extension(peer_cert, x509_username_field+4, common_name, cn_len)) + { + return FAILURE; + } + } + else #endif - if (FAILURE == extract_x509_field_ssl (X509_get_subject_name (peer_cert), - x509_username_field, common_name, cn_len)) - return FAILURE; + if (FAILURE == extract_x509_field_ssl(X509_get_subject_name(peer_cert), + x509_username_field, common_name, cn_len)) + { + return FAILURE; + } - return SUCCESS; + return SUCCESS; } char * -backend_x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc) +backend_x509_get_serial(openvpn_x509_cert_t *cert, struct gc_arena *gc) { - ASN1_INTEGER *asn1_i; - BIGNUM *bignum; - char *openssl_serial, *serial; + ASN1_INTEGER *asn1_i; + BIGNUM *bignum; + char *openssl_serial, *serial; - asn1_i = X509_get_serialNumber(cert); - bignum = ASN1_INTEGER_to_BN(asn1_i, NULL); - openssl_serial = BN_bn2dec(bignum); + asn1_i = X509_get_serialNumber(cert); + bignum = ASN1_INTEGER_to_BN(asn1_i, NULL); + openssl_serial = BN_bn2dec(bignum); - serial = string_alloc(openssl_serial, gc); + serial = string_alloc(openssl_serial, gc); - BN_free(bignum); - OPENSSL_free(openssl_serial); + BN_free(bignum); + OPENSSL_free(openssl_serial); - return serial; + return serial; } char * -backend_x509_get_serial_hex (openvpn_x509_cert_t *cert, struct gc_arena *gc) +backend_x509_get_serial_hex(openvpn_x509_cert_t *cert, struct gc_arena *gc) { - const ASN1_INTEGER *asn1_i = X509_get_serialNumber(cert); + const ASN1_INTEGER *asn1_i = X509_get_serialNumber(cert); - return format_hex_ex(asn1_i->data, asn1_i->length, 0, 1, ":", gc); + return format_hex_ex(asn1_i->data, asn1_i->length, 0, 1, ":", gc); } struct buffer -x509_get_sha1_fingerprint (X509 *cert, struct gc_arena *gc) +x509_get_sha1_fingerprint(X509 *cert, struct gc_arena *gc) { - struct buffer hash = alloc_buf_gc(sizeof(cert->sha1_hash), gc); - memcpy(BPTR(&hash), cert->sha1_hash, sizeof(cert->sha1_hash)); - ASSERT (buf_inc_len(&hash, sizeof (cert->sha1_hash))); - return hash; + struct buffer hash = alloc_buf_gc(sizeof(cert->sha1_hash), gc); + memcpy(BPTR(&hash), cert->sha1_hash, sizeof(cert->sha1_hash)); + ASSERT(buf_inc_len(&hash, sizeof(cert->sha1_hash))); + return hash; } struct buffer -x509_get_sha256_fingerprint (X509 *cert, struct gc_arena *gc) +x509_get_sha256_fingerprint(X509 *cert, struct gc_arena *gc) { - struct buffer hash = alloc_buf_gc((EVP_sha256())->md_size, gc); - X509_digest(cert, EVP_sha256(), BPTR(&hash), NULL); - ASSERT (buf_inc_len(&hash, (EVP_sha256())->md_size)); - return hash; + struct buffer hash = alloc_buf_gc((EVP_sha256())->md_size, gc); + X509_digest(cert, EVP_sha256(), BPTR(&hash), NULL); + ASSERT(buf_inc_len(&hash, (EVP_sha256())->md_size)); + return hash; } char * -x509_get_subject (X509 *cert, struct gc_arena *gc) +x509_get_subject(X509 *cert, struct gc_arena *gc) { - BIO *subject_bio = NULL; - BUF_MEM *subject_mem; - char *subject = NULL; - int maxlen = 0; - - /* - * Generate the subject string in OpenSSL proprietary format, - * when in --compat-names mode - */ - if (compat_flag (COMPAT_FLAG_QUERY | COMPAT_NAMES)) + BIO *subject_bio = NULL; + BUF_MEM *subject_mem; + char *subject = NULL; + int maxlen = 0; + + /* + * Generate the subject string in OpenSSL proprietary format, + * when in --compat-names mode + */ + if (compat_flag(COMPAT_FLAG_QUERY | COMPAT_NAMES)) { - subject = gc_malloc (256, false, gc); - X509_NAME_oneline (X509_get_subject_name (cert), subject, 256); - subject[255] = '\0'; - return subject; + subject = gc_malloc(256, false, gc); + X509_NAME_oneline(X509_get_subject_name(cert), subject, 256); + subject[255] = '\0'; + return subject; } - subject_bio = BIO_new (BIO_s_mem ()); - if (subject_bio == NULL) - goto err; + subject_bio = BIO_new(BIO_s_mem()); + if (subject_bio == NULL) + { + goto err; + } - X509_NAME_print_ex (subject_bio, X509_get_subject_name (cert), - 0, XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_FN_SN | - ASN1_STRFLGS_UTF8_CONVERT | ASN1_STRFLGS_ESC_CTRL); + X509_NAME_print_ex(subject_bio, X509_get_subject_name(cert), + 0, XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_FN_SN + |ASN1_STRFLGS_UTF8_CONVERT | ASN1_STRFLGS_ESC_CTRL); - if (BIO_eof (subject_bio)) - goto err; + if (BIO_eof(subject_bio)) + { + goto err; + } - BIO_get_mem_ptr (subject_bio, &subject_mem); + BIO_get_mem_ptr(subject_bio, &subject_mem); - maxlen = subject_mem->length + 1; - subject = gc_malloc (maxlen, false, gc); + maxlen = subject_mem->length + 1; + subject = gc_malloc(maxlen, false, gc); - memcpy (subject, subject_mem->data, maxlen); - subject[maxlen - 1] = '\0'; + memcpy(subject, subject_mem->data, maxlen); + subject[maxlen - 1] = '\0'; err: - if (subject_bio) - BIO_free (subject_bio); + if (subject_bio) + { + BIO_free(subject_bio); + } - return subject; + return subject; } @@ -348,121 +373,128 @@ err: */ void -x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc) +x509_track_add(const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc) { - struct x509_track *xt; - ALLOC_OBJ_CLEAR_GC (xt, struct x509_track, gc); - if (*name == '+') + struct x509_track *xt; + ALLOC_OBJ_CLEAR_GC(xt, struct x509_track, gc); + if (*name == '+') + { + xt->flags |= XT_FULL_CHAIN; + ++name; + } + xt->name = name; + xt->nid = OBJ_txt2nid(name); + if (xt->nid != NID_undef) { - xt->flags |= XT_FULL_CHAIN; - ++name; + xt->next = *ll_head; + *ll_head = xt; } - xt->name = name; - xt->nid = OBJ_txt2nid(name); - if (xt->nid != NID_undef) + else { - xt->next = *ll_head; - *ll_head = xt; + msg(msglevel, "x509_track: no such attribute '%s'", name); } - else - msg(msglevel, "x509_track: no such attribute '%s'", name); } /* worker method for setenv_x509_track */ static void -do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth) +do_setenv_x509(struct env_set *es, const char *name, char *value, int depth) { - char *name_expand; - size_t name_expand_size; - - string_mod (value, CC_ANY, CC_CRLF, '?'); - msg (D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth); - name_expand_size = 64 + strlen (name); - name_expand = (char *) malloc (name_expand_size); - check_malloc_return (name_expand); - openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", depth, name); - setenv_str (es, name_expand, value); - free (name_expand); + char *name_expand; + size_t name_expand_size; + + string_mod(value, CC_ANY, CC_CRLF, '?'); + msg(D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth); + name_expand_size = 64 + strlen(name); + name_expand = (char *) malloc(name_expand_size); + check_malloc_return(name_expand); + openvpn_snprintf(name_expand, name_expand_size, "X509_%d_%s", depth, name); + setenv_str(es, name_expand, value); + free(name_expand); } void -x509_setenv_track (const struct x509_track *xt, struct env_set *es, const int depth, X509 *x509) +x509_setenv_track(const struct x509_track *xt, struct env_set *es, const int depth, X509 *x509) { - struct gc_arena gc = gc_new(); - X509_NAME *x509_name = X509_get_subject_name (x509); - const char nullc = '\0'; - - while (xt) - { - if (depth == 0 || (xt->flags & XT_FULL_CHAIN)) - { - switch (xt->nid) - { - case NID_sha1: - case NID_sha256: - { - struct buffer fp_buf; - char *fp_str = NULL; - - if (xt->nid == NID_sha1) - fp_buf = x509_get_sha1_fingerprint(x509, &gc); - else - fp_buf = x509_get_sha256_fingerprint(x509, &gc); - - fp_str = format_hex_ex(BPTR(&fp_buf), BLEN(&fp_buf), 0, - 1 | FHE_CAPS, ":", &gc); - do_setenv_x509(es, xt->name, fp_str, depth); - } - break; - default: - { - int i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1); - if (i >= 0) - { - X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i); - if (ent) - { - ASN1_STRING *val = X509_NAME_ENTRY_get_data (ent); - unsigned char *buf; - buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ - if (ASN1_STRING_to_UTF8 (&buf, val) > 0) - { - do_setenv_x509(es, xt->name, (char *)buf, depth); - OPENSSL_free (buf); - } - } - } - else - { - i = X509_get_ext_by_NID(x509, xt->nid, -1); - if (i >= 0) - { - X509_EXTENSION *ext = X509_get_ext(x509, i); - if (ext) - { - BIO *bio = BIO_new(BIO_s_mem()); - if (bio) - { - if (X509V3_EXT_print(bio, ext, 0, 0)) - { - if (BIO_write(bio, &nullc, 1) == 1) - { - char *str; - BIO_get_mem_data(bio, &str); - do_setenv_x509(es, xt->name, str, depth); - } - } - BIO_free(bio); - } - } - } - } - } - } - } - xt = xt->next; - } - gc_free(&gc); + struct gc_arena gc = gc_new(); + X509_NAME *x509_name = X509_get_subject_name(x509); + const char nullc = '\0'; + + while (xt) + { + if (depth == 0 || (xt->flags & XT_FULL_CHAIN)) + { + switch (xt->nid) + { + case NID_sha1: + case NID_sha256: + { + struct buffer fp_buf; + char *fp_str = NULL; + + if (xt->nid == NID_sha1) + { + fp_buf = x509_get_sha1_fingerprint(x509, &gc); + } + else + { + fp_buf = x509_get_sha256_fingerprint(x509, &gc); + } + + fp_str = format_hex_ex(BPTR(&fp_buf), BLEN(&fp_buf), 0, + 1 | FHE_CAPS, ":", &gc); + do_setenv_x509(es, xt->name, fp_str, depth); + } + break; + + default: + { + int i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1); + if (i >= 0) + { + X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i); + if (ent) + { + ASN1_STRING *val = X509_NAME_ENTRY_get_data(ent); + unsigned char *buf; + buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ + if (ASN1_STRING_to_UTF8(&buf, val) > 0) + { + do_setenv_x509(es, xt->name, (char *)buf, depth); + OPENSSL_free(buf); + } + } + } + else + { + i = X509_get_ext_by_NID(x509, xt->nid, -1); + if (i >= 0) + { + X509_EXTENSION *ext = X509_get_ext(x509, i); + if (ext) + { + BIO *bio = BIO_new(BIO_s_mem()); + if (bio) + { + if (X509V3_EXT_print(bio, ext, 0, 0)) + { + if (BIO_write(bio, &nullc, 1) == 1) + { + char *str; + BIO_get_mem_data(bio, &str); + do_setenv_x509(es, xt->name, str, depth); + } + } + BIO_free(bio); + } + } + } + } + } + } + } + xt = xt->next; + } + gc_free(&gc); } /* @@ -471,195 +503,227 @@ x509_setenv_track (const struct x509_track *xt, struct env_set *es, const int de * X509_{cert_depth}_{name}={value} */ void -x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *peer_cert) +x509_setenv(struct env_set *es, int cert_depth, openvpn_x509_cert_t *peer_cert) { - int i, n; - int fn_nid; - ASN1_OBJECT *fn; - ASN1_STRING *val; - X509_NAME_ENTRY *ent; - const char *objbuf; - unsigned char *buf; - char *name_expand; - size_t name_expand_size; - X509_NAME *x509 = X509_get_subject_name (peer_cert); - - n = X509_NAME_entry_count (x509); - for (i = 0; i < n; ++i) - { - ent = X509_NAME_get_entry (x509, i); - if (!ent) - continue; - fn = X509_NAME_ENTRY_get_object (ent); - if (!fn) - continue; - val = X509_NAME_ENTRY_get_data (ent); - if (!val) - continue; - fn_nid = OBJ_obj2nid (fn); - if (fn_nid == NID_undef) - continue; - objbuf = OBJ_nid2sn (fn_nid); - if (!objbuf) - continue; - buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ - if (ASN1_STRING_to_UTF8 (&buf, val) <= 0) - continue; - name_expand_size = 64 + strlen (objbuf); - name_expand = (char *) malloc (name_expand_size); - check_malloc_return (name_expand); - openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", cert_depth, - objbuf); - string_mod (name_expand, CC_PRINT, CC_CRLF, '_'); - string_mod ((char*)buf, CC_PRINT, CC_CRLF, '_'); - setenv_str_incr (es, name_expand, (char*)buf); - free (name_expand); - OPENSSL_free (buf); + int i, n; + int fn_nid; + ASN1_OBJECT *fn; + ASN1_STRING *val; + X509_NAME_ENTRY *ent; + const char *objbuf; + unsigned char *buf; + char *name_expand; + size_t name_expand_size; + X509_NAME *x509 = X509_get_subject_name(peer_cert); + + n = X509_NAME_entry_count(x509); + for (i = 0; i < n; ++i) + { + ent = X509_NAME_get_entry(x509, i); + if (!ent) + { + continue; + } + fn = X509_NAME_ENTRY_get_object(ent); + if (!fn) + { + continue; + } + val = X509_NAME_ENTRY_get_data(ent); + if (!val) + { + continue; + } + fn_nid = OBJ_obj2nid(fn); + if (fn_nid == NID_undef) + { + continue; + } + objbuf = OBJ_nid2sn(fn_nid); + if (!objbuf) + { + continue; + } + buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ + if (ASN1_STRING_to_UTF8(&buf, val) <= 0) + { + continue; + } + name_expand_size = 64 + strlen(objbuf); + name_expand = (char *) malloc(name_expand_size); + check_malloc_return(name_expand); + openvpn_snprintf(name_expand, name_expand_size, "X509_%d_%s", cert_depth, + objbuf); + string_mod(name_expand, CC_PRINT, CC_CRLF, '_'); + string_mod((char *)buf, CC_PRINT, CC_CRLF, '_'); + setenv_str_incr(es, name_expand, (char *)buf); + free(name_expand); + OPENSSL_free(buf); } } result_t x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage) { - if (usage == NS_CERT_CHECK_NONE) - return SUCCESS; - if (usage == NS_CERT_CHECK_CLIENT) - return ((peer_cert->ex_flags & EXFLAG_NSCERT) - && (peer_cert->ex_nscert & NS_SSL_CLIENT)) ? SUCCESS: FAILURE; - if (usage == NS_CERT_CHECK_SERVER) - return ((peer_cert->ex_flags & EXFLAG_NSCERT) - && (peer_cert->ex_nscert & NS_SSL_SERVER)) ? SUCCESS: FAILURE; - - return FAILURE; + if (usage == NS_CERT_CHECK_NONE) + { + return SUCCESS; + } + if (usage == NS_CERT_CHECK_CLIENT) + { + return ((peer_cert->ex_flags & EXFLAG_NSCERT) + && (peer_cert->ex_nscert & NS_SSL_CLIENT)) ? SUCCESS : FAILURE; + } + if (usage == NS_CERT_CHECK_SERVER) + { + return ((peer_cert->ex_flags & EXFLAG_NSCERT) + && (peer_cert->ex_nscert & NS_SSL_SERVER)) ? SUCCESS : FAILURE; + } + + return FAILURE; } result_t -x509_verify_cert_ku (X509 *x509, const unsigned * const expected_ku, - int expected_len) +x509_verify_cert_ku(X509 *x509, const unsigned *const expected_ku, + int expected_len) { - ASN1_BIT_STRING *ku = NULL; - result_t fFound = FAILURE; - - if ((ku = (ASN1_BIT_STRING *) X509_get_ext_d2i (x509, NID_key_usage, NULL, - NULL)) == NULL) - { - msg (D_HANDSHAKE, "Certificate does not have key usage extension"); - } - else - { - unsigned nku = 0; - int i; - for (i = 0; i < 8; i++) - { - if (ASN1_BIT_STRING_get_bit (ku, i)) - nku |= 1 << (7 - i); - } - - /* - * Fixup if no LSB bits - */ - if ((nku & 0xff) == 0) - { - nku >>= 8; - } - - msg (D_HANDSHAKE, "Validating certificate key usage"); - for (i = 0; fFound != SUCCESS && i < expected_len; i++) - { - if (expected_ku[i] != 0) - { - msg (D_HANDSHAKE, "++ Certificate has key usage %04x, expects " - "%04x", nku, expected_ku[i]); - - if (nku == expected_ku[i]) - fFound = SUCCESS; - } - } - } - - if (ku != NULL) - ASN1_BIT_STRING_free (ku); - - return fFound; + ASN1_BIT_STRING *ku = NULL; + result_t fFound = FAILURE; + + if ((ku = (ASN1_BIT_STRING *) X509_get_ext_d2i(x509, NID_key_usage, NULL, + NULL)) == NULL) + { + msg(D_HANDSHAKE, "Certificate does not have key usage extension"); + } + else + { + unsigned nku = 0; + int i; + for (i = 0; i < 8; i++) + { + if (ASN1_BIT_STRING_get_bit(ku, i)) + { + nku |= 1 << (7 - i); + } + } + + /* + * Fixup if no LSB bits + */ + if ((nku & 0xff) == 0) + { + nku >>= 8; + } + + msg(D_HANDSHAKE, "Validating certificate key usage"); + for (i = 0; fFound != SUCCESS && i < expected_len; i++) + { + if (expected_ku[i] != 0) + { + msg(D_HANDSHAKE, "++ Certificate has key usage %04x, expects " + "%04x", nku, expected_ku[i]); + + if (nku == expected_ku[i]) + { + fFound = SUCCESS; + } + } + } + } + + if (ku != NULL) + { + ASN1_BIT_STRING_free(ku); + } + + return fFound; } result_t -x509_verify_cert_eku (X509 *x509, const char * const expected_oid) +x509_verify_cert_eku(X509 *x509, const char *const expected_oid) { - EXTENDED_KEY_USAGE *eku = NULL; - result_t fFound = FAILURE; + EXTENDED_KEY_USAGE *eku = NULL; + result_t fFound = FAILURE; - if ((eku = (EXTENDED_KEY_USAGE *) X509_get_ext_d2i (x509, NID_ext_key_usage, - NULL, NULL)) == NULL) + if ((eku = (EXTENDED_KEY_USAGE *) X509_get_ext_d2i(x509, NID_ext_key_usage, + NULL, NULL)) == NULL) { - msg (D_HANDSHAKE, "Certificate does not have extended key usage extension"); + msg(D_HANDSHAKE, "Certificate does not have extended key usage extension"); } - else + else { - int i; + int i; - msg (D_HANDSHAKE, "Validating certificate extended key usage"); - for (i = 0; SUCCESS != fFound && i < sk_ASN1_OBJECT_num (eku); i++) - { - ASN1_OBJECT *oid = sk_ASN1_OBJECT_value (eku, i); - char szOid[1024]; + msg(D_HANDSHAKE, "Validating certificate extended key usage"); + for (i = 0; SUCCESS != fFound && i < sk_ASN1_OBJECT_num(eku); i++) + { + ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(eku, i); + char szOid[1024]; - if (SUCCESS != fFound && OBJ_obj2txt (szOid, sizeof(szOid), oid, 0) != -1) - { - msg (D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s", - szOid, expected_oid); - if (!strcmp (expected_oid, szOid)) - fFound = SUCCESS; - } - if (SUCCESS != fFound && OBJ_obj2txt (szOid, sizeof(szOid), oid, 1) != -1) - { - msg (D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s", - szOid, expected_oid); - if (!strcmp (expected_oid, szOid)) - fFound = SUCCESS; - } - } + if (SUCCESS != fFound && OBJ_obj2txt(szOid, sizeof(szOid), oid, 0) != -1) + { + msg(D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s", + szOid, expected_oid); + if (!strcmp(expected_oid, szOid)) + { + fFound = SUCCESS; + } + } + if (SUCCESS != fFound && OBJ_obj2txt(szOid, sizeof(szOid), oid, 1) != -1) + { + msg(D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s", + szOid, expected_oid); + if (!strcmp(expected_oid, szOid)) + { + fFound = SUCCESS; + } + } + } } - if (eku != NULL) - sk_ASN1_OBJECT_pop_free (eku, ASN1_OBJECT_free); + if (eku != NULL) + { + sk_ASN1_OBJECT_pop_free(eku, ASN1_OBJECT_free); + } - return fFound; + return fFound; } result_t x509_write_pem(FILE *peercert_file, X509 *peercert) { - if (PEM_write_X509(peercert_file, peercert) < 0) + if (PEM_write_X509(peercert_file, peercert) < 0) { - msg (M_ERR, "Failed to write peer certificate in PEM format"); - return FAILURE; + msg(M_ERR, "Failed to write peer certificate in PEM format"); + return FAILURE; } - return SUCCESS; + return SUCCESS; } bool tls_verify_crl_missing(const struct tls_options *opt) { - if (!opt->crl_file || (opt->ssl_flags & SSLF_CRL_VERIFY_DIR)) + if (!opt->crl_file || (opt->ssl_flags & SSLF_CRL_VERIFY_DIR)) { - return false; + return false; } - X509_STORE *store = SSL_CTX_get_cert_store(opt->ssl_ctx.ctx); - if (!store) - crypto_msg (M_FATAL, "Cannot get certificate store"); + X509_STORE *store = SSL_CTX_get_cert_store(opt->ssl_ctx.ctx); + if (!store) + { + crypto_msg(M_FATAL, "Cannot get certificate store"); + } - for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++) + for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++) { - X509_OBJECT* obj = sk_X509_OBJECT_value(store->objs, i); - ASSERT(obj); - if (obj->type == X509_LU_CRL) - { - return false; - } + X509_OBJECT *obj = sk_X509_OBJECT_value(store->objs, i); + ASSERT(obj); + if (obj->type == X509_LU_CRL) + { + return false; + } } - return true; + return true; } #endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL) */ |