static void infinoted_plugin_certificate_auth_certificate_func(InfXmppConnection* xmpp, gnutls_session_t session, InfCertificateChain* chain, gpointer user_data) { InfinotedPluginCertificateAuth* plugin; int res; int verify_result; GError* error; plugin = (InfinotedPluginCertificateAuth*)user_data; if(chain != NULL) { /* Note that we don't require client certificates to be signed by a CA. * We only require them to be signed by one of the certificates in our * list, but we don't care whether that's a CA or not. A common use case * is to sign client certificates with our own server certificate. */ res = gnutls_x509_crt_list_verify( inf_certificate_chain_get_raw(chain), inf_certificate_chain_get_n_certificates(chain), plugin->cas, plugin->n_cas, NULL, 0, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT | GNUTLS_VERIFY_DISABLE_CA_SIGN, &verify_result ); error = NULL; if(res != GNUTLS_E_SUCCESS) inf_gnutls_set_error(&error, res); else if( (verify_result & GNUTLS_CERT_INVALID) != 0) inf_gnutls_certificate_verification_set_error(&error, res); if(error != NULL) { inf_xmpp_connection_certificate_verify_cancel(xmpp, error); g_error_free(error); } else { inf_xmpp_connection_certificate_verify_continue(xmpp); } } else { /* If we do not accept unauthenticated clients, then GnuTLS should have * blocked the connection already, since we set the certificate request * to GNUTLS_CERT_REQUIRE in that case. */ g_assert(plugin->accept_unauthenticated_clients == TRUE); inf_xmpp_connection_certificate_verify_continue(xmpp); } }
static int qcrypto_tls_creds_check_cert_pair(gnutls_x509_crt_t cert, const char *certFile, gnutls_x509_crt_t *cacerts, size_t ncacerts, const char *cacertFile, bool isServer, Error **errp) { unsigned int status; if (gnutls_x509_crt_list_verify(&cert, 1, cacerts, ncacerts, NULL, 0, 0, &status) < 0) { error_setg(errp, isServer ? "Unable to verify server certificate %s against " "CA certificate %s" : "Unable to verify client certificate %s against " "CA certificate %s", certFile, cacertFile); return -1; } if (status != 0) { const char *reason = "Invalid certificate"; if (status & GNUTLS_CERT_INVALID) { reason = "The certificate is not trusted"; } if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { reason = "The certificate hasn't got a known issuer"; } if (status & GNUTLS_CERT_REVOKED) { reason = "The certificate has been revoked"; } #ifndef GNUTLS_1_0_COMPAT if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { reason = "The certificate uses an insecure algorithm"; } #endif error_setg(errp, "Our own certificate %s failed validation against %s: %s", certFile, cacertFile, reason); return -1; } return 0; }
static void perform_verification (EmpathyTLSVerifier *self, GcrCertificateChain *chain) { gboolean ret = FALSE; EmpTLSCertificateRejectReason reason = EMP_TLS_CERTIFICATE_REJECT_REASON_UNKNOWN; gnutls_x509_crt_t *list, *anchors; guint n_list, n_anchors; guint verify_output; gint res; gint i; gboolean matched = FALSE; EmpathyTLSVerifierPriv *priv = GET_PRIV (self); DEBUG ("Performing verification"); debug_certificate_chain (chain); list = anchors = NULL; n_list = n_anchors = 0; /* * If the first certificate is an pinned certificate then we completely * ignore the rest of the verification process. */ if (gcr_certificate_chain_get_status (chain) == GCR_CERTIFICATE_CHAIN_PINNED) { DEBUG ("Found pinned certificate for %s", priv->hostname); complete_verification (self); goto out; } build_certificate_list_for_gnutls (chain, &list, &n_list, &anchors, &n_anchors); if (list == NULL || n_list == 0) { g_warn_if_reached (); abort_verification (self, EMP_TLS_CERTIFICATE_REJECT_REASON_UNKNOWN); goto out; } verify_output = 0; res = gnutls_x509_crt_list_verify (list, n_list, anchors, n_anchors, NULL, 0, 0, &verify_output); ret = verification_output_to_reason (res, verify_output, &reason); DEBUG ("Certificate verification gave result %d with reason %u", ret, reason); if (!ret) { abort_verification (self, reason); goto out; } /* now check if the certificate matches one of the reference identities. */ if (priv->reference_identities != NULL) { for (i = 0, matched = FALSE; priv->reference_identities[i] != NULL; ++i) { if (gnutls_x509_crt_check_hostname (list[0], priv->reference_identities[i]) == 1) { matched = TRUE; break; } } } if (!matched) { gchar *certified_hostname; certified_hostname = empathy_get_x509_certificate_hostname (list[0]); tp_asv_set_string (priv->details, "expected-hostname", priv->hostname); tp_asv_set_string (priv->details, "certificate-hostname", certified_hostname); DEBUG ("Hostname mismatch: got %s but expected %s", certified_hostname, priv->hostname); g_free (certified_hostname); abort_verification (self, EMP_TLS_CERTIFICATE_REJECT_REASON_HOSTNAME_MISMATCH); goto out; } DEBUG ("Hostname matched"); complete_verification (self); out: free_certificate_list_for_gnutls (list, n_list); free_certificate_list_for_gnutls (anchors, n_anchors); }
static void inf_gtk_certificate_manager_certificate_func(InfXmppConnection* connection, gnutls_session_t session, InfCertificateChain* chain, gpointer user_data) { InfGtkCertificateManager* manager; InfGtkCertificateManagerPrivate* priv; InfGtkCertificateDialogFlags flags; gnutls_x509_crt_t presented_cert; gnutls_x509_crt_t known_cert; gchar* hostname; gboolean match_hostname; gboolean issuer_known; gnutls_x509_crt_t root_cert; int ret; unsigned int verify; GHashTable* table; gboolean cert_equal; time_t expiration_time; InfGtkCertificateManagerQuery* query; gchar* text; GtkWidget* vbox; GtkWidget* button; GtkWidget* image; GtkWidget* label; GError* error; manager = INF_GTK_CERTIFICATE_MANAGER(user_data); priv = INF_GTK_CERTIFICATE_MANAGER_PRIVATE(manager); g_object_get(G_OBJECT(connection), "remote-hostname", &hostname, NULL); presented_cert = inf_certificate_chain_get_own_certificate(chain); match_hostname = gnutls_x509_crt_check_hostname(presented_cert, hostname); /* First, validate the certificate */ ret = gnutls_certificate_verify_peers2(session, &verify); error = NULL; if(ret != GNUTLS_E_SUCCESS) inf_gnutls_set_error(&error, ret); /* Remove the GNUTLS_CERT_ISSUER_NOT_KNOWN flag from the verification * result, and if the certificate is still invalid, then set an error. */ if(error == NULL) { issuer_known = TRUE; if(verify & GNUTLS_CERT_SIGNER_NOT_FOUND) { issuer_known = FALSE; /* Re-validate the certificate for other failure reasons -- * unfortunately the gnutls_certificate_verify_peers2() call * does not tell us whether the certificate is otherwise invalid * if a signer is not found already. */ /* TODO: Here it would be good to use the verify flags from the * certificate credentials, but GnuTLS does not have API to * retrieve them. */ root_cert = inf_certificate_chain_get_root_certificate(chain); ret = gnutls_x509_crt_list_verify( inf_certificate_chain_get_raw(chain), inf_certificate_chain_get_n_certificates(chain), &root_cert, 1, NULL, 0, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, &verify ); if(ret != GNUTLS_E_SUCCESS) inf_gnutls_set_error(&error, ret); else if(verify & GNUTLS_CERT_INVALID) inf_gnutls_certificate_verification_set_error(&error, verify); } } /* Look up the host in our database of pinned certificates if we could not * fully verify the certificate, i.e. if either the issuer is not known or * the hostname of the connection does not match the certificate. */ table = NULL; if(error == NULL) { known_cert = NULL; if(!match_hostname || !issuer_known) { /* If we cannot load the known host file, then cancel the connection. * Otherwise it might happen that someone shows us a certificate that we * tell the user we don't know, if though actually for that host we expect * a different certificate. */ table = inf_gtk_certificate_manager_ref_known_hosts(manager, &error); if(table != NULL) known_cert = g_hash_table_lookup(table, hostname); } } /* Next, configure the flags for the dialog to be shown based on the * verification result, and on whether the pinned certificate matches * the one presented by the host or not. */ flags = 0; if(error == NULL) { if(known_cert != NULL) { cert_equal = inf_gtk_certificate_manager_compare_fingerprint( known_cert, presented_cert, &error ); if(error == NULL && cert_equal == FALSE) { if(!match_hostname) flags |= INF_GTK_CERTIFICATE_DIALOG_CERT_HOSTNAME_MISMATCH; if(!issuer_known) flags |= INF_GTK_CERTIFICATE_DIALOG_CERT_ISSUER_NOT_KNOWN; flags |= INF_GTK_CERTIFICATE_DIALOG_CERT_UNEXPECTED; expiration_time = gnutls_x509_crt_get_expiration_time(known_cert); if(expiration_time != (time_t)(-1)) { expiration_time -= INF_GTK_CERTIFICATE_MANAGER_EXPIRATION_TOLERANCE; if(time(NULL) > expiration_time) { flags |= INF_GTK_CERTIFICATE_DIALOG_CERT_OLD_EXPIRED; } } } } else { if(!match_hostname) flags |= INF_GTK_CERTIFICATE_DIALOG_CERT_HOSTNAME_MISMATCH; if(!issuer_known) flags |= INF_GTK_CERTIFICATE_DIALOG_CERT_ISSUER_NOT_KNOWN; } } /* Now proceed either by accepting the connection, rejecting it, or * bothering the user with an annoying dialog. */ if(error == NULL) { if(flags == 0) { if(match_hostname && issuer_known) { /* Remove the pinned entry if we now have a valid certificate for * this host. */ if(table != NULL && g_hash_table_remove(table, hostname) == TRUE) { inf_gtk_certificate_manager_write_known_hosts_with_warning( manager, table ); } } inf_xmpp_connection_certificate_verify_continue(connection); } else { query = g_slice_new(InfGtkCertificateManagerQuery); query->manager = manager; query->known_hosts = table; query->connection = connection; query->dialog = inf_gtk_certificate_dialog_new( priv->parent_window, 0, flags, hostname, chain ); query->certificate_chain = chain; table = NULL; g_object_ref(query->connection); inf_certificate_chain_ref(chain); g_signal_connect( G_OBJECT(connection), "notify::status", G_CALLBACK(inf_gtk_certificate_manager_notify_status_cb), query ); g_signal_connect( G_OBJECT(query->dialog), "response", G_CALLBACK(inf_gtk_certificate_manager_response_cb), query ); image = gtk_image_new_from_stock(GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON); gtk_widget_show(image); button = gtk_dialog_add_button( GTK_DIALOG(query->dialog), _("_Cancel connection"), GTK_RESPONSE_REJECT ); gtk_button_set_image(GTK_BUTTON(button), image); image = gtk_image_new_from_stock(GTK_STOCK_CONNECT, GTK_ICON_SIZE_BUTTON); gtk_widget_show(image); button = gtk_dialog_add_button( GTK_DIALOG(query->dialog), _("C_ontinue connection"), GTK_RESPONSE_ACCEPT ); gtk_button_set_image(GTK_BUTTON(button), image); text = g_strdup_printf( _("Do you want to continue the connection to host \"%s\"? If you " "choose to continue, this certificate will be trusted in the " "future when connecting to this host."), hostname ); label = gtk_label_new(text); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD_CHAR); gtk_label_set_width_chars(GTK_LABEL(label), 60); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); gtk_widget_show(label); g_free(text); vbox = gtk_dialog_get_content_area(GTK_DIALOG(query->dialog)); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); priv->queries = g_slist_prepend(priv->queries, query); gtk_window_present(GTK_WINDOW(query->dialog)); } } else { inf_xmpp_connection_certificate_verify_cancel(connection, error); g_error_free(error); } if(table != NULL) g_hash_table_unref(table); g_free(hostname); }
void doit (void) { int exit_val = 0; size_t i; int ret; /* The overloading of time() seems to work in linux (ELF?) * systems only. Disable it on windows. */ #ifdef _WIN32 exit(77); #endif ret = gnutls_global_init (); if (ret != 0) { fail ("%d: %s\n", ret, gnutls_strerror (ret)); exit (EXIT_FAILURE); } gnutls_global_set_time_function (mytime); gnutls_global_set_log_function (tls_log_func); if (debug) gnutls_global_set_log_level (4711); for (i = 0; chains[i].chain; i++) { unsigned int verify_status; gnutls_x509_crt_t certs[4]; gnutls_x509_crt_t ca; gnutls_datum_t tmp; size_t j; if (debug) printf ("Chain '%s' (%d)...\n", chains[i].name, (int) i); for (j = 0; chains[i].chain[j]; j++) { if (debug > 2) printf ("\tAdding certificate %d...", (int) j); ret = gnutls_x509_crt_init (&certs[j]); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_init[%d,%d]: %s", (int) i, (int) j, gnutls_strerror (ret)); tmp.data = (unsigned char *) chains[i].chain[j]; tmp.size = strlen (chains[i].chain[j]); ret = gnutls_x509_crt_import (certs[j], &tmp, GNUTLS_X509_FMT_PEM); if (debug > 2) printf ("done\n"); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_import[%d,%d]: %s", (int) i, (int) j, gnutls_strerror (ret)); gnutls_x509_crt_print (certs[j], GNUTLS_CRT_PRINT_ONELINE, &tmp); if (debug) printf ("\tCertificate %d: %.*s\n", (int) j, tmp.size, tmp.data); gnutls_free (tmp.data); } if (debug > 2) printf ("\tAdding CA certificate..."); ret = gnutls_x509_crt_init (&ca); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_init: %s", gnutls_strerror (ret)); tmp.data = (unsigned char *) *chains[i].ca; tmp.size = strlen (*chains[i].ca); ret = gnutls_x509_crt_import (ca, &tmp, GNUTLS_X509_FMT_PEM); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_import: %s", gnutls_strerror (ret)); if (debug > 2) printf ("done\n"); gnutls_x509_crt_print (ca, GNUTLS_CRT_PRINT_ONELINE, &tmp); if (debug) printf ("\tCA Certificate: %.*s\n", tmp.size, tmp.data); gnutls_free (tmp.data); if (debug) printf ("\tVerifying..."); ret = gnutls_x509_crt_list_verify (certs, j, &ca, 1, NULL, 0, chains[i].verify_flags, &verify_status); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_list_verify[%d,%d]: %s", (int) i, (int) j, gnutls_strerror (ret)); if (verify_status != chains[i].expected_verify_result) { fail ("chain[%s]: verify_status: %d expected: %d\n", chains[i].name, verify_status, chains[i].expected_verify_result); #if 0 j = 0; do { fprintf (stderr, "%s\n", chains[i].chain[j]); } while (chains[i].chain[++j] != NULL); #endif if (!debug) exit (1); } else if (debug) printf ("done\n"); if (debug) printf ("\tCleanup..."); gnutls_x509_crt_deinit (ca); for (j = 0; chains[i].chain[j]; j++) gnutls_x509_crt_deinit (certs[j]); if (debug) printf ("done\n\n\n"); } gnutls_global_deinit (); if (debug) printf ("Exit status...%d\n", exit_val); exit (exit_val); }
/*- * gnutls_x509_verify_certificate - This function verifies given certificate list * @cert_list: is the certificate list to be verified * @cert_list_length: holds the number of certificate in cert_list * @CA_list: is the CA list which will be used in verification * @CA_list_length: holds the number of CA certificate in CA_list * @CRL_list: not used * @CRL_list_length: not used * * This function will try to verify the given certificate list and return its status (TRUSTED, EXPIRED etc.). * The return value (status) should be one or more of the gnutls_certificate_status_t * enumerated elements bitwise or'd. Note that expiration and activation dates are not checked * by this function, you should check them using the appropriate functions. * * This function understands the basicConstraints (2.5.29.19) PKIX extension. * This means that only a certificate authority can sign a certificate. * * However you must also check the peer's name in order to check if the verified certificate belongs to the * actual peer. * * The return value (status) should be one or more of the gnutls_certificate_status_t * enumerated elements bitwise or'd. * * GNUTLS_CERT_INVALID: the peer's certificate is not valid. * * GNUTLS_CERT_REVOKED: the certificate has been revoked. * * A negative error code is returned in case of an error. * GNUTLS_E_NO_CERTIFICATE_FOUND is returned to indicate that * no certificate was sent by the peer. * * -*/ int gnutls_x509_verify_certificate (const gnutls_datum_t * cert_list, int cert_list_length, const gnutls_datum_t * CA_list, int CA_list_length, const gnutls_datum_t * CRL_list, int CRL_list_length) { unsigned int verify; gnutls_x509_crt_t *peer_certificate_list = NULL; gnutls_x509_crt_t *ca_certificate_list = NULL; gnutls_x509_crl_t *crl_list = NULL; int peer_certificate_list_size = 0, i, x, ret; int ca_certificate_list_size = 0, crl_list_size = 0; if (cert_list == NULL || cert_list_length == 0) return GNUTLS_E_NO_CERTIFICATE_FOUND; /* generate a list of gnutls_certs based on the auth info * raw certs. */ peer_certificate_list_size = cert_list_length; peer_certificate_list = gnutls_calloc (1, peer_certificate_list_size * sizeof (gnutls_x509_crt_t)); if (peer_certificate_list == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } ca_certificate_list_size = CA_list_length; ca_certificate_list = gnutls_calloc (1, ca_certificate_list_size * sizeof (gnutls_x509_crt_t)); if (ca_certificate_list == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } /* allocate memory for CRL */ crl_list_size = CRL_list_length; crl_list = gnutls_calloc (1, crl_list_size * sizeof (gnutls_x509_crl_t)); if (crl_list == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } /* convert certA_list to gnutls_cert* list */ for (i = 0; i < peer_certificate_list_size; i++) { ret = gnutls_x509_crt_init (&peer_certificate_list[i]); if (ret < 0) { gnutls_assert (); goto cleanup; } ret = gnutls_x509_crt_import (peer_certificate_list[i], &cert_list[i], GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert (); goto cleanup; } } /* convert CA_list to gnutls_x509_cert* list */ for (i = 0; i < ca_certificate_list_size; i++) { ret = gnutls_x509_crt_init (&ca_certificate_list[i]); if (ret < 0) { gnutls_assert (); goto cleanup; } ret = gnutls_x509_crt_import (ca_certificate_list[i], &CA_list[i], GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert (); goto cleanup; } } #ifdef ENABLE_PKI /* convert CRL_list to gnutls_x509_crl* list */ for (i = 0; i < crl_list_size; i++) { ret = gnutls_x509_crl_init (&crl_list[i]); if (ret < 0) { gnutls_assert (); goto cleanup; } ret = gnutls_x509_crl_import (crl_list[i], &CRL_list[i], GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert (); goto cleanup; } } #endif /* Verify certificate */ ret = gnutls_x509_crt_list_verify (peer_certificate_list, peer_certificate_list_size, ca_certificate_list, ca_certificate_list_size, crl_list, crl_list_size, 0, &verify); if (ret < 0) { gnutls_assert (); goto cleanup; } ret = verify; cleanup: if (peer_certificate_list != NULL) for (x = 0; x < peer_certificate_list_size; x++) { if (peer_certificate_list[x] != NULL) gnutls_x509_crt_deinit (peer_certificate_list[x]); } if (ca_certificate_list != NULL) for (x = 0; x < ca_certificate_list_size; x++) { if (ca_certificate_list[x] != NULL) gnutls_x509_crt_deinit (ca_certificate_list[x]); } #ifdef ENABLE_PKI if (crl_list != NULL) for (x = 0; x < crl_list_size; x++) { if (crl_list[x] != NULL) gnutls_x509_crl_deinit (crl_list[x]); } gnutls_free (crl_list); #endif gnutls_free (ca_certificate_list); gnutls_free (peer_certificate_list); return ret; }
void doit (void) { int exit_val = 0; size_t i; int ret; ret = gnutls_global_init (); if (ret != 0) { fail ("%d: %s\n", ret, gnutls_strerror (ret)); exit (EXIT_FAILURE); } gnutls_global_set_log_function (tls_log_func); if (debug) gnutls_global_set_log_level (4711); for (i = 0; chains[i].chain; i++) { unsigned int verify_status; gnutls_x509_crt_t certs[4]; gnutls_x509_crt_t ca; gnutls_datum_t tmp; size_t j; if (debug) printf ("Chain '%s' (%d)...\n", chains[i].name, (int) i); for (j = 0; chains[i].chain[j]; j++) { if (debug) printf ("\tAdding certificate %d...", (int) j); ret = gnutls_x509_crt_init (&certs[j]); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_init[%d,%d]: %s", (int) i, (int) j, gnutls_strerror (ret)); tmp.data = (char *) chains[i].chain[j]; tmp.size = strlen (chains[i].chain[j]); ret = gnutls_x509_crt_import (certs[j], &tmp, GNUTLS_X509_FMT_PEM); if (debug) printf ("done\n"); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_import[%d,%d]: %s", (int) i, (int) j, gnutls_strerror (ret)); gnutls_x509_crt_print (certs[j], GNUTLS_CRT_PRINT_ONELINE, &tmp); if (debug) printf ("\tCertificate %d: %.*s\n", (int) j, tmp.size, tmp.data); gnutls_free (tmp.data); } if (debug) printf ("\tAdding CA certificate..."); ret = gnutls_x509_crt_init (&ca); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_init: %s", gnutls_strerror (ret)); tmp.data = (char *) *chains[i].ca; tmp.size = strlen (*chains[i].ca); ret = gnutls_x509_crt_import (ca, &tmp, GNUTLS_X509_FMT_PEM); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_import: %s", gnutls_strerror (ret)); if (debug) printf ("done\n"); gnutls_x509_crt_print (ca, GNUTLS_CRT_PRINT_ONELINE, &tmp); if (debug) printf ("\tCA Certificate: %.*s\n", tmp.size, tmp.data); gnutls_free (tmp.data); if (debug) printf ("\tVerifying..."); ret = gnutls_x509_crt_list_verify (certs, j, &ca, 1, NULL, 0, chains[i].verify_flags, &verify_status); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_list_verify[%d,%d]: %s", (int) i, (int) j, gnutls_strerror (ret)); if (verify_status != chains[i].expected_verify_result) { fail ("verify_status: %d expected: %d", verify_status, chains[i].expected_verify_result); if (!debug) exit (1); } else if (debug) printf ("done\n"); if (debug) printf ("\tCleanup..."); gnutls_x509_crt_deinit (ca); for (j = 0; chains[i].chain[j]; j++) gnutls_x509_crt_deinit (certs[j]); if (debug) printf ("done\n"); } gnutls_global_deinit (); if (debug) printf ("Exit status...%d\n", exit_val); exit (exit_val); }
/*- * _gnutls_x509_cert_verify_peers - return the peer's certificate status * @session: is a gnutls session * * This function will try to verify the peer's certificate and return its status (TRUSTED, REVOKED etc.). * The return value (status) should be one of the gnutls_certificate_status_t enumerated elements. * However you must also check the peer's name in order to check if the verified certificate belongs to the * actual peer. Returns a negative error code in case of an error, or GNUTLS_E_NO_CERTIFICATE_FOUND if no certificate was sent. -*/ int _gnutls_x509_cert_verify_peers (gnutls_session_t session, unsigned int *status) { cert_auth_info_t info; gnutls_certificate_credentials_t cred; gnutls_x509_crt_t *peer_certificate_list; int peer_certificate_list_size, i, x, ret; CHECK_AUTH (GNUTLS_CRD_CERTIFICATE, GNUTLS_E_INVALID_REQUEST); info = _gnutls_get_auth_info (session); if (info == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } cred = (gnutls_certificate_credentials_t) _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL); if (cred == NULL) { gnutls_assert (); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } if (info->raw_certificate_list == NULL || info->ncerts == 0) return GNUTLS_E_NO_CERTIFICATE_FOUND; if (info->ncerts > cred->verify_depth && cred->verify_depth > 0) { gnutls_assert (); return GNUTLS_E_CONSTRAINT_ERROR; } /* generate a list of gnutls_certs based on the auth info * raw certs. */ peer_certificate_list_size = info->ncerts; peer_certificate_list = gnutls_calloc (peer_certificate_list_size, sizeof (gnutls_x509_crt_t)); if (peer_certificate_list == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } for (i = 0; i < peer_certificate_list_size; i++) { ret = gnutls_x509_crt_init (&peer_certificate_list[i]); if (ret < 0) { gnutls_assert (); CLEAR_CERTS; return ret; } ret = gnutls_x509_crt_import (peer_certificate_list[i], &info->raw_certificate_list[i], GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert (); CLEAR_CERTS; return ret; } if (ret < 0) { gnutls_assert (); CLEAR_CERTS; return ret; } ret = check_bits (peer_certificate_list[i], cred->verify_bits); if (ret < 0) { gnutls_assert (); CLEAR_CERTS; return ret; } } /* Verify certificate */ ret = gnutls_x509_crt_list_verify (peer_certificate_list, peer_certificate_list_size, cred->x509_ca_list, cred->x509_ncas, cred->x509_crl_list, cred->x509_ncrls, cred->verify_flags | session->internals. priorities.additional_verify_flags, status); CLEAR_CERTS; if (ret < 0) { gnutls_assert (); return ret; } return 0; }
int main (int argc, char *argv[]) { int ret; gnutls_x509_crt_t certs[3]; gnutls_x509_crt_t ca; gnutls_x509_crt_t self_cert; gnutls_datum_t tmp; size_t i; unsigned int verify_status; ret = gnutls_global_init (); if (ret != 0) { printf ("%d: %s\n", ret, gnutls_strerror (ret)); return EXIT_FAILURE; } for (i = 0; i < CHAIN_LENGTH; i++) { ret = gnutls_x509_crt_init (&certs[i]); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_init[%d]: %s", (int) i, gnutls_strerror (ret)); tmp.data = (char *) pem_certs[i]; tmp.size = strlen (pem_certs[i]); ret = gnutls_x509_crt_import (certs[i], &tmp, GNUTLS_X509_FMT_PEM); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_import[%d]: %s", (int) i, gnutls_strerror (ret)); } ret = gnutls_x509_crt_init (&ca); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_init: %s", gnutls_strerror (ret)); tmp.data = (char *) pem_ca; tmp.size = strlen (pem_ca); ret = gnutls_x509_crt_import (ca, &tmp, GNUTLS_X509_FMT_PEM); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_import: %s", gnutls_strerror (ret)); ret = gnutls_x509_crt_list_verify (certs, CHAIN_LENGTH, &ca, 1, NULL, 0, GNUTLS_VERIFY_DISABLE_TIME_CHECKS, &verify_status); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_list_verify[%d]: %s", (int) i, gnutls_strerror (ret)); if (verify_status != (GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID)) error (EXIT_FAILURE, 0, "verify_status: %d", verify_status); gnutls_x509_crt_deinit (ca); for (i = 0; i < CHAIN_LENGTH; i++) gnutls_x509_crt_deinit (certs[i]); /* Also test chain length of 1, since the initial patch to solve the problem caused a crash in this situation. */ ret = gnutls_x509_crt_init (&self_cert); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_init: %s", gnutls_strerror (ret)); tmp.data = (char *) pem_self_cert; tmp.size = strlen (pem_self_cert); ret = gnutls_x509_crt_import (self_cert, &tmp, GNUTLS_X509_FMT_PEM); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_import: %s", gnutls_strerror (ret)); ret = gnutls_x509_crt_list_verify (&self_cert, 1, &self_cert, 1, NULL, 0, GNUTLS_VERIFY_DISABLE_TIME_CHECKS, &verify_status); if (ret < 0) error (EXIT_FAILURE, 0, "gnutls_x509_crt_list_verify[%d]: %s", (int) i, gnutls_strerror (ret)); if (verify_status != 0) error (EXIT_FAILURE, 0, "verify_status: %d", verify_status); gnutls_x509_crt_deinit (self_cert); gnutls_global_deinit (); return 0; }