From bc5eb93e40534f55b240d33dd605ed3e52bae555 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 26 May 2008 14:47:36 +0200 Subject: added certificate validity date check (gtls) --- runtime/nsd_gtls.c | 65 +++++++++++++++++++++++++++++++++++++++++++++--------- runtime/rsyslog.h | 3 +++ 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/runtime/nsd_gtls.c b/runtime/nsd_gtls.c index f3c0d983..5c82d082 100644 --- a/runtime/nsd_gtls.c +++ b/runtime/nsd_gtls.c @@ -113,7 +113,7 @@ gtlsGetCertInfo(nsd_gtls_t *pThis, cstr_t **ppStr) if(cert_list_size > 0) { /* we only print information about the first certificate */ - gnutls_x509_crt_init( &cert); + CHKgnutls(gnutls_x509_crt_init(&cert)); CHKgnutls(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER)); @@ -762,25 +762,35 @@ gtlsChkPeerCertValidity(nsd_gtls_t *pThis) char *pszErrCause; int gnuRet; cstr_t *pStr; + unsigned stateCert; + const gnutls_datum *cert_list; + unsigned cert_list_size = 0; + gnutls_x509_crt cert; + unsigned i; + time_t ttCert; + time_t ttNow; ISOBJ_TYPE_assert(pThis, nsd_gtls); - gnuRet = gnutls_certificate_verify_peers(pThis->sess); - if(gnuRet == GNUTLS_E_NO_CERTIFICATE_FOUND) { + + /* check if we have at least one cert */ + cert_list = gnutls_certificate_get_peers(pThis->sess, &cert_list_size); + if(cert_list_size < 1) { errno = 0; errmsg.LogError(NO_ERRCODE, "peer did not provide a certificate, not permitted to talk to it"); ABORT_FINALIZE(RS_RET_TLS_NO_CERT); - } else if(gnuRet < 1) - CHKgnutls(gnuRet); + } + + CHKgnutls(gnutls_certificate_verify_peers2(pThis->sess, &stateCert)); - if(gnuRet & GNUTLS_CERT_INVALID) { + if(stateCert & GNUTLS_CERT_INVALID) { /* provide error details if we have them */ - if(gnuRet & GNUTLS_CERT_SIGNER_NOT_FOUND) { + if(stateCert & GNUTLS_CERT_SIGNER_NOT_FOUND) { pszErrCause = "signer not found"; - } else if(gnuRet & GNUTLS_CERT_SIGNER_NOT_FOUND) { + } else if(stateCert & GNUTLS_CERT_SIGNER_NOT_FOUND) { pszErrCause = "signer is not a CA"; - } else if(gnuRet & GNUTLS_CERT_SIGNER_NOT_CA) { + } else if(stateCert & GNUTLS_CERT_SIGNER_NOT_CA) { pszErrCause = "insecure algorithm"; - } else if(gnuRet & GNUTLS_CERT_REVOKED) { + } else if(stateCert & GNUTLS_CERT_REVOKED) { pszErrCause = "certificate revoked"; } else { pszErrCause = "no specific reason"; @@ -793,6 +803,41 @@ gtlsChkPeerCertValidity(nsd_gtls_t *pThis) ABORT_FINALIZE(RS_RET_CERT_INVALID); } + /* get current time for certificate validation */ + if(time(&ttNow) == -1) + ABORT_FINALIZE(RS_RET_SYS_ERR); + + /* as it looks, we need to validate the expiration dates ourselves... + * We need to loop through all certificates as we need to make sure the + * interim certificates are also not expired. + */ + for(i = 0 ; i < cert_list_size ; ++i) { + CHKgnutls(gnutls_x509_crt_init(&cert)); + CHKgnutls(gnutls_x509_crt_import(cert, &cert_list[i], GNUTLS_X509_FMT_DER)); + ttCert = gnutls_x509_crt_get_activation_time(cert); + if(ttCert == -1) + ABORT_FINALIZE(RS_RET_TLS_CERT_ERR); + else if(ttCert > ttNow) { + errmsg.LogError(NO_ERRCODE, "not permitted to talk to peer: certificate %d not yet active", i); + gtlsGetCertInfo(pThis, &pStr); + errmsg.LogError(NO_ERRCODE, "info on invalid cert: %s", rsCStrGetSzStr(pStr)); + rsCStrDestruct(&pStr); + ABORT_FINALIZE(RS_RET_CERT_NOT_YET_ACTIVE); + } + + ttCert = gnutls_x509_crt_get_expiration_time(cert); + if(ttCert == -1) + ABORT_FINALIZE(RS_RET_TLS_CERT_ERR); + else if(ttCert > ttNow) { + errmsg.LogError(NO_ERRCODE, "not permitted to talk to peer: certificate %d expired", i); + gtlsGetCertInfo(pThis, &pStr); + errmsg.LogError(NO_ERRCODE, "info on invalid cert: %s", rsCStrGetSzStr(pStr)); + rsCStrDestruct(&pStr); + ABORT_FINALIZE(RS_RET_CERT_EXPIRED); + } + gnutls_x509_crt_deinit(cert); + } + finalize_it: RETiRet; } diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 4f858928..5f39c3d8 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -231,6 +231,9 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_CONNECTION_ABORTREQ = -2089, /**< connection was abort requested due to previous error */ RS_RET_CERT_INVALID = -2090, /**< a x509 certificate failed validation */ RS_RET_CERT_INVALID_DN = -2091, /**< distinguised name in x509 certificate is invalid (e.g. wrong escaping) */ + RS_RET_CERT_EXPIRED = -2092, /**< we are past a x.509 cert's expiration time */ + RS_RET_CERT_NOT_YET_ACTIVE = -2094, /**< x.509 cert's activation time not yet reached */ + RS_RET_SYS_ERR = -2095, /**< system error occured (e.g. time() returned -1, quite unexpected) */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ -- cgit