static int _dsa_params_generate(struct ck_function_list *module, ck_session_handle_t session, unsigned long bits, struct dsa_params *params, struct ck_attribute *a, int *a_val) { struct ck_mechanism mech = { CKM_DSA_PARAMETER_GEN }; struct ck_attribute attr = { CKA_PRIME_BITS, &bits, sizeof(bits) }; ck_object_handle_t key; ck_rv_t rv; /* Generate DSA parameters from prime length. */ rv = pkcs11_generate_key(module, session, &mech, &attr, 1, &key); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); return pkcs11_rv_to_err(rv); } /* Retrieve generated parameters to be used with the new key pair. */ a[*a_val + 0].type = CKA_PRIME; a[*a_val + 0].value = params->prime; a[*a_val + 0].value_len = sizeof(params->prime); a[*a_val + 1].type = CKA_SUBPRIME; a[*a_val + 1].value = params->subprime; a[*a_val + 1].value_len = sizeof(params->subprime); a[*a_val + 2].type = CKA_BASE; a[*a_val + 2].value = params->generator; a[*a_val + 2].value_len = sizeof(params->generator); rv = pkcs11_get_attribute_value(module, session, key, &a[*a_val], 3); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); return pkcs11_rv_to_err(rv); } *a_val += 3; return 0; }
/** * gnutls_pkcs11_privkey_import_url: * @pkey: The private key * @url: a PKCS 11 url identifying the key * @flags: Or sequence of GNUTLS_PKCS11_OBJ_* flags * * This function will "import" a PKCS 11 URL identifying a private * key to the #gnutls_pkcs11_privkey_t type. In reality since * in most cases keys cannot be exported, the private key structure * is being associated with the available operations on the token. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_pkcs11_privkey_import_url(gnutls_pkcs11_privkey_t pkey, const char *url, unsigned int flags) { int ret; struct ck_attribute *attr; struct ck_attribute a[4]; ck_key_type_t key_type; ck_bool_t reauth = 0; PKCS11_CHECK_INIT; memset(&pkey->sinfo, 0, sizeof(pkey->sinfo)); if (pkey->url) { gnutls_free(pkey->url); pkey->url = NULL; } if (pkey->uinfo) { p11_kit_uri_free(pkey->uinfo); pkey->uinfo = NULL; } pkey->url = gnutls_strdup(url); if (pkey->url == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); ret = pkcs11_url_to_info(pkey->url, &pkey->uinfo, flags|GNUTLS_PKCS11_OBJ_FLAG_EXPECT_PRIVKEY); if (ret < 0) { gnutls_assert(); goto cleanup; } pkey->flags = flags; attr = p11_kit_uri_get_attribute(pkey->uinfo, CKA_CLASS); if (!attr || attr->value_len != sizeof(ck_object_class_t) || *(ck_object_class_t *) attr->value != CKO_PRIVATE_KEY) { gnutls_assert(); ret = GNUTLS_E_INVALID_REQUEST; goto cleanup; } attr = p11_kit_uri_get_attribute(pkey->uinfo, CKA_ID); if (!attr) { attr = p11_kit_uri_get_attribute(pkey->uinfo, CKA_LABEL); if (!attr) { gnutls_assert(); ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; goto cleanup; } } FIND_OBJECT(pkey); pkey->pk_algorithm = GNUTLS_PK_UNKNOWN; a[0].type = CKA_KEY_TYPE; a[0].value = &key_type; a[0].value_len = sizeof(key_type); if (pkcs11_get_attribute_value(pkey->sinfo.module, pkey->sinfo.pks, pkey->ref, a, 1) == CKR_OK) { pkey->pk_algorithm = key_type_to_pk(key_type); } if (pkey->pk_algorithm == GNUTLS_PK_UNKNOWN) { _gnutls_debug_log ("Cannot determine PKCS #11 key algorithm\n"); ret = GNUTLS_E_UNKNOWN_ALGORITHM; goto cleanup; } a[0].type = CKA_ALWAYS_AUTHENTICATE; a[0].value = &reauth; a[0].value_len = sizeof(reauth); if (pkcs11_get_attribute_value(pkey->sinfo.module, pkey->sinfo.pks, pkey->ref, a, 1) == CKR_OK) { pkey->reauth = reauth; } ret = 0; return ret; cleanup: if (pkey->uinfo != NULL) { p11_kit_uri_free(pkey->uinfo); pkey->uinfo = NULL; } gnutls_free(pkey->url); pkey->url = NULL; return ret; }
/** * gnutls_pkcs11_privkey_import_url: * @pkey: The structure to store the parsed key * @url: a PKCS 11 url identifying the key * @flags: sequence of GNUTLS_PKCS_PRIVKEY_* * * This function will "import" a PKCS 11 URL identifying a private * key to the #gnutls_pkcs11_privkey_t structure. In reality since * in most cases keys cannot be exported, the private key structure * is being associated with the available operations on the token. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_pkcs11_privkey_import_url(gnutls_pkcs11_privkey_t pkey, const char *url, unsigned int flags) { int ret; struct ck_attribute *attr; ck_object_handle_t obj; struct ck_attribute a[4]; ck_key_type_t key_type; struct pkcs11_session_info sinfo; PKCS11_CHECK_INIT; memset(&sinfo, 0, sizeof(sinfo)); ret = pkcs11_url_to_info(url, &pkey->info); if (ret < 0) { gnutls_assert(); return ret; } pkey->flags = flags; attr = p11_kit_uri_get_attribute(pkey->info, CKA_CLASS); if (!attr || attr->value_len != sizeof(ck_object_class_t) || *(ck_object_class_t *) attr->value != CKO_PRIVATE_KEY) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } attr = p11_kit_uri_get_attribute(pkey->info, CKA_ID); if (!attr || !attr->value_len) { attr = p11_kit_uri_get_attribute(pkey->info, CKA_LABEL); if (!attr || !attr->value_len) { gnutls_assert(); return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } } FIND_OBJECT(&sinfo, &pkey->pin, obj, pkey); a[0].type = CKA_KEY_TYPE; a[0].value = &key_type; a[0].value_len = sizeof(key_type); if (pkcs11_get_attribute_value(sinfo.module, sinfo.pks, obj, a, 1) == CKR_OK) { pkey->pk_algorithm = mech_to_pk(key_type); if (pkey->pk_algorithm == GNUTLS_PK_UNKNOWN) { _gnutls_debug_log ("Cannot determine PKCS #11 key algorithm\n"); ret = GNUTLS_E_UNKNOWN_ALGORITHM; goto cleanup; } } ret = 0; if (pkey->sinfo.init) pkcs11_close_session(&pkey->sinfo); if (sinfo.tinfo.max_session_count != 1) { /* We do not keep the session open in tokens that can * only support a single session. */ memcpy(&pkey->sinfo, &sinfo, sizeof(pkey->sinfo)); pkey->obj = obj; return ret; } cleanup: pkcs11_close_session(&sinfo); return ret; }
int pkcs11_override_cert_exts(struct pkcs11_session_info *sinfo, gnutls_datum_t *spki, gnutls_datum_t *der) { int ret; gnutls_datum_t new_der = {NULL, 0}; struct ck_attribute a[2]; struct ck_attribute b[1]; unsigned long count; unsigned ext_data_size = der->size; uint8_t *ext_data = NULL; ck_object_class_t class = -1; gnutls_x509_crt_t crt = NULL; unsigned finalize = 0; ck_rv_t rv; ck_object_handle_t obj; /* retrieve the extensions */ class = CKO_X_CERTIFICATE_EXTENSION; a[0].type = CKA_CLASS; a[0].value = &class; a[0].value_len = sizeof class; a[1].type = CKA_PUBLIC_KEY_INFO; a[1].value = spki->data; a[1].value_len = spki->size; rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, a, 2); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log ("p11: FindObjectsInit failed for cert extensions.\n"); ret = pkcs11_rv_to_err(rv); goto cleanup; } finalize = 1; rv = pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count); if (rv == CKR_OK && count == 1) { ext_data = gnutls_malloc(ext_data_size); if (ext_data == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } ret = gnutls_x509_crt_init(&crt); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_x509_crt_import(crt, der, GNUTLS_X509_FMT_DER); if (ret < 0) { gnutls_assert(); goto cleanup; } do { b[0].type = CKA_VALUE; b[0].value = ext_data; b[0].value_len = ext_data_size; if (pkcs11_get_attribute_value (sinfo->module, sinfo->pks, obj, b, 1) == CKR_OK) { gnutls_datum_t data = { b[0].value, b[0].value_len }; ret = override_ext(crt, &data); if (ret < 0) { gnutls_assert(); goto cleanup; } } } while (pkcs11_find_objects(sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK && count == 1); /* overwrite the old certificate with the new */ ret = gnutls_x509_crt_export2(crt, GNUTLS_X509_FMT_DER, &new_der); if (ret < 0) { gnutls_assert(); goto cleanup; } gnutls_free(der->data); der->data = new_der.data; der->size = new_der.size; } ret = 0; cleanup: if (crt != NULL) gnutls_x509_crt_deinit(crt); if (finalize != 0) pkcs11_find_objects_final(sinfo); gnutls_free(ext_data); return ret; }
/** * gnutls_pkcs11_privkey_import_url: * @pkey: The structure to store the parsed key * @url: a PKCS 11 url identifying the key * @flags: sequence of GNUTLS_PKCS_PRIVKEY_* * * This function will "import" a PKCS 11 URL identifying a private * key to the #gnutls_pkcs11_privkey_t structure. In reality since * in most cases keys cannot be exported, the private key structure * is being associated with the available operations on the token. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_pkcs11_privkey_import_url (gnutls_pkcs11_privkey_t pkey, const char *url, unsigned int flags) { int ret; struct ck_function_list *module; struct ck_attribute *attr; ck_session_handle_t pks; ck_object_handle_t obj; struct ck_attribute a[4]; ck_key_type_t key_type; ret = pkcs11_url_to_info (url, &pkey->info); if (ret < 0) { gnutls_assert (); return ret; } pkey->flags = flags; attr = p11_kit_uri_get_attribute (pkey->info, CKA_CLASS); if (!attr || attr->value_len != sizeof (ck_object_class_t) || *(ck_object_class_t*)attr->value != CKO_PRIVATE_KEY) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } attr = p11_kit_uri_get_attribute (pkey->info, CKA_ID); if (!attr || !attr->value_len) { attr = p11_kit_uri_get_attribute (pkey->info, CKA_LABEL); if (!attr || !attr->value_len) { gnutls_assert (); return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } } FIND_OBJECT (module, pks, obj, pkey); a[0].type = CKA_KEY_TYPE; a[0].value = &key_type; a[0].value_len = sizeof (key_type); if (pkcs11_get_attribute_value (module, pks, obj, a, 1) == CKR_OK) { pkey->pk_algorithm = mech_to_pk(key_type); if (pkey->pk_algorithm == GNUTLS_PK_UNKNOWN) { _gnutls_debug_log("Cannot determine PKCS #11 key algorithm\n"); ret = GNUTLS_E_UNKNOWN_ALGORITHM; goto cleanup; } } ret = 0; cleanup: pkcs11_close_session (module, pks); return ret; }