/*- * gnutls_x509_extract_certificate_ca_status - This function returns the certificate CA status * @cert: should contain an X.509 DER encoded certificate * * This function will return certificates CA status, by reading the * basicConstraints X.509 extension. If the certificate is a CA a positive * value will be returned, or zero if the certificate does not have * CA flag set. * * A negative value may be returned in case of parsing error. * If the certificate does not contain the basicConstraints extension * GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned. * -*/ int gnutls_x509_extract_certificate_ca_status (const gnutls_datum_t * cert) { gnutls_x509_crt_t xcert; int result; result = gnutls_x509_crt_init (&xcert); if (result < 0) return result; result = gnutls_x509_crt_import (xcert, cert, GNUTLS_X509_FMT_DER); if (result < 0) { gnutls_x509_crt_deinit (xcert); return result; } result = gnutls_x509_crt_get_ca_status (xcert, NULL); gnutls_x509_crt_deinit (xcert); return result; }
/* * Returns only 0 or 1. If 1 it means that the CRL * was successfuly verified. * * 'flags': an OR of the gnutls_certificate_verify_flags enumeration. * * Output will hold information about the verification * procedure. */ static int _gnutls_verify_crl2 (gnutls_x509_crl_t crl, const gnutls_x509_crt_t * trusted_cas, int tcas_size, unsigned int flags, unsigned int *output) { /* CRL is ignored for now */ gnutls_datum_t crl_signed_data = { NULL, 0 }; gnutls_datum_t crl_signature = { NULL, 0 }; gnutls_x509_crt_t issuer; int result, hash_algo; if (output) *output = 0; if (tcas_size >= 1) issuer = find_crl_issuer (crl, trusted_cas, tcas_size); else { gnutls_assert (); if (output) *output |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID; return 0; } /* issuer is not in trusted certificate * authorities. */ if (issuer == NULL) { gnutls_assert (); if (output) *output |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID; return 0; } if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN)) { if (gnutls_x509_crt_get_ca_status (issuer, NULL) != 1) { gnutls_assert (); if (output) *output |= GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID; return 0; } } result = _gnutls_x509_get_signed_data (crl->crl, "tbsCertList", &crl_signed_data); if (result < 0) { gnutls_assert (); goto cleanup; } result = _gnutls_x509_get_signature (crl->crl, "signature", &crl_signature); if (result < 0) { gnutls_assert (); goto cleanup; } result = _gnutls_x509_get_signature_algorithm(crl->crl, "signatureAlgorithm.algorithm"); if (result < 0) { gnutls_assert (); goto cleanup; } hash_algo = gnutls_sign_get_hash_algorithm(result); result = _gnutls_x509_verify_data (hash_algo, &crl_signed_data, &crl_signature, issuer); if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED) { gnutls_assert (); /* error. ignore it */ if (output) *output |= GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNATURE_FAILURE; result = 0; } else if (result < 0) { gnutls_assert (); goto cleanup; } { int sigalg; sigalg = gnutls_x509_crl_get_signature_algorithm (crl); if (((sigalg == GNUTLS_SIGN_RSA_MD2) && !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) || ((sigalg == GNUTLS_SIGN_RSA_MD5) && !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5))) { if (output) *output |= GNUTLS_CERT_INSECURE_ALGORITHM | GNUTLS_CERT_INVALID; result = 0; } } cleanup: _gnutls_free_datum (&crl_signed_data); _gnutls_free_datum (&crl_signature); return result; }
/* Checks if the issuer of a certificate is a * Certificate Authority, or if the certificate is the same * as the issuer (and therefore it doesn't need to be a CA). * * Returns true or false, if the issuer is a CA, * or not. */ static int check_if_ca (gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer, unsigned int flags) { gnutls_datum_t cert_signed_data = { NULL, 0 }; gnutls_datum_t issuer_signed_data = { NULL, 0 }; gnutls_datum_t cert_signature = { NULL, 0 }; gnutls_datum_t issuer_signature = { NULL, 0 }; int result; /* Check if the issuer is the same with the * certificate. This is added in order for trusted * certificates to be able to verify themselves. */ result = _gnutls_x509_get_signed_data (issuer->cert, "tbsCertificate", &issuer_signed_data); if (result < 0) { gnutls_assert (); goto cleanup; } result = _gnutls_x509_get_signed_data (cert->cert, "tbsCertificate", &cert_signed_data); if (result < 0) { gnutls_assert (); goto cleanup; } result = _gnutls_x509_get_signature (issuer->cert, "signature", &issuer_signature); if (result < 0) { gnutls_assert (); goto cleanup; } result = _gnutls_x509_get_signature (cert->cert, "signature", &cert_signature); if (result < 0) { gnutls_assert (); goto cleanup; } /* If the subject certificate is the same as the issuer * return true. */ if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME)) if (cert_signed_data.size == issuer_signed_data.size) { if ((memcmp (cert_signed_data.data, issuer_signed_data.data, cert_signed_data.size) == 0) && (cert_signature.size == issuer_signature.size) && (memcmp (cert_signature.data, issuer_signature.data, cert_signature.size) == 0)) { result = 1; goto cleanup; } } result = gnutls_x509_crt_get_ca_status (issuer, NULL); if (result == 1) { result = 1; goto cleanup; } /* Handle V1 CAs that do not have a basicConstraint, but accept these certs only if the appropriate flags are set. */ else if ((result == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) && ((flags & GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT) || (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_X509_V1_CA_CRT) && (gnutls_x509_crt_check_issuer (issuer, issuer) == 1)))) { gnutls_assert (); result = 1; goto cleanup; } else gnutls_assert (); result = 0; cleanup: _gnutls_free_datum (&cert_signed_data); _gnutls_free_datum (&issuer_signed_data); _gnutls_free_datum (&cert_signature); _gnutls_free_datum (&issuer_signature); return result; }
/** * gnutls_x509_crl_verify: * @crl: is the crl to be verified * @trusted_cas: is a certificate list that is considered to be trusted one * @tcas_size: holds the number of CA certificates in CA_list * @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations. * @verify: will hold the crl verification output. * * This function will try to verify the given crl and return its verification status. * See gnutls_x509_crt_list_verify() for a detailed description of * return values. Note that since GnuTLS 3.1.4 this function includes * the time checks. * * Note that value in @verify is set only when the return value of this * function is success (i.e, failure to trust a CRL a certificate does not imply * a negative return value). * * Before GnuTLS 3.5.7 this function would return zero or a positive * number on success. * * Returns: On success, %GNUTLS_E_SUCCESS (0), otherwise a * negative error value. **/ int gnutls_x509_crl_verify(gnutls_x509_crl_t crl, const gnutls_x509_crt_t * trusted_cas, unsigned tcas_size, unsigned int flags, unsigned int *verify) { /* CRL is ignored for now */ gnutls_datum_t crl_signed_data = { NULL, 0 }; gnutls_datum_t crl_signature = { NULL, 0 }; gnutls_x509_crt_t issuer = NULL; int result, hash_algo; time_t now = gnutls_time(0); unsigned int usage; if (verify) *verify = 0; if (tcas_size >= 1) issuer = find_crl_issuer(crl, trusted_cas, tcas_size); result = _gnutls_x509_get_signed_data(crl->crl, &crl->der, "tbsCertList", &crl_signed_data); if (result < 0) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_INVALID; goto cleanup; } result = _gnutls_x509_get_signature(crl->crl, "signature", &crl_signature); if (result < 0) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_INVALID; goto cleanup; } result = _gnutls_x509_get_signature_algorithm(crl->crl, "signatureAlgorithm.algorithm"); if (result < 0) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_INVALID; goto cleanup; } hash_algo = gnutls_sign_get_hash_algorithm(result); /* issuer is not in trusted certificate * authorities. */ if (issuer == NULL) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID; } else { if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN)) { if (gnutls_x509_crt_get_ca_status(issuer, NULL) != 1) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID; } result = gnutls_x509_crt_get_key_usage(issuer, &usage, NULL); if (result != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { if (result < 0) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_INVALID; } else if (!(usage & GNUTLS_KEY_CRL_SIGN)) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE | GNUTLS_CERT_INVALID; } } } result = _gnutls_x509_verify_data(mac_to_entry(hash_algo), &crl_signed_data, &crl_signature, issuer); if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED) { gnutls_assert(); /* error. ignore it */ if (verify) *verify |= GNUTLS_CERT_SIGNATURE_FAILURE; result = 0; } else if (result < 0) { gnutls_assert(); if (verify) *verify |= GNUTLS_CERT_INVALID; goto cleanup; } else if (result >= 0) { result = 0; /* everything ok */ } } { int sigalg; sigalg = gnutls_x509_crl_get_signature_algorithm(crl); if (((sigalg == GNUTLS_SIGN_RSA_MD2) && !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) || ((sigalg == GNUTLS_SIGN_RSA_MD5) && !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5))) { if (verify) *verify |= GNUTLS_CERT_INSECURE_ALGORITHM; result = 0; } } if (gnutls_x509_crl_get_this_update(crl) > now && verify) *verify |= GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE; if (gnutls_x509_crl_get_next_update(crl) < now && verify) *verify |= GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED; cleanup: if (verify && *verify != 0) *verify |= GNUTLS_CERT_INVALID; _gnutls_free_datum(&crl_signed_data); _gnutls_free_datum(&crl_signature); return result; }
/** * gnutls_x509_trust_list_add_cas: * @list: The structure of the list * @clist: A list of CAs * @clist_size: The length of the CA list * @flags: should be 0 or an or'ed sequence of %GNUTLS_TL options. * * This function will add the given certificate authorities * to the trusted list. The list of CAs must not be deinitialized * during this structure's lifetime. * * If the flag %GNUTLS_TL_NO_DUPLICATES is specified, then * the provided @clist entries that are duplicates will not be * added to the list and will be deinitialized. * * Returns: The number of added elements is returned. * * Since: 3.0.0 **/ int gnutls_x509_trust_list_add_cas(gnutls_x509_trust_list_t list, const gnutls_x509_crt_t * clist, unsigned clist_size, unsigned int flags) { unsigned i, j; uint32_t hash; int ret; unsigned exists; for (i = 0; i < clist_size; i++) { exists = 0; hash = hash_pjw_bare(clist[i]->raw_dn.data, clist[i]->raw_dn.size); hash %= list->size; /* avoid duplicates */ if (flags & GNUTLS_TL_NO_DUPLICATES || flags & GNUTLS_TL_NO_DUPLICATE_KEY) { for (j=0;j<list->node[hash].trusted_ca_size;j++) { if (flags & GNUTLS_TL_NO_DUPLICATES) ret = _gnutls_check_if_same_cert(list->node[hash].trusted_cas[j], clist[i]); else ret = _gnutls_check_if_same_key(list->node[hash].trusted_cas[j], clist[i], 1); if (ret != 0) { exists = 1; break; } } if (exists != 0) { gnutls_x509_crt_deinit(list->node[hash].trusted_cas[j]); list->node[hash].trusted_cas[j] = clist[i]; continue; } } list->node[hash].trusted_cas = gnutls_realloc_fast(list->node[hash].trusted_cas, (list->node[hash].trusted_ca_size + 1) * sizeof(list->node[hash]. trusted_cas[0])); if (list->node[hash].trusted_cas == NULL) { gnutls_assert(); return i; } if (gnutls_x509_crt_get_version(clist[i]) >= 3 && gnutls_x509_crt_get_ca_status(clist[i], NULL) <= 0) { gnutls_datum_t dn; gnutls_assert(); if (gnutls_x509_crt_get_dn2(clist[i], &dn) >= 0) { _gnutls_audit_log(NULL, "There was a non-CA certificate in the trusted list: %s.\n", dn.data); gnutls_free(dn.data); } } list->node[hash].trusted_cas[list->node[hash]. trusted_ca_size] = clist[i]; list->node[hash].trusted_ca_size++; if (flags & GNUTLS_TL_USE_IN_TLS) { ret = add_new_ca_to_rdn_seq(list, clist[i]); if (ret < 0) { gnutls_assert(); return i; } } } return i; }
bool Certificate::isCA() const { unsigned critical; return gnutls_x509_crt_get_ca_status(cert, &critical) > 0; }
void empathy_tls_certificate_store_ca (EmpathyTLSCertificate *self) { GArray *last_cert; gnutls_x509_crt_t cert; gnutls_datum_t datum = { NULL, 0 }; gsize exported_len; guchar *exported_cert = NULL; gint res, offset; gchar *user_certs_dir = NULL, *filename = NULL, *path = NULL; gchar *hostname = NULL; GError *error = NULL; EmpathyTLSCertificatePriv *priv = GET_PRIV (self); last_cert = g_ptr_array_index (priv->cert_data, priv->cert_data->len - 1); datum.data = (guchar *) last_cert->data; datum.size = last_cert->len; gnutls_x509_crt_init (&cert); gnutls_x509_crt_import (cert, &datum, GNUTLS_X509_FMT_DER); /* make sure it's self-signed, otherwise it's not a CA */ if (gnutls_x509_crt_check_issuer (cert, cert) <= 0) { DEBUG ("Can't import the CA, as it's not self-signed"); gnutls_x509_crt_deinit (cert); return; } if (gnutls_x509_crt_get_ca_status (cert, NULL) <= 0) { DEBUG ("Can't import the CA, it's not a valid CA certificate"); gnutls_x509_crt_deinit (cert); goto out; } exported_len = get_exported_size (cert); exported_cert = g_malloc (sizeof (guchar) * exported_len); res = gnutls_x509_crt_export (cert, GNUTLS_X509_FMT_PEM, exported_cert, &exported_len); if (res < 0) { DEBUG ("Failed to export the CA certificate; GnuTLS returned %d," "and should be %lu bytes long", res, (gulong) exported_len); gnutls_x509_crt_deinit (cert); goto out; } hostname = empathy_get_x509_certificate_hostname (cert); if (hostname == NULL) hostname = g_strdup ("ca"); gnutls_x509_crt_deinit (cert); /* write the file */ user_certs_dir = g_build_filename (g_get_user_config_dir (), "telepathy", "certs", NULL); res = g_mkdir_with_parents (user_certs_dir, S_IRWXU | S_IRWXG); if (res < 0) { DEBUG ("Failed to create the user certificate directory: %s", g_strerror (errno)); goto out; } offset = 0; do { g_free (path); if (offset == 0) filename = g_strdup_printf ("cert-%s", hostname); else filename = g_strdup_printf ("cert-%s-%d", hostname, offset); path = g_build_filename (user_certs_dir, filename, NULL); offset++; g_free (filename); } while (g_file_test (path, G_FILE_TEST_EXISTS)); DEBUG ("Will save to %s", path); g_file_set_contents (path, (const gchar *) exported_cert, exported_len, &error); if (error != NULL) { DEBUG ("Can't save the CA certificate to %s: %s", path, error->message); g_error_free (error); } out: g_free (path); g_free (exported_cert); g_free (user_certs_dir); g_free (hostname); }
void doit(void) { int ret; gnutls_x509_crt_t crt, ocrt; unsigned keyusage; const char *lib; ret = global_init(); if (ret != 0) { fail("%d: %s\n", ret, gnutls_strerror(ret)); exit(1); } lib = getenv("P11MOCKLIB1"); if (lib == NULL) lib = P11LIB; gnutls_global_set_time_function(mytime); if (debug) { gnutls_global_set_log_level(4711); success("loading lib %s\n", lib); } ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); if (ret != 0) { fail("%d: %s\n", ret, gnutls_strerror(ret)); exit(1); } ret = gnutls_pkcs11_add_provider(lib, "trusted"); if (ret != 0) { fail("%d: %s\n", ret, gnutls_strerror(ret)); exit(1); } assert(gnutls_x509_crt_init(&crt)>=0); assert(gnutls_x509_crt_init(&ocrt)>=0); /* check high level certificate functions */ ret = gnutls_x509_crt_import_url(crt, "pkcs11:type=cert;object=cert1", 0); if (ret < 0) { fail("%d: %s\n", ret, gnutls_strerror(ret)); exit(1); } ret = gnutls_x509_crt_import_url(ocrt, "pkcs11:type=cert;object=cert1", GNUTLS_PKCS11_OBJ_FLAG_OVERWRITE_TRUSTMOD_EXT); if (ret < 0) { fail("%d: %s\n", ret, gnutls_strerror(ret)); exit(1); } ret = gnutls_x509_crt_equals(crt, ocrt); if (ret != 0) { fail("exported certificates are equal!\n"); } ret = gnutls_x509_crt_get_ca_status(ocrt, NULL); if (ret < 0) { fail("%d: %s\n", ret, gnutls_strerror(ret)); exit(1); } if (ret == 0) { fail("overriden cert is not a CA!\n"); exit(1); } ret = gnutls_x509_crt_get_key_usage(ocrt, &keyusage, NULL); if (ret < 0) { fail("%d: %s\n", ret, gnutls_strerror(ret)); exit(1); } if (keyusage != (GNUTLS_KEY_KEY_ENCIPHERMENT|GNUTLS_KEY_ENCIPHER_ONLY|GNUTLS_KEY_KEY_CERT_SIGN)) { fail("Extension does not have the expected key usage!\n"); } gnutls_x509_crt_deinit(crt); gnutls_x509_crt_deinit(ocrt); if (debug) printf("done\n\n\n"); gnutls_global_deinit(); }