diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index a7f51751d22..fd2bb2e53ba 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -431,6 +431,17 @@ verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert, return SUCCESS; } +static void +setenv_validity (struct env_set *es, char *envprefix, int depth, char *dt) +{ + char varname[32]; + + if (!dt[0]) return; + + openvpn_snprintf(varname, sizeof(varname), "%s_%d", envprefix, depth); + setenv_str(es, varname, dt); +} + /* * Export the subject, common_name, and raw certificate fields to the * environment for later verification by scripts and plugins. @@ -660,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); @@ -754,6 +767,13 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep /* export current untrusted IP */ setenv_untrusted(session); + 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); + + 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)) { @@ -793,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..51c5d56aa3f 100644 --- a/src/openvpn/ssl_verify_backend.h +++ b/src/openvpn/ssl_verify_backend.h @@ -268,4 +268,31 @@ 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 + * + * Not all backend (versions) support the same features (yet), so: + * + * On failing to retrieve notBefore attributes: + * - notbefore[0] = '\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 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 fd31bbbdaea..342828da195 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 +backend_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..7624eacc7e3 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -790,4 +790,39 @@ 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 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; + +fail: + dt[0] = '\0'; + *cmpnow = 0; + return 0; +} + +void +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); +} + #endif /* defined(ENABLE_CRYPTO_OPENSSL) */