to have a way to pass the gnutls_verify_output_function() as a callback so that the full
path of the certificate chain to the trusted root can be avaiable as output.
Signed-off-by: Sahana Prasad <sahana@redhat.com>
** libgnutls: Added a new API that provides a callback function to
retrieve missing certificates from incomplete certificate chains (#202).
+** libgnutls: Added a new API that provides a callback function to
+ output the complete path to the trusted root during certificate
+ chain verification (#1012)
+
** API and ABI modifications:
gnutls_x509_trust_list_set_getissuer_function: Added
gnutls_x509_trust_list_get_ptr: Added
gnutls_x509_trust_list_set_ptr: Added
+gnutls_session_set_verify_output_function: Added
* Version 3.6.14 (released 2020-06-03)
<elf-symbol name='gnutls_session_set_verify_cert2' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_session_set_verify_cert' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_session_set_verify_function' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='gnutls_session_set_verify_output_function' version='GNUTLS_3_7_0' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_session_supplemental_register' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_session_ticket_enable_client' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='gnutls_session_ticket_enable_server' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
gnutls_session_set_verify_cert2@GNUTLS_3_4
gnutls_session_set_verify_cert@GNUTLS_3_4
gnutls_session_set_verify_function@GNUTLS_3_4
+gnutls_session_set_verify_output_function@GNUTLS_3_7_0
gnutls_session_supplemental_register@GNUTLS_3_4
gnutls_session_ticket_enable_client@GNUTLS_3_4
gnutls_session_ticket_enable_server@GNUTLS_3_4
FUNCS += functions/gnutls_session_set_verify_cert2.short
FUNCS += functions/gnutls_session_set_verify_function
FUNCS += functions/gnutls_session_set_verify_function.short
+FUNCS += functions/gnutls_session_set_verify_output_function
+FUNCS += functions/gnutls_session_set_verify_output_function.short
FUNCS += functions/gnutls_session_supplemental_register
FUNCS += functions/gnutls_session_supplemental_register.short
FUNCS += functions/gnutls_session_ticket_enable_client
APIMANS += gnutls_session_set_verify_cert.3
APIMANS += gnutls_session_set_verify_cert2.3
APIMANS += gnutls_session_set_verify_function.3
+APIMANS += gnutls_session_set_verify_output_function.3
APIMANS += gnutls_session_supplemental_register.3
APIMANS += gnutls_session_ticket_enable_client.3
APIMANS += gnutls_session_ticket_enable_server.3
return tlist->usr_ptr;
}
+/**
+ * gnutls_session_set_verify_output_function:
+ * @session: 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 has to be verified and full path to the trusted root has to be
+ * printed.
+ *
+ * The callback's function prototype is defined in `x509.h':
+ * int (*callback)(
+ * gnutls_x509_crt_t cert,
+ * gnutls_x509_crt_t issuer,
+ * gnutls_x509_crl_t crl,
+ * unsigned int verification_output);
+ *
+ * If the callback function is provided then gnutls will call it, in the
+ * certificate verification procedure.
+ * To verify the certificate chain and print its path uptp the trusted root,
+ * functions such as gnutls_certificate_verify_peers(),
+ * gnutls_x509_trust_list_verify_crt(), and gnutls_x509_trust_list_verify_crt2()
+ * can be used. The callback is set in _gnutls_verify_crt_status() and
+ * _gnutls_pkcs11_verify_crt_status().
+ *
+ * Since: 3.7.0
+ **/
+void gnutls_session_set_verify_output_function(gnutls_session_t session,
+ gnutls_verify_output_function * func)
+{
+ session->internals.cert_output_callback = func;
+}
+
#define TEST_TEXT "test text"
/* returns error if the certificate has different algorithm than
* the given key parameters.
ret =
check_ocsp_response(session,
peer_certificate_list[i],
- cred->tlist,
+ cred->tlist,
verify_flags, cand_issuers,
cand_issuers_size,
&resp, &ocsp_status);
#endif
skip_ocsp:
- /* Verify certificate
+ /* Verify certificate
*/
- ret =
- gnutls_x509_trust_list_verify_crt2(cred->tlist,
- peer_certificate_list,
- peer_certificate_list_size,
- data, elements,
- verify_flags, status, NULL);
+ if (session->internals.cert_output_callback != NULL) {
+ _gnutls_debug_log("Print full certificate path validation to trust root.\n");
+ ret =
+ gnutls_x509_trust_list_verify_crt2(cred->tlist,
+ peer_certificate_list,
+ peer_certificate_list_size,
+ data, elements,
+ verify_flags, status,
+ session->internals.cert_output_callback);
+ } else {
+ ret =
+ gnutls_x509_trust_list_verify_crt2(cred->tlist,
+ peer_certificate_list,
+ peer_certificate_list_size,
+ data, elements,
+ verify_flags, status, NULL);
+ }
if (ret < 0) {
gnutls_assert();
*/
gnutls_certificate_request_t send_cert_req;
+ /* callback to print the full path of certificate
+ * validation to the trusted root.
+ */
+ gnutls_verify_output_function *cert_output_callback;
+
size_t max_handshake_data_buffer_size;
/* PUSH & PULL functions.
void gnutls_x509_trust_list_iter_deinit(gnutls_x509_trust_list_iter_t iter);
-typedef int gnutls_verify_output_function(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer, /* The issuer if verification failed
+typedef int gnutls_verify_output_function(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer,
+ /* The issuer if verification failed
* because of him. might be null.
*/
gnutls_x509_crl_t crl, /* The CRL that caused verification failure
- * if any. Might be null.
+ * if any. Might be null.
*/
unsigned int
verification_output);
+void gnutls_session_set_verify_output_function(gnutls_session_t session,
+ gnutls_verify_output_function * func);
+
int gnutls_x509_trust_list_verify_named_crt
(gnutls_x509_trust_list_t list, gnutls_x509_crt_t cert,
const void *name, size_t name_size, unsigned int flags,
gnutls_x509_trust_list_set_getissuer_function;
gnutls_x509_trust_list_get_ptr;
gnutls_x509_trust_list_set_ptr;
+ gnutls_session_set_verify_output_function;
local:
*;
} GNUTLS_3_4;
sizeof(server_key_pem)
};
+static void print_verification_res(unsigned int output)
+{
+ gnutls_datum_t pout;
+ int ret;
+
+ if (output) {
+ success("Not verified.");
+ } else {
+ success("Verified.");
+ }
+
+ ret =
+ gnutls_certificate_verification_status_print(output,
+ GNUTLS_CRT_X509,
+ &pout, 0);
+ if (ret < 0) {
+ fprintf(stderr, "error: %s\n", gnutls_strerror(ret));
+ exit(1);
+ }
+
+ success(" %s", pout.data);
+ gnutls_free(pout.data);
+}
+
+static const char *get_signature_algo(gnutls_x509_crt_t crt)
+{
+ int ret;
+ static char oid[128];
+
+ ret = gnutls_x509_crt_get_signature_algorithm(crt);
+ if (ret < 0 || ret == GNUTLS_SIGN_UNKNOWN) {
+ size_t oid_size = sizeof(oid);
+ ret = gnutls_x509_crt_get_signature_oid(crt, oid, &oid_size);
+ if (ret < 0)
+ return NULL;
+ return oid;
+ }
+
+ return gnutls_sign_get_name(ret);
+}
+
+static int cert_out_callback(gnutls_x509_crt_t cert,
+ gnutls_x509_crt_t issuer,
+ gnutls_x509_crl_t crl,
+ unsigned int verification_output)
+{
+ char tmp[255];
+ size_t tmp_size;
+ gnutls_datum_t name = {NULL,0}, issuer_name = {NULL,0};
+ gnutls_datum_t serial = {NULL,0};
+ int ret;
+
+ success("Printing full certificate path validation to trust root.\n");
+
+ ret =
+ gnutls_x509_crt_get_issuer_dn3(cert, &issuer_name, 0);
+ if (ret < 0) {
+ fprintf(stderr, "gnutls_x509_crt_get_issuer_dn: %s\n",
+ gnutls_strerror(ret));
+ exit(1);
+ }
+
+ ret = gnutls_x509_crt_get_dn3(cert, &name, 0);
+ if (ret < 0) {
+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ name.data = 0;
+ name.size = 0;
+ } else {
+ fprintf(stderr, "gnutls_x509_crt_get_dn: %s\n",
+ gnutls_strerror(ret));
+ exit(1);
+ }
+ }
+
+ success("\tSubject: %s\n", name.data);
+ success("\tIssuer: %s\n", issuer_name.data);
+
+ if (issuer != NULL) {
+ gnutls_free(issuer_name.data);
+ ret =
+ gnutls_x509_crt_get_dn3(issuer, &issuer_name, 0);
+ if (ret < 0) {
+ fprintf(stderr,
+ "gnutls_x509_crt_get_issuer_dn: %s\n",
+ gnutls_strerror(ret));
+ exit(1);
+ }
+
+ success("\tChecked against: %s\n", issuer_name.data);
+ }
+
+ success("\tSignature algorithm: %s\n", get_signature_algo(cert));
+
+ if (crl != NULL) {
+ gnutls_datum_t data;
+ gnutls_free(issuer_name.data);
+
+ ret =
+ gnutls_x509_crl_get_issuer_dn3(crl, &issuer_name, 0);
+ if (ret < 0) {
+ fprintf(stderr,
+ "gnutls_x509_crl_get_issuer_dn: %s\n",
+ gnutls_strerror(ret));
+ exit(1);
+ }
+
+ tmp_size = sizeof(tmp);
+ ret =
+ gnutls_x509_crl_get_number(crl, tmp, &tmp_size, NULL);
+ if (ret < 0) {
+ serial.data = (void*)gnutls_strdup("unnumbered");
+ } else {
+ data.data = (void *) tmp;
+ data.size = tmp_size;
+
+ ret = gnutls_hex_encode2(&data, &serial);
+ if (ret < 0) {
+ fprintf(stderr, "gnutls_hex_encode: %s\n",
+ gnutls_strerror(ret));
+ exit(1);
+ }
+ }
+ success("\tChecked against CRL[%s] of: %s\n",
+ serial.data, issuer_name.data);
+ }
+
+ success("\tOutput: ");
+ print_verification_res(verification_output);
+
+ success("\n\n");
+
+ gnutls_free(serial.data);
+ gnutls_free(name.data);
+ gnutls_free(issuer_name.data);
+
+ return 0;
+}
+
static
void test_failure(const char *name, const char *prio)
{
if (ret < 0)
exit(1);
+ gnutls_session_set_verify_output_function(client, cert_out_callback);
assert(gnutls_priority_set_direct(client, prio, NULL) >= 0);
gnutls_transport_set_push_function(client, client_push);
gnutls_transport_set_pull_function(client, client_pull);