From 6ec5acc2802acdfa9a0fe653811cf505d1f1f7af Mon Sep 17 00:00:00 2001 From: Rolf Fokkens Date: Fri, 16 Aug 2019 09:26:49 +0200 Subject: [PATCH 1/3] Export ASN1_TIME items to the environment. Useful in anticipating potential certificate expiry. --- src/openvpn/ssl_verify.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index a7f51751d22..37b3b599436 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -431,6 +431,25 @@ verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert, return SUCCESS; } +/* + * Export ASN1_TIME items to the environment + */ +static void +setenv_ASN1_TIME(struct env_set *es, char *envname, int envnamesize, + char *envprefix, int depth, const ASN1_TIME *asn1_time) +{ + char timestamp[32]; + BIO *mem; + + mem = BIO_new(BIO_s_mem()); + if (ASN1_TIME_print (mem, asn1_time)) { + timestamp[BIO_read(mem, timestamp, sizeof(timestamp)-1)] = '\0'; + openvpn_snprintf(envname, envnamesize, "%s_%d", envprefix, depth); + setenv_str(es, envname, timestamp); + } + BIO_free(mem); +} + /* * Export the subject, common_name, and raw certificate fields to the * environment for later verification by scripts and plugins. @@ -489,6 +508,12 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert openvpn_snprintf(envname, sizeof(envname), "tls_serial_hex_%d", cert_depth); setenv_str(es, envname, serial); + setenv_ASN1_TIME(es, envname, sizeof(envname), "tls_notbefore", cert_depth, + X509_get_notBefore(peer_cert)); + + setenv_ASN1_TIME(es, envname, sizeof(envname), "tls_notafter", cert_depth, + X509_get_notAfter(peer_cert)); + gc_free(&gc); } From 52f2ca05fb930583d62ceb0c5235ddb253f3678c Mon Sep 17 00:00:00 2001 From: Rolf Fokkens Date: Sat, 17 Aug 2019 13:55:49 +0200 Subject: [PATCH 2/3] Process notAfter and notBefore during verify_cert based on feedback --- src/openvpn/ssl_verify.c | 38 ++++++++++++++------------------ src/openvpn/ssl_verify_backend.h | 21 ++++++++++++++++++ src/openvpn/ssl_verify_mbedtls.c | 10 +++++++++ src/openvpn/ssl_verify_openssl.c | 31 ++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 21 deletions(-) diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index 37b3b599436..4fe4f9385bc 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -431,23 +431,15 @@ verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert, return SUCCESS; } -/* - * Export ASN1_TIME items to the environment - */ static void -setenv_ASN1_TIME(struct env_set *es, char *envname, int envnamesize, - char *envprefix, int depth, const ASN1_TIME *asn1_time) +setenv_validity (struct env_set *es, char *envprefix, int depth, char *dt) { - char timestamp[32]; - BIO *mem; + char varname[32]; - mem = BIO_new(BIO_s_mem()); - if (ASN1_TIME_print (mem, asn1_time)) { - timestamp[BIO_read(mem, timestamp, sizeof(timestamp)-1)] = '\0'; - openvpn_snprintf(envname, envnamesize, "%s_%d", envprefix, depth); - setenv_str(es, envname, timestamp); - } - BIO_free(mem); + if (!dt[0]) return; + + openvpn_snprintf(varname, sizeof(varname), "%s_%d", envprefix, depth); + setenv_str(es, varname, dt); } /* @@ -508,12 +500,6 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert openvpn_snprintf(envname, sizeof(envname), "tls_serial_hex_%d", cert_depth); setenv_str(es, envname, serial); - setenv_ASN1_TIME(es, envname, sizeof(envname), "tls_notbefore", cert_depth, - X509_get_notBefore(peer_cert)); - - setenv_ASN1_TIME(es, envname, sizeof(envname), "tls_notafter", cert_depth, - X509_get_notAfter(peer_cert)); - gc_free(&gc); } @@ -685,6 +671,8 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep char common_name[TLS_USERNAME_LEN+1] = {0}; /* null-terminated */ const struct tls_options *opt; struct gc_arena gc = gc_new(); + char notbefore_buf[32], notafter_buf[32]; + int notbefore_cmp, notafter_cmp; opt = session->opt; ASSERT(opt); @@ -779,6 +767,13 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep /* export current untrusted IP */ setenv_untrusted(session); + x509_get_validity(cert, sizeof (notbefore_buf), notbefore_buf, ¬before_cmp, notafter_buf, ¬after_cmp); + setenv_validity (opt->es, "tls_notbefore", cert_depth, notbefore_buf); + setenv_validity (opt->es, "tls_notafter", cert_depth, notafter_buf); + + if (notbefore_cmp < 0) msg(M_WARN, "Certificate notBefore (%s)", notbefore_buf); + if (notafter_cmp > 0) msg(M_WARN, "Certificate notAfter (%s)", notafter_buf); + /* If this is the peer's own certificate, verify it */ if (cert_depth == 0 && SUCCESS != verify_peer_cert(opt, cert, subject, common_name)) { @@ -818,7 +813,8 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep } } - msg(D_HANDSHAKE, "VERIFY OK: depth=%d, %s", cert_depth, subject); + msg(D_HANDSHAKE, "VERIFY OK: depth=%d, %s, notAfter=%s", cert_depth, subject, + (notafter_buf[0] ? notafter_buf : "-")); session->verified = true; ret = SUCCESS; diff --git a/src/openvpn/ssl_verify_backend.h b/src/openvpn/ssl_verify_backend.h index d6b31bfa666..e0fe17434d6 100644 --- a/src/openvpn/ssl_verify_backend.h +++ b/src/openvpn/ssl_verify_backend.h @@ -268,4 +268,25 @@ result_t x509_write_pem(FILE *peercert_file, openvpn_x509_cert_t *peercert); */ bool tls_verify_crl_missing(const struct tls_options *opt); +/* + * Get certificate notBefore and notAfter attributes + * + * @param cert Certificate to retrieve attributes from + * @param notsize Size of char buffers for notbefore and notafter + * @param notbefore Charachter representation of notBefore attribute + * @param cmpbefore Compare notBefore with "now"; > 0 if notBefore in the past + * @param notafter Character representation of notAfter attribute + * @param cmpafter Compare notAfter with "now"; > 0 if notAfter in the past + * + * On failing to retrieve notBefore attributes: + * - notbefore[0] = '\0' + * - cmpbefore = 0 + * + * On failing to retrieve notAfter attributes: + * - notafter[0] = '\0' + * - cmpafter = 0 + */ + +void x509_get_validity(openvpn_x509_cert_t *cert, int notsize, char *notbefore, int *cmpbefore, char *notafter, int *cmpafter); + #endif /* SSL_VERIFY_BACKEND_H_ */ diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index fd31bbbdaea..72cb6906e0e 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -550,4 +550,14 @@ tls_verify_crl_missing(const struct tls_options *opt) return false; } +void +x509_get_validity(mbedtls_x509_crt *cert, int notsize, char *notbefore, int *cmpbefore, char *notafter, int *cmpafter) +{ + notbefore[0] = '\0'; + notafter[0] = '\0'; + + *cmpbefore = 0; + *cmpafter = 0; +} + #endif /* #if defined(ENABLE_CRYPTO_MBEDTLS) */ diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index ff14db23886..0e4ce82892b 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -790,4 +790,35 @@ tls_verify_crl_missing(const struct tls_options *opt) return true; } +static int +get_ASN1_TIME(const ASN1_TIME *asn1_time, char *dt, int dtsize, int *cmpnow) +{ + BIO *mem; + int ret, pday, psec; + + mem = BIO_new(BIO_s_mem()); + if ((ret = ASN1_TIME_print (mem, asn1_time))) { + dt[BIO_read(mem, dt, dtsize-1)] = '\0'; + } + BIO_free(mem); + if (!ret) goto fail; + + if (!ASN1_TIME_diff(&pday, &psec, asn1_time, NULL)) goto fail; + *cmpnow = (pday ? pday : psec); + + return 1; + +fail: + dt[0] = '\0'; + *cmpnow = 0; + return 0; +} + +void +x509_get_validity(X509 *cert, int notsize, char *notbefore, int *cmpbefore, char *notafter, int *cmpafter) +{ + get_ASN1_TIME(X509_get_notBefore(cert), notbefore, notsize, cmpbefore); + get_ASN1_TIME(X509_get_notAfter(cert), notafter, notsize, cmpafter); +} + #endif /* defined(ENABLE_CRYPTO_OPENSSL) */ From 0b643cf5f783e0c1993f09246db1b4fc1e87a920 Mon Sep 17 00:00:00 2001 From: Rolf Fokkens Date: Sat, 17 Aug 2019 17:49:44 +0200 Subject: [PATCH 3/3] Not all openssl versions are equal. Take care of it. Prefix the backend functions with backend_. --- src/openvpn/ssl_verify.c | 2 +- src/openvpn/ssl_verify_backend.h | 10 ++++++++-- src/openvpn/ssl_verify_mbedtls.c | 2 +- src/openvpn/ssl_verify_openssl.c | 6 +++++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index 4fe4f9385bc..fd2bb2e53ba 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -767,7 +767,7 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep /* export current untrusted IP */ setenv_untrusted(session); - x509_get_validity(cert, sizeof (notbefore_buf), notbefore_buf, ¬before_cmp, notafter_buf, ¬after_cmp); + backend_x509_get_validity(cert, sizeof (notbefore_buf), notbefore_buf, ¬before_cmp, notafter_buf, ¬after_cmp); setenv_validity (opt->es, "tls_notbefore", cert_depth, notbefore_buf); setenv_validity (opt->es, "tls_notafter", cert_depth, notafter_buf); diff --git a/src/openvpn/ssl_verify_backend.h b/src/openvpn/ssl_verify_backend.h index e0fe17434d6..51c5d56aa3f 100644 --- a/src/openvpn/ssl_verify_backend.h +++ b/src/openvpn/ssl_verify_backend.h @@ -278,15 +278,21 @@ bool tls_verify_crl_missing(const struct tls_options *opt); * @param notafter Character representation of notAfter attribute * @param cmpafter Compare notAfter with "now"; > 0 if notAfter in the past * + * Not all backend (versions) support the same features (yet), so: + * * On failing to retrieve notBefore attributes: * - notbefore[0] = '\0' - * - cmpbefore = 0 * * On failing to retrieve notAfter attributes: * - notafter[0] = '\0' + * + * On failing to compare notBefore attributes with "now": + * - cmpbefore = 0 + * + * On failing to compare notAfter attributes with "now": * - cmpafter = 0 */ -void x509_get_validity(openvpn_x509_cert_t *cert, int notsize, char *notbefore, int *cmpbefore, char *notafter, int *cmpafter); +void backend_x509_get_validity(openvpn_x509_cert_t *cert, int notsize, char *notbefore, int *cmpbefore, char *notafter, int *cmpafter); #endif /* SSL_VERIFY_BACKEND_H_ */ diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index 72cb6906e0e..342828da195 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -551,7 +551,7 @@ tls_verify_crl_missing(const struct tls_options *opt) } void -x509_get_validity(mbedtls_x509_crt *cert, int notsize, char *notbefore, int *cmpbefore, char *notafter, int *cmpafter) +backend_x509_get_validity(mbedtls_x509_crt *cert, int notsize, char *notbefore, int *cmpbefore, char *notafter, int *cmpafter) { notbefore[0] = '\0'; notafter[0] = '\0'; diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 0e4ce82892b..7624eacc7e3 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -803,8 +803,12 @@ get_ASN1_TIME(const ASN1_TIME *asn1_time, char *dt, int dtsize, int *cmpnow) BIO_free(mem); if (!ret) goto fail; +#if OPENSSL_VERSION_NUMBER >= 0x10002000L if (!ASN1_TIME_diff(&pday, &psec, asn1_time, NULL)) goto fail; *cmpnow = (pday ? pday : psec); +#else + *cmpnow = 0; +#endif /* OPENSSL_VERSION_NUMBER >= 1.0.2 */ return 1; @@ -815,7 +819,7 @@ get_ASN1_TIME(const ASN1_TIME *asn1_time, char *dt, int dtsize, int *cmpnow) } void -x509_get_validity(X509 *cert, int notsize, char *notbefore, int *cmpbefore, char *notafter, int *cmpafter) +backend_x509_get_validity(X509 *cert, int notsize, char *notbefore, int *cmpbefore, char *notafter, int *cmpafter) { get_ASN1_TIME(X509_get_notBefore(cert), notbefore, notsize, cmpbefore); get_ASN1_TIME(X509_get_notAfter(cert), notafter, notsize, cmpafter);