Reported by Jonathan Nieder <jrnieder@gmail.com> in
<http://bugs.debian.org/640639>.
+** libgnutls: Added support for elliptic curves in
+PKCS #11.
+
** libgnutls: Added gnutls_pkcs11_privkey_generate()
to allow generating a key in a token.
** API and ABI modifications:
gnutls_pkcs11_privkey_generate: Added
+gnutls_pubkey_import_ecc_raw: Added
+gnutls_pubkey_import_ecc_x962: Added
+gnutls_pubkey_get_pk_ecc_x962: Added
* Version 3.0.2 (released 2011-09-01)
#include <x509/common.h>
#include <x509_b64.h>
#include <abstract_int.h>
+#include <gnutls_ecc.h>
#define PK_PEM_HEADER "PUBLIC KEY"
&obj->pubkey[1],
&obj->pubkey[2], &obj->pubkey[3]);
break;
+ case GNUTLS_PK_ECC:
+ ret = gnutls_pubkey_import_ecc_x962 (key, &obj->pubkey[0],
+ &obj->pubkey[1]);
+ break;
default:
gnutls_assert ();
return GNUTLS_E_UNIMPLEMENTED_FEATURE;
return 0;
}
+/**
+ * gnutls_pubkey_get_pk_ecc_x962:
+ * @key: Holds the public key
+ * @parameters: DER encoding of an ANSI X9.62 parameters
+ * @ecpoint: DER encoding of ANSI X9.62 ECPoint
+ *
+ * This function will export the ECC public key's parameters found in
+ * the given certificate. The new parameters will be allocated using
+ * gnutls_malloc() and will be stored in the appropriate datum.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
+ *
+ * Since: 3.0.0
+ **/
+int gnutls_pubkey_get_pk_ecc_x962 (gnutls_pubkey_t key, gnutls_datum_t* parameters,
+ gnutls_datum_t * ecpoint)
+{
+ int ret;
+
+ if (key == NULL || key->pk_algorithm != GNUTLS_PK_ECC)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ ret = _gnutls_x509_write_ecc_pubkey(&key->params, ecpoint);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = _gnutls_x509_write_ecc_params(&key->params, parameters);
+ if (ret < 0)
+ {
+ _gnutls_free_datum(ecpoint);
+ return gnutls_assert_val(ret);
+ }
+
+ return 0;
+}
+
/**
* gnutls_pubkey_import:
* @key: The structure to store the parsed public key.
return 0;
}
+/**
+ * gnutls_pubkey_import_ecc_raw:
+ * @key: The structure to store the parsed key
+ * @curve: holds the curve
+ * @x: holds the x
+ * @y: holds the y
+ *
+ * This function will convert the given elliptic curve parameters to a
+ * #gnutls_pubkey_t. The output will be stored in @key.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.0.0
+ **/
+int
+gnutls_pubkey_import_ecc_raw (gnutls_pubkey_t key,
+ gnutls_ecc_curve_t curve,
+ const gnutls_datum_t * x,
+ const gnutls_datum_t * y)
+{
+ int ret;
+
+ if (key == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ key->params.flags = curve;
+
+ ret = _gnutls_ecc_curve_fill_params(curve, &key->params);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ if (_gnutls_mpi_scan_nz (&key->params.params[5], x->data, x->size))
+ {
+ gnutls_assert ();
+ ret = GNUTLS_E_MPI_SCAN_FAILED;
+ goto cleanup;
+ }
+ key->params.params_nr++;
+
+ if (_gnutls_mpi_scan_nz (&key->params.params[6], y->data, y->size))
+ {
+ gnutls_assert ();
+ ret = GNUTLS_E_MPI_SCAN_FAILED;
+ goto cleanup;
+ }
+ key->params.params_nr++;
+ key->pk_algorithm = GNUTLS_PK_ECC;
+
+ return 0;
+
+cleanup:
+ gnutls_pk_params_release(&key->params);
+ return ret;
+}
+
+/**
+ * gnutls_pubkey_import_ecc_x962:
+ * @key: The structure to store the parsed key
+ * @parameters: DER encoding of an ANSI X9.62 parameters
+ * @ecpoint: DER encoding of ANSI X9.62 ECPoint
+ *
+ * This function will convert the given elliptic curve parameters to a
+ * #gnutls_pubkey_t. The output will be stored in @key.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.0.0
+ **/
+int
+gnutls_pubkey_import_ecc_x962 (gnutls_pubkey_t key,
+ const gnutls_datum_t * parameters,
+ const gnutls_datum_t * ecpoint)
+{
+ int ret;
+
+ if (key == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ key->params.params_nr = 0;
+
+ ret = _gnutls_x509_read_ecc_params(parameters->data, parameters->size,
+ &key->params);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ goto cleanup;
+ }
+
+ ret = _gnutls_ecc_ansi_x963_import(ecpoint->data, ecpoint->size,
+ &key->params.params[5], &key->params.params[6]);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ goto cleanup;
+ }
+ key->params.params_nr+=2;
+ key->pk_algorithm = GNUTLS_PK_ECC;
+
+ return 0;
+
+cleanup:
+ gnutls_pk_params_release(&key->params);
+ return ret;
+}
+
/**
* gnutls_pubkey_import_dsa_raw:
* @key: The structure to store the parsed key
gnutls_datum_t * g, gnutls_datum_t * y);
int gnutls_pubkey_get_pk_ecc_raw (gnutls_pubkey_t key, gnutls_ecc_curve_t *curve,
gnutls_datum_t * x, gnutls_datum_t * y);
+int gnutls_pubkey_get_pk_ecc_x962 (gnutls_pubkey_t key, gnutls_datum_t* parameters,
+ gnutls_datum_t * ecpoint);
int gnutls_pubkey_export (gnutls_pubkey_t key,
gnutls_x509_crt_fmt_t format,
const gnutls_datum_t * m,
const gnutls_datum_t * e);
+int
+gnutls_pubkey_import_ecc_x962 (gnutls_pubkey_t key,
+ const gnutls_datum_t * parameters,
+ const gnutls_datum_t * ecpoint);
+
+int
+gnutls_pubkey_import_ecc_raw (gnutls_pubkey_t key,
+ gnutls_ecc_curve_t curve,
+ const gnutls_datum_t * x,
+ const gnutls_datum_t * y);
+
int gnutls_x509_crt_set_pubkey (gnutls_x509_crt_t crt, gnutls_pubkey_t key);
int gnutls_x509_crq_set_pubkey (gnutls_x509_crq_t crq, gnutls_pubkey_t key);
gnutls_alert_get_strname;
gnutls_pcert_list_import_x509_raw;
gnutls_pkcs11_privkey_generate;
+ gnutls_pubkey_import_ecc_raw;
+ gnutls_pubkey_import_ecc_raw2;
} GNUTLS_2_12;
GNUTLS_PRIVATE {
return 0;
}
-static int
-pkcs11_obj_import_pubkey (struct ck_function_list *module,
- ck_session_handle_t pks,
- ck_object_handle_t obj,
- gnutls_pkcs11_obj_t crt,
- const gnutls_datum_t * id,
- const gnutls_datum_t * label,
- struct ck_token_info *tinfo,
- struct ck_info *lib_info)
+static int read_pkcs11_pubkey(struct ck_function_list *module,
+ ck_session_handle_t pks, ck_object_handle_t obj,
+ ck_key_type_t key_type, gnutls_datum_t * pubkey)
{
-
struct ck_attribute a[4];
- ck_key_type_t key_type;
opaque tmp1[2048];
opaque tmp2[2048];
int ret;
- ck_bool_t tval;
- 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)
- {
switch (key_type)
{
case CKK_RSA:
{
ret =
- _gnutls_set_datum (&crt->pubkey[0],
+ _gnutls_set_datum (&pubkey[0],
a[0].value, a[0].value_len);
if (ret >= 0)
ret =
- _gnutls_set_datum (&crt->pubkey
+ _gnutls_set_datum (&pubkey
[1], a[1].value, a[1].value_len);
if (ret < 0)
{
gnutls_assert ();
- _gnutls_free_datum (&crt->pubkey[1]);
- _gnutls_free_datum (&crt->pubkey[0]);
+ _gnutls_free_datum (&pubkey[1]);
+ _gnutls_free_datum (&pubkey[0]);
return GNUTLS_E_MEMORY_ERROR;
}
}
gnutls_assert ();
return GNUTLS_E_PKCS11_ERROR;
}
- crt->pk_algorithm = GNUTLS_PK_RSA;
break;
case CKK_DSA:
a[0].type = CKA_PRIME;
if (pkcs11_get_attribute_value (module, pks, obj, a, 2) == CKR_OK)
{
ret =
- _gnutls_set_datum (&crt->pubkey[0],
+ _gnutls_set_datum (&pubkey[0],
a[0].value, a[0].value_len);
if (ret >= 0)
ret =
- _gnutls_set_datum (&crt->pubkey
+ _gnutls_set_datum (&pubkey
[1], a[1].value, a[1].value_len);
if (ret < 0)
{
gnutls_assert ();
- _gnutls_free_datum (&crt->pubkey[1]);
- _gnutls_free_datum (&crt->pubkey[0]);
+ _gnutls_free_datum (&pubkey[1]);
+ _gnutls_free_datum (&pubkey[0]);
return GNUTLS_E_MEMORY_ERROR;
}
}
if (pkcs11_get_attribute_value (module, pks, obj, a, 2) == CKR_OK)
{
ret =
- _gnutls_set_datum (&crt->pubkey[2],
+ _gnutls_set_datum (&pubkey[2],
a[0].value, a[0].value_len);
if (ret >= 0)
ret =
- _gnutls_set_datum (&crt->pubkey
+ _gnutls_set_datum (&pubkey
[3], a[1].value, a[1].value_len);
if (ret < 0)
{
gnutls_assert ();
- _gnutls_free_datum (&crt->pubkey[0]);
- _gnutls_free_datum (&crt->pubkey[1]);
- _gnutls_free_datum (&crt->pubkey[2]);
- _gnutls_free_datum (&crt->pubkey[3]);
+ _gnutls_free_datum (&pubkey[0]);
+ _gnutls_free_datum (&pubkey[1]);
+ _gnutls_free_datum (&pubkey[2]);
+ _gnutls_free_datum (&pubkey[3]);
return GNUTLS_E_MEMORY_ERROR;
}
}
gnutls_assert ();
return GNUTLS_E_PKCS11_ERROR;
}
- crt->pk_algorithm = GNUTLS_PK_RSA;
+ break;
+ case CKK_ECDSA:
+ a[0].type = CKA_EC_PARAMS;
+ a[0].value = tmp1;
+ a[0].value_len = sizeof (tmp1);
+ a[1].type = CKA_EC_POINT;
+ a[1].value = tmp2;
+ a[1].value_len = sizeof (tmp2);
+
+ if (pkcs11_get_attribute_value (module, pks, obj, a, 2) == CKR_OK)
+ {
+ ret =
+ _gnutls_set_datum (&pubkey[0],
+ a[0].value, a[0].value_len);
+
+ if (ret >= 0)
+ ret =
+ _gnutls_set_datum (&pubkey
+ [1], a[1].value, a[1].value_len);
+
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ _gnutls_free_datum (&pubkey[1]);
+ _gnutls_free_datum (&pubkey[0]);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ }
+ else
+ {
+ gnutls_assert ();
+ return GNUTLS_E_PKCS11_ERROR;
+ }
+
break;
default:
- gnutls_assert ();
- return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+ return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
}
+
+ return 0;
+}
+
+static int
+pkcs11_obj_import_pubkey (struct ck_function_list *module,
+ ck_session_handle_t pks,
+ ck_object_handle_t obj,
+ gnutls_pkcs11_obj_t crt,
+ const gnutls_datum_t * id,
+ const gnutls_datum_t * label,
+ struct ck_token_info *tinfo,
+ struct ck_info *lib_info)
+{
+ struct ck_attribute a[4];
+ ck_key_type_t key_type;
+ int ret;
+ ck_bool_t tval;
+
+ 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)
+ {
+ crt->pk_algorithm = mech_to_pk(key_type);
+
+ ret = read_pkcs11_pubkey(module, pks, obj, key_type, crt->pubkey);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
}
/* read key usage flags */
return CKM_RSA_PKCS;
}
+static inline gnutls_pk_algorithm_t mech_to_pk(ck_key_type_t m)
+{
+ if (m == CKK_RSA)
+ return GNUTLS_PK_RSA;
+ else if (m == CKK_DSA)
+ return GNUTLS_PK_DSA;
+ else if (m == CKK_ECDSA)
+ return GNUTLS_PK_ECC;
+ else return GNUTLS_PK_UNKNOWN;
+}
+
static inline int pk_to_genmech(gnutls_pk_algorithm_t pk)
{
if (pk == GNUTLS_PK_DSA)
if (pkcs11_get_attribute_value (module, pks, obj, a, 1) == CKR_OK)
{
- switch (key_type)
+ pkey->pk_algorithm = mech_to_pk(key_type);
+ if (pkey->pk_algorithm == GNUTLS_PK_UNKNOWN)
{
- case CKK_RSA:
- pkey->pk_algorithm = GNUTLS_PK_RSA;
- break;
- case CKK_DSA:
- pkey->pk_algorithm = GNUTLS_PK_DSA;
- break;
- default:
_gnutls_debug_log("Cannot determine PKCS #11 key algorithm\n");
ret = GNUTLS_E_UNKNOWN_ALGORITHM;
goto cleanup;
gnutls_datum_t p, q, g, y, x;
gnutls_datum_t m, e, d, u, exp1, exp2;
+ 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);
if (ret < 0)
a[a_val].value_len = x.size;
a_val++;
+ break;
+ }
+ case GNUTLS_PK_ECC:
+ {
+ ret = _gnutls_x509_write_ecc_params(&key->params, &p);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ goto cleanup;
+ }
+
+ ret = _gnutls_mpi_dprint_lz(&key->params.params[7], &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:
goto cleanup;
}
- /* generated!
- */
+ ret = 0;
+cleanup:
switch (pk)
{
case GNUTLS_PK_RSA:
gnutls_free (x.data);
break;
}
+ case GNUTLS_PK_ECC:
+ {
+ gnutls_free (p.data);
+ gnutls_free (x.data);
+ break;
+ }
default:
gnutls_assert ();
ret = GNUTLS_E_INVALID_REQUEST;
goto cleanup;
}
- ret = 0;
-
-cleanup:
if (pks != 0)
pkcs11_close_session (module, pks);
static int
_gnutls_x509_read_dsa_params (opaque * der, int dersize, gnutls_pk_params_st * params);
-static int
-_gnutls_x509_read_ecc_params (opaque * der, int dersize, gnutls_pk_params_st * params);
-
/*
* some x509 certificate parsing functions that relate to MPI parameter
* extraction. This reads the BIT STRING subjectPublicKey.
/* reads the curve from the certificate.
* params[0-4]. It does NOT set params_nr.
*/
-static int
+int
_gnutls_x509_read_ecc_params (opaque * der, int dersize, gnutls_pk_params_st * params)
{
int ret;
static int _gnutls_x509_write_dsa_pubkey (gnutls_pk_params_st * params,
gnutls_datum_t * der);
-static int _gnutls_x509_write_ecc_params (gnutls_pk_params_st * params,
- gnutls_datum_t * der);
-static int _gnutls_x509_write_ecc_pubkey (gnutls_pk_params_st * params,
- gnutls_datum_t * der);
-
-
/*
* some x509 certificate functions that relate to MPI parameter
* setting. This writes the BIT STRING subjectPublicKey.
*
* Allocates the space used to store the DER data.
*/
-static int
+int
_gnutls_x509_write_ecc_pubkey (gnutls_pk_params_st * params,
gnutls_datum_t * der)
{
int result;
- ASN1_TYPE spk = ASN1_TYPE_EMPTY;
der->data = NULL;
der->size = 0;
if (params->params_nr < ECC_PUBLIC_PARAMS)
- {
- gnutls_assert ();
- result = GNUTLS_E_INVALID_REQUEST;
- goto cleanup;
- }
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
result = _gnutls_ecc_ansi_x963_export(params->flags, params->params[5], params->params[6], /*&out*/der);
if (result < 0)
return gnutls_assert_val(result);
- result = 0;
-
-cleanup:
- asn1_delete_structure (&spk);
-
- return result;
+ return 0;
}
int
*
* Allocates the space used to store the DER data.
*/
-static int
+int
_gnutls_x509_write_ecc_params (gnutls_pk_params_st* params,
gnutls_datum_t * der)
{
* @y: holds the y
* @k: holds the k
*
- * This function will convert the given DSA raw parameters to the
+ * This function will convert the given elliptic curve parameters to the
* native #gnutls_x509_privkey_t format. The output will be stored
* in @key.
*
ASN1_TYPE _gnutls_privkey_decode_ecc_key (const gnutls_datum_t *
raw_key,
gnutls_x509_privkey_t pkey);
+
+int
+_gnutls_x509_read_ecc_params (opaque * der, int dersize, gnutls_pk_params_st * params);
+
int _gnutls_asn1_encode_privkey (gnutls_pk_algorithm_t pk, ASN1_TYPE * c2, gnutls_pk_params_st * params);
/* extensions.c */
int _gnutls_x509_read_pubkey (gnutls_pk_algorithm_t, opaque * der, int dersize,
gnutls_pk_params_st * params);
+int _gnutls_x509_write_ecc_params (gnutls_pk_params_st * params,
+ gnutls_datum_t * der);
+int _gnutls_x509_write_ecc_pubkey (gnutls_pk_params_st * params,
+ gnutls_datum_t * der);
+
int
_gnutls_x509_write_pubkey_params (gnutls_pk_algorithm_t algo,
gnutls_pk_params_st* params,
const char *request;
const char *ca;
const char *ca_privkey;
+ int bits;
+ const char* sec_param;
} common_info_st;
gnutls_pubkey_t load_public_key_or_import(int mand, gnutls_privkey_t privkey, common_info_st * info);
gnutls_sec_param_t str_to_sec_param (const char *str);
/* prime.c */
-int generate_prime (int how);
+int generate_prime (int how, common_info_st * info);
FILE *safe_open_rw (const char *file, int privkey_op);
cinfo.request = info.request;
cinfo.ca = info.ca;
cinfo.ca_privkey = info.ca_privkey;
+ cinfo.bits = info.bits;
+ cinfo.sec_param = info.sec_param;
switch (info.action)
{
pkcs12_info ();
break;
case ACTION_GENERATE_DH:
- generate_prime (1);
+ generate_prime (1, &cinfo);
break;
case ACTION_GET_DH:
- generate_prime (0);
+ generate_prime (0, &cinfo);
break;
case ACTION_CRL_INFO:
crl_info ();
[0x2000] = "CKM_DSA_PARAMETER_GEN",
[0x2001] = "CKM_DH_PKCS_PARAMETER_GEN",
[0x2002] = "CKM_X9_42_DH_PARAMETER_GEN",
+ [0x1200] = "CKM_GOSTR3410_KEY_PAIR_GEN",
+ [0x1201] = "CKM_GOSTR3410",
+ [0x1202] = "CKM_GOSTR3410_WITH_GOSTR3411",
+ [0x1203] = "CKM_GOSTR3410_KEY_WRAP",
+ [0x1204] = "CKM_GOSTR3410_DERIVE",
+ [0x1210] = "CKM_GOSTR3411",
+ [0x1211] = "CKM_GOSTR3411_HMAC",
[0x255] = "CKM_SHA224",
[0x256] = "CKM_SHA224_HMAC",
[0x257] = "CKM_SHA224_HMAC_GENERAL",
extern FILE *outfile;
extern FILE *infile;
-static int cparams = 0;
+const static int cparams = 0;
/* If how is zero then the included parameters are used.
*/
int
-generate_prime (int how)
+generate_prime (int how, common_info_st * info)
{
unsigned int i;
int ret;
gnutls_dh_params_t dh_params;
gnutls_datum_t p, g;
- int bits = get_bits (GNUTLS_PK_DH);
+ int bits = get_bits (GNUTLS_PK_DH, info->bits, info->sec_param);
gnutls_dh_params_init (&dh_params);
- fprintf (stderr, "Generating DH parameters...");
+ if (how != 0)
+ {
+ fprintf (stderr, "Generating DH parameters (%d bits)...\n", bits);
+ fprintf (stderr, "(might take long time)\n");
+ }
+ else
+ fprintf (stderr, "Retrieving DH parameters...\n", bits);
if (how != 0)
{
{
p = gnutls_srp_1024_group_prime;
g = gnutls_srp_1024_group_generator;
+ bits = 1024;
}
else if (bits <= 1536)
{
p = gnutls_srp_1536_group_prime;
g = gnutls_srp_1536_group_generator;
+ bits = 1536;
}
else
{
p = gnutls_srp_2048_group_prime;
g = gnutls_srp_2048_group_generator;
+ bits = 2048;
}
ret = gnutls_dh_params_import_raw (dh_params, &p, &g);
exit (1);
}
#else
- fprintf (stderr, "Parameters unavailable as SRP disabled.\n");
+ fprintf (stderr, "Parameters unavailable as SRP is disabled.\n");
+ exit(1);
#endif
}
}
else
{
- fprintf (outfile, "Prime: ");
+ fprintf (outfile, "Prime (%d bits):", bits);
for (i = 0; i < p.size; i++)
{
- if (i != 0 && i % 12 == 0)
+ if (i % 12 == 0)
fprintf (outfile, "\n\t");
else if (i != 0 && i != p.size)
fprintf (outfile, ":");