/** * gnutls_store_pubkey: * @db_name: A file specifying the stored keys (use NULL for the default) * @tdb: A storage structure or NULL to use the default * @host: The peer's name * @service: non-NULL if this key is specific to a service (e.g. http) * @cert_type: The type of the certificate * @cert: The data of the certificate * @expiration: The expiration time (use 0 to disable expiration) * @flags: should be 0. * * This function will store the provided certificate to * the list of stored public keys. The key will be considered valid until * the provided expiration time. * * The @store variable if non-null specifies a custom backend for * the storage of entries. If it is NULL then the * default file backend will be used. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.0 **/ int gnutls_store_pubkey(const char* db_name, gnutls_tdb_t tdb, const char* host, const char* service, gnutls_certificate_type_t cert_type, const gnutls_datum_t * cert, time_t expiration, unsigned int flags) { FILE* fd = NULL; gnutls_datum_t pubkey = { NULL, 0 }; int ret; char local_file[MAX_FILENAME]; if (cert_type != GNUTLS_CRT_X509 && cert_type != GNUTLS_CRT_OPENPGP) return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE); if (db_name == NULL && tdb == NULL) { ret = _gnutls_find_config_path(local_file, sizeof(local_file)); if (ret < 0) return gnutls_assert_val(ret); _gnutls_debug_log("Configuration path: %s\n", local_file); mkdir(local_file, 0700); ret = find_config_file(local_file, sizeof(local_file)); if (ret < 0) return gnutls_assert_val(ret); db_name = local_file; } if (tdb == NULL) tdb = &default_tdb; if (cert_type == GNUTLS_CRT_X509) ret = x509_crt_to_raw_pubkey(cert, &pubkey); else ret = pgp_crt_to_raw_pubkey(cert, &pubkey); if (ret < 0) { gnutls_assert(); goto cleanup; } _gnutls_debug_log("Configuration file: %s\n", db_name); tdb->store(db_name, host, service, expiration, &pubkey); ret = 0; cleanup: gnutls_free(pubkey.data); if (fd != NULL) fclose(fd); return ret; }
/** * gnutls_verify_stored_pubkey: * @db_name: A file specifying the stored keys (use NULL for the default) * @tdb: A storage structure or NULL to use the default * @host: The peer's name * @service: non-NULL if this key is specific to a service (e.g. http) * @cert_type: The type of the certificate * @cert: The raw (der) data of the certificate * @flags: should be 0. * * This function will try to verify the provided (raw or DER-encoded) certificate * using a list of stored public keys. The @service field if non-NULL should * be a port number. * * The @retrieve variable if non-null specifies a custom backend for * the retrieval of entries. If it is NULL then the * default file backend will be used. In POSIX-like systems the * file backend uses the $HOME/.gnutls/known_hosts file. * * Note that if the custom storage backend is provided the * retrieval function should return %GNUTLS_E_CERTIFICATE_KEY_MISMATCH * if the host/service pair is found but key doesn't match, * %GNUTLS_E_NO_CERTIFICATE_FOUND if no such host/service with * the given key is found, and 0 if it was found. The storage * function should return 0 on success. * * Returns: If no associated public key is found * then %GNUTLS_E_NO_CERTIFICATE_FOUND will be returned. If a key * is found but does not match %GNUTLS_E_CERTIFICATE_KEY_MISMATCH * is returned. On success, %GNUTLS_E_SUCCESS (0) is returned, * or a negative error value on other errors. * * Since: 3.0.13 **/ int gnutls_verify_stored_pubkey(const char *db_name, gnutls_tdb_t tdb, const char *host, const char *service, gnutls_certificate_type_t cert_type, const gnutls_datum_t * cert, unsigned int flags) { gnutls_datum_t pubkey = { NULL, 0 }; int ret; char local_file[MAX_FILENAME]; if (cert_type != GNUTLS_CRT_X509 && cert_type != GNUTLS_CRT_OPENPGP) return gnutls_assert_val (GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE); if (db_name == NULL && tdb == NULL) { ret = find_config_file(local_file, sizeof(local_file)); if (ret < 0) return gnutls_assert_val(ret); db_name = local_file; } if (tdb == NULL) tdb = &default_tdb; if (cert_type == GNUTLS_CRT_X509) ret = x509_crt_to_raw_pubkey(cert, &pubkey); else ret = pgp_crt_to_raw_pubkey(cert, &pubkey); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = tdb->verify(db_name, host, service, &pubkey); if (ret < 0 && ret != GNUTLS_E_CERTIFICATE_KEY_MISMATCH) ret = gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND); cleanup: gnutls_free(pubkey.data); return ret; }
/* Converts an X.509 certificate to subjectPublicKeyInfo */ int x509_raw_crt_to_raw_pubkey(const gnutls_datum_t * cert, gnutls_datum_t * rpubkey) { gnutls_x509_crt_t crt = NULL; int ret; ret = gnutls_x509_crt_init(&crt); if (ret < 0) return gnutls_assert_val(ret); ret = gnutls_x509_crt_import(crt, cert, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = x509_crt_to_raw_pubkey(crt, rpubkey); cleanup: gnutls_x509_crt_deinit(crt); return ret; }
/** * gnutls_pkcs11_copy_attached_extension: * @token_url: A PKCS #11 URL specifying a token * @crt: An X.509 certificate object * @data: the attached extension * @label: A name to be used for the attached extension (may be %NULL) * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_* * * This function will copy an the attached extension in @data for * the certificate provided in @crt in the PKCS #11 token specified * by the URL (typically a trust module). The extension must be in * RFC5280 Extension format. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.3.8 **/ int gnutls_pkcs11_copy_attached_extension(const char *token_url, gnutls_x509_crt_t crt, gnutls_datum_t *data, const char *label, unsigned int flags) { int ret; struct p11_kit_uri *info = NULL; ck_rv_t rv; struct ck_attribute a[MAX_ASIZE]; ck_object_handle_t ctx; unsigned a_vals; struct pkcs11_session_info sinfo; ck_object_class_t class; gnutls_datum_t spki = {NULL, 0}; PKCS11_CHECK_INIT; ret = pkcs11_url_to_info(token_url, &info, 0); if (ret < 0) { gnutls_assert(); return ret; } ret = pkcs11_open_session(&sinfo, NULL, info, SESSION_WRITE | pkcs11_obj_flags_to_int(flags)); p11_kit_uri_free(info); if (ret < 0) { gnutls_assert(); return ret; } ret = x509_crt_to_raw_pubkey(crt, &spki); if (ret < 0) { gnutls_assert(); goto cleanup; } class = CKO_X_CERTIFICATE_EXTENSION; a_vals = 0; a[a_vals].type = CKA_CLASS; a[a_vals].value = &class; a[a_vals++].value_len = sizeof(class); a[a_vals].type = CKA_PUBLIC_KEY_INFO; a[a_vals].value = spki.data; a[a_vals++].value_len = spki.size; a[a_vals].type = CKA_VALUE; a[a_vals].value = data->data; a[a_vals++].value_len = data->size; a[a_vals].type = CKA_TOKEN; a[a_vals].value = (void *) &tval; a[a_vals++].value_len = sizeof(tval); if (label) { a[a_vals].type = CKA_LABEL; a[a_vals].value = (void *) label; a[a_vals++].value_len = strlen(label); } rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_vals, &ctx); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); ret = pkcs11_rv_to_err(rv); goto cleanup; } ret = 0; cleanup: pkcs11_close_session(&sinfo); gnutls_free(spki.data); return ret; }