summaryrefslogtreecommitdiff
path: root/src/openvpn/ssl_verify_openssl.c
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2017-06-27 13:56:16 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2017-06-27 13:56:16 +0200
commit749384a154025e268b53cf3cc79eaeddde2b3ceb (patch)
tree27baa9e6aec76635d750405d90cd461440a656d1 /src/openvpn/ssl_verify_openssl.c
parentdb4f04c584f7d4e828b5d317cf40962b9d854ac5 (diff)
initial stretch branch release 2.4.0-6
Diffstat (limited to 'src/openvpn/ssl_verify_openssl.c')
-rw-r--r--src/openvpn/ssl_verify_openssl.c231
1 files changed, 77 insertions, 154 deletions
diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c
index 468b495..e9692a0 100644
--- a/src/openvpn/ssl_verify_openssl.c
+++ b/src/openvpn/ssl_verify_openssl.c
@@ -17,9 +17,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
@@ -42,7 +43,6 @@
#include "ssl_openssl.h"
#include "ssl_verify.h"
#include "ssl_verify_backend.h"
-#include "openssl_compat.h"
#include <openssl/x509v3.h>
#include <openssl/err.h>
@@ -61,15 +61,14 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
session = (struct tls_session *) SSL_get_ex_data(ssl, mydata_index);
ASSERT(session);
- X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx);
- struct buffer cert_hash = x509_get_sha256_fingerprint(current_cert, &gc);
- cert_hash_remember(session, X509_STORE_CTX_get_error_depth(ctx), &cert_hash);
+ 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(current_cert, &gc);
+ char *subject = x509_get_subject(ctx->current_cert, &gc);
if (!subject)
{
@@ -77,11 +76,11 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
}
/* Log and ignore missing CRL errors */
- if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_UNABLE_TO_GET_CRL)
+ if (ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL)
{
msg(D_TLS_DEBUG_LOW, "VERIFY WARNING: depth=%d, %s: %s",
- X509_STORE_CTX_get_error_depth(ctx),
- X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)),
+ ctx->error_depth,
+ X509_verify_cert_error_string(ctx->error),
subject);
ret = 1;
goto cleanup;
@@ -89,8 +88,8 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
/* Remote site specified a certificate, but it's not correct */
msg(D_TLS_ERRORS, "VERIFY ERROR: depth=%d, error=%s: %s",
- X509_STORE_CTX_get_error_depth(ctx),
- X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)),
+ ctx->error_depth,
+ X509_verify_cert_error_string(ctx->error),
subject);
ERR_clear_error();
@@ -99,7 +98,7 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
goto cleanup;
}
- if (SUCCESS != verify_cert(session, current_cert, X509_STORE_CTX_get_error_depth(ctx)))
+ if (SUCCESS != verify_cert(session, ctx->current_cert, ctx->error_depth))
{
goto cleanup;
}
@@ -113,29 +112,16 @@ cleanup:
}
#ifdef ENABLE_X509ALTUSERNAME
-bool x509_username_field_ext_supported(const char *fieldname)
-{
- int nid = OBJ_txt2nid(fieldname);
- return nid == NID_subject_alt_name || nid == NID_issuer_alt_name;
-}
-
static
bool
extract_x509_extension(X509 *cert, char *fieldname, char *out, int size)
{
bool retval = false;
char *buf = 0;
-
- if (!x509_username_field_ext_supported(fieldname))
- {
- msg(D_TLS_ERRORS,
- "ERROR: --x509-alt-username field 'ext:%s' not supported",
- fieldname);
- return false;
- }
-
+ GENERAL_NAMES *extensions;
int nid = OBJ_txt2nid(fieldname);
- GENERAL_NAMES *extensions = X509_get_ext_d2i(cert, nid, NULL, NULL);
+
+ extensions = (GENERAL_NAMES *)X509_get_ext_d2i(cert, nid, NULL, NULL);
if (extensions)
{
int numalts;
@@ -156,10 +142,7 @@ extract_x509_extension(X509 *cert, char *fieldname, char *out, int size)
switch (name->type)
{
case GEN_EMAIL:
- if (ASN1_STRING_to_UTF8((unsigned char **)&buf, name->d.ia5) < 0)
- {
- continue;
- }
+ 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");
@@ -179,7 +162,7 @@ extract_x509_extension(X509 *cert, char *fieldname, char *out, int size)
break;
}
}
- GENERAL_NAMES_free(extensions);
+ sk_GENERAL_NAME_free(extensions);
}
return retval;
}
@@ -206,24 +189,15 @@ extract_x509_field_ssl(X509_NAME *x509, const char *field_name, char *out,
X509_NAME_ENTRY *x509ne = 0;
ASN1_STRING *asn1 = 0;
unsigned char *buf = NULL;
- ASN1_OBJECT *field_name_obj = OBJ_txt2obj(field_name, 0);
-
- if (field_name_obj == NULL)
- {
- msg(D_TLS_ERRORS, "Invalid X509 attribute name '%s'", field_name);
- return FAILURE;
- }
+ int nid = OBJ_txt2nid(field_name);
ASSERT(size > 0);
*out = '\0';
- do
- {
+ do {
lastpos = tmp;
- tmp = X509_NAME_get_index_by_OBJ(x509, field_name_obj, lastpos);
+ tmp = X509_NAME_get_index_by_NID(x509, nid, lastpos);
} while (tmp > -1);
- ASN1_OBJECT_free(field_name_obj);
-
/* Nothing found */
if (lastpos == -1)
{
@@ -241,7 +215,8 @@ extract_x509_field_ssl(X509_NAME *x509, const char *field_name, char *out,
{
return FAILURE;
}
- if (ASN1_STRING_to_UTF8(&buf, asn1) < 0)
+ tmp = ASN1_STRING_to_UTF8(&buf, asn1);
+ if (tmp <= 0)
{
return FAILURE;
}
@@ -308,20 +283,18 @@ backend_x509_get_serial_hex(openvpn_x509_cert_t *cert, struct gc_arena *gc)
struct buffer
x509_get_sha1_fingerprint(X509 *cert, struct gc_arena *gc)
{
- const EVP_MD *sha1 = EVP_sha1();
- struct buffer hash = alloc_buf_gc(EVP_MD_size(sha1), gc);
- X509_digest(cert, EVP_sha1(), BPTR(&hash), NULL);
- ASSERT(buf_inc_len(&hash, EVP_MD_size(sha1)));
+ 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)
{
- const EVP_MD *sha256 = EVP_sha256();
- struct buffer hash = alloc_buf_gc(EVP_MD_size(sha256), 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_MD_size(sha256)));
+ ASSERT(buf_inc_len(&hash, (EVP_sha256())->md_size));
return hash;
}
@@ -331,6 +304,7 @@ 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,
@@ -361,10 +335,11 @@ x509_get_subject(X509 *cert, struct gc_arena *gc)
BIO_get_mem_ptr(subject_bio, &subject_mem);
- subject = gc_malloc(subject_mem->length + 1, false, gc);
+ maxlen = subject_mem->length + 1;
+ subject = gc_malloc(maxlen, false, gc);
- memcpy(subject, subject_mem->data, subject_mem->length);
- subject[subject_mem->length] = '\0';
+ memcpy(subject, subject_mem->data, maxlen);
+ subject[maxlen - 1] = '\0';
err:
if (subject_bio)
@@ -482,7 +457,7 @@ x509_setenv_track(const struct x509_track *xt, struct env_set *es, const int dep
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)
+ if (ASN1_STRING_to_UTF8(&buf, val) > 0)
{
do_setenv_x509(es, xt->name, (char *)buf, depth);
OPENSSL_free(buf);
@@ -570,7 +545,7 @@ x509_setenv(struct env_set *es, int cert_depth, openvpn_x509_cert_t *peer_cert)
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)
+ if (ASN1_STRING_to_UTF8(&buf, val) <= 0)
{
continue;
}
@@ -588,7 +563,7 @@ x509_setenv(struct env_set *es, int cert_depth, openvpn_x509_cert_t *peer_cert)
}
result_t
-x509_verify_ns_cert_type(openvpn_x509_cert_t *peer_cert, const int usage)
+x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage)
{
if (usage == NS_CERT_CHECK_NONE)
{
@@ -596,59 +571,13 @@ x509_verify_ns_cert_type(openvpn_x509_cert_t *peer_cert, const int usage)
}
if (usage == NS_CERT_CHECK_CLIENT)
{
- /*
- * Unfortunately, X509_check_purpose() does some weird thing that
- * prevent it to take a const argument
- */
- result_t result = X509_check_purpose(peer_cert, X509_PURPOSE_SSL_CLIENT, 0) ?
- SUCCESS : FAILURE;
-
- /*
- * old versions of OpenSSL allow us to make the less strict check we used to
- * do. If this less strict check pass, warn user that this might not be the
- * case when its distribution will update to OpenSSL 1.1
- */
- if (result == FAILURE)
- {
- ASN1_BIT_STRING *ns;
- ns = X509_get_ext_d2i(peer_cert, NID_netscape_cert_type, NULL, NULL);
- result = (ns && ns->length > 0 && (ns->data[0] & NS_SSL_CLIENT)) ? SUCCESS : FAILURE;
- if (result == SUCCESS)
- {
- msg(M_WARN, "X509: Certificate is a client certificate yet it's purpose "
- "cannot be verified (check may fail in the future)");
- }
- ASN1_BIT_STRING_free(ns);
- }
- return result;
+ return ((peer_cert->ex_flags & EXFLAG_NSCERT)
+ && (peer_cert->ex_nscert & NS_SSL_CLIENT)) ? SUCCESS : FAILURE;
}
if (usage == NS_CERT_CHECK_SERVER)
{
- /*
- * Unfortunately, X509_check_purpose() does some weird thing that
- * prevent it to take a const argument
- */
- result_t result = X509_check_purpose(peer_cert, X509_PURPOSE_SSL_SERVER, 0) ?
- SUCCESS : FAILURE;
-
- /*
- * old versions of OpenSSL allow us to make the less strict check we used to
- * do. If this less strict check pass, warn user that this might not be the
- * case when its distribution will update to OpenSSL 1.1
- */
- if (result == FAILURE)
- {
- ASN1_BIT_STRING *ns;
- ns = X509_get_ext_d2i(peer_cert, NID_netscape_cert_type, NULL, NULL);
- result = (ns && ns->length > 0 && (ns->data[0] & NS_SSL_SERVER)) ? SUCCESS : FAILURE;
- if (result == SUCCESS)
- {
- msg(M_WARN, "X509: Certificate is a server certificate yet it's purpose "
- "cannot be verified (check may fail in the future)");
- }
- ASN1_BIT_STRING_free(ns);
- }
- return result;
+ return ((peer_cert->ex_flags & EXFLAG_NSCERT)
+ && (peer_cert->ex_nscert & NS_SSL_SERVER)) ? SUCCESS : FAILURE;
}
return FAILURE;
@@ -658,59 +587,54 @@ result_t
x509_verify_cert_ku(X509 *x509, const unsigned *const expected_ku,
int expected_len)
{
- ASN1_BIT_STRING *ku = X509_get_ext_d2i(x509, NID_key_usage, NULL, NULL);
-
- if (ku == NULL)
- {
- msg(D_TLS_ERRORS, "Certificate does not have key usage extension");
- return FAILURE;
- }
+ ASN1_BIT_STRING *ku = NULL;
+ result_t fFound = FAILURE;
- if (expected_ku[0] == OPENVPN_KU_REQUIRED)
+ if ((ku = (ASN1_BIT_STRING *) X509_get_ext_d2i(x509, NID_key_usage, NULL,
+ NULL)) == NULL)
{
- /* Extension required, value checked by TLS library */
- ASN1_BIT_STRING_free(ku);
- return SUCCESS;
+ msg(D_HANDSHAKE, "Certificate does not have key usage extension");
}
-
- unsigned nku = 0;
- for (size_t i = 0; i < 8; i++)
+ else
{
- if (ASN1_BIT_STRING_get_bit(ku, i))
+ unsigned nku = 0;
+ int i;
+ for (i = 0; i < 8; i++)
{
- nku |= 1 << (7 - 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");
- result_t fFound = FAILURE;
- for (size_t i = 0; fFound != SUCCESS && i < expected_len; i++)
- {
- if (expected_ku[i] != 0 && (nku & expected_ku[i]) == expected_ku[i])
+ /*
+ * Fixup if no LSB bits
+ */
+ if ((nku & 0xff) == 0)
{
- fFound = SUCCESS;
+ nku >>= 8;
}
- }
- if (fFound != SUCCESS)
- {
- msg(D_TLS_ERRORS,
- "ERROR: Certificate has key usage %04x, expected one of:", nku);
- for (size_t i = 0; i < expected_len && expected_ku[i]; i++)
+ msg(D_HANDSHAKE, "Validating certificate key usage");
+ for (i = 0; fFound != SUCCESS && i < expected_len; i++)
{
- msg(D_TLS_ERRORS, " * %04x", expected_ku[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;
+ }
+ }
}
}
- ASN1_BIT_STRING_free(ku);
+ if (ku != NULL)
+ {
+ ASN1_BIT_STRING_free(ku);
+ }
return fFound;
}
@@ -790,12 +714,11 @@ tls_verify_crl_missing(const struct tls_options *opt)
crypto_msg(M_FATAL, "Cannot get certificate store");
}
- STACK_OF(X509_OBJECT) *objs = X509_STORE_get0_objects(store);
- for (int i = 0; i < sk_X509_OBJECT_num(objs); i++)
+ for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++)
{
- X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i);
+ X509_OBJECT *obj = sk_X509_OBJECT_value(store->objs, i);
ASSERT(obj);
- if (X509_OBJECT_get_type(obj) == X509_LU_CRL)
+ if (obj->type == X509_LU_CRL)
{
return false;
}