/** * gnutls_pkcs11_privkey_deinit: * @key: The structure to be initialized * * This function will deinitialize a private key structure. **/ void gnutls_pkcs11_privkey_deinit(gnutls_pkcs11_privkey_t key) { p11_kit_uri_free(key->info); if (key->sinfo.init != 0) pkcs11_close_session(&key->sinfo); gnutls_free(key); }
/** * gnutls_pkcs11_privkey_status: * @key: Holds the key * * Checks the status of the private key token. * * Returns: this function will return non-zero if the token * holding the private key is still available (inserted), and zero otherwise. * * Since: 3.1.9 * **/ int gnutls_pkcs11_privkey_status(gnutls_pkcs11_privkey_t key) { ck_rv_t rv; int ret; struct pkcs11_session_info _sinfo; struct pkcs11_session_info *sinfo; ck_object_handle_t obj; struct ck_session_info session_info; PKCS11_CHECK_INIT; if (key->sinfo.init != 0) { sinfo = &key->sinfo; obj = key->obj; } else { sinfo = &_sinfo; memset(sinfo, 0, sizeof(*sinfo)); FIND_OBJECT(sinfo, &key->pin, obj, key); } rv = (sinfo->module)->C_GetSessionInfo(sinfo->pks, &session_info); if (rv != CKR_OK) { ret = 0; goto cleanup; } ret = 1; cleanup: if (sinfo != &key->sinfo) pkcs11_close_session(sinfo); return ret; }
static int find_object(struct pkcs11_session_info *sinfo, struct pin_info_st *pin_info, ck_object_handle_t * _ctx, struct p11_kit_uri *info, unsigned int flags) { int ret; ck_object_handle_t ctx; struct ck_attribute *attrs; unsigned long attr_count; unsigned long count; ck_rv_t rv; ret = pkcs11_open_session(sinfo, pin_info, info, flags & SESSION_LOGIN); if (ret < 0) { gnutls_assert(); return ret; } attrs = p11_kit_uri_get_attributes(info, &attr_count); rv = pkcs11_find_objects_init(sinfo->module, sinfo->pks, attrs, attr_count); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: FindObjectsInit failed.\n"); ret = pkcs11_rv_to_err(rv); goto fail; } if (pkcs11_find_objects(sinfo->module, sinfo->pks, &ctx, 1, &count) == CKR_OK && count == 1) { *_ctx = ctx; pkcs11_find_objects_final(sinfo); return 0; } ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; pkcs11_find_objects_final(sinfo); fail: pkcs11_close_session(sinfo); 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; }
/** * gnutls_pkcs11_copy_pubkey: * @token_url: A PKCS #11 URL specifying a token * @pubkey: The public key to copy * @label: The name to be used for the stored data * @cid: The CKA_ID to set for the object -if NULL, the ID will be derived from the public key * @key_usage: One of GNUTLS_KEY_* * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_* * * This function will copy a public key object into a PKCS #11 token specified by * a URL. Valid flags to mark the key: %GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED, * %GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE, %GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE, * %GNUTLS_PKCS11_OBJ_FLAG_MARK_CA, %GNUTLS_PKCS11_OBJ_FLAG_MARK_ALWAYS_AUTH. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.4.6 **/ int gnutls_pkcs11_copy_pubkey(const char *token_url, gnutls_pubkey_t pubkey, const char *label, const gnutls_datum_t *cid, unsigned int key_usage, unsigned int flags) { int ret; struct p11_kit_uri *info = NULL; ck_rv_t rv; size_t id_size; uint8_t id[20]; struct ck_attribute a[MAX_ASIZE]; gnutls_pk_algorithm_t pk; ck_object_class_t class = CKO_PUBLIC_KEY; ck_object_handle_t ctx; unsigned a_val; ck_key_type_t type; struct pkcs11_session_info sinfo; 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; } a[0].type = CKA_CLASS; a[0].value = &class; a[0].value_len = sizeof(class); a[1].type = CKA_TOKEN; a[1].value = (void *) &tval; a[1].value_len = sizeof(tval); a_val = 2; ret = add_pubkey(pubkey, a, &a_val); if (ret < 0) { gnutls_assert(); goto cleanup; } if (label) { a[a_val].type = CKA_LABEL; a[a_val].value = (void *) label; a[a_val].value_len = strlen(label); a_val++; } pk = gnutls_pubkey_get_pk_algorithm(pubkey, NULL); type = pk_to_key_type(pk); FIX_KEY_USAGE(pk, key_usage); a[a_val].type = CKA_KEY_TYPE; a[a_val].value = &type; a[a_val].value_len = sizeof(type); a_val++; a[a_val].type = CKA_ID; if (cid == NULL || cid->size == 0) { id_size = sizeof(id); ret = gnutls_pubkey_get_key_id(pubkey, 0, id, &id_size); if (ret < 0) { gnutls_assert(); goto cleanup; } a[a_val].value = id; a[a_val].value_len = id_size; } else { a[a_val].value = cid->data; a[a_val].value_len = cid->size; } a_val++; mark_flags(flags, a, &a_val, sinfo.trusted); a[a_val].type = CKA_VERIFY; if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) { a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof(tval); } else { a[a_val].value = (void*)&fval; a[a_val].value_len = sizeof(fval); } a_val++; if (pk == GNUTLS_PK_RSA) { a[a_val].type = CKA_ENCRYPT; if (key_usage & (GNUTLS_KEY_ENCIPHER_ONLY|GNUTLS_KEY_DECIPHER_ONLY)) { a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof(tval); } else { a[a_val].value = (void*)&fval; a[a_val].value_len = sizeof(fval); } a_val++; } rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_val, &ctx); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); ret = pkcs11_rv_to_err(rv); goto cleanup; } /* generated! */ ret = 0; cleanup: clean_pubkey(a, a_val); pkcs11_close_session(&sinfo); return ret; }
/** * gnutls_pkcs11_copy_x509_crt2: * @token_url: A PKCS #11 URL specifying a token * @crt: The certificate to copy * @label: The name to be used for the stored data * @cid: The CKA_ID to set for the object -if NULL, the ID will be derived from the public key * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_* * * This function will copy a certificate into a PKCS #11 token specified by * a URL. Valid flags to mark the certificate: %GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED, * %GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE, %GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE, * %GNUTLS_PKCS11_OBJ_FLAG_MARK_CA, %GNUTLS_PKCS11_OBJ_FLAG_MARK_ALWAYS_AUTH. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.4.0 **/ int gnutls_pkcs11_copy_x509_crt2(const char *token_url, gnutls_x509_crt_t crt, const char *label, const gnutls_datum_t *cid, unsigned int flags) { int ret; struct p11_kit_uri *info = NULL; ck_rv_t rv; size_t der_size, id_size, serial_size; gnutls_datum_t serial_der = {NULL, 0}; uint8_t *der = NULL; uint8_t serial[128]; uint8_t id[20]; struct ck_attribute a[MAX_ASIZE]; ck_object_class_t class = CKO_CERTIFICATE; ck_certificate_type_t type = CKC_X_509; ck_object_handle_t ctx; unsigned a_val; struct pkcs11_session_info sinfo; 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; } der_size = 0; ret = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, NULL, &der_size); if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { gnutls_assert(); goto cleanup; } der = gnutls_malloc(der_size); if (der == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } ret = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, der, &der_size); if (ret < 0) { gnutls_assert(); goto cleanup; } a[0].type = CKA_CLASS; a[0].value = &class; a[0].value_len = sizeof(class); a[1].type = CKA_ID; if (cid == NULL || cid->size == 0) { id_size = sizeof(id); ret = gnutls_x509_crt_get_subject_key_id(crt, id, &id_size, NULL); if (ret < 0) { id_size = sizeof(id); ret = gnutls_x509_crt_get_key_id(crt, 0, id, &id_size); if (ret < 0) { gnutls_assert(); goto cleanup; } } a[1].value = id; a[1].value_len = id_size; } else { a[1].value = cid->data; a[1].value_len = cid->size; } a[2].type = CKA_VALUE; a[2].value = der; a[2].value_len = der_size; a[3].type = CKA_TOKEN; a[3].value = (void *) &tval; a[3].value_len = sizeof(tval); a[4].type = CKA_CERTIFICATE_TYPE; a[4].value = &type; a[4].value_len = sizeof(type); /* FIXME: copy key usage flags */ a_val = 5; a[a_val].type = CKA_SUBJECT; a[a_val].value = crt->raw_dn.data; a[a_val].value_len = crt->raw_dn.size; a_val++; a[a_val].type = CKA_ISSUER; a[a_val].value = crt->raw_issuer_dn.data; a[a_val].value_len = crt->raw_issuer_dn.size; a_val++; serial_size = sizeof(serial); if (gnutls_x509_crt_get_serial(crt, serial, &serial_size) >= 0) { ret = _gnutls_x509_ext_gen_number(serial, serial_size, &serial_der); if (ret >= 0) { a[a_val].type = CKA_SERIAL_NUMBER; a[a_val].value = (void *) serial_der.data; a[a_val].value_len = serial_der.size; a_val++; } } if (label) { a[a_val].type = CKA_LABEL; a[a_val].value = (void *) label; a[a_val].value_len = strlen(label); a_val++; } mark_flags(flags, a, &a_val, sinfo.trusted); rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_val, &ctx); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); ret = pkcs11_rv_to_err(rv); goto cleanup; } /* generated! */ ret = 0; cleanup: gnutls_free(der); gnutls_free(serial_der.data); pkcs11_close_session(&sinfo); return ret; }
/** * gnutls_pkcs11_privkey_generate2: * @url: a token URL * @pk: the public key algorithm * @bits: the security bits * @label: a label * @fmt: the format of output params. PEM or DER. * @pubkey: will hold the public key (may be %NULL) * @flags: should be zero * * This function will generate a private key in the specified * by the @url token. The private key will be generate within * the token and will not be exportable. This function will * store the DER-encoded public key in the SubjectPublicKeyInfo format * in @pubkey. The @pubkey should be deinitialized using gnutls_free(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.1.5 **/ int gnutls_pkcs11_privkey_generate2(const char *url, gnutls_pk_algorithm_t pk, unsigned int bits, const char *label, gnutls_x509_crt_fmt_t fmt, gnutls_datum_t * pubkey, unsigned int flags) { int ret; const ck_bool_t tval = 1; const ck_bool_t fval = 0; struct pkcs11_session_info sinfo; struct p11_kit_uri *info = NULL; ck_rv_t rv; struct ck_attribute a[10], p[10]; ck_object_handle_t pub, priv; unsigned long _bits = bits; int a_val, p_val; struct ck_mechanism mech; gnutls_pubkey_t pkey = NULL; gnutls_pkcs11_obj_t obj = NULL; PKCS11_CHECK_INIT; memset(&sinfo, 0, sizeof(sinfo)); ret = pkcs11_url_to_info(url, &info); 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(); goto cleanup; } /* a holds the public key template * and p the private key */ a_val = p_val = 0; mech.parameter = NULL; mech.parameter_len = 0; mech.mechanism = pk_to_genmech(pk); switch (pk) { case GNUTLS_PK_RSA: p[p_val].type = CKA_DECRYPT; p[p_val].value = (void *) &tval; p[p_val].value_len = sizeof(tval); p_val++; p[p_val].type = CKA_SIGN; p[p_val].value = (void *) &tval; p[p_val].value_len = sizeof(tval); p_val++; a[a_val].type = CKA_ENCRYPT; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; a[a_val].type = CKA_VERIFY; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; a[a_val].type = CKA_MODULUS_BITS; a[a_val].value = &_bits; a[a_val].value_len = sizeof(_bits); a_val++; break; case GNUTLS_PK_DSA: p[p_val].type = CKA_SIGN; p[p_val].value = (void *) &tval; p[p_val].value_len = sizeof(tval); p_val++; a[a_val].type = CKA_VERIFY; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; a[a_val].type = CKA_MODULUS_BITS; a[a_val].value = &_bits; a[a_val].value_len = sizeof(_bits); a_val++; break; case GNUTLS_PK_EC: p[p_val].type = CKA_SIGN; p[p_val].value = (void *) &tval; p[p_val].value_len = sizeof(tval); p_val++; a[a_val].type = CKA_VERIFY; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; a[a_val].type = CKA_MODULUS_BITS; a[a_val].value = &_bits; a[a_val].value_len = sizeof(_bits); a_val++; break; default: ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); goto cleanup; } /* a private key is set always as private unless * requested otherwise */ if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE) { p[p_val].type = CKA_PRIVATE; p[p_val].value = (void *) &fval; p[p_val].value_len = sizeof(fval); p_val++; } else { p[p_val].type = CKA_PRIVATE; p[p_val].value = (void *) &tval; p[p_val].value_len = sizeof(tval); p_val++; } p[p_val].type = CKA_TOKEN; p[p_val].value = (void *) &tval; p[p_val].value_len = sizeof(tval); p_val++; if (label) { p[p_val].type = CKA_LABEL; p[p_val].value = (void *) label; p[p_val].value_len = strlen(label); p_val++; a[a_val].type = CKA_LABEL; a[a_val].value = (void *) label; a[a_val].value_len = strlen(label); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE) { p[p_val].type = CKA_SENSITIVE; p[p_val].value = (void *) &tval; p[p_val].value_len = sizeof(tval); p_val++; } else { p[p_val].type = CKA_SENSITIVE; p[p_val].value = (void *) &fval; p[p_val].value_len = sizeof(fval); p_val++; } rv = pkcs11_generate_key_pair(sinfo.module, sinfo.pks, &mech, a, a_val, p, p_val, &pub, &priv); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); ret = pkcs11_rv_to_err(rv); goto cleanup; } /* extract the public key */ if (pubkey) { ret = gnutls_pubkey_init(&pkey); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_pkcs11_obj_init(&obj); if (ret < 0) { gnutls_assert(); goto cleanup; } obj->pk_algorithm = pk; obj->type = GNUTLS_PKCS11_OBJ_PUBKEY; ret = pkcs11_read_pubkey(sinfo.module, sinfo.pks, pub, mech.mechanism, obj->pubkey); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_pubkey_import_pkcs11(pkey, obj, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_pubkey_export2(pkey, fmt, pubkey); if (ret < 0) { gnutls_assert(); goto cleanup; } } cleanup: if (obj != NULL) gnutls_pkcs11_obj_deinit(obj); if (pkey != NULL) gnutls_pubkey_deinit(pkey); if (sinfo.pks != 0) pkcs11_close_session(&sinfo); 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; }
/*- * _gnutls_pkcs11_privkey_sign_hash: * @key: Holds the key * @hash: holds the data to be signed (should be output of a hash) * @signature: will contain the signature allocated with gnutls_malloc() * * This function will sign the given data using a signature algorithm * supported by the private key. It is assumed that the given data * are the output of a hash function. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. -*/ int _gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key, const gnutls_datum_t * hash, gnutls_datum_t * signature) { ck_rv_t rv; int ret; struct ck_mechanism mech; gnutls_datum_t tmp = { NULL, 0 }; unsigned long siglen; struct pkcs11_session_info *sinfo; unsigned req_login = 0; unsigned login_flags = SESSION_LOGIN|SESSION_CONTEXT_SPECIFIC; PKCS11_CHECK_INIT_PRIVKEY(key); sinfo = &key->sinfo; mech.mechanism = pk_to_mech(key->pk_algorithm); mech.parameter = NULL; mech.parameter_len = 0; ret = gnutls_mutex_lock(&key->mutex); if (ret != 0) return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR); /* Initialize signing operation; using the private key discovered * earlier. */ REPEAT_ON_INVALID_HANDLE(rv = pkcs11_sign_init(sinfo->module, sinfo->pks, &mech, key->ref)); if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } retry_login: if (key->reauth || req_login) { if (req_login) login_flags = SESSION_LOGIN|SESSION_FORCE_LOGIN; ret = pkcs11_login(&key->sinfo, &key->pin, key->uinfo, login_flags); if (ret < 0) { gnutls_assert(); _gnutls_debug_log("PKCS #11 login failed, trying operation anyway\n"); /* let's try the operation anyway */ } } /* Work out how long the signature must be: */ rv = pkcs11_sign(sinfo->module, sinfo->pks, hash->data, hash->size, NULL, &siglen); if (unlikely(rv == CKR_USER_NOT_LOGGED_IN && req_login == 0)) { req_login = 1; goto retry_login; } if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } tmp.data = gnutls_malloc(siglen); tmp.size = siglen; rv = pkcs11_sign(sinfo->module, sinfo->pks, hash->data, hash->size, tmp.data, &siglen); if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } if (key->pk_algorithm == GNUTLS_PK_EC || key->pk_algorithm == GNUTLS_PK_DSA) { unsigned int hlen = siglen / 2; gnutls_datum_t r, s; if (siglen % 2 != 0) { gnutls_assert(); ret = GNUTLS_E_PK_SIGN_FAILED; goto cleanup; } r.data = tmp.data; r.size = hlen; s.data = &tmp.data[hlen]; s.size = hlen; ret = _gnutls_encode_ber_rs_raw(signature, &r, &s); if (ret < 0) { gnutls_assert(); goto cleanup; } gnutls_free(tmp.data); tmp.data = NULL; } else { signature->size = siglen; signature->data = tmp.data; } ret = 0; cleanup: gnutls_mutex_unlock(&key->mutex); if (sinfo != &key->sinfo) pkcs11_close_session(sinfo); if (ret < 0) gnutls_free(tmp.data); return ret; }
/*- * _gnutls_pkcs11_privkey_sign_hash: * @key: Holds the key * @hash: holds the data to be signed (should be output of a hash) * @signature: will contain the signature allocated with gnutls_malloc() * * This function will sign the given data using a signature algorithm * supported by the private key. It is assumed that the given data * are the output of a hash function. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. -*/ int _gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key, const gnutls_datum_t * hash, gnutls_datum_t * signature) { ck_rv_t rv; int ret; struct ck_mechanism mech; gnutls_datum_t tmp = { NULL, 0 }; unsigned long siglen; struct pkcs11_session_info _sinfo; struct pkcs11_session_info *sinfo; ck_object_handle_t obj; PKCS11_CHECK_INIT; if (key->sinfo.init != 0) { sinfo = &key->sinfo; obj = key->obj; } else { sinfo = &_sinfo; memset(sinfo, 0, sizeof(*sinfo)); FIND_OBJECT(sinfo, &key->pin, obj, key); } mech.mechanism = pk_to_mech(key->pk_algorithm); mech.parameter = NULL; mech.parameter_len = 0; /* Initialize signing operation; using the private key discovered * earlier. */ rv = pkcs11_sign_init(sinfo->module, sinfo->pks, &mech, obj); if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } /* Work out how long the signature must be: */ rv = pkcs11_sign(sinfo->module, sinfo->pks, hash->data, hash->size, NULL, &siglen); if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } tmp.data = gnutls_malloc(siglen); tmp.size = siglen; rv = pkcs11_sign(sinfo->module, sinfo->pks, hash->data, hash->size, tmp.data, &siglen); if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } if (key->pk_algorithm == GNUTLS_PK_EC || key->pk_algorithm == GNUTLS_PK_DSA) { unsigned int hlen = siglen / 2; gnutls_datum_t r, s; if (siglen % 2 != 0) { gnutls_assert(); ret = GNUTLS_E_PK_SIGN_FAILED; goto cleanup; } r.data = tmp.data; r.size = hlen; s.data = &tmp.data[hlen]; s.size = hlen; ret = _gnutls_encode_ber_rs_raw(signature, &r, &s); if (ret < 0) { gnutls_assert(); goto cleanup; } gnutls_free(tmp.data); tmp.data = NULL; } else { signature->size = siglen; signature->data = tmp.data; } ret = 0; cleanup: if (sinfo != &key->sinfo) pkcs11_close_session(sinfo); if (ret < 0) gnutls_free(tmp.data); return ret; }
/** * gnutls_pkcs11_copy_secret_key: * @token_url: A PKCS #11 URL specifying a token * @key: The raw key * @label: A name to be used for the stored data * @key_usage: One of GNUTLS_KEY_* * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_* * * This function will copy a raw secret (symmetric) key into a PKCS #11 * token specified by a URL. The key can be marked as sensitive or not. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 2.12.0 **/ int gnutls_pkcs11_copy_secret_key(const char *token_url, gnutls_datum_t * key, const char *label, unsigned int key_usage, unsigned int flags /* GNUTLS_PKCS11_OBJ_FLAG_* */ ) { int ret; struct p11_kit_uri *info = NULL; ck_rv_t rv; struct ck_attribute a[12]; ck_object_class_t class = CKO_SECRET_KEY; ck_object_handle_t obj; ck_key_type_t keytype = CKK_GENERIC_SECRET; ck_bool_t tval = 1; int a_val; uint8_t id[16]; struct pkcs11_session_info sinfo; PKCS11_CHECK_INIT; memset(&sinfo, 0, sizeof(sinfo)); ret = pkcs11_url_to_info(token_url, &info); if (ret < 0) { gnutls_assert(); return ret; } /* generate a unique ID */ ret = _gnutls_rnd(GNUTLS_RND_NONCE, id, sizeof(id)); 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; } /* FIXME: copy key usage flags */ a[0].type = CKA_CLASS; a[0].value = &class; a[0].value_len = sizeof(class); a[1].type = CKA_VALUE; a[1].value = key->data; a[1].value_len = key->size; a[2].type = CKA_TOKEN; a[2].value = &tval; a[2].value_len = sizeof(tval); a[3].type = CKA_PRIVATE; a[3].value = &tval; a[3].value_len = sizeof(tval); a[4].type = CKA_KEY_TYPE; a[4].value = &keytype; a[4].value_len = sizeof(keytype); a[5].type = CKA_ID; a[5].value = id; a[5].value_len = sizeof(id); a_val = 6; if (label) { a[a_val].type = CKA_LABEL; a[a_val].value = (void *) label; a[a_val].value_len = strlen(label); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE) tval = 1; else tval = 0; a[a_val].type = CKA_SENSITIVE; a[a_val].value = &tval; a[a_val].value_len = sizeof(tval); a_val++; rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_val, &obj); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); ret = pkcs11_rv_to_err(rv); goto cleanup; } /* generated! */ ret = 0; cleanup: pkcs11_close_session(&sinfo); return ret; }
/** * gnutls_pkcs11_copy_x509_crt: * @token_url: A PKCS #11 URL specifying a token * @crt: A certificate * @label: A name to be used for the stored data * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_* * * This function will copy a certificate into a PKCS #11 token specified by * a URL. The certificate can be marked as trusted or not. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 2.12.0 **/ int gnutls_pkcs11_copy_x509_crt(const char *token_url, gnutls_x509_crt_t crt, const char *label, unsigned int flags) { int ret; struct p11_kit_uri *info = NULL; ck_rv_t rv; size_t der_size, id_size; uint8_t *der = NULL; uint8_t id[20]; struct ck_attribute a[16]; ck_object_class_t class = CKO_CERTIFICATE; ck_certificate_type_t type = CKC_X_509; ck_object_handle_t obj; int a_val; unsigned long category; struct pkcs11_session_info sinfo; PKCS11_CHECK_INIT; memset(&sinfo, 0, sizeof(sinfo)); ret = pkcs11_url_to_info(token_url, &info); 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; } der_size = 0; ret = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, NULL, &der_size); if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { gnutls_assert(); goto cleanup; } der = gnutls_malloc(der_size); if (der == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } ret = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, der, &der_size); if (ret < 0) { gnutls_assert(); goto cleanup; } id_size = sizeof(id); ret = gnutls_x509_crt_get_subject_key_id(crt, id, &id_size, NULL); if (ret < 0) { id_size = sizeof(id); ret = gnutls_x509_crt_get_key_id(crt, 0, id, &id_size); if (ret < 0) { gnutls_assert(); goto cleanup; } } /* FIXME: copy key usage flags */ a[0].type = CKA_CLASS; a[0].value = &class; a[0].value_len = sizeof(class); a[1].type = CKA_ID; a[1].value = id; a[1].value_len = id_size; a[2].type = CKA_VALUE; a[2].value = der; a[2].value_len = der_size; a[3].type = CKA_TOKEN; a[3].value = (void *) &tval; a[3].value_len = sizeof(tval); a[4].type = CKA_CERTIFICATE_TYPE; a[4].value = &type; a[4].value_len = sizeof(type); a_val = 5; a[a_val].type = CKA_SUBJECT; a[a_val].value = crt->raw_dn.data; a[a_val].value_len = crt->raw_dn.size; a_val++; if (label) { a[a_val].type = CKA_LABEL; a[a_val].value = (void *) label; a[a_val].value_len = strlen(label); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_CA) { category = 2; a[a_val].type = CKA_CERTIFICATE_CATEGORY; a[a_val].value = (void *) &category; a[a_val].value_len = sizeof(category); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED) { a[a_val].type = CKA_TRUSTED; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; a[a_val].type = CKA_PRIVATE; a[a_val].value = (void *) &fval; a[a_val].value_len = sizeof(fval); a_val++; } else { if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE) { a[a_val].type = CKA_PRIVATE; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; } else if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE) { a[a_val].type = CKA_PRIVATE; a[a_val].value = (void *) &fval; a[a_val].value_len = sizeof(fval); a_val++; } } rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_val, &obj); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); ret = pkcs11_rv_to_err(rv); goto cleanup; } /* generated! */ ret = 0; cleanup: gnutls_free(der); pkcs11_close_session(&sinfo); return ret; }
/** * gnutls_pkcs11_privkey_generate: * @url: a token URL * @pk: the public key algorithm * @bits: the security bits * @label: a label * @flags: should be zero * * This function will generate a private key in the specified * by the @url token. The pivate key will be generate within * the token and will not be exportable. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.0 **/ int gnutls_pkcs11_privkey_generate (const char* url, gnutls_pk_algorithm_t pk, unsigned int bits, const char* label, unsigned int flags) { int ret; const ck_bool_t tval = 1; const ck_bool_t fval = 0; struct ck_function_list *module; ck_session_handle_t pks = 0; struct p11_kit_uri *info = NULL; ck_rv_t rv; struct ck_attribute a[10], p[10]; ck_object_handle_t pub, priv; unsigned long _bits = bits; int a_val, p_val; struct ck_mechanism mech; ret = pkcs11_url_to_info (url, &info); if (ret < 0) { gnutls_assert (); return ret; } ret = pkcs11_open_session (&module, &pks, info, SESSION_WRITE | pkcs11_obj_flags_to_int (flags)); p11_kit_uri_free (info); if (ret < 0) { gnutls_assert (); goto cleanup; } /* a holds the public key template * and p the private key */ a_val = p_val = 0; mech.parameter = NULL; mech.parameter_len = 0; mech.mechanism = pk_to_genmech(pk); switch(pk) { case GNUTLS_PK_RSA: p[p_val].type = CKA_DECRYPT; p[p_val].value = (void*)&tval; p[p_val].value_len = sizeof (tval); p_val++; p[p_val].type = CKA_SIGN; p[p_val].value = (void*)&tval; p[p_val].value_len = sizeof (tval); p_val++; a[a_val].type = CKA_ENCRYPT; a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof (tval); a_val++; a[a_val].type = CKA_VERIFY; a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof (tval); a_val++; a[a_val].type = CKA_MODULUS_BITS; a[a_val].value = &_bits; a[a_val].value_len = sizeof (_bits); a_val++; break; case GNUTLS_PK_DSA: p[p_val].type = CKA_SIGN; p[p_val].value = (void*)&tval; p[p_val].value_len = sizeof (tval); p_val++; a[a_val].type = CKA_VERIFY; a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof (tval); a_val++; a[a_val].type = CKA_MODULUS_BITS; a[a_val].value = &_bits; a[a_val].value_len = sizeof (_bits); a_val++; break; case GNUTLS_PK_EC: p[p_val].type = CKA_SIGN; p[p_val].value = (void*)&tval; p[p_val].value_len = sizeof (tval); p_val++; a[a_val].type = CKA_VERIFY; a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof (tval); a_val++; a[a_val].type = CKA_MODULUS_BITS; a[a_val].value = &_bits; a[a_val].value_len = sizeof (_bits); a_val++; break; default: ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); goto cleanup; } /* a private key is set always as private unless * requested otherwise */ if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE) { p[p_val].type = CKA_PRIVATE; p[p_val].value = (void*)&fval; p[p_val].value_len = sizeof(fval); p_val++; } else { p[p_val].type = CKA_PRIVATE; p[p_val].value = (void*)&tval; p[p_val].value_len = sizeof (tval); p_val++; } p[p_val].type = CKA_TOKEN; p[p_val].value = (void *)&tval; p[p_val].value_len = sizeof (tval); p_val++; if (label) { p[p_val].type = CKA_LABEL; p[p_val].value = (void*)label; p[p_val].value_len = strlen (label); p_val++; a[a_val].type = CKA_LABEL; a[a_val].value = (void*)label; a[a_val].value_len = strlen (label); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE) { p[p_val].type = CKA_SENSITIVE; p[p_val].value = (void*)&tval; p[p_val].value_len = sizeof (tval); p_val++; } else { p[p_val].type = CKA_SENSITIVE; p[p_val].value = (void*)&fval; p[p_val].value_len = sizeof (fval); p_val++; } rv = pkcs11_generate_key_pair( module, pks, &mech, a, a_val, p, p_val, &pub, &priv); if (rv != CKR_OK) { gnutls_assert (); _gnutls_debug_log ("pkcs11: %s\n", pkcs11_strerror (rv)); ret = pkcs11_rv_to_err (rv); goto cleanup; } cleanup: if (pks != 0) pkcs11_close_session (module, pks); return ret; }
/*- * _gnutls_pkcs11_privkey_decrypt_data: * @key: Holds the key * @flags: should be 0 for now * @ciphertext: holds the data to be signed * @plaintext: will contain the plaintext, allocated with gnutls_malloc() * * This function will decrypt the given data using the public key algorithm * supported by the private key. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. -*/ int _gnutls_pkcs11_privkey_decrypt_data (gnutls_pkcs11_privkey_t key, unsigned int flags, const gnutls_datum_t * ciphertext, gnutls_datum_t * plaintext) { ck_rv_t rv; int ret; struct ck_mechanism mech; unsigned long siglen; struct ck_function_list *module; ck_session_handle_t pks; ck_object_handle_t obj; FIND_OBJECT (module, pks, obj, key); if (key->pk_algorithm != GNUTLS_PK_RSA) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); mech.mechanism = CKM_RSA_PKCS; mech.parameter = NULL; mech.parameter_len = 0; /* Initialize signing operation; using the private key discovered * earlier. */ rv = pkcs11_decrypt_init (module, pks, &mech, obj); if (rv != CKR_OK) { gnutls_assert (); ret = pkcs11_rv_to_err (rv); goto cleanup; } /* Work out how long the plaintext must be: */ rv = pkcs11_decrypt (module, pks, ciphertext->data, ciphertext->size, NULL, &siglen); if (rv != CKR_OK) { gnutls_assert (); ret = pkcs11_rv_to_err (rv); goto cleanup; } plaintext->data = gnutls_malloc (siglen); plaintext->size = siglen; rv = pkcs11_decrypt (module, pks, ciphertext->data, ciphertext->size, plaintext->data, &siglen); if (rv != CKR_OK) { gnutls_free (plaintext->data); gnutls_assert (); ret = pkcs11_rv_to_err (rv); goto cleanup; } plaintext->size = siglen; ret = 0; cleanup: pkcs11_close_session (module, pks); return ret; }
/** * gnutls_pkcs11_copy_x509_privkey2: * @token_url: A PKCS #11 URL specifying a token * @key: A private key * @label: A name to be used for the stored data * @cid: The CKA_ID to set for the object -if NULL, the ID will be derived from the public key * @key_usage: One of GNUTLS_KEY_* * @flags: One of GNUTLS_PKCS11_OBJ_* flags * * This function will copy a private key into a PKCS #11 token specified by * a URL. It is highly recommended flags to contain %GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE * unless there is a strong reason not to. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.4.0 **/ int gnutls_pkcs11_copy_x509_privkey2(const char *token_url, gnutls_x509_privkey_t key, const char *label, const gnutls_datum_t *cid, unsigned int key_usage, unsigned int flags) { int ret; struct p11_kit_uri *info = NULL; ck_rv_t rv; size_t id_size; uint8_t id[20]; struct ck_attribute a[32]; ck_object_class_t class = CKO_PRIVATE_KEY; ck_object_handle_t ctx; ck_key_type_t type; int a_val; gnutls_pk_algorithm_t pk; gnutls_datum_t p, q, g, y, x; gnutls_datum_t m, e, d, u, exp1, exp2; struct pkcs11_session_info sinfo; PKCS11_CHECK_INIT; memset(&p, 0, sizeof(p)); memset(&q, 0, sizeof(q)); memset(&g, 0, sizeof(g)); memset(&y, 0, sizeof(y)); memset(&x, 0, sizeof(x)); memset(&m, 0, sizeof(m)); memset(&e, 0, sizeof(e)); memset(&d, 0, sizeof(d)); memset(&u, 0, sizeof(u)); memset(&exp1, 0, sizeof(exp1)); memset(&exp2, 0, sizeof(exp2)); 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; } pk = gnutls_x509_privkey_get_pk_algorithm(key); FIX_KEY_USAGE(pk, key_usage); /* FIXME: copy key usage flags */ a_val = 0; a[a_val].type = CKA_CLASS; a[a_val].value = &class; a[a_val].value_len = sizeof(class); a_val++; a[a_val].type = CKA_ID; if (cid == NULL || cid->size == 0) { id_size = sizeof(id); ret = gnutls_x509_privkey_get_key_id(key, 0, id, &id_size); if (ret < 0) { p11_kit_uri_free(info); gnutls_assert(); return ret; } a[a_val].value = id; a[a_val].value_len = id_size; } else { a[a_val].value = cid->data; a[a_val].value_len = cid->size; } a_val++; a[a_val].type = CKA_SIGN; if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) { a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof(tval); } else { a[a_val].value = (void*)&fval; a[a_val].value_len = sizeof(fval); } a_val++; if (pk == GNUTLS_PK_RSA) { a[a_val].type = CKA_DECRYPT; if (key_usage & (GNUTLS_KEY_ENCIPHER_ONLY|GNUTLS_KEY_DECIPHER_ONLY)) { a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof(tval); } else { a[a_val].value = (void*)&fval; a[a_val].value_len = sizeof(fval); } a_val++; } a[a_val].type = CKA_TOKEN; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; /* a private key is set always as private unless * requested otherwise */ if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE) { a[a_val].type = CKA_PRIVATE; a[a_val].value = (void *) &fval; a[a_val].value_len = sizeof(fval); a_val++; } else { a[a_val].type = CKA_PRIVATE; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_ALWAYS_AUTH) { a[a_val].type = CKA_ALWAYS_AUTHENTICATE; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_EXTRACTABLE) { a[a_val].type = CKA_EXTRACTABLE; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); (a_val)++; } else { a[a_val].type = CKA_EXTRACTABLE; a[a_val].value = (void *) &fval; a[a_val].value_len = sizeof(fval); (a_val)++; } if (label) { a[a_val].type = CKA_LABEL; a[a_val].value = (void *) label; a[a_val].value_len = strlen(label); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE) { a[a_val].type = CKA_SENSITIVE; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; } else { a[a_val].type = CKA_SENSITIVE; a[a_val].value = (void *) &fval; a[a_val].value_len = sizeof(fval); a_val++; } switch (pk) { case GNUTLS_PK_RSA: { ret = gnutls_x509_privkey_export_rsa_raw2(key, &m, &e, &d, &p, &q, &u, &exp1, &exp2); if (ret < 0) { gnutls_assert(); goto cleanup; } type = CKK_RSA; skip_leading_zeros(&m); skip_leading_zeros(&e); skip_leading_zeros(&d); skip_leading_zeros(&p); skip_leading_zeros(&q); skip_leading_zeros(&u); skip_leading_zeros(&exp1); skip_leading_zeros(&exp2); a[a_val].type = CKA_MODULUS; a[a_val].value = m.data; a[a_val].value_len = m.size; a_val++; a[a_val].type = CKA_PUBLIC_EXPONENT; a[a_val].value = e.data; a[a_val].value_len = e.size; a_val++; a[a_val].type = CKA_PRIVATE_EXPONENT; a[a_val].value = d.data; a[a_val].value_len = d.size; a_val++; a[a_val].type = CKA_PRIME_1; a[a_val].value = p.data; a[a_val].value_len = p.size; a_val++; a[a_val].type = CKA_PRIME_2; a[a_val].value = q.data; a[a_val].value_len = q.size; a_val++; a[a_val].type = CKA_COEFFICIENT; a[a_val].value = u.data; a[a_val].value_len = u.size; a_val++; a[a_val].type = CKA_EXPONENT_1; a[a_val].value = exp1.data; a[a_val].value_len = exp1.size; a_val++; a[a_val].type = CKA_EXPONENT_2; a[a_val].value = exp2.data; a[a_val].value_len = exp2.size; a_val++; break; } case GNUTLS_PK_DSA: { ret = gnutls_x509_privkey_export_dsa_raw(key, &p, &q, &g, &y, &x); if (ret < 0) { gnutls_assert(); goto cleanup; } type = CKK_DSA; skip_leading_zeros(&p); skip_leading_zeros(&q); skip_leading_zeros(&g); skip_leading_zeros(&y); skip_leading_zeros(&x); a[a_val].type = CKA_PRIME; a[a_val].value = p.data; a[a_val].value_len = p.size; a_val++; a[a_val].type = CKA_SUBPRIME; a[a_val].value = q.data; a[a_val].value_len = q.size; a_val++; a[a_val].type = CKA_BASE; a[a_val].value = g.data; a[a_val].value_len = g.size; a_val++; a[a_val].type = CKA_VALUE; a[a_val].value = x.data; a[a_val].value_len = x.size; a_val++; break; } case GNUTLS_PK_EC: { ret = _gnutls_x509_write_ecc_params(key->params.flags, &p); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = _gnutls_mpi_dprint(key->params. params[ECC_K], &x); if (ret < 0) { gnutls_assert(); goto cleanup; } type = CKK_ECDSA; a[a_val].type = CKA_EC_PARAMS; a[a_val].value = p.data; a[a_val].value_len = p.size; a_val++; a[a_val].type = CKA_VALUE; a[a_val].value = x.data; a[a_val].value_len = x.size; a_val++; break; } default: gnutls_assert(); ret = GNUTLS_E_INVALID_REQUEST; goto cleanup; } a[a_val].type = CKA_KEY_TYPE; a[a_val].value = &type; a[a_val].value_len = sizeof(type); a_val++; rv = pkcs11_create_object(sinfo.module, sinfo.pks, a, a_val, &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: switch (pk) { case GNUTLS_PK_RSA: { gnutls_free(m.data); gnutls_free(e.data); gnutls_free(d.data); gnutls_free(p.data); gnutls_free(q.data); gnutls_free(u.data); gnutls_free(exp1.data); gnutls_free(exp2.data); break; } case GNUTLS_PK_DSA: { gnutls_free(p.data); gnutls_free(q.data); gnutls_free(g.data); gnutls_free(y.data); gnutls_free(x.data); break; } case GNUTLS_PK_EC: { gnutls_free(p.data); gnutls_free(x.data); break; } default: gnutls_assert(); ret = GNUTLS_E_INVALID_REQUEST; break; } if (sinfo.pks != 0) pkcs11_close_session(&sinfo); 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; }
/*- * _gnutls_pkcs11_privkey_decrypt_data: * @key: Holds the key * @flags: should be 0 for now * @ciphertext: holds the data to be signed * @plaintext: will contain the plaintext, allocated with gnutls_malloc() * * This function will decrypt the given data using the public key algorithm * supported by the private key. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. -*/ int _gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key, unsigned int flags, const gnutls_datum_t * ciphertext, gnutls_datum_t * plaintext) { ck_rv_t rv; int ret; struct ck_mechanism mech; unsigned long siglen; ck_object_handle_t obj; struct pkcs11_session_info _sinfo; struct pkcs11_session_info *sinfo; PKCS11_CHECK_INIT; if (key->sinfo.init != 0) { sinfo = &key->sinfo; obj = key->obj; } else { sinfo = &_sinfo; memset(sinfo, 0, sizeof(*sinfo)); FIND_OBJECT(sinfo, &key->pin, obj, key); } if (key->pk_algorithm != GNUTLS_PK_RSA) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); mech.mechanism = CKM_RSA_PKCS; mech.parameter = NULL; mech.parameter_len = 0; /* Initialize signing operation; using the private key discovered * earlier. */ rv = pkcs11_decrypt_init(sinfo->module, sinfo->pks, &mech, obj); if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } /* Work out how long the plaintext must be: */ rv = pkcs11_decrypt(sinfo->module, sinfo->pks, ciphertext->data, ciphertext->size, NULL, &siglen); if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } plaintext->data = gnutls_malloc(siglen); plaintext->size = siglen; rv = pkcs11_decrypt(sinfo->module, sinfo->pks, ciphertext->data, ciphertext->size, plaintext->data, &siglen); if (rv != CKR_OK) { gnutls_free(plaintext->data); gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } plaintext->size = siglen; ret = 0; cleanup: if (key->sinfo.init == 0) pkcs11_close_session(sinfo); return ret; }
/** * gnutls_pkcs11_privkey_generate3: * @url: a token URL * @pk: the public key algorithm * @bits: the security bits * @label: a label * @cid: The CKA_ID to use for the new object * @fmt: the format of output params. PEM or DER * @pubkey: will hold the public key (may be %NULL) * @key_usage: One of GNUTLS_KEY_* * @flags: zero or an OR'ed sequence of %GNUTLS_PKCS11_OBJ_FLAGs * * This function will generate a private key in the specified * by the @url token. The private key will be generate within * the token and will not be exportable. This function will * store the DER-encoded public key in the SubjectPublicKeyInfo format * in @pubkey. The @pubkey should be deinitialized using gnutls_free(). * * Note that when generating an elliptic curve key, the curve * can be substituted in the place of the bits parameter using the * GNUTLS_CURVE_TO_BITS() macro. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.4.0 **/ int gnutls_pkcs11_privkey_generate3(const char *url, gnutls_pk_algorithm_t pk, unsigned int bits, const char *label, const gnutls_datum_t *cid, gnutls_x509_crt_fmt_t fmt, gnutls_datum_t * pubkey, unsigned int key_usage, unsigned int flags) { int ret; const ck_bool_t tval = 1; const ck_bool_t fval = 0; struct pkcs11_session_info sinfo; struct p11_kit_uri *info = NULL; ck_rv_t rv; struct ck_attribute a[22], p[22]; ck_object_handle_t pub_ctx, priv_ctx; unsigned long _bits = bits; int a_val, p_val; struct ck_mechanism mech; gnutls_pubkey_t pkey = NULL; gnutls_pkcs11_obj_t obj = NULL; gnutls_datum_t der = {NULL, 0}; ck_key_type_t key_type; uint8_t id[20]; struct dsa_params dsa_params; PKCS11_CHECK_INIT; FIX_KEY_USAGE(pk, key_usage); memset(&sinfo, 0, sizeof(sinfo)); ret = pkcs11_url_to_info(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(); goto cleanup; } /* a holds the public key template * and p the private key */ a_val = p_val = 0; mech.parameter = NULL; mech.parameter_len = 0; mech.mechanism = pk_to_genmech(pk, &key_type); if (!(flags & GNUTLS_PKCS11_OBJ_FLAG_NO_STORE_PUBKEY)) { a[a_val].type = CKA_TOKEN; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; a[a_val].type = CKA_PRIVATE; a[a_val].value = (void *) &fval; a[a_val].value_len = sizeof(fval); a_val++; } a[a_val].type = CKA_ID; if (cid == NULL || cid->size == 0) { ret = gnutls_rnd(GNUTLS_RND_NONCE, id, sizeof(id)); if (ret < 0) { gnutls_assert(); goto cleanup; } a[a_val].value = (void *) id; a[a_val].value_len = sizeof(id); } else { a[a_val].value = (void *) cid->data; a[a_val].value_len = cid->size; } p[p_val].type = CKA_ID; p[p_val].value = a[a_val].value; p[p_val].value_len = a[a_val].value_len; a_val++; p_val++; switch (pk) { case GNUTLS_PK_RSA: p[p_val].type = CKA_DECRYPT; if (key_usage & (GNUTLS_KEY_DECIPHER_ONLY|GNUTLS_KEY_ENCIPHER_ONLY)) { p[p_val].value = (void *) &tval; p[p_val].value_len = sizeof(tval); } else { p[p_val].value = (void *) &fval; p[p_val].value_len = sizeof(fval); } p_val++; p[p_val].type = CKA_SIGN; if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) { p[p_val].value = (void *) &tval; p[p_val].value_len = sizeof(tval); } else { p[p_val].value = (void *) &fval; p[p_val].value_len = sizeof(fval); } p_val++; a[a_val].type = CKA_ENCRYPT; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; a[a_val].type = CKA_VERIFY; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; a[a_val].type = CKA_MODULUS_BITS; a[a_val].value = &_bits; a[a_val].value_len = sizeof(_bits); a_val++; a[a_val].type = CKA_PUBLIC_EXPONENT; a[a_val].value = (char*)def_rsa_pub_exp; a[a_val].value_len = sizeof(def_rsa_pub_exp); a_val++; break; case GNUTLS_PK_DSA: p[p_val].type = CKA_SIGN; if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) { p[p_val].value = (void *) &tval; p[p_val].value_len = sizeof(tval); } else { p[p_val].value = (void *) &fval; p[p_val].value_len = sizeof(fval); } p_val++; a[a_val].type = CKA_VERIFY; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; ret = _dsa_params_generate(sinfo.module, sinfo.pks, _bits, &dsa_params, a, &a_val); if (ret < 0) { goto cleanup; } break; case GNUTLS_PK_EC: p[p_val].type = CKA_SIGN; if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) { p[p_val].value = (void *) &tval; p[p_val].value_len = sizeof(tval); } else { p[p_val].value = (void *) &fval; p[p_val].value_len = sizeof(fval); } p_val++; a[a_val].type = CKA_VERIFY; a[a_val].value = (void *) &tval; a[a_val].value_len = sizeof(tval); a_val++; if (GNUTLS_BITS_ARE_CURVE(bits)) { bits = GNUTLS_BITS_TO_CURVE(bits); } else { bits = _gnutls_ecc_bits_to_curve(bits); } ret = _gnutls_x509_write_ecc_params(bits, &der); if (ret < 0) { gnutls_assert(); goto cleanup; } a[a_val].type = CKA_EC_PARAMS; a[a_val].value = der.data; a[a_val].value_len = der.size; a_val++; break; default: ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); goto cleanup; } /* * on request, add the CKA_WRAP/CKA_UNWRAP key attribute */ if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_KEY_WRAP) { p[p_val].type = CKA_UNWRAP; p[p_val].value = (void*)&tval; p[p_val].value_len = sizeof(tval); p_val++; a[a_val].type = CKA_WRAP; a[a_val].value = (void*)&tval; a[a_val].value_len = sizeof(tval); a_val++; } /* a private key is set always as private unless * requested otherwise */ if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE) { p[p_val].type = CKA_PRIVATE; p[p_val].value = (void *) &fval; p[p_val].value_len = sizeof(fval); p_val++; } else { p[p_val].type = CKA_PRIVATE; p[p_val].value = (void *) &tval; p[p_val].value_len = sizeof(tval); p_val++; } p[p_val].type = CKA_TOKEN; p[p_val].value = (void *) &tval; p[p_val].value_len = sizeof(tval); p_val++; if (label) { p[p_val].type = CKA_LABEL; p[p_val].value = (void *) label; p[p_val].value_len = strlen(label); p_val++; a[a_val].type = CKA_LABEL; a[a_val].value = (void *) label; a[a_val].value_len = strlen(label); a_val++; } if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE) { p[p_val].type = CKA_SENSITIVE; p[p_val].value = (void *) &tval; p[p_val].value_len = sizeof(tval); p_val++; } else { p[p_val].type = CKA_SENSITIVE; p[p_val].value = (void *) &fval; p[p_val].value_len = sizeof(fval); p_val++; } rv = pkcs11_generate_key_pair(sinfo.module, sinfo.pks, &mech, a, a_val, p, p_val, &pub_ctx, &priv_ctx); if (rv != CKR_OK) { gnutls_assert(); _gnutls_debug_log("p11: %s\n", pkcs11_strerror(rv)); ret = pkcs11_rv_to_err(rv); goto cleanup; } /* extract the public key */ if (pubkey) { ret = gnutls_pubkey_init(&pkey); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_pkcs11_obj_init(&obj); if (ret < 0) { gnutls_assert(); goto cleanup; } obj->pk_algorithm = pk; obj->type = GNUTLS_PKCS11_OBJ_PUBKEY; ret = pkcs11_read_pubkey(sinfo.module, sinfo.pks, pub_ctx, key_type, obj); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_pubkey_import_pkcs11(pkey, obj, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = gnutls_pubkey_export2(pkey, fmt, pubkey); if (ret < 0) { gnutls_assert(); goto cleanup; } } cleanup: if (obj != NULL) gnutls_pkcs11_obj_deinit(obj); if (pkey != NULL) gnutls_pubkey_deinit(pkey); if (sinfo.pks != 0) pkcs11_close_session(&sinfo); gnutls_free(der.data); return ret; }
/*- * _gnutls_pkcs11_privkey_sign_hash: * @key: Holds the key * @hash: holds the data to be signed (should be output of a hash) * @signature: will contain the signature allocated with gnutls_malloc() * * This function will sign the given data using a signature algorithm * supported by the private key. It is assumed that the given data * are the output of a hash function. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. -*/ int _gnutls_pkcs11_privkey_sign_hash (gnutls_pkcs11_privkey_t key, const gnutls_datum_t * hash, gnutls_datum_t * signature) { ck_rv_t rv; int ret; struct ck_mechanism mech; unsigned long siglen; struct ck_function_list *module; ck_session_handle_t pks; ck_object_handle_t obj; FIND_OBJECT (module, pks, obj, key); mech.mechanism = pk_to_mech(key->pk_algorithm); mech.parameter = NULL; mech.parameter_len = 0; /* Initialize signing operation; using the private key discovered * earlier. */ rv = pkcs11_sign_init (module, pks, &mech, obj); if (rv != CKR_OK) { gnutls_assert (); ret = pkcs11_rv_to_err (rv); goto cleanup; } /* Work out how long the signature must be: */ rv = pkcs11_sign (module, pks, hash->data, hash->size, NULL, &siglen); if (rv != CKR_OK) { gnutls_assert (); ret = pkcs11_rv_to_err (rv); goto cleanup; } signature->data = gnutls_malloc (siglen); signature->size = siglen; rv = pkcs11_sign (module, pks, hash->data, hash->size, signature->data, &siglen); if (rv != CKR_OK) { gnutls_free (signature->data); gnutls_assert (); ret = pkcs11_rv_to_err (rv); goto cleanup; } signature->size = siglen; if (key->pk_algorithm == GNUTLS_PK_EC || key->pk_algorithm == GNUTLS_PK_DSA) { bigint_t r,s; if (siglen % 2 != 0) { gnutls_assert(); ret = GNUTLS_E_PK_SIGN_FAILED; goto cleanup; } ret = read_rs(&r, &s, signature->data, signature->size); if (ret < 0) { gnutls_assert(); goto cleanup; } gnutls_free(signature->data); ret = _gnutls_encode_ber_rs (signature, r, s); _gnutls_mpi_release(&r); _gnutls_mpi_release(&s); if (ret < 0) { gnutls_assert(); goto cleanup; } } ret = 0; cleanup: pkcs11_close_session (module, pks); return ret; }