diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2012-09-30 18:09:46 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2012-09-30 18:09:46 +0200 |
commit | 7b9d0158f022b8468ea7cd362ef9142889f4ff29 (patch) | |
tree | b51e18b22ea218d20606fd4ddfdc1e4bbfdc0eda /lib | |
parent | 52f373cdf26d50e05f5dd49e4ecc8b29fc742535 (diff) | |
download | gnutls-7b9d0158f022b8468ea7cd362ef9142889f4ff29.tar.gz |
Added gnutls_ocsp_resp_check_crt() to check whether the OCSP
response corresponds to the given certificate.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/gnutls_errors.c | 2 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 2 | ||||
-rw-r--r-- | lib/includes/gnutls/ocsp.h | 4 | ||||
-rw-r--r-- | lib/libgnutls.map | 1 | ||||
-rw-r--r-- | lib/x509/ocsp.c | 97 |
5 files changed, 106 insertions, 0 deletions
diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c index 71b6e6acf1..5e8df249e9 100644 --- a/lib/gnutls_errors.c +++ b/lib/gnutls_errors.c @@ -334,6 +334,8 @@ static const gnutls_error_entry error_algorithms[] = { GNUTLS_E_PKCS11_REQUESTED_OBJECT_NOT_AVAILBLE, 1), ERROR_ENTRY (N_("The provided X.509 certificate list is not sorted (in subject to issuer order)"), GNUTLS_E_CERTIFICATE_LIST_UNSORTED, 1), + ERROR_ENTRY (N_("The OCSP response is invalid"), + GNUTLS_E_OCSP_RESPONSE_ERROR, 1), {NULL, NULL, 0, 0} }; diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 773834cedc..355621a370 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -1905,6 +1905,8 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session); #define GNUTLS_E_X509_UNSUPPORTED_EXTENSION -327 #define GNUTLS_E_SESSION_EOF -328 +#define GNUTLS_E_OCSP_RESPONSE_ERROR -341 + #define GNUTLS_E_UNIMPLEMENTED_FEATURE -1250 diff --git a/lib/includes/gnutls/ocsp.h b/lib/includes/gnutls/ocsp.h index db16b70c10..70343a23e9 100644 --- a/lib/includes/gnutls/ocsp.h +++ b/lib/includes/gnutls/ocsp.h @@ -249,6 +249,10 @@ extern "C" unsigned int *verify, unsigned int flags); +int +gnutls_ocsp_resp_check_crt (gnutls_ocsp_resp_t resp, + gnutls_x509_crt_t crt); + #ifdef __cplusplus } #endif diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 1078a07680..f1647335ee 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -790,6 +790,7 @@ GNUTLS_3_0_0 { gnutls_pk_to_sign; gnutls_certificate_set_x509_system_trust; gnutls_session_set_premaster; + gnutls_ocsp_resp_check_crt; } GNUTLS_2_12; GNUTLS_PRIVATE { diff --git a/lib/x509/ocsp.c b/lib/x509/ocsp.c index 0857e33acf..3aca0f52f7 100644 --- a/lib/x509/ocsp.c +++ b/lib/x509/ocsp.c @@ -1275,6 +1275,103 @@ gnutls_ocsp_resp_get_produced (gnutls_ocsp_resp_t resp) } /** + * gnutls_ocsp_resp_check_crt: + * @resp: should contain a #gnutls_ocsp_resp_t structure + * @crt: The certificate to check + * + * This function will check whether the OCSP response + * is about the provided certificate. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error code is returned. + **/ +int +gnutls_ocsp_resp_check_crt (gnutls_ocsp_resp_t resp, + gnutls_x509_crt_t crt) +{ +int ret; +gnutls_digest_algorithm_t digest; +gnutls_datum_t rdn_hash = {NULL, 0}, rserial = {NULL, 0}; +gnutls_datum_t cserial = {NULL, 0}; +gnutls_datum_t dn = {NULL, 0}; +uint8_t cdn_hash[MAX_HASH_SIZE]; +size_t t, hash_len; + + ret = gnutls_ocsp_resp_get_single (resp, 0, &digest, &rdn_hash, NULL, + &rserial, NULL, NULL, NULL, NULL, NULL); + if (ret < 0) + return gnutls_assert_val(ret); + + if (rserial.size == 0 || digest == GNUTLS_DIG_UNKNOWN) + { + ret = gnutls_assert_val(GNUTLS_E_OCSP_RESPONSE_ERROR); + goto cleanup; + } + + hash_len = _gnutls_hash_get_algo_len(digest); + if (hash_len != rdn_hash.size) + { + ret = gnutls_assert_val(GNUTLS_E_OCSP_RESPONSE_ERROR); + goto cleanup; + } + + cserial.size = rserial.size; + cserial.data = gnutls_malloc(cserial.size); + if (cserial.data == NULL) + { + ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + goto cleanup; + } + + t = cserial.size; + ret = gnutls_x509_crt_get_serial(crt, cserial.data, &t); + if (ret < 0) + { + gnutls_assert(); + goto cleanup; + } + + if (rserial.size != cserial.size || memcmp(cserial.data, rserial.data, rserial.size) != 0) + { + ret = GNUTLS_E_OCSP_RESPONSE_ERROR; + gnutls_assert(); + goto cleanup; + } + + ret = gnutls_x509_crt_get_raw_issuer_dn(crt, &dn); + if (ret < 0) + { + gnutls_assert(); + goto cleanup; + } + + ret = _gnutls_hash_fast( digest, dn.data, dn.size, cdn_hash); + if (ret < 0) + { + gnutls_assert(); + goto cleanup; + } + + if (memcmp(cdn_hash, rdn_hash.data, hash_len) != 0) + { + ret = GNUTLS_E_OCSP_RESPONSE_ERROR; + gnutls_assert(); + goto cleanup; + } + + ret = 0; + +cleanup: + gnutls_free(rdn_hash.data); + gnutls_free(rserial.data); + gnutls_free(cserial.data); + gnutls_free(dn.data); + + return ret; +} + + +/** * gnutls_ocsp_resp_get_single: * @resp: should contain a #gnutls_ocsp_resp_t structure * @indx: Specifies which extension OID to get. Use (0) to get the first one. |