int get_bits(gnutls_pk_algorithm_t key_type, int info_bits, const char *info_sec_param, int warn) { int bits; if (info_bits != 0) { static int warned = 0; if (warned == 0 && warn != 0 && GNUTLS_BITS_ARE_CURVE(info_bits)==0) { warned = 1; fprintf(stderr, "** Note: You may use '--sec-param %s' instead of '--bits %d'\n", bits_to_sp(key_type, info_bits), info_bits); } bits = info_bits; } else { if (info_sec_param == 0) { /* For ECDSA keys use 256 bits or better, as they are widely supported */ info_sec_param = "HIGH"; } bits = gnutls_sec_param_to_pk_bits(key_type, str_to_sec_param (info_sec_param)); } return bits; }
/** * gnutls_x509_privkey_generate: * @key: should contain a #gnutls_x509_privkey_t structure * @algo: is one of the algorithms in #gnutls_pk_algorithm_t. * @bits: the size of the modulus * @flags: unused for now. Must be 0. * * This function will generate a random private key. Note that this * function must be called on an empty private key. * * 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. * * For DSA keys, if the subgroup size needs to be specified check * the GNUTLS_SUBGROUP_TO_BITS() macro. * * Do not set the number of bits directly, use gnutls_sec_param_to_pk_bits(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_x509_privkey_generate(gnutls_x509_privkey_t key, gnutls_pk_algorithm_t algo, unsigned int bits, unsigned int flags) { int ret; if (key == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } gnutls_pk_params_init(&key->params); if (algo == GNUTLS_PK_EC) { if (GNUTLS_BITS_ARE_CURVE(bits)) bits = GNUTLS_BITS_TO_CURVE(bits); else bits = _gnutls_ecc_bits_to_curve(bits); } ret = _gnutls_pk_generate_params(algo, bits, &key->params); if (ret < 0) { gnutls_assert(); return ret; } ret = _gnutls_pk_generate_keys(algo, bits, &key->params); if (ret < 0) { gnutls_assert(); return ret; } #ifndef ENABLE_FIPS140 ret = _gnutls_pk_verify_priv_params(algo, &key->params); #else ret = pct_test(algo, &key->params); #endif if (ret < 0) { gnutls_assert(); return ret; } ret = _gnutls_asn1_encode_privkey(algo, &key->key, &key->params); if (ret < 0) { gnutls_assert(); goto cleanup; } key->pk_algorithm = algo; return 0; cleanup: key->pk_algorithm = GNUTLS_PK_UNKNOWN; gnutls_pk_params_clear(&key->params); gnutls_pk_params_release(&key->params); 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; }