summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSahana Prasad <sahana@redhat.com>2020-05-22 09:42:47 +0200
committerSahana Prasad <sahana@redhat.com>2020-06-03 15:41:26 +0200
commite476e4b7e0de11820123da06ca9fcd0cbb94b8ff (patch)
tree40e9c5feae982c00c5f9fe0e35e4af5082bb2160
parent86012fd64e248c31554d42e6d6b38bfcd4357f92 (diff)
downloadgnutls-e476e4b7e0de11820123da06ca9fcd0cbb94b8ff.tar.gz
Implements a callback function gnutls_x509_trust_list_set_getissuer_function()
Signed-off-by: Sahana Prasad <sahana@redhat.com>
-rw-r--r--lib/cert-cred.c32
-rw-r--r--lib/includes/gnutls/x509.h6
-rw-r--r--lib/libgnutls.map8
-rw-r--r--lib/x509/verify-high.c37
-rw-r--r--lib/x509/verify-high.h6
-rw-r--r--lib/x509/verify.c129
-rw-r--r--lib/x509/x509_int.h33
7 files changed, 169 insertions, 82 deletions
diff --git a/lib/cert-cred.c b/lib/cert-cred.c
index 7311737298..8d3214dcbb 100644
--- a/lib/cert-cred.c
+++ b/lib/cert-cred.c
@@ -882,6 +882,38 @@ void
cred->verify_callback = func;
}
+/**
+ * gnutls_x509_trust_list_set_getissuer_function:
+ * @tlist: is a #gnutls_x509_trust_list_t type.
+ * @func: is the callback function
+ *
+ * This function sets a callback to be called when the peer's certificate
+ * chain is incomplete due a missing intermediate certificate/certificates.
+ *
+ * The callback's function prototype is defined in `abstract.h':
+ * int (*callback)(
+ * gnutls_x509_trust_list_t tlist,
+ * const gnutls_x509_crt_t crt);
+ *
+ * If the callback function is provided then gnutls will call it, in the
+ * certificate verification procedure.
+ * To verify or obtain the certificate the verification functions such as
+ * gnutls_x509_trust_list_verify_crt() and gnutls_x509_trust_list_verify_crt2()
+ * can be used.
+ *
+ * The callback function should return 0 if the missing issuer certificate
+ * for 'crt' was properly polulated and added to the 'tlist' using
+ * gnutls_x509_trust_list_add_cas() or non-zero to continue the certificate list
+ * verification but with issuer as %NULL.
+ *
+ * Since: 3.7.0
+ **/
+void gnutls_x509_trust_list_set_getissuer_function(gnutls_x509_trust_list_t tlist,
+ gnutls_x509_trust_list_getissuer_function * func)
+{
+ tlist->issuer_callback = func;
+}
+
#define TEST_TEXT "test text"
/* returns error if the certificate has different algorithm than
* the given key parameters.
diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h
index 6807271b2a..bcb687ce27 100644
--- a/lib/includes/gnutls/x509.h
+++ b/lib/includes/gnutls/x509.h
@@ -1698,6 +1698,12 @@ gnutls_x509_trust_list_add_system_trust(gnutls_x509_trust_list_t
unsigned int tl_flags,
unsigned int tl_vflags);
+typedef int gnutls_x509_trust_list_getissuer_function(gnutls_x509_trust_list_t tlist,
+ const gnutls_x509_crt_t crt);
+
+void gnutls_x509_trust_list_set_getissuer_function(gnutls_x509_trust_list_t tlist,
+ gnutls_x509_trust_list_getissuer_function *func);
+
void gnutls_certificate_set_trust_list
(gnutls_certificate_credentials_t res,
gnutls_x509_trust_list_t tlist, unsigned flags);
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index ac6be479f1..e29f064a30 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1331,6 +1331,14 @@ GNUTLS_3_6_14
gnutls_pkcs7_print_signature_info;
} GNUTLS_3_6_13;
+GNUTLS_3_7_0
+{
+ global:
+ gnutls_x509_trust_list_set_getissuer_function;
+ local:
+ *;
+} GNUTLS_3_4;
+
GNUTLS_FIPS140_3_4 {
global:
gnutls_cipher_self_test;
diff --git a/lib/x509/verify-high.c b/lib/x509/verify-high.c
index 40638ad3aa..763c527a59 100644
--- a/lib/x509/verify-high.c
+++ b/lib/x509/verify-high.c
@@ -851,11 +851,10 @@ static int shorten_clist(gnutls_x509_trust_list_t list,
return clist_size;
}
-static
-int trust_list_get_issuer(gnutls_x509_trust_list_t list,
- gnutls_x509_crt_t cert,
- gnutls_x509_crt_t * issuer,
- unsigned int flags)
+int _gnutls_trust_list_get_issuer(gnutls_x509_trust_list_t list,
+ gnutls_x509_crt_t cert,
+ gnutls_x509_crt_t * issuer,
+ unsigned int flags)
{
int ret;
unsigned int i;
@@ -968,7 +967,7 @@ int gnutls_x509_trust_list_get_issuer(gnutls_x509_trust_list_t list,
{
int ret;
- ret = trust_list_get_issuer(list, cert, issuer, flags);
+ ret = _gnutls_trust_list_get_issuer(list, cert, issuer, flags);
if (ret == 0) {
return 0;
}
@@ -1335,11 +1334,10 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
}
*voutput =
- _gnutls_verify_crt_status(cert_list, cert_list_size,
- list->node[hash].trusted_cas,
- list->
- node[hash].trusted_ca_size,
- flags, purpose, func);
+ _gnutls_verify_crt_status(list, cert_list, cert_list_size,
+ list->node[hash].trusted_cas,
+ list->node[hash].trusted_ca_size,
+ flags, purpose, func);
saved_output = *voutput;
if (SIGNER_OLD_OR_UNKNOWN(*voutput) &&
@@ -1357,11 +1355,10 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
_gnutls_debug_log("issuer in verification was not found or insecure; trying against trust list\n");
*voutput =
- _gnutls_verify_crt_status(cert_list, cert_list_size,
- list->node[hash].trusted_cas,
- list->
- node[hash].trusted_ca_size,
- flags, purpose, func);
+ _gnutls_verify_crt_status(list, cert_list, cert_list_size,
+ list->node[hash].trusted_cas,
+ list->node[hash].trusted_ca_size,
+ flags, purpose, func);
if (*voutput != 0) {
if (SIGNER_WAS_KNOWN(saved_output))
*voutput = saved_output;
@@ -1375,10 +1372,10 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
if (SIGNER_OLD_OR_UNKNOWN(*voutput) && list->pkcs11_token) {
/* use the token for verification */
- *voutput = _gnutls_pkcs11_verify_crt_status(list->pkcs11_token,
- cert_list, cert_list_size,
- purpose,
- flags, func);
+ *voutput = _gnutls_pkcs11_verify_crt_status(list, list->pkcs11_token,
+ cert_list, cert_list_size,
+ purpose,
+ flags, func);
if (*voutput != 0) {
if (SIGNER_WAS_KNOWN(saved_output))
*voutput = saved_output;
diff --git a/lib/x509/verify-high.h b/lib/x509/verify-high.h
index ca1f98b831..6ce5f958ae 100644
--- a/lib/x509/verify-high.h
+++ b/lib/x509/verify-high.h
@@ -39,8 +39,12 @@ struct gnutls_x509_trust_list_st {
* will be deinitialized */
gnutls_x509_crt_t *keep_certs;
unsigned int keep_certs_size;
-
+
char* pkcs11_token;
+
+ /* set this callback if the issuer in the certificate
+ * chain is missing. */
+ gnutls_x509_trust_list_getissuer_function *issuer_callback;
};
int _gnutls_trustlist_inlist(gnutls_x509_trust_list_t list,
diff --git a/lib/x509/verify.c b/lib/x509/verify.c
index fd7c6a1642..4363e818b1 100644
--- a/lib/x509/verify.c
+++ b/lib/x509/verify.c
@@ -38,6 +38,7 @@
#include <x509_int.h>
#include <common.h>
#include <pk.h>
+#include <x509/verify-high.h>
#include "supported_exts.h"
#include "profiles.h"
@@ -604,11 +605,11 @@ static int _gnutls_x509_verify_data(gnutls_sign_algorithm_t sign,
gnutls_x509_crt_t issuer,
unsigned vflags);
-/*
+/*
* Verifies the given certificate against a certificate list of
* trusted CAs.
*
- * Returns only 0 or 1. If 1 it means that the certificate
+ * Returns only 0 or 1. If 1 it means that the certificate
* was successfully verified.
*
* 'flags': an OR of the gnutls_certificate_verify_flags enumeration.
@@ -616,13 +617,13 @@ static int _gnutls_x509_verify_data(gnutls_sign_algorithm_t sign,
* Output will hold some extra information about the verification
* procedure.
*/
-static unsigned
-verify_crt(gnutls_x509_crt_t cert,
- const gnutls_x509_crt_t * trusted_cas,
- int tcas_size, unsigned int flags,
- unsigned int *output,
- verify_state_st *vparams,
- unsigned end_cert)
+static unsigned verify_crt(gnutls_x509_trust_list_t tlist,
+ gnutls_x509_crt_t cert,
+ const gnutls_x509_crt_t * trusted_cas,
+ int tcas_size, unsigned int flags,
+ unsigned int *output,
+ verify_state_st *vparams,
+ unsigned end_cert)
{
gnutls_datum_t cert_signed_data = { NULL, 0 };
gnutls_datum_t cert_signature = { NULL, 0 };
@@ -646,6 +647,25 @@ verify_crt(gnutls_x509_crt_t cert,
if (tcas_size >= 1)
issuer = find_issuer(cert, trusted_cas, tcas_size);
+ if (issuer == NULL && tlist != NULL && tlist->issuer_callback != NULL) {
+ _gnutls_debug_log("Missing issuer callback set.\n");
+
+ /* missing issuer is populated by the callback */
+ ret = tlist->issuer_callback(tlist, cert);
+ if (ret < 0) {
+ /* if the callback fails, continue as though the callback
+ * wasn't invoked i.e issuer remains NULL */
+ gnutls_assert();
+ issuer = NULL;
+ }
+
+ ret = _gnutls_trust_list_get_issuer(tlist, cert, &issuer, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ issuer = NULL;
+ }
+ }
+
ret =
_gnutls_x509_get_signed_data(cert->cert, &cert->der, "tbsCertificate",
&cert_signed_data);
@@ -680,7 +700,7 @@ verify_crt(gnutls_x509_crt_t cert,
} else {
if (vparams->nc != NULL) {
/* append the issuer's constraints */
- ret = gnutls_x509_crt_get_name_constraints(issuer, vparams->nc,
+ ret = gnutls_x509_crt_get_name_constraints(issuer, vparams->nc,
GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND, NULL);
if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
@@ -909,13 +929,14 @@ unsigned check_ca_sanity(const gnutls_x509_crt_t issuer,
* list should lead to a trusted certificate in order to be trusted.
*/
unsigned int
-_gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
- int clist_size,
- const gnutls_x509_crt_t * trusted_cas,
- int tcas_size,
- unsigned int flags,
- const char *purpose,
- gnutls_verify_output_function func)
+_gnutls_verify_crt_status(gnutls_x509_trust_list_t tlist,
+ const gnutls_x509_crt_t * certificate_list,
+ int clist_size,
+ const gnutls_x509_crt_t * trusted_cas,
+ int tcas_size,
+ unsigned int flags,
+ const char *purpose,
+ gnutls_verify_output_function func)
{
int i = 0, ret;
unsigned int status = 0, output;
@@ -1010,11 +1031,12 @@ _gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
*/
output = 0;
- ret = verify_crt(certificate_list[clist_size - 1],
- trusted_cas, tcas_size, flags,
- &output,
- &vparams,
- clist_size==1?1:0);
+ ret = verify_crt(tlist,
+ certificate_list[clist_size - 1],
+ trusted_cas, tcas_size, flags,
+ &output,
+ &vparams,
+ clist_size==1?1:0);
if (ret != 1) {
/* if the last certificate in the certificate
* list is invalid, then the certificate is not
@@ -1053,11 +1075,12 @@ _gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
}
if ((ret =
- verify_crt(certificate_list[i - 1],
- &certificate_list[i], 1,
- flags, &output,
- &vparams,
- i==1?1:0)) != 1) {
+ verify_crt(tlist,
+ certificate_list[i - 1],
+ &certificate_list[i], 1,
+ flags, &output,
+ &vparams,
+ i==1?1:0)) != 1) {
gnutls_assert();
status |= output;
status |= GNUTLS_CERT_INVALID;
@@ -1147,12 +1170,13 @@ unsigned _gnutls_check_key_purpose(gnutls_x509_crt_t cert, const char *purpose,
* list should lead to a trusted certificate in order to be trusted.
*/
unsigned int
-_gnutls_pkcs11_verify_crt_status(const char* url,
- const gnutls_x509_crt_t * certificate_list,
- unsigned clist_size,
- const char *purpose,
- unsigned int flags,
- gnutls_verify_output_function func)
+_gnutls_pkcs11_verify_crt_status(gnutls_x509_trust_list_t tlist,
+ const char* url,
+ const gnutls_x509_crt_t * certificate_list,
+ unsigned clist_size,
+ const char *purpose,
+ unsigned int flags,
+ gnutls_verify_output_function func)
{
int ret;
unsigned int status = 0, i;
@@ -1249,9 +1273,10 @@ _gnutls_pkcs11_verify_crt_status(const char* url,
ret = gnutls_pkcs11_crt_is_known(url, certificate_list[clist_size - 1],
GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED|GNUTLS_PKCS11_OBJ_FLAG_COMPARE);
if (ret != 0) {
- return _gnutls_verify_crt_status(certificate_list, clist_size,
- &certificate_list[clist_size - 1], 1, flags,
- purpose, func);
+ return _gnutls_verify_crt_status(tlist,
+ certificate_list, clist_size,
+ &certificate_list[clist_size - 1],
+ 1, flags, purpose, func);
}
}
@@ -1260,7 +1285,7 @@ _gnutls_pkcs11_verify_crt_status(const char* url,
/* verify the certificate list against 0 trusted CAs in order
* to get, any additional flags from the certificate list (e.g.,
* insecure algorithms or expired */
- status |= _gnutls_verify_crt_status(certificate_list, clist_size,
+ status |= _gnutls_verify_crt_status(tlist, certificate_list, clist_size,
NULL, 0, flags, purpose, func);
goto cleanup;
}
@@ -1303,8 +1328,8 @@ _gnutls_pkcs11_verify_crt_status(const char* url,
goto cleanup;
}
- status = _gnutls_verify_crt_status(certificate_list, clist_size,
- &issuer, 1, flags, purpose, func);
+ status = _gnutls_verify_crt_status(tlist, certificate_list, clist_size,
+ &issuer, 1, flags, purpose, func);
cleanup:
gnutls_free(raw_issuer.data);
@@ -1468,18 +1493,20 @@ gnutls_x509_crt_list_verify(const gnutls_x509_crt_t * cert_list,
{
unsigned i;
int ret;
+ gnutls_x509_trust_list_t tlist;
if (cert_list == NULL || cert_list_length == 0)
return GNUTLS_E_NO_CERTIFICATE_FOUND;
- /* Verify certificate
+ gnutls_x509_trust_list_init(&tlist, 0);
+
+ /* Verify certificate
*/
- *verify =
- _gnutls_verify_crt_status(cert_list, cert_list_length,
+ *verify = _gnutls_verify_crt_status(tlist, cert_list, cert_list_length,
CA_list, CA_list_length,
flags, NULL, NULL);
- /* Check for revoked certificates in the chain.
+ /* Check for revoked certificates in the chain.
*/
for (i = 0; i < cert_list_length; i++) {
ret = gnutls_x509_crt_check_revocation(cert_list[i],
@@ -1491,6 +1518,7 @@ gnutls_x509_crt_list_verify(const gnutls_x509_crt_t * cert_list,
}
}
+ gnutls_x509_trust_list_deinit(tlist, 0);
return 0;
}
@@ -1518,12 +1546,17 @@ gnutls_x509_crt_verify(gnutls_x509_crt_t cert,
unsigned CA_list_length, unsigned int flags,
unsigned int *verify)
{
- /* Verify certificate
+ gnutls_x509_trust_list_t tlist;
+
+ gnutls_x509_trust_list_init(&tlist, 0);
+
+ /* Verify certificate
*/
- *verify =
- _gnutls_verify_crt_status(&cert, 1,
+ *verify = _gnutls_verify_crt_status(tlist, &cert, 1,
CA_list, CA_list_length,
flags, NULL, NULL);
+
+ gnutls_x509_trust_list_deinit(tlist, 0);
return 0;
}
@@ -1533,9 +1566,9 @@ gnutls_x509_crt_verify(gnutls_x509_crt_t cert,
* @issuer: is the certificate of a possible issuer
*
* This function will check if the given CRL was issued by the given
- * issuer certificate.
+ * issuer certificate.
*
- * Returns: true (1) if the given CRL was issued by the given issuer,
+ * Returns: true (1) if the given CRL was issued by the given issuer,
* and false (0) if not.
**/
unsigned
diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h
index 050e95059e..a41cc5827a 100644
--- a/lib/x509/x509_int.h
+++ b/lib/x509/x509_int.h
@@ -495,23 +495,30 @@ gnutls_x509_crt_verify_data3(gnutls_x509_crt_t crt,
const gnutls_datum_t *signature,
unsigned int flags);
+int _gnutls_trust_list_get_issuer(gnutls_x509_trust_list_t list,
+ gnutls_x509_crt_t cert,
+ gnutls_x509_crt_t * issuer,
+ unsigned int flags);
+
unsigned int
-_gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
- int clist_size,
- const gnutls_x509_crt_t * trusted_cas,
- int tcas_size,
- unsigned int flags,
- const char *purpose,
- gnutls_verify_output_function func);
+_gnutls_verify_crt_status(gnutls_x509_trust_list_t tlist,
+ const gnutls_x509_crt_t * certificate_list,
+ int clist_size,
+ const gnutls_x509_crt_t * trusted_cas,
+ int tcas_size,
+ unsigned int flags,
+ const char *purpose,
+ gnutls_verify_output_function func);
#ifdef ENABLE_PKCS11
unsigned int
-_gnutls_pkcs11_verify_crt_status(const char* url,
- const gnutls_x509_crt_t * certificate_list,
- unsigned clist_size,
- const char *purpose,
- unsigned int flags,
- gnutls_verify_output_function func);
+_gnutls_pkcs11_verify_crt_status(gnutls_x509_trust_list_t tlist,
+ const char* url,
+ const gnutls_x509_crt_t * certificate_list,
+ unsigned clist_size,
+ const char *purpose,
+ unsigned int flags,
+ gnutls_verify_output_function func);
#endif
int _gnutls_check_cert_sanity(gnutls_x509_crt_t cert);