static int qcrypto_tls_creds_check_cert_key_usage(QCryptoTLSCredsX509 *creds, gnutls_x509_crt_t cert, const char *certFile, bool isCA, Error **errp) { int status; unsigned int usage = 0; unsigned int critical = 0; status = gnutls_x509_crt_get_key_usage(cert, &usage, &critical); trace_qcrypto_tls_creds_x509_check_key_usage( creds, certFile, status, usage, critical); if (status < 0) { if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { usage = isCA ? GNUTLS_KEY_KEY_CERT_SIGN : GNUTLS_KEY_DIGITAL_SIGNATURE|GNUTLS_KEY_KEY_ENCIPHERMENT; } else { error_setg(errp, "Unable to query certificate %s key usage: %s", certFile, gnutls_strerror(status)); return -1; } } if (isCA) { if (!(usage & GNUTLS_KEY_KEY_CERT_SIGN)) { if (critical) { error_setg(errp, "Certificate %s usage does not permit " "certificate signing", certFile); return -1; } } } else { if (!(usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { if (critical) { error_setg(errp, "Certificate %s usage does not permit digital " "signature", certFile); return -1; } } if (!(usage & GNUTLS_KEY_KEY_ENCIPHERMENT)) { if (critical) { error_setg(errp, "Certificate %s usage does not permit key " "encipherment", certFile); return -1; } } } return 0; }
void __certificate_properties_fill_cert_ext_KeyUsage (GtkTreeStore *store, GtkTreeIter *parent, gnutls_x509_crt_t *certificate) { guint critical; guint key_usage; gint result; gchar * buffer = NULL; GtkTreeIter l; result = gnutls_x509_crt_get_key_usage(*certificate, &key_usage, &critical); if (result < 0) { fprintf(stderr, "Error: %s\n", gnutls_strerror(result)); return; } buffer = __certificate_properties_dump_key_usage(key_usage); gtk_tree_store_append(store, &l, parent); gtk_tree_store_set(store, &l, CERTIFICATE_PROPERTIES_COL_NAME, _("Value"), CERTIFICATE_PROPERTIES_COL_VALUE, buffer, -1); g_free(buffer); }
/** * gnutls_pubkey_import_x509: * @key: The public key * @crt: The certificate to be imported * @flags: should be zero * * This function will import the given public key to the abstract * #gnutls_pubkey_t type. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 2.12.0 **/ int gnutls_pubkey_import_x509(gnutls_pubkey_t key, gnutls_x509_crt_t crt, unsigned int flags) { int ret; gnutls_pk_params_release(&key->params); /* params initialized in _gnutls_x509_crt_get_mpis */ key->pk_algorithm = gnutls_x509_crt_get_pk_algorithm(crt, &key->bits); ret = gnutls_x509_crt_get_key_usage(crt, &key->key_usage, NULL); if (ret < 0) key->key_usage = 0; ret = _gnutls_x509_crt_get_mpis(crt, &key->params); if (ret < 0) { gnutls_assert(); return ret; } return 0; }
/* * Verifies the given certificate against a certificate list of * trusted CAs. * * Returns only 0 or 1. If 1 it means that the certificate * was successfuly verified. * * 'flags': an OR of the gnutls_certificate_verify_flags enumeration. * * 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) { gnutls_datum_t cert_signed_data = { NULL, 0 }; gnutls_datum_t cert_signature = { NULL, 0 }; gnutls_x509_crt_t issuer = NULL; int issuer_version, hash_algo; unsigned result = 1; const mac_entry_st * me; unsigned int out = 0, usage; int sigalg, ret; if (output) *output = 0; if (vparams->max_path == 0) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); /* bail immediately, to avoid inconistency */ goto cleanup; } vparams->max_path--; if (tcas_size >= 1) issuer = find_issuer(cert, trusted_cas, tcas_size); ret = _gnutls_x509_get_signed_data(cert->cert, &cert->der, "tbsCertificate", &cert_signed_data); if (ret < 0) { MARK_INVALID(0); cert_signed_data.data = NULL; } ret = _gnutls_x509_get_signature(cert->cert, "signature", &cert_signature); if (ret < 0) { MARK_INVALID(0); cert_signature.data = NULL; } ret = _gnutls_x509_get_signature_algorithm(cert->cert, "signatureAlgorithm.algorithm"); if (ret < 0) { MARK_INVALID(0); } sigalg = ret; /* issuer is not in trusted certificate * authorities. */ if (issuer == NULL) { MARK_INVALID(GNUTLS_CERT_SIGNER_NOT_FOUND); } else { if (vparams->nc != NULL) { /* append the issuer's constraints */ 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); goto nc_done; } /* only check name constraints in server certificates, not CAs */ if (end_cert != 0) { ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_DNSNAME, cert); if (ret == 0) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); goto nc_done; } ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_RFC822NAME, cert); if (ret == 0) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); goto nc_done; } ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_DN, cert); if (ret == 0) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); goto nc_done; } ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_URI, cert); if (ret == 0) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); goto nc_done; } ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_IPADDRESS, cert); if (ret == 0) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); goto nc_done; } } } nc_done: if (vparams->tls_feat != NULL) { /* append the issuer's constraints */ ret = gnutls_x509_crt_get_tlsfeatures(issuer, vparams->tls_feat, GNUTLS_EXT_FLAG_APPEND, NULL); if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); goto feat_done; } ret = gnutls_x509_tlsfeatures_check_crt(vparams->tls_feat, cert); if (ret == 0) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); goto feat_done; } } feat_done: issuer_version = gnutls_x509_crt_get_version(issuer); if (issuer_version < 0) { MARK_INVALID(0); } else if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN) && ((flags & GNUTLS_VERIFY_DO_NOT_ALLOW_X509_V1_CA_CRT) || issuer_version != 1)) { if (check_if_ca(cert, issuer, &vparams->max_path, flags) != 1) { MARK_INVALID(GNUTLS_CERT_SIGNER_NOT_CA); } ret = gnutls_x509_crt_get_key_usage(issuer, &usage, NULL); if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { if (ret < 0) { MARK_INVALID(0); } else if (!(usage & GNUTLS_KEY_KEY_CERT_SIGN)) { MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE); } } } if (sigalg >= 0) { hash_algo = gnutls_sign_get_hash_algorithm(sigalg); me = mac_to_entry(hash_algo); } else { me = NULL; } if (me == NULL) { MARK_INVALID(0); } else if (cert_signed_data.data != NULL && cert_signature.data != NULL) { ret = _gnutls_x509_verify_data(me, &cert_signed_data, &cert_signature, issuer); if (ret == GNUTLS_E_PK_SIG_VERIFY_FAILED) { MARK_INVALID(GNUTLS_CERT_SIGNATURE_FAILURE); } else if (ret < 0) { MARK_INVALID(0); } } } /* we always check the issuer for unsupported critical extensions */ if (issuer && check_for_unknown_exts(issuer) != 0) { if (!(flags & GNUTLS_VERIFY_IGNORE_UNKNOWN_CRIT_EXTENSIONS)) { MARK_INVALID(GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS); } } /* we only check the end-certificate for critical extensions; that * way do not perform this check twice on the certificates when * verifying a large list */ if (end_cert && check_for_unknown_exts(cert) != 0) { if (!(flags & GNUTLS_VERIFY_IGNORE_UNKNOWN_CRIT_EXTENSIONS)) { MARK_INVALID(GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS); } } if (sigalg >= 0) { if (is_level_acceptable(cert, issuer, sigalg, flags) == 0) { MARK_INVALID(GNUTLS_CERT_INSECURE_ALGORITHM); } /* If the certificate is not self signed check if the algorithms * used are secure. If the certificate is self signed it doesn't * really matter. */ if (gnutls_sign_is_secure(sigalg) == 0 && _gnutls_is_broken_sig_allowed(sigalg, flags) == 0 && is_issuer(cert, cert) == 0) { MARK_INVALID(GNUTLS_CERT_INSECURE_ALGORITHM); } } /* Check activation/expiration times */ if (!(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) { /* check the time of the issuer first */ if (issuer != NULL && !(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS)) { out |= check_time_status(issuer, vparams->now); if (out != 0) { gnutls_assert(); result = 0; } } out |= check_time_status(cert, vparams->now); if (out != 0) { gnutls_assert(); result = 0; } } cleanup: if (output) *output |= out; if (vparams->func) { if (result == 0) { out |= GNUTLS_CERT_INVALID; } vparams->func(cert, issuer, NULL, out); } _gnutls_free_datum(&cert_signed_data); _gnutls_free_datum(&cert_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; }
/* Like above but it accepts a parsed certificate instead. */ int _gnutls_x509_crt_to_gcert (gnutls_cert * gcert, gnutls_x509_crt_t cert, unsigned int flags) { int ret = 0; memset (gcert, 0, sizeof (gnutls_cert)); gcert->cert_type = GNUTLS_CRT_X509; if (!(flags & CERT_NO_COPY)) { #define SMALL_DER 512 opaque *der; size_t der_size = SMALL_DER; /* initially allocate a bogus size, just in case the certificate * fits in it. That way we minimize the DER encodings performed. */ der = gnutls_malloc (SMALL_DER); if (der == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = gnutls_x509_crt_export (cert, GNUTLS_X509_FMT_DER, der, &der_size); if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { gnutls_assert (); gnutls_free (der); return ret; } if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { der = gnutls_realloc (der, der_size); if (der == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = gnutls_x509_crt_export (cert, GNUTLS_X509_FMT_DER, der, &der_size); if (ret < 0) { gnutls_assert (); gnutls_free (der); return ret; } } gcert->raw.data = der; gcert->raw.size = der_size; } else /* now we have 0 or a bitwise or of things to decode */ flags ^= CERT_NO_COPY; if (flags & CERT_ONLY_EXTENSIONS || flags == 0) { gnutls_x509_crt_get_key_usage (cert, &gcert->key_usage, NULL); gcert->version = gnutls_x509_crt_get_version (cert); } gcert->subject_pk_algorithm = gnutls_x509_crt_get_pk_algorithm (cert, NULL); if (flags & CERT_ONLY_PUBKEY || flags == 0) { gcert->params_size = MAX_PUBLIC_PARAMS_SIZE; ret = _gnutls_x509_crt_get_mpis (cert, gcert->params, &gcert->params_size); if (ret < 0) { gnutls_assert (); return ret; } } return 0; }
void pkcs11_write(FILE * outfile, const char *url, const char *label, const char *id, unsigned flags, common_info_st * info) { gnutls_x509_crt_t xcrt; gnutls_x509_privkey_t xkey; gnutls_pubkey_t xpubkey; int ret; gnutls_datum_t *secret_key; unsigned key_usage = 0; unsigned char raw_id[128]; size_t raw_id_size; gnutls_datum_t cid = {NULL, 0}; pkcs11_common(info); FIX(url, outfile, 0, info); CHECK_LOGIN_FLAG(flags); if (label == NULL && info->batch == 0) { label = read_str("warning: The object's label was not specified.\nLabel: "); } if (id != NULL) { raw_id_size = sizeof(raw_id); ret = gnutls_hex2bin(id, strlen(id), raw_id, &raw_id_size); if (ret < 0) { fprintf(stderr, "Error converting hex: %s\n", gnutls_strerror(ret)); exit(1); } cid.data = raw_id; cid.size = raw_id_size; } secret_key = load_secret_key(0, info); if (secret_key != NULL) { ret = gnutls_pkcs11_copy_secret_key(url, secret_key, label, info->key_usage, flags | GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE); if (ret < 0) { fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror(ret)); exit(1); } } xcrt = load_cert(0, info); if (xcrt != NULL) { ret = gnutls_pkcs11_copy_x509_crt2(url, xcrt, label, &cid, flags); if (ret < 0) { fprintf(stderr, "Error writing certificate: %s\n", gnutls_strerror(ret)); if (((flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_CA) || (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED)) && (flags & GNUTLS_PKCS11_OBJ_FLAG_LOGIN_SO) == 0) fprintf(stderr, "note: some tokens may require security officer login for this operation\n"); exit(1); } gnutls_x509_crt_get_key_usage(xcrt, &key_usage, NULL); gnutls_x509_crt_deinit(xcrt); } xkey = load_x509_private_key(0, info); if (xkey != NULL) { ret = gnutls_pkcs11_copy_x509_privkey2(url, xkey, label, &cid, key_usage|info->key_usage, flags | GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE); if (ret < 0) { fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror(ret)); exit(1); } gnutls_x509_privkey_deinit(xkey); } xpubkey = load_pubkey(0, info); if (xpubkey != NULL) { ret = gnutls_pkcs11_copy_pubkey(url, xpubkey, label, &cid, 0, flags); if (ret < 0) { fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror(ret)); exit(1); } gnutls_pubkey_deinit(xpubkey); } if (xkey == NULL && xcrt == NULL && secret_key == NULL && xpubkey == NULL) { fprintf(stderr, "You must use --load-privkey, --load-certificate, --load-pubkey or --secret-key to load the file to be copied\n"); exit(1); } UNFIX; return; }
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(); }