static void real_start_verification(HevImpathyTLSVerifier *self) { HevImpathyTLSVerifierPrivate *priv = HEV_IMPATHY_TLS_VERIFIER_GET_PRIVATE(self); gnutls_x509_crt_t first_cert = 0, last_cert = 0; gint idx = 0; gboolean res = FALSE; gint num_certs = 0; TpTLSCertificateRejectReason reason = TP_TLS_CERTIFICATE_REJECT_REASON_UNKNOWN; g_debug("%s:%d[%s]", __FILE__, __LINE__, __FUNCTION__); /* check if the certificate matches the hostname first. */ first_cert = g_ptr_array_index(priv->cert_chain, 0); if(0 == gnutls_x509_crt_check_hostname(first_cert, priv->hostname)) { gchar *certified_hostname = NULL; reason = TP_TLS_CERTIFICATE_REJECT_REASON_HOSTNAME_MISMATCH; certified_hostname = (gchar *)hev_impathy_get_x509_certificate_hostname(first_cert); tp_asv_set_string(priv->details, "expected-hostname", priv->hostname); tp_asv_set_string(priv->details, "certificate-hostname", certified_hostname); g_free(certified_hostname); goto out; } num_certs = priv->cert_chain->len; if(0 < priv->trusted_ca_list->len) { /* if the last certificate is self-signed, and we have a list of * trusted CAs, ignore it, as we want to check the chain against our * trusted CAs list first. * if we have only one certificate in the chain, don't ignore it though, * as it's the CA certificate itself. */ last_cert = g_ptr_array_index(priv->cert_chain, num_certs - 1); if((0<gnutls_x509_crt_check_issuer(last_cert, last_cert)) && (1<num_certs)) num_certs --; } for (idx = 1; idx < num_certs; idx++) { res = verify_certificate(self, g_ptr_array_index(priv->cert_chain, idx-1), g_ptr_array_index(priv->cert_chain, idx), &reason); if(!res) { abort_verification(self, reason); return; } } res = verify_last_certificate(self, g_ptr_array_index(priv->cert_chain, num_certs - 1), &reason); out: if(!res) { abort_verification(self, reason); return; } complete_verification(self); }
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); }