From 6b9818ec4a10466c871b7a99bc7b392d4a590877 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Mon, 17 Oct 2016 15:07:03 +0200 Subject: gnutls_x509_crt_verify_data2: introduce constraints checks on the provided certificate That is check the provided certificate for validity in time and key usage. --- lib/errors.c | 4 +- lib/includes/gnutls/gnutls.h.in | 1 + lib/x509/pkcs7.c | 8 +++- lib/x509/x509.c | 86 ++++++++++++++++++++++++++++++++++++----- lib/x509/x509_int.h | 9 +++++ 5 files changed, 95 insertions(+), 13 deletions(-) diff --git a/lib/errors.c b/lib/errors.c index 5e4610bf8f..9f46374978 100644 --- a/lib/errors.c +++ b/lib/errors.c @@ -134,8 +134,10 @@ static const gnutls_error_entry error_entries[] = { ERROR_ENTRY(N_("Error in password file."), GNUTLS_E_SRP_PWD_ERROR), ERROR_ENTRY(N_("Wrong padding in PKCS1 packet."), GNUTLS_E_PKCS1_WRONG_PAD), - ERROR_ENTRY(N_("The requested session has expired."), + ERROR_ENTRY(N_("The session or certificate has expired."), GNUTLS_E_EXPIRED), + ERROR_ENTRY(N_("The certificate is not yet activated."), + GNUTLS_E_NOT_YET_ACTIVATED), ERROR_ENTRY(N_("Hashing has failed."), GNUTLS_E_HASH_FAILED), ERROR_ENTRY(N_("Base64 decoding error."), GNUTLS_E_BASE64_DECODING_ERROR), diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 75673c88ad..7134e2c094 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -2813,6 +2813,7 @@ unsigned gnutls_fips140_mode_enabled(void); #define GNUTLS_E_UNAVAILABLE_DURING_HANDSHAKE -408 #define GNUTLS_E_PK_INVALID_PUBKEY -409 #define GNUTLS_E_PK_INVALID_PRIVKEY -410 +#define GNUTLS_E_NOT_YET_ACTIVATED -411 #define GNUTLS_E_UNIMPLEMENTED_FEATURE -1250 diff --git a/lib/x509/pkcs7.c b/lib/x509/pkcs7.c index b2de03f2d4..764fb599fd 100644 --- a/lib/x509/pkcs7.c +++ b/lib/x509/pkcs7.c @@ -965,6 +965,10 @@ gnutls_pkcs7_get_embedded_data_oid(gnutls_pkcs7_t pkcs7) * provided are NULL then the data in the encapsulatedContent field * will be used instead. * + * Note that, unlike gnutls_pkcs7_verify() this function does not + * verify the key purpose of the signer. It is expected for the caller + * to verify the intended purpose of the %signer -e.g., via gnutls_x509_crt_get_key_purpose_oid(). + * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. A verification error results to a * %GNUTLS_E_PK_SIG_VERIFY_FAILED and the lack of encapsulated data @@ -1239,8 +1243,8 @@ int gnutls_pkcs7_verify(gnutls_pkcs7_t pkcs7, signer = find_signer(pkcs7, tl, vdata, vdata_size, &info); if (signer) { ret = - gnutls_x509_crt_verify_data2(signer, info.algo, flags, - &sigdata, &info.sig); + gnutls_x509_crt_verify_data3(signer, info.algo, vdata, vdata_size, + &sigdata, &info.sig, flags); if (ret < 0) { gnutls_assert(); } diff --git a/lib/x509/x509.c b/lib/x509/x509.c index 25f1d2691a..a60d667033 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -3862,8 +3862,8 @@ gnutls_x509_crt_import_url(gnutls_x509_crt_t crt, return ret; } -/** - * gnutls_x509_crt_verify_data2: +/*- + * gnutls_x509_crt_verify_data3: * @crt: Holds the certificate to verify with * @algo: The signature algorithm used * @flags: Zero or an OR list of #gnutls_certificate_verify_flags @@ -3874,16 +3874,19 @@ gnutls_x509_crt_import_url(gnutls_x509_crt_t crt, * parameters from the certificate. * * Returns: In case of a verification failure %GNUTLS_E_PK_SIG_VERIFY_FAILED - * is returned, and zero or positive code on success. + * is returned, %GNUTLS_E_EXPIRED or %GNUTLS_E_NOT_YET_ACTIVATED on expired + * or not yet activated certificate and zero or positive code on success. * - * Since: 3.4.0 - **/ + * Since: 3.5.6 + -*/ int -gnutls_x509_crt_verify_data2(gnutls_x509_crt_t crt, - gnutls_sign_algorithm_t algo, - unsigned int flags, - const gnutls_datum_t * data, - const gnutls_datum_t * signature) +gnutls_x509_crt_verify_data3(gnutls_x509_crt_t crt, + gnutls_sign_algorithm_t algo, + gnutls_typed_vdata_st *vdata, + unsigned int vdata_size, + const gnutls_datum_t *data, + const gnutls_datum_t *signature, + unsigned int flags) { int ret; gnutls_pubkey_t pubkey; @@ -3893,6 +3896,7 @@ gnutls_x509_crt_verify_data2(gnutls_x509_crt_t crt, return GNUTLS_E_INVALID_REQUEST; } + ret = gnutls_pubkey_init(&pubkey); if (ret < 0) return gnutls_assert_val(ret); @@ -3904,5 +3908,67 @@ gnutls_x509_crt_verify_data2(gnutls_x509_crt_t crt, ret = gnutls_pubkey_verify_data2(pubkey, algo, flags, data, signature); gnutls_pubkey_deinit(pubkey); + if (ret >= 0) { + time_t now = gnutls_time(0); + int res; + unsigned usage, i; + + if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) || + !(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) { + if (now > gnutls_x509_crt_get_expiration_time(crt)) { + return gnutls_assert_val(GNUTLS_E_EXPIRED); + } + + if (now < gnutls_x509_crt_get_activation_time(crt)) { + return gnutls_assert_val(GNUTLS_E_NOT_YET_ACTIVATED); + } + } + + res = gnutls_x509_crt_get_key_usage(crt, &usage, NULL); + if (res >= 0) { + if (!(usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { + return gnutls_assert_val(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); + } + } + + for (i=0;i