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; }
/* * Class: org_opensc_pkcs11_wrap_PKCS11Session * Method: logoutNative * Signature: (JJJ)V */ JNIEXPORT void JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Session_logoutNative) (JNIEnv *env, jobject jsession, jlong mh, jlong shandle, jlong hsession) { int rv; pkcs11_slot_t *slot; pkcs11_module_t *mod = pkcs11_module_from_jhandle(env,mh); if (!mod) return; slot = pkcs11_slot_from_jhandle(env,shandle); if (!slot) return; rv = mod->method->C_Logout(hsession); if (rv != CKR_OK) { fprintf(stderr,"PKCS11Session.logoutNative: C_Logout for PKCS11 slot %d(" PKCS11_MOD_NAME_FMT ") failed (%s).", (int)slot->id,mod->name,pkcs11_strerror(rv)); } }
/** * 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_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_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_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; }
/* * Set up metaslot for the framework using either user configuration * or system wide configuration options * * Also sets up the global "slottable" to have the first slot be metaslot. */ static CK_RV setup_metaslot(uentry_t *metaslot_entry) { CK_RV rv; CK_MECHANISM_TYPE_PTR prov_pol_mechs = NULL; pkcs11_slot_t *cur_slot; /* process policies for mechanisms */ if ((metaslot_entry) && (metaslot_entry->count > 0)) { rv = pkcs11_mech_parse(metaslot_entry->policylist, &prov_pol_mechs, metaslot_entry->count); if (rv == CKR_HOST_MEMORY) { cryptoerror(LOG_ERR, "libpkcs11: Could not parse configuration," "out of memory. Cannot continue parsing " "%s.\n", _PATH_PKCS11_CONF); return (rv); } else if (rv == CKR_MECHANISM_INVALID) { /* * Configuration file is corrupted for metaslot */ cryptoerror(LOG_ERR, "libpkcs11: Policy invalid or corrupted " "for metaslot. Use cryptoadm(1M) to fix " "this. Disabling metaslot functionality.\n"); metaslot_enabled = B_FALSE; return (rv); } } /* * Check for metaslot policy. If all mechanisms are * disabled, disable metaslot since there is nothing * interesting for it to do */ if ((metaslot_entry) && (metaslot_entry->flag_enabledlist) && (prov_pol_mechs == NULL)) { metaslot_enabled = B_FALSE; return (rv); } /* * save system wide value for metaslot's keystore. * If either slot description or token label is specified by * the user, the system wide value for both is ignored. */ if ((metaslot_entry) && (!metaslot_config.keystore_token_specified) && (!metaslot_config.keystore_slot_specified)) { /* * blank_str is used for comparing with token label, * and slot description, make sure it is better than * the larger of both */ char blank_str[TOKEN_LABEL_SIZE + SLOT_DESCRIPTION_SIZE]; bzero(blank_str, sizeof (blank_str)); if (memcmp(metaslot_entry->metaslot_ks_token, blank_str, TOKEN_LABEL_SIZE) != 0) { metaslot_config.keystore_token_specified = B_TRUE; (void) strlcpy( (char *)metaslot_config.keystore_token, (const char *)metaslot_entry->metaslot_ks_token, TOKEN_LABEL_SIZE); } if (memcmp(metaslot_entry->metaslot_ks_slot, blank_str, SLOT_DESCRIPTION_SIZE) != 0) { metaslot_config.keystore_slot_specified = B_TRUE; (void) strlcpy( (char *)metaslot_config.keystore_slot, (const char *)metaslot_entry->metaslot_ks_slot, SLOT_DESCRIPTION_SIZE); } } /* check system-wide value for auto_key_migrate */ if (metaslot_config.auto_key_migrate_specified) { /* take user's specified value */ metaslot_auto_key_migrate = metaslot_config.auto_key_migrate; } else { if (metaslot_entry) { /* use system-wide default */ metaslot_auto_key_migrate = metaslot_entry->flag_metaslot_auto_key_migrate; } else { /* * there's no system wide metaslot entry, * default auto_key_migrate to true */ metaslot_auto_key_migrate = B_TRUE; } } /* Make first slotID be 0, for metaslot. */ slottable->st_first = 0; /* Set up the slottable entry for metaslot */ slottable->st_slots[0] = NULL; cur_slot = calloc(1, sizeof (pkcs11_slot_t)); if (cur_slot == NULL) { rv = CKR_HOST_MEMORY; return (rv); } cur_slot->sl_wfse_state = WFSE_CLEAR; cur_slot->sl_enabledpol = B_FALSE; cur_slot->sl_no_wfse = B_FALSE; (void) pthread_mutex_init(&cur_slot->sl_mutex, NULL); /* * The metaslot entry was prealloc'd by * pkcs11_slottable_increase() */ (void) pthread_mutex_lock(&slottable->st_mutex); slottable->st_slots[0] = cur_slot; (void) pthread_mutex_unlock(&slottable->st_mutex); (void) pthread_mutex_lock(&cur_slot->sl_mutex); cur_slot->sl_id = METASLOT_SLOTID; cur_slot->sl_func_list = &metaslot_functionList; if (metaslot_entry) { cur_slot->sl_enabledpol = metaslot_entry->flag_enabledlist; cur_slot->sl_pol_count = metaslot_entry->count; } else { /* if no metaslot entry, assume all mechs are enabled */ cur_slot->sl_enabledpol = B_FALSE; cur_slot->sl_pol_count = 0; } cur_slot->sl_pol_mechs = prov_pol_mechs; cur_slot->sl_dldesc = NULL; /* not applicable */ cur_slot->sl_prov_id = 0; (void) pthread_mutex_unlock(&cur_slot->sl_mutex); /* Call the meta_Initialize() to initialize metaslot */ rv = meta_Initialize(NULL); if (rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: Can't initialize metaslot (%s)", pkcs11_strerror(rv)); goto cleanup; } return (CKR_OK); cleanup: metaslot_enabled = B_FALSE; slottable->st_slots[0] = NULL; if (cur_slot) { (void) pthread_mutex_destroy(&cur_slot->sl_mutex); free(cur_slot); } return (rv); }
/* * For each provider found in pkcs11.conf: expand $ISA if necessary, * verify the module is signed, load the provider, find all of its * slots, and store the function list and disabled policy. * * This function requires that the uentrylist_t and pkcs11_slottable_t * already have memory allocated, and that the uentrylist_t is already * populated with provider and policy information. * * pInitArgs can be set to NULL, but is normally the same value * the framework's C_Initialize() was called with. * * Unless metaslot is explicitly disabled, it is setup when all other * providers are loaded. */ CK_RV pkcs11_slot_mapping(uentrylist_t *pplist, CK_VOID_PTR pInitArgs) { CK_RV rv = CKR_OK; CK_RV prov_rv; /* Provider's return code */ CK_INFO prov_info; CK_RV (*Tmp_C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR); CK_FUNCTION_LIST_PTR prov_funcs = NULL; /* Provider's function list */ CK_ULONG prov_slot_count; /* Number of slots */ CK_SLOT_ID slot_id; /* slotID assigned for framework */ CK_SLOT_ID_PTR prov_slots = NULL; /* Provider's slot list */ /* Enabled or Disabled policy */ CK_MECHANISM_TYPE_PTR prov_pol_mechs = NULL; void *dldesc = NULL; char *isa, *fullpath = NULL, *dl_error; uentrylist_t *phead; uint_t prov_count = 0; pkcs11_slot_t *cur_slot; CK_ULONG i; size_t len; uentry_t *metaslot_entry = NULL; /* number of slots in the framework, not including metaslot */ uint_t slot_count = 0; ELFsign_status_t estatus = ELFSIGN_UNKNOWN; char *estatus_str = NULL; int kcfdfd = -1; door_arg_t darg; kcf_door_arg_t *kda = NULL; kcf_door_arg_t *rkda = NULL; int r; phead = pplist; /* Loop through all of the provider listed in pkcs11.conf */ while (phead != NULL) { if (!strcasecmp(phead->puent->name, "metaslot")) { /* * Skip standard processing for metaslot * entry since it is not an actual library * that can be dlopened. * It will be initialized later. */ if (metaslot_entry != NULL) { cryptoerror(LOG_ERR, "libpkcs11: multiple entries for metaslot " "detected. All but the first entry will " "be ignored"); } else { metaslot_entry = phead->puent; } goto contparse; } /* Check for Instruction Set Architecture indicator */ if ((isa = strstr(phead->puent->name, PKCS11_ISA)) != NULL) { /* Substitute the architecture dependent path */ len = strlen(phead->puent->name) - strlen(PKCS11_ISA) + strlen(PKCS11_ISA_DIR) + 1; if ((fullpath = (char *)malloc(len)) == NULL) { cryptoerror(LOG_ERR, "libpksc11: parsing %s, out of memory. " "Cannot continue parsing.", _PATH_PKCS11_CONF); rv = CKR_HOST_MEMORY; goto conferror; } *isa = '\000'; isa += strlen(PKCS11_ISA); (void) snprintf(fullpath, len, "%s%s%s", phead->puent->name, PKCS11_ISA_DIR, isa); } else if ((fullpath = strdup(phead->puent->name)) == 0) { cryptoerror(LOG_ERR, "libpkcs11: parsing %s, out of memory. " "Cannot continue parsing.", _PATH_PKCS11_CONF); rv = CKR_HOST_MEMORY; goto conferror; } /* * Open the provider. Use RTLD_NOW to make sure we * will not encounter symbol referencing errors later. * Use RTLD_GROUP to limit the provider to it's own * symbols, which prevents it from mistakenly accessing * the framework's C_* functions. */ dldesc = dlopen(fullpath, RTLD_NOW|RTLD_GROUP); /* * If we failed to load it, we will just skip this * provider and move on to the next one. */ if (dldesc == NULL) { dl_error = dlerror(); cryptoerror(LOG_ERR, "libpkcs11: Cannot load PKCS#11 library %s. " "dlerror: %s. %s", fullpath, dl_error != NULL ? dl_error : "Unknown", conf_err); goto contparse; } /* Get the pointer to provider's C_GetFunctionList() */ Tmp_C_GetFunctionList = (CK_RV(*)())dlsym(dldesc, "C_GetFunctionList"); /* * If we failed to get the pointer to C_GetFunctionList(), * skip this provider and continue to the next one. */ if (Tmp_C_GetFunctionList == NULL) { cryptoerror(LOG_ERR, "libpkcs11: Could not dlsym() C_GetFunctionList() " "for %s. May not be a PKCS#11 library. %s", fullpath, conf_err); (void) dlclose(dldesc); goto contparse; } /* Get the provider's function list */ prov_rv = Tmp_C_GetFunctionList(&prov_funcs); /* * If we failed to get the provider's function list, * skip this provider and continue to the next one. */ if (prov_rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: Could not get function list for %s. " "%s Error: %s.", fullpath, conf_err, pkcs11_strerror(prov_rv)); (void) dlclose(dldesc); goto contparse; } /* Initialize this provider */ prov_rv = prov_funcs->C_Initialize(pInitArgs); /* * If we failed to initialize this provider, * skip this provider and continue to the next one. */ if ((prov_rv != CKR_OK) && (prov_rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) { cryptoerror(LOG_ERR, "libpkcs11: Could not initialize %s. " "%s Error: %s.", fullpath, conf_err, pkcs11_strerror(prov_rv)); (void) dlclose(dldesc); goto contparse; } /* * Make sure this provider is implementing the same * major version, and at least the same minor version * that we are. */ prov_rv = prov_funcs->C_GetInfo(&prov_info); /* * If we can't verify that we are implementing the * same major version, or if it is definitely not the same * version, we need to skip this provider. */ if ((prov_rv != CKR_OK) || (prov_info.cryptokiVersion.major != CRYPTOKI_VERSION_MAJOR)) { if (prov_rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: Could not verify version of " "%s. %s Error: %s.", fullpath, conf_err, pkcs11_strerror(prov_rv)); } else { cryptoerror(LOG_ERR, "libpkcs11: Only CRYPTOKI major version " "%d is supported. %s is major " "version %d. %s", CRYPTOKI_VERSION_MAJOR, fullpath, prov_info.cryptokiVersion.major, conf_err); } (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); goto contparse; } /* * Warn the administrator (at debug) that a provider with * a significantly older or newer version of * CRYPTOKI is being used. It should not cause * problems, but logging a warning makes it easier * to debug later. */ if ((prov_info.cryptokiVersion.minor < CRYPTOKI_VERSION_WARN_MINOR) || (prov_info.cryptokiVersion.minor > CRYPTOKI_VERSION_MINOR)) { cryptoerror(LOG_DEBUG, "libpkcs11: %s CRYPTOKI minor version, %d, may " "not be compatible with minor version %d.", fullpath, prov_info.cryptokiVersion.minor, CRYPTOKI_VERSION_MINOR); } /* * Find out how many slots this provider has, * call with tokenPresent set to FALSE so all * potential slots are returned. */ prov_rv = prov_funcs->C_GetSlotList(FALSE, NULL, &prov_slot_count); /* * If the call failed, or if no slots are returned, * then skip this provider and continue to next one. */ if (prov_rv != CKR_OK) { cryptoerror(LOG_ERR, "libpksc11: Could not get slot list from %s. " "%s Error: %s.", fullpath, conf_err, pkcs11_strerror(prov_rv)); (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); goto contparse; } if (prov_slot_count == 0) { cryptodebug("libpkcs11: No slots presented from %s. " "Skipping this plug-in at this time.\n", fullpath); (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); goto contparse; } /* * Verify that the module is signed correctly. * * NOTE: there is a potential race condition here, * since the module is verified well after we have * opened the provider via dlopen(). This could be * resolved by a variant of dlopen() that would take a * file descriptor as an argument and by changing the * kcfd libelfsign door protocol to use and fd instead * of a path - but that wouldn't work in the kernel case. */ while ((kcfdfd = open(_PATH_KCFD_DOOR, O_RDONLY)) == -1) { if (!(errno == EINTR || errno == EAGAIN)) break; } if (kcfdfd == -1) { cryptoerror(LOG_ERR, "libpkcs11: open %s: %s", _PATH_KCFD_DOOR, strerror(errno)); goto verifycleanup; } /* Mark the door "close on exec" */ (void) fcntl(kcfdfd, F_SETFD, FD_CLOEXEC); if ((kda = malloc(sizeof (kcf_door_arg_t))) == NULL) { cryptoerror(LOG_ERR, "libpkcs11: malloc of kda " "failed: %s", strerror(errno)); goto verifycleanup; } kda->da_version = KCF_KCFD_VERSION1; kda->da_iskernel = B_FALSE; (void) strlcpy(kda->da_u.filename, fullpath, strlen(fullpath) + 1); darg.data_ptr = (char *)kda; darg.data_size = sizeof (kcf_door_arg_t); darg.desc_ptr = NULL; darg.desc_num = 0; darg.rbuf = (char *)kda; darg.rsize = sizeof (kcf_door_arg_t); while ((r = door_call(kcfdfd, &darg)) != 0) { if (!(errno == EINTR || errno == EAGAIN)) break; } if (r != 0) { cryptoerror(LOG_ERR, "libpkcs11: Unable to contact kcfd: %s", strerror(errno)); goto verifycleanup; } /*LINTED*/ rkda = (kcf_door_arg_t *)darg.rbuf; if (rkda->da_version != KCF_KCFD_VERSION1) { cryptoerror(LOG_ERR, "libpkcs11: kcfd and libelfsign versions " "don't match: got %d expected %d", rkda->da_version, KCF_KCFD_VERSION1); goto verifycleanup; } estatus = rkda->da_u.result.status; verifycleanup: if (kcfdfd != -1) { (void) close(kcfdfd); } if (rkda != NULL && rkda != kda) (void) munmap((char *)rkda, darg.rsize); if (kda != NULL) { bzero(kda, sizeof (kda)); free(kda); kda = NULL; rkda = NULL; /* rkda is an alias of kda */ } switch (estatus) { case ELFSIGN_SUCCESS: case ELFSIGN_RESTRICTED: break; case ELFSIGN_NOTSIGNED: estatus_str = strdup("not a signed provider."); break; case ELFSIGN_FAILED: estatus_str = strdup("signature verification failed."); break; default: estatus_str = strdup("unexpected failure in ELF " "signature verification. " "System may have been tampered with."); } if (estatus_str != NULL) { cryptoerror(LOG_ERR, "libpkcs11: %s %s %s", fullpath, estatus_str ? estatus_str : "", estatus == ELFSIGN_UNKNOWN ? "Cannot continue parsing " _PATH_PKCS11_CONF: conf_err); (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); free(estatus_str); estatus_str = NULL; if (estatus == ELFSIGN_UNKNOWN) { prov_funcs = NULL; dldesc = NULL; rv = CKR_GENERAL_ERROR; goto conferror; } goto contparse; } /* Allocate memory for the slot list */ prov_slots = calloc(prov_slot_count, sizeof (CK_SLOT_ID)); if (prov_slots == NULL) { cryptoerror(LOG_ERR, "libpkcs11: Could not allocate memory for " "plug-in slots. Cannot continue parsing %s\n", _PATH_PKCS11_CONF); rv = CKR_HOST_MEMORY; goto conferror; } /* Get slot list from provider */ prov_rv = prov_funcs->C_GetSlotList(FALSE, prov_slots, &prov_slot_count); /* if second call fails, drop this provider */ if (prov_rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: Second call to C_GetSlotList() for %s " "failed. %s Error: %s.", fullpath, conf_err, pkcs11_strerror(prov_rv)); (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); goto contparse; } /* * Parse the list of disabled or enabled mechanisms, will * apply to each of the provider's slots. */ if (phead->puent->count > 0) { rv = pkcs11_mech_parse(phead->puent->policylist, &prov_pol_mechs, phead->puent->count); if (rv == CKR_HOST_MEMORY) { cryptoerror(LOG_ERR, "libpkcs11: Could not parse configuration," "out of memory. Cannot continue parsing " "%s.", _PATH_PKCS11_CONF); goto conferror; } else if (rv == CKR_MECHANISM_INVALID) { /* * Configuration file is corrupted for this * provider. */ cryptoerror(LOG_ERR, "libpkcs11: Policy invalid or corrupted " "for %s. Use cryptoadm(1M) to fix " "this. Skipping this plug-in.", fullpath); (void) prov_funcs->C_Finalize(NULL); (void) dlclose(dldesc); goto contparse; } } /* Allocate memory in our slottable for these slots */ rv = pkcs11_slottable_increase(prov_slot_count); /* * If any error is returned, it will be memory related, * so we need to abort the attempt at filling the * slottable. */ if (rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: slottable could not increase. " "Cannot continue parsing %s.", _PATH_PKCS11_CONF); goto conferror; } /* Configure information for each new slot */ for (i = 0; i < prov_slot_count; i++) { /* allocate slot in framework */ rv = pkcs11_slot_allocate(&slot_id); if (rv != CKR_OK) { cryptoerror(LOG_ERR, "libpkcs11: Could not allocate " "new slot. Cannot continue parsing %s.", _PATH_PKCS11_CONF); goto conferror; } slot_count++; cur_slot = slottable->st_slots[slot_id]; (void) pthread_mutex_lock(&cur_slot->sl_mutex); cur_slot->sl_id = prov_slots[i]; cur_slot->sl_func_list = prov_funcs; cur_slot->sl_enabledpol = phead->puent->flag_enabledlist; cur_slot->sl_pol_mechs = prov_pol_mechs; cur_slot->sl_pol_count = phead->puent->count; cur_slot->sl_norandom = phead->puent->flag_norandom; cur_slot->sl_dldesc = dldesc; cur_slot->sl_prov_id = prov_count + 1; (void) pthread_mutex_unlock(&cur_slot->sl_mutex); } /* Set and reset values to process next provider */ prov_count++; contparse: prov_slot_count = 0; Tmp_C_GetFunctionList = NULL; prov_funcs = NULL; dldesc = NULL; if (fullpath != NULL) { free(fullpath); fullpath = NULL; } if (prov_slots != NULL) { free(prov_slots); prov_slots = NULL; } phead = phead->next; } if (slot_count == 0) { /* * there's no other slot in the framework, * there is nothing to do */ goto config_complete; } /* determine if metaslot should be enabled */ /* * Check to see if any environment variable is defined * by the user for configuring metaslot. Users' * setting always take precedence over the system wide * setting. So, we will first check for any user's * defined env variables before looking at the system-wide * configuration. */ get_user_metaslot_config(); /* no metaslot entry in /etc/crypto/pkcs11.conf */ if (!metaslot_entry) { /* * If user env variable indicates metaslot should be enabled, * but there's no entry in /etc/crypto/pkcs11.conf for * metaslot at all, will respect the user's defined value */ if ((metaslot_config.enabled_specified) && (metaslot_config.enabled)) { metaslot_enabled = B_TRUE; } } else { if (!metaslot_config.enabled_specified) { /* * take system wide value if * it is not specified by user */ metaslot_enabled = metaslot_entry->flag_metaslot_enabled; } else { metaslot_enabled = metaslot_config.enabled; } } /* * * As long as the user or system configuration file does not * disable metaslot, it will be enabled regardless of the * number of slots plugged into the framework. Therefore, * metaslot is enabled even when there's only one slot * plugged into the framework. This is necessary for * presenting a consistent token label view to applications. * * However, for the case where there is only 1 slot plugged into * the framework, we can use "fastpath". * * "fastpath" will pass all of the application's requests * directly to the underlying provider. Only when policy is in * effect will we need to keep slotID around. * * When metaslot is enabled, and fastpath is enabled, * all the metaslot processing will be skipped. * When there is only 1 slot, there's * really not much metaslot can do in terms of combining functionality * of different slots, and object migration. * */ /* check to see if fastpath can be used */ if (slottable->st_last == slottable->st_first) { cur_slot = slottable->st_slots[slottable->st_first]; (void) pthread_mutex_lock(&cur_slot->sl_mutex); if ((cur_slot->sl_pol_count == 0) && (!cur_slot->sl_enabledpol) && (!cur_slot->sl_norandom)) { /* No policy is in effect, don't need slotid */ fast_funcs = cur_slot->sl_func_list; purefastpath = B_TRUE; } else { fast_funcs = cur_slot->sl_func_list; fast_slot = slottable->st_first; policyfastpath = B_TRUE; } (void) pthread_mutex_unlock(&cur_slot->sl_mutex); } if ((purefastpath || policyfastpath) && (!metaslot_enabled)) { goto config_complete; } /* * If we get here, there are more than 2 slots in the framework, * we need to set up metaslot if it is enabled */ if (metaslot_enabled) { rv = setup_metaslot(metaslot_entry); if (rv != CKR_OK) { goto conferror; } } config_complete: return (CKR_OK); conferror: /* * This cleanup code is only exercised when a major, * unrecoverable error like "out of memory" occurs. */ if (prov_funcs != NULL) { (void) prov_funcs->C_Finalize(NULL); } if (dldesc != NULL) { (void) dlclose(dldesc); } if (fullpath != NULL) { free(fullpath); fullpath = NULL; } if (prov_slots != NULL) { free(prov_slots); prov_slots = NULL; } return (rv); }
static int key_hdl_to_zc(libzfs_handle_t *hdl, zfs_handle_t *zhp, char *keysource, int crypt, zfs_cmd_t *zc, zfs_crypto_zckey_t cmd) { // CK_SESSION_HANDLE session; int ret = 0; key_format_t format; key_locator_t locator; char *uri; //pkcs11_uri_t p11uri; size_t keylen = zio_crypt_table[crypt].ci_keylen; char *keydata = NULL; size_t keydatalen = 0; char *tmpkeydata = NULL; size_t tmpkeydatalen = 0; uint64_t salt; //struct cb_arg_curl cb_curl = { 0 }; fprintf(stderr, "in key_hdl_to_zc\r\n"); zc->zc_crypto.zic_clone_newkey = hdl->libzfs_crypt.zc_clone_newkey; if (!keysource_prop_parser(keysource, &format, &locator, &uri)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid keysource property.")); return (-1); } /* * First check if there was anything in the handle already * if so we use that and we are done with locating the data. * Note that we may be looking at other fields * and zic_clone_newkey even if zc_key_data_len is empty. * * We allow this regardless of the locator so that things * like a PAM module can provide the passphrase but the user * can still have "passphrase,prompt" to use zfs(1M) interactively. */ if (hdl->libzfs_crypt.zc_key_data_len != 0) { keydata = zfs_alloc(hdl, hdl->libzfs_crypt.zc_key_data_len); bcopy(hdl->libzfs_crypt.zc_key_data, keydata, hdl->libzfs_crypt.zc_key_data_len); keydatalen = hdl->libzfs_crypt.zc_key_data_len; goto format_key; } /* * Get the key from the URI or prompt for it. * If the format is raw then prompting is a simple read(2) * otherwise we put up a prompt saying what we are asking for. * We can't do this with the 'zfs mount -a' that is in * sys:/system/filesystem/local:default but we shouldn't * cause errors or warnings there either. */ switch (locator) { case KEY_LOCATOR_PROMPT: if (format == KEY_FORMAT_RAW) { keydata = zfs_alloc(hdl, keylen); errno = 0; keydatalen = read(STDIN_FILENO, keydata, keylen); if (keydatalen != keylen) { free(keydata); return (-1); } } else { int tries = 0; do { /* get_passphrase allocates keydata */ ret = get_passphrase(hdl, &keydata, &keydatalen, format, zc, cmd); } while (ret != 0 && ++tries < 3); if (ret) return (-1); } break; case KEY_LOCATOR_FILE_URI: /* * Need to tell pkcs11_read_data() how big of a key * we want in case the locator URI is a device (eg, /dev/random) * to be read from and not a file. * * Note that pkcs11_read_data allocates memory with malloc * that we need to free. */ #if 0 // FIXME keydatalen = keylen; ret = pkcs11_read_data(&(uri[7]), (void **)&keydata, &keydatalen); if (ret != 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "failed to read key file: %s"), strerror(ret)); errno = ret; return (-1); } #endif break; case KEY_LOCATOR_PKCS11_URI: #if 0 // FIXME keydatalen = keylen; /* * Parse out the PKCS#11 URI and * get the value of the wrapping key. */ if (pkcs11_parse_uri(uri, &p11uri) != PK11_URI_OK) { errno = EINVAL; return (-1); } ret = get_pkcs11_key_value(hdl, zc, cmd, &p11uri, &keydata, &keydatalen); pkcs11_free_uri(&p11uri); if (ret != 0) { return (-1); } #endif break; case KEY_LOCATOR_HTTPS_URI: { #if 0 CURL *curl_hdl = curl_easy_init(); CURLcode cerr; cerr = curl_easy_setopt(curl_hdl, CURLOPT_URL, uri); if (cerr != CURLE_OK) goto curl_fail; cerr = curl_easy_setopt(curl_hdl, CURLOPT_FAILONERROR, 1L); if (cerr != CURLE_OK) goto curl_fail; cerr = curl_easy_setopt(curl_hdl, CURLOPT_WRITEFUNCTION, get_keydata_curl); if (cerr != CURLE_OK) goto curl_fail; cb_curl.cb_hdl = hdl; cerr = curl_easy_setopt(curl_hdl, CURLOPT_WRITEDATA, &cb_curl); if (cerr != CURLE_OK) goto curl_fail; cerr = curl_easy_perform(curl_hdl); curl_fail: /* * Just deal with libcurl errors here, reading the wrong key * size is dealt with generically in the format_key section. */ if (cerr != 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "failed to retreive key from '%s': '%s'"), uri, curl_easy_strerror(cerr)); return (-1); } keydata = cb_curl.cb_keydata; keydatalen = cb_curl.cb_keydatalen; curl_easy_cleanup(curl_hdl); #endif break; case KEY_LOCATOR_NONE: // Avoid Warning break; } } format_key: if (keydata == NULL || keydatalen == 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "key can not be of zero size")); errno = ret; return (-1); } /* * Now that we have the key do any transform that is necessary * such as turning the hex format into raw or in the case of * a passphrase running it through PKCS#5 to get the raw key. * * Note that zic_keydata is not malloc'd memory so that we * don't have to worry about our caller freeing it. */ switch (format) { case KEY_FORMAT_RAW: bcopy(keydata, zc->zc_crypto.zic_keydata, keydatalen); zc->zc_crypto.zic_keydatalen = keydatalen; zc->zc_crypto.zic_salt = 0; break; case KEY_FORMAT_HEX: /* * If the keylen is not on the byte boundary, in terms of hex * format, and that extra char is a linefeed, we can trim it */ if (keydatalen == (keylen * 2) + 1 && keydata[keydatalen] == '\n') { keydatalen--; } /* * hexstr_to_bytes allocates memory with malloc * but we want the data in zic_keydata which isn't malloc'd * so to avoid a memory leak we use a tmpkeydata buffer * and bcopy it. */ #if 0 // FIXME ret = hexstr_to_bytes(keydata, keydatalen, (uchar_t **)&tmpkeydata, &tmpkeydatalen); #endif if (ret) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid hex format key.")); errno = EACCES; ret = -1; goto out; } bcopy(tmpkeydata, zc->zc_crypto.zic_keydata, tmpkeydatalen); bzero(tmpkeydata, tmpkeydatalen); free(tmpkeydata); zc->zc_crypto.zic_keydatalen = tmpkeydatalen; zc->zc_crypto.zic_salt = 0; break; case KEY_FORMAT_PASSPHRASE: /* Remove any extra linefeed that may be on the end */ if (keydata[keydatalen - 1] == '\n') keydatalen--; if (cmd == ZFS_CRYPTO_KEY_LOAD) { salt = zfs_prop_get_int(zhp, ZFS_PROP_SALT); } else { #if 0 // FIXME ret = pkcs11_get_random(&salt, sizeof (uint64_t)); if (ret) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "failed to obtain salt: %s."), pkcs11_strerror(ret)); errno = EINVAL; ret = -1; goto out; } #endif } fprintf(stderr, "Key is '%s' and is len %u\r\n", keydata, keydatalen); // FIXME tmpkeydata = strdup(keydata); tmpkeydatalen = keydatalen; salt = 0x1234; #if 0 // FIXME ret = SUNW_C_GetMechSession(CKM_PKCS5_PBKD2, &session); if (ret) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "failed to access CKM_PKCS5_PBKD2: %s."), pkcs11_strerror(ret)); errno = EINVAL; ret = -1; goto out; } /* * pkcs11_PasswdToKey allocates memory with malloc * but we want the data in zic_keydata which isn't malloc'd * so to avoid a memory leak we use a tmpkeydata buffer * and bcopy it. */ ret = pkcs11_PasswdToKey(session, keydata, keydatalen, (void *)&salt, sizeof (uint64_t), CKK_AES, keylen, (void **)&tmpkeydata, &tmpkeydatalen); (void) C_CloseSession(session); if (ret) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "failed to generate key: %s."), pkcs11_strerror(ret)); errno = EINVAL; ret = -1; goto out; } #endif bcopy(tmpkeydata, zc->zc_crypto.zic_keydata, tmpkeydatalen); bzero(tmpkeydata, tmpkeydatalen); free(tmpkeydata); zc->zc_crypto.zic_keydatalen = tmpkeydatalen; zc->zc_crypto.zic_salt = salt; break; default: ASSERT(format); } if (zc->zc_crypto.zic_keydatalen != keylen) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "key length invalid. expected %lu bytes have %lu"), keylen, zc->zc_crypto.zic_keydatalen); errno = EIO; ret = -1; } if (tmpkeydatalen) // Only decrease if NOT zero. tmpkeydatalen--; while (zc->zc_crypto.zic_keydata[tmpkeydatalen] == 0 && tmpkeydatalen > 0) tmpkeydatalen--; if (tmpkeydatalen == 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid all zeros key %lu"), tmpkeydatalen); errno = EIO; ret = -1; } out: if (keydata) { bzero(keydata, keydatalen); free(keydata); } 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; }
/* * Lists all slots with tokens in them. */ int pk_tokens(int argc, char *argv[]) { CK_SLOT_ID_PTR slots = NULL; CK_ULONG slot_count = 0; CK_TOKEN_INFO token_info; const char *fmt = NULL; CK_RV rv = CKR_OK; int i; cryptodebug("inside pk_tokens"); /* Get rid of subcommand word "tokens". */ argc--; argv++; /* No additional args allowed. */ if (argc != 0) return (PK_ERR_USAGE); /* Done parsing command line options. */ /* Get the list of slots with tokens in them. */ if ((rv = get_token_slots(&slots, &slot_count)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to get token slot list (%s)."), pkcs11_strerror(rv)); return (PK_ERR_PK11); } /* Make sure we have something to display. */ if (slot_count == 0) { cryptoerror(LOG_STDERR, gettext("No slots with tokens found.")); return (0); } /* Display the list. */ fmt = "%-30.30s %-15.15s %-15.15s %-10.10s\n"; /* No I18N/L10N. */ (void) fprintf(stdout, fmt, gettext("Token Label"), gettext("Manuf ID"), gettext("Serial No"), gettext("PIN State")); for (i = 0; i < slot_count; i++) { cryptodebug("calling C_GetTokenInfo"); if ((rv = C_GetTokenInfo(slots[i], &token_info)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to get slot %d token info (%s)."), i, pkcs11_strerror(rv)); cryptodebug("token info error, slot %d (%s)", i, pkcs11_strerror(rv)); continue; } (void) fprintf(stdout, fmt, token_info.label, token_info.manufacturerID, token_info.serialNumber, (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) ? gettext("default") : gettext("user set")); } /* Clean up. */ free(slots); quick_finish(NULL); return (0); }