diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2010-05-23 14:05:32 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2010-06-03 19:54:31 +0200 |
commit | d4a4643dbe1bd739e55706fa4affaf10aae1dfa9 (patch) | |
tree | 9370894ecc414e53d4cca7aa2449c24e10ec89bc | |
parent | b6e40a9119444a56af19f5bbbd33c3842b758438 (diff) | |
download | gnutls-d4a4643dbe1bd739e55706fa4affaf10aae1dfa9.tar.gz |
Added support to copy certificates and private keys to tokens.
New functions:
gnutls_pkcs11_copy_x509_crt()
gnutls_pkcs11_copy_x509_privkey()
gnutls_pkcs11_delete_url()
Certtool was updated to allow copying certificates and private keys
to tokens. Deleting an object has issues (segfault) but it seems to be related
with libopensc and its pkcs11 API.
-rw-r--r-- | lib/Makefile.am | 7 | ||||
-rw-r--r-- | lib/gcrypt/mpi.c | 1 | ||||
-rw-r--r-- | lib/gcrypt/pk.c | 37 | ||||
-rw-r--r-- | lib/includes/gnutls/crypto.h | 8 | ||||
-rw-r--r-- | lib/includes/gnutls/pkcs11.h | 11 | ||||
-rw-r--r-- | lib/includes/gnutls/x509.h | 14 | ||||
-rw-r--r-- | lib/libgnutls.map | 3 | ||||
-rw-r--r-- | lib/nettle/pk.c | 16 | ||||
-rw-r--r-- | lib/pkcs11.c | 305 | ||||
-rw-r--r-- | lib/pkcs11_int.h | 9 | ||||
-rw-r--r-- | lib/pkcs11_privkey.c | 37 | ||||
-rw-r--r-- | lib/pkcs11_write.c | 508 | ||||
-rw-r--r-- | lib/x509/privkey.c | 246 | ||||
-rw-r--r-- | lib/x509/x509_int.h | 8 | ||||
-rw-r--r-- | src/certtool-common.h | 14 | ||||
-rw-r--r-- | src/certtool-gaa.c | 219 | ||||
-rw-r--r-- | src/certtool-gaa.h | 6 | ||||
-rw-r--r-- | src/certtool.c | 12 | ||||
-rw-r--r-- | src/certtool.gaa | 11 | ||||
-rw-r--r-- | src/crypt-gaa.c | 64 | ||||
-rw-r--r-- | src/pkcs11.c | 37 |
21 files changed, 1225 insertions, 348 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 061184035b..12b686bb03 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -80,10 +80,9 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c gnutls_cipher.c \ gnutls_str.c gnutls_state.c gnutls_x509.c ext_cert_type.c \ gnutls_rsa_export.c auth_rsa_export.c ext_server_name.c \ auth_dh_common.c gnutls_helper.c gnutls_supplemental.c \ - crypto.c random.c pk-libgcrypt.c mpi-libgcrypt.c cryptodev.c \ - rnd-libgcrypt.c cipher-libgcrypt.c ext_signature.c \ - crypto-api.c ext_safe_renegotiation.c gnutls_mbuffers.c \ - gnutls_privkey.c pkcs11.c pkcs11_privkey.c gnutls_pubkey.c + crypto.c random.c cryptodev.c ext_signature.c crypto-api.c \ + ext_safe_renegotiation.c gnutls_mbuffers.c gnutls_privkey.c pkcs11.c \ + pkcs11_privkey.c gnutls_pubkey.c pkcs11_write.c if ENABLE_PKCS11 COBJECTS += pkcs11.c pkcs11_privkey.c diff --git a/lib/gcrypt/mpi.c b/lib/gcrypt/mpi.c index d45f023514..6adbb1bc9c 100644 --- a/lib/gcrypt/mpi.c +++ b/lib/gcrypt/mpi.c @@ -78,6 +78,7 @@ wrap_gcry_mpi_print (const bigint_t a, void *buffer, size_t * nbytes, ret = gcry_mpi_print (format, buffer, *nbytes, nbytes, a); if (!ret) { if (buffer==NULL || init_bytes < *nbytes) { + (*nbytes)++; return GNUTLS_E_SHORT_MEMORY_BUFFER; } return 0; diff --git a/lib/gcrypt/pk.c b/lib/gcrypt/pk.c index 5e0b159be6..84fedfe4aa 100644 --- a/lib/gcrypt/pk.c +++ b/lib/gcrypt/pk.c @@ -625,8 +625,9 @@ static int _rsa_generate_params (bigint_t * resarr, int *resarr_len, int bits) { - int ret; + int ret, i; gcry_sexp_t parms, key, list; + bigint_t tmp; ret = gcry_sexp_build (&parms, NULL, "(genkey(rsa(nbits %d)))", bits); if (ret != 0) @@ -722,9 +723,43 @@ _rsa_generate_params (bigint_t * resarr, int *resarr_len, int bits) _gnutls_mpi_log ("q: ", resarr[4]); _gnutls_mpi_log ("u: ", resarr[5]); + /* generate e1 and e2 */ + *resarr_len = 6; + + tmp = _gnutls_mpi_alloc_like(resarr[0]); + if (tmp == NULL) + { + gnutls_assert (); + ret = GNUTLS_E_MEMORY_ERROR; + goto cleanup; + } + + /* [6] = d % p-1, [7] = d % q-1 */ + _gnutls_mpi_sub_ui(tmp, resarr[3], 1); + resarr[6] = _gnutls_mpi_mod(resarr[2]/*d*/, tmp); + + _gnutls_mpi_sub_ui(tmp, resarr[4], 1); + resarr[7] = _gnutls_mpi_mod(resarr[2]/*d*/, tmp); + + _gnutls_mpi_release(&tmp); + + if (resarr[6] == NULL || resarr[7] == NULL) + { + gnutls_assert(); + ret= GNUTLS_E_MEMORY_ERROR; + goto cleanup; + } + + (*resarr_len)+=2; return 0; + +cleanup: + for (i=0;i<*resarr_len;i++) + _gnutls_mpi_release(&resarr[i]); + + return ret; } diff --git a/lib/includes/gnutls/crypto.h b/lib/includes/gnutls/crypto.h index e2cb8f821e..64cf7a6a19 100644 --- a/lib/includes/gnutls/crypto.h +++ b/lib/includes/gnutls/crypto.h @@ -214,7 +214,7 @@ typedef struct gnutls_crypto_bigint gnutls_bigint_format_t format); } gnutls_crypto_bigint_st; -#define GNUTLS_MAX_PK_PARAMS 6 +#define GNUTLS_MAX_PK_PARAMS 16 typedef struct { @@ -234,9 +234,11 @@ void gnutls_pk_params_init (gnutls_pk_params_st * p); * [3] is prime1 (p) (private key only) * [4] is prime2 (q) (private key only) * [5] is coefficient (u == inverse of p mod q) (private key only) + * [6] e1 == d mod (p-1) + * [7] e2 == d mod (q-1) * - * note that other packages use inverse of q mod p, - * so we need to perform conversions using fixup_params(). + * note that for libgcrypt that does not use the inverse of q mod p, + * we need to perform conversions using fixup_params(). * * DSA: * [0] is p diff --git a/lib/includes/gnutls/pkcs11.h b/lib/includes/gnutls/pkcs11.h index c1f83bf2b0..1064c5e2cc 100644 --- a/lib/includes/gnutls/pkcs11.h +++ b/lib/includes/gnutls/pkcs11.h @@ -139,6 +139,14 @@ void gnutls_pkcs11_obj_deinit ( gnutls_pkcs11_obj_t); int gnutls_pkcs11_obj_export(gnutls_pkcs11_obj_t obj, void *output_data, size_t * output_data_size); +#define GNUTLS_PKCS11_OBJ_FLAG_TRUSTED 1 /* object marked as trusted */ + +int gnutls_pkcs11_copy_x509_crt(const char* token_url, gnutls_x509_crt_t crt, + const char* label, unsigned int flags /* GNUTLS_PKCS11_OBJ_FLAG_* */); +int gnutls_pkcs11_copy_x509_privkey(const char* token_url, + gnutls_x509_privkey_t crt, const char* label, unsigned int key_usage /*GNUTLS_KEY_* */); +int gnutls_pkcs11_delete_url(const char* object_url); + /** * @brief Release array of certificate references. * @param certificates Array to free. @@ -212,8 +220,7 @@ int gnutls_pkcs11_privkey_get_info(gnutls_pkcs11_privkey_t crt, gnutls_pkcs11_ob int gnutls_pkcs11_privkey_import_url (gnutls_pkcs11_privkey_t key, const char* url); -int -gnutls_pkcs11_privkey_sign_data(gnutls_pkcs11_privkey_t signer, +int gnutls_pkcs11_privkey_sign_data(gnutls_pkcs11_privkey_t signer, gnutls_digest_algorithm_t hash, unsigned int flags, const gnutls_datum_t * data, diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h index 54ba9e2793..308e7057be 100644 --- a/lib/includes/gnutls/x509.h +++ b/lib/includes/gnutls/x509.h @@ -633,6 +633,15 @@ extern "C" const gnutls_datum_t * p, const gnutls_datum_t * q, const gnutls_datum_t * u); + int gnutls_x509_privkey_import_rsa_raw2 (gnutls_x509_privkey_t key, + const gnutls_datum_t * m, + const gnutls_datum_t * e, + const gnutls_datum_t * d, + const gnutls_datum_t * p, + const gnutls_datum_t * q, + const gnutls_datum_t * u, + const gnutls_datum_t *exp1, + const gnutls_datum_t *exp2); int gnutls_x509_privkey_fix (gnutls_x509_privkey_t key); int gnutls_x509_privkey_export_dsa_raw (gnutls_x509_privkey_t key, @@ -668,6 +677,11 @@ extern "C" unsigned int flags, void *output_data, size_t * output_data_size); + int gnutls_x509_privkey_export_rsa_raw2 (gnutls_x509_privkey_t key, + gnutls_datum_t * m, gnutls_datum_t * e, + gnutls_datum_t * d, gnutls_datum_t * p, + gnutls_datum_t * q, gnutls_datum_t * u, + gnutls_datum_t* e1, gnutls_datum_t* e2); int gnutls_x509_privkey_export_rsa_raw (gnutls_x509_privkey_t key, gnutls_datum_t * m, gnutls_datum_t * e, diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 256d01664c..950ac59590 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -669,6 +669,9 @@ GNUTLS_2_11 gnutls_pubkey_import; gnutls_x509_crt_set_pubkey; gnutls_x509_crq_set_pubkey; + gnutls_pkcs11_copy_x509_crt; + gnutls_pkcs11_copy_x509_privkey; + gnutls_pkcs11_delete_url; } GNUTLS_2_10; GNUTLS_PRIVATE { diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c index 081c08c34c..e028d9b49e 100644 --- a/lib/nettle/pk.c +++ b/lib/nettle/pk.c @@ -72,17 +72,8 @@ mpz_t q_1; memcpy(&priv->q, pk_params->params[4], sizeof(mpz_t)); memcpy(&priv->c, pk_params->params[5], sizeof(mpz_t)); - /* FIXME: possibly move it to fixup to avoid those calculations here */ - - /* b = d % q-1 */ - mpz_init(q_1); - mpz_sub_ui(q_1, priv->q, 1); - - mpz_fdiv_r(priv->b, priv->d, q_1); - - /* a = d % p-1 */ - mpz_sub_ui(q_1, priv->p, 1); - mpz_fdiv_r(priv->a, priv->d, q_1); + memcpy(&priv->a, pk_params->params[6], sizeof(mpz_t)); + memcpy(&priv->b, pk_params->params[7], sizeof(mpz_t)); } static int @@ -425,7 +416,8 @@ int ret, i; _gnutls_mpi_set(params->params[3], priv.p); _gnutls_mpi_set(params->params[4], priv.q); _gnutls_mpi_set(params->params[5], priv.c); - + _gnutls_mpi_set(params->params[6], priv.a); + _gnutls_mpi_set(params->params[7], priv.b); rsa_private_key_clear(&priv); rsa_public_key_clear(&pub); diff --git a/lib/pkcs11.c b/lib/pkcs11.c index 21ddae53d3..6b658b9b4f 100644 --- a/lib/pkcs11.c +++ b/lib/pkcs11.c @@ -26,7 +26,6 @@ #include <gnutls_int.h> #include <gnutls/pkcs11.h> #include <stdio.h> -#include <stdbool.h> #include <string.h> #include <gnutls_errors.h> #include <gnutls_datum.h> @@ -43,10 +42,6 @@ struct gnutls_pkcs11_provider_s { ck_slot_id_t *slots; }; -struct url_find_data_st { - gnutls_pkcs11_obj_t crt; -}; - struct flags_find_data_st { struct pkcs11_url_info info; unsigned int slot_flags; @@ -154,11 +149,7 @@ fail: * * Returns: zero on success or a negative value on error. **/ -<<<<<<< HEAD:lib/pkcs11.c -int gnutls_pkcs11_crt_get_info(gnutls_pkcs11_crt_t crt, gnutls_pkcs11_cert_info_t itype, -======= int gnutls_pkcs11_obj_get_info(gnutls_pkcs11_obj_t crt, gnutls_pkcs11_obj_info_t itype, ->>>>>>> Added gnutls_pubkey_t abstract type to handle public keys. It can currently:lib/pkcs11.c void* output, size_t* output_size) { return pkcs11_get_info(&crt->info, itype, output, output_size); @@ -715,8 +706,66 @@ static void terminate_string(unsigned char *str, size_t len) ptr[1] = '\0'; } +int pkcs11_open_session (pakchois_session_t** _pks, struct pkcs11_url_info *info, unsigned int flags) +{ + ck_rv_t rv; + int x, z, ret; + pakchois_session_t *pks = NULL; + + for (x=0;x<active_providers;x++) { + for (z=0;z<providers[x].nslots;z++) { + struct token_info tinfo; + + rv = pakchois_open_session(providers[x].module, providers[x].slots[z], + ((flags&SESSION_WRITE)?CKF_RW_SESSION:0)|CKF_SERIAL_SESSION, NULL, NULL, &pks); + if (rv != CKR_OK) { + continue; + } + + if (pakchois_get_token_info(providers[x].module, providers[x].slots[z], &tinfo.tinfo) != CKR_OK) { + goto next; + } + tinfo.sid = providers[x].slots[z]; + tinfo.prov = &providers[x]; + + if (pakchois_get_slot_info(providers[x].module, providers[x].slots[z], &tinfo.sinfo) != CKR_OK) { + goto next; + } + + /* XXX make wrapper for token_info? */ + terminate_string(tinfo.tinfo.manufacturer_id, sizeof tinfo.tinfo.manufacturer_id); + terminate_string(tinfo.tinfo.label, sizeof tinfo.tinfo.label); + terminate_string(tinfo.tinfo.model, sizeof tinfo.tinfo.model); + terminate_string(tinfo.tinfo.serial_number, sizeof tinfo.tinfo.serial_number); + + if (pkcs11_token_matches_info( info, &tinfo.tinfo) < 0) { + goto next; + } -int _pkcs11_traverse_tokens (find_func_t find_func, void* input, int leave_session) + if (flags&SESSION_LOGIN) { + ret = pkcs11_login(pks, &tinfo); + if (ret < 0) { + gnutls_assert(); + pakchois_close_session(pks); + return ret; + } + } + + /* ok found */ + *_pks = pks; + return 0; + +next: + pakchois_close_session(pks); + } + } + + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; +} + + +int _pkcs11_traverse_tokens (find_func_t find_func, void* input, + int leave_session, unsigned int flags) { ck_rv_t rv; int found = 0, x, z, ret; @@ -726,20 +775,22 @@ int _pkcs11_traverse_tokens (find_func_t find_func, void* input, int leave_sessi for (z=0;z<providers[x].nslots;z++) { struct token_info info; + ret = GNUTLS_E_PKCS11_ERROR; + rv = pakchois_open_session(providers[x].module, providers[x].slots[z], - CKF_SERIAL_SESSION, NULL, NULL, &pks); + ((flags&SESSION_WRITE)?CKF_RW_SESSION:0)|CKF_SERIAL_SESSION, NULL, NULL, &pks); if (rv != CKR_OK) { continue; } if (pakchois_get_token_info(providers[x].module, providers[x].slots[z], &info.tinfo) != CKR_OK) { - continue; + goto next; } info.sid = providers[x].slots[z]; info.prov = &providers[x]; if (pakchois_get_slot_info(providers[x].module, providers[x].slots[z], &info.sinfo) != CKR_OK) { - continue; + goto next; } /* XXX make wrapper for token_info? */ @@ -750,6 +801,8 @@ int _pkcs11_traverse_tokens (find_func_t find_func, void* input, int leave_sessi ret = find_func(pks, &info, input); + next: + if (ret == 0) { found = 1; goto finish; @@ -1046,13 +1099,33 @@ static int pkcs11_obj_import_pubkey(pakchois_session_t *pks, ck_object_handle_t return pkcs11_obj_import(CKO_PUBLIC_KEY, crt, NULL, id, label, tinfo); } +ck_object_class_t pkcs11_strtype_to_class(const char* type) +{ + ck_object_class_t class; + + if (strcmp(type, "cert") == 0) { + class = CKO_CERTIFICATE; + } else if (strcmp(type, "public") == 0) { + class = CKO_PUBLIC_KEY; + } else if (strcmp(type, "private") == 0) { + class = CKO_PRIVATE_KEY; + } else if (strcmp(type, "secretkey") == 0) { + class = CKO_SECRET_KEY; + } else if (strcmp(type, "data") == 0) { + class = CKO_DATA; + } else { + class = -1; + } + + return class; +} static int find_obj_url(pakchois_session_t *pks, struct token_info *info, void* input) { struct url_find_data_st* find_data = input; struct ck_attribute a[4]; - ck_object_class_t class; + ck_object_class_t class = -1; ck_certificate_type_t type = -1; ck_rv_t rv; ck_object_handle_t obj; @@ -1068,40 +1141,19 @@ static int find_obj_url(pakchois_session_t *pks, struct token_info *info, void* /* do not bother reading the token if basic fields do not match */ - if (find_data->crt->info.manufacturer[0] != 0) { - if (strcmp(find_data->crt->info.manufacturer, info->tinfo.manufacturer_id) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } - - if (find_data->crt->info.token[0] != 0) { - if (strcmp(find_data->crt->info.token, info->tinfo.label) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } - - if (find_data->crt->info.model[0] != 0) { - if (strcmp(find_data->crt->info.model, info->tinfo.model) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } - - if (find_data->crt->info.serial[0] != 0) { - if (strcmp(find_data->crt->info.serial, info->tinfo.serial_number) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } - - class = CKO_CERTIFICATE; /* default */ + if (pkcs11_token_matches_info( &find_data->crt->info, &info->tinfo) < 0) { + gnutls_assert(); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } if (find_data->crt->info.type[0] != 0) { - if (strcmp(find_data->crt->info.type, "cert") == 0) { - class = CKO_CERTIFICATE; + class = pkcs11_strtype_to_class(find_data->crt->info.type); + if (class == CKO_CERTIFICATE) type = CKC_X_509; - } else if (strcmp(find_data->crt->info.type, "public") == 0) { - class = CKO_PUBLIC_KEY; - } else if (strcmp(find_data->crt->info.type, "private") == 0) { - class = CKO_PRIVATE_KEY; - } else if (strcmp(find_data->crt->info.type, "secretkey") == 0) { - class = CKO_SECRET_KEY; - } else if (strcmp(find_data->crt->info.type, "data") == 0) { - class = CKO_DATA; + + if (class == -1) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; } } @@ -1115,20 +1167,23 @@ static int find_obj_url(pakchois_session_t *pks, struct token_info *info, void* /* Find objects with given class and type */ - a[0].type = CKA_CLASS; - a[0].value = &class; - a[0].value_len = sizeof class; - - a[1].type = CKA_ID; - a[1].value = find_data->crt->info.certid_raw; - a[1].value_len = find_data->crt->info.certid_raw_size; - - a_vals = 2; + a[0].type = CKA_ID; + a[0].value = find_data->crt->info.certid_raw; + a[0].value_len = find_data->crt->info.certid_raw_size; + + a_vals = 1; + if (class != -1) { + a[a_vals].type = CKA_CLASS; + a[a_vals].value = &class; + a[a_vals].value_len = sizeof class; + a_vals++; + } + if (type != -1) { - a[2].type = CKA_CERTIFICATE_TYPE; - a[2].value = &type; - a[2].value_len = sizeof type; + a[a_vals].type = CKA_CERTIFICATE_TYPE; + a[a_vals].value = &type; + a[a_vals].value_len = sizeof type; a_vals++; } @@ -1214,7 +1269,7 @@ int gnutls_pkcs11_obj_import_url (gnutls_pkcs11_obj_t cert, const char * url) return ret; } - ret = _pkcs11_traverse_tokens(find_obj_url, &find_data, 0); + ret = _pkcs11_traverse_tokens(find_obj_url, &find_data, 0, 0); if (ret < 0) { gnutls_assert(); return ret; @@ -1274,7 +1329,7 @@ int gnutls_pkcs11_token_get_url (unsigned int seq, char** url) memset(&tn, 0, sizeof(tn)); tn.seq = seq; - ret = _pkcs11_traverse_tokens(find_token_num, &tn, 0); + ret = _pkcs11_traverse_tokens(find_token_num, &tn, 0, 0); if (ret < 0) { gnutls_assert(); return ret; @@ -1729,9 +1784,9 @@ static int find_objs(pakchois_session_t *pks, struct token_info *info, void* inp { struct crt_find_data_st* find_data = input; struct ck_attribute a[4]; - ck_object_class_t class; - ck_certificate_type_t type; - bool trusted; + ck_object_class_t class=-1; + ck_certificate_type_t type=-1; + unsigned int trusted; ck_rv_t rv; ck_object_handle_t obj; unsigned long count; @@ -1755,27 +1810,27 @@ static int find_objs(pakchois_session_t *pks, struct token_info *info, void* inp /* do not bother reading the token if basic fields do not match */ - if (find_data->info.manufacturer[0] != 0) { - if (strcmp(find_data->info.manufacturer, info->tinfo.manufacturer_id) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } - - if (find_data->info.token[0] != 0) { - if (strcmp(find_data->info.token, info->tinfo.label) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } + if (pkcs11_token_matches_info( &find_data->info, &info->tinfo) < 0) { + gnutls_assert(); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } - if (find_data->info.model[0] != 0) { - if (strcmp(find_data->info.model, info->tinfo.model) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } + if (find_data->info.type[0] != 0) { + class = pkcs11_strtype_to_class(find_data->info.type); + if (class == CKO_CERTIFICATE) + type = CKC_X_509; + else + type = -1; - if (find_data->info.serial[0] != 0) { - if (strcmp(find_data->info.serial, info->tinfo.serial_number) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + if (class == -1) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } } + memset(&plist, 0, sizeof(plist)); + if (find_data->flags==GNUTLS_PKCS11_OBJ_ATTR_CRT_WITH_PRIVKEY) { ret = pkcs11_login(pks, info); if (ret < 0) { @@ -1809,47 +1864,69 @@ static int find_objs(pakchois_session_t *pks, struct token_info *info, void* inp /* Find objects with cert class and X.509 cert type. */ + tot_values = 0; + if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_CRT_ALL || find_data->flags==GNUTLS_PKCS11_OBJ_ATTR_CRT_WITH_PRIVKEY) { class = CKO_CERTIFICATE; type = CKC_X_509; trusted = 1; - a[0].type = CKA_CLASS; - a[0].value = &class; - a[0].value_len = sizeof class; + a[tot_values].type = CKA_CLASS; + a[tot_values].value = &class; + a[tot_values].value_len = sizeof class; + tot_values++; - a[1].type = CKA_CERTIFICATE_TYPE; - a[1].value = &type; - a[1].value_len = sizeof type; + a[tot_values].type = CKA_CERTIFICATE_TYPE; + a[tot_values].value = &type; + a[tot_values].value_len = sizeof type; + tot_values++; - tot_values = 2; } else if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_CRT_TRUSTED) { class = CKO_CERTIFICATE; type = CKC_X_509; trusted = 1; - a[0].type = CKA_CLASS; - a[0].value = &class; - a[0].value_len = sizeof class; - - a[1].type = CKA_TRUSTED; - a[1].value = &trusted; - a[1].value_len = sizeof trusted; + a[tot_values].type = CKA_CLASS; + a[tot_values].value = &class; + a[tot_values].value_len = sizeof class; + tot_values++; + + a[tot_values].type = CKA_TRUSTED; + a[tot_values].value = &trusted; + a[tot_values].value_len = sizeof trusted; + tot_values++; - tot_values = 2; } else if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_PUBKEY) { class = CKO_PUBLIC_KEY; - a[0].type = CKA_CLASS; - a[0].value = &class; - a[0].value_len = sizeof class; - - tot_values = 1; + a[tot_values].type = CKA_CLASS; + a[tot_values].value = &class; + a[tot_values].value_len = sizeof class; + tot_values++; } else if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_ALL) { - tot_values = 0; + if (class != -1) { + a[tot_values].type = CKA_CLASS; + a[tot_values].value = &class; + a[tot_values].value_len = sizeof class; + tot_values++; + } + if (type != -1) { + a[tot_values].type = CKA_CERTIFICATE_TYPE; + a[tot_values].value = &type; + a[tot_values].value_len = sizeof type; + tot_values++; + } } else { gnutls_assert(); - return GNUTLS_E_INVALID_REQUEST; + ret = GNUTLS_E_INVALID_REQUEST; + goto fail; + } + + if (find_data->info.certid_raw_size != 0) { + a[tot_values].type = CKA_ID; + a[tot_values].value = find_data->info.certid_raw; + a[tot_values].value_len = find_data->info.certid_raw_size; + tot_values++; } rv = pakchois_find_objects_init(pks, a, tot_values); @@ -1878,6 +1955,7 @@ static int find_objs(pakchois_session_t *pks, struct token_info *info, void* inp a[0].type = CKA_ID; a[0].value = certid_tmp; a[0].value_len = sizeof certid_tmp; + if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK) { id.data = a[0].value; id.size = a[0].value_len; @@ -1993,7 +2071,7 @@ int gnutls_pkcs11_obj_list_import_url (gnutls_pkcs11_obj_t * p_list, unsigned in return ret; } - ret = _pkcs11_traverse_tokens(find_objs, &find_data, 0); + ret = _pkcs11_traverse_tokens(find_objs, &find_data, 0, 0); if (ret < 0) { gnutls_assert(); return ret; @@ -2104,25 +2182,10 @@ static int find_flags(pakchois_session_t *pks, struct token_info *info, void* in /* do not bother reading the token if basic fields do not match */ - if (find_data->info.manufacturer[0] != 0) { - if (strcmp(find_data->info.manufacturer, info->tinfo.manufacturer_id) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } - - if (find_data->info.token[0] != 0) { - if (strcmp(find_data->info.token, info->tinfo.label) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } - - if (find_data->info.model[0] != 0) { - if (strcmp(find_data->info.model, info->tinfo.model) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } - - if (find_data->info.serial[0] != 0) { - if (strcmp(find_data->info.serial, info->tinfo.serial_number) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } + if (pkcs11_token_matches_info( &find_data->info, &info->tinfo) < 0) { + gnutls_assert(); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } /* found token! */ @@ -2151,7 +2214,7 @@ int gnutls_pkcs11_token_get_flags(const char* url, unsigned int *flags) return ret; } - ret = _pkcs11_traverse_tokens(find_flags, &find_data, 0); + ret = _pkcs11_traverse_tokens(find_flags, &find_data, 0, 0); if (ret < 0) { gnutls_assert(); return ret; diff --git a/lib/pkcs11_int.h b/lib/pkcs11_int.h index 7b8c120e9d..2eea03cb78 100644 --- a/lib/pkcs11_int.h +++ b/lib/pkcs11_int.h @@ -46,7 +46,7 @@ struct gnutls_pkcs11_obj_st { */ typedef int (*find_func_t)(pakchois_session_t *pks, struct token_info* tinfo, void* input); -int _pkcs11_traverse_tokens (find_func_t find_func, void* input, int leave_session); + int pkcs11_url_to_info(const char* url, struct pkcs11_url_info* info); int pkcs11_get_info(struct pkcs11_url_info *info, gnutls_pkcs11_obj_info_t itype, @@ -59,5 +59,12 @@ extern void* token_data; void pkcs11_rescan_slots(void); int pkcs11_info_to_url(const struct pkcs11_url_info* info, char** url); +#define SESSION_WRITE 1 +#define SESSION_LOGIN 2 +int pkcs11_open_session (pakchois_session_t** _pks, struct pkcs11_url_info *info, unsigned int flags); +int _pkcs11_traverse_tokens (find_func_t find_func, void* input, int leave_session, unsigned int flags); +ck_object_class_t pkcs11_strtype_to_class(const char* type); + +int pkcs11_token_matches_info( struct pkcs11_url_info* info, struct ck_token_info* tinfo); #endif diff --git a/lib/pkcs11_privkey.c b/lib/pkcs11_privkey.c index 2ead5ab8fb..608b6e97c0 100644 --- a/lib/pkcs11_privkey.c +++ b/lib/pkcs11_privkey.c @@ -134,7 +134,7 @@ int gnutls_pkcs11_privkey_get_info(gnutls_pkcs11_privkey_t pkey, key->pks = NULL; \ ret = token_func(token_data, label, retries++); \ if (ret == 0) { \ - _pkcs11_traverse_tokens(find_privkey_url, &find_data, 1); \ + _pkcs11_traverse_tokens(find_privkey_url, &find_data, 1, 0); \ goto retry; \ } \ } \ @@ -287,36 +287,13 @@ static int find_privkey_url(pakchois_session_t * pks, /* do not bother reading the token if basic fields do not match */ - if (find_data->privkey->info.manufacturer[0] != 0) { - if (strcmp - (find_data->privkey->info.manufacturer, - info->tinfo.manufacturer_id) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } - - if (find_data->privkey->info.token[0] != 0) { - if (strcmp - (find_data->privkey->info.token, - info->tinfo.label) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } - - if (find_data->privkey->info.model[0] != 0) { - if (strcmp - (find_data->privkey->info.model, - info->tinfo.model) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; - } - - if (find_data->privkey->info.serial[0] != 0) { - if (strcmp - (find_data->privkey->info.serial, - info->tinfo.serial_number) != 0) - return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + if (pkcs11_token_matches_info( &find_data->privkey->info, &info->tinfo) < 0) { + gnutls_assert(); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } - + if (find_data->privkey->info.type[0] != 0) { - if (strcmp(find_data->privkey->info.type, "cert") != 0) { + if (strcmp(find_data->privkey->info.type, "private") != 0) { gnutls_assert(); return GNUTLS_E_UNIMPLEMENTED_FEATURE; } @@ -422,7 +399,7 @@ int gnutls_pkcs11_privkey_import_url(gnutls_pkcs11_privkey_t pkey, return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } - ret = _pkcs11_traverse_tokens(find_privkey_url, &find_data, 1); + ret = _pkcs11_traverse_tokens(find_privkey_url, &find_data, 1, 0); if (ret < 0) { gnutls_assert(); return ret; diff --git a/lib/pkcs11_write.c b/lib/pkcs11_write.c new file mode 100644 index 0000000000..a8ed760435 --- /dev/null +++ b/lib/pkcs11_write.c @@ -0,0 +1,508 @@ +/* + * GnuTLS PKCS#11 support + * Copyright (C) 2010 Free Software Foundation + * + * Author: Nikos Mavrogiannopoulos + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA +*/ + +#include <gnutls_int.h> +#include <gnutls/pkcs11.h> +#include <stdio.h> +#include <string.h> +#include <gnutls_errors.h> +#include <gnutls_datum.h> +#include <pkcs11_int.h> + +/** + * 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 is returned, otherwise a + * negative error value. + **/ +int gnutls_pkcs11_copy_x509_crt(const char* token_url, gnutls_x509_crt_t crt, + const char* label, unsigned int flags) +{ + int ret; + pakchois_session_t *pks; + struct pkcs11_url_info info; + ck_rv_t rv; + size_t der_size, id_size; + opaque* der = NULL; + opaque id[20]; + struct ck_attribute a[8]; + ck_object_class_t class = CKO_CERTIFICATE; + ck_certificate_type_t type = CKC_X_509; + ck_object_handle_t obj; + unsigned int tval = 1; + int a_val; + + ret = pkcs11_url_to_info(token_url, &info); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + ret = pkcs11_open_session (&pks, &info, SESSION_WRITE|SESSION_LOGIN); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + 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_key_id (crt, 0, id, &id_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; + 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 = &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; + + 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_TRUSTED) { + a[a_val].type = CKA_TRUSTED; + a[a_val].value = &tval; + a[a_val].value_len = sizeof(tval); + a_val++; + } + + rv = pakchois_create_object(pks, a, a_val, &obj); + if (rv != CKR_OK) { + gnutls_assert(); + _gnutls_debug_log("pkcs11: %s\n", pakchois_error(rv)); + ret = GNUTLS_E_PKCS11_ERROR; + goto cleanup; + } + + /* generated! + */ + + ret = 0; + +cleanup: + gnutls_free(der); + pakchois_close_session(pks); + + return ret; + +} + +/** + * gnutls_pkcs11_copy_x509_privkey: + * @token_url: A PKCS #11 URL specifying a token + * @key: A private key + * @label: A name to be used for the stored data + * @key_usage: One of GNUTLS_KEY_* + * + * This function will copy a private key into a PKCS #11 token specified by + * a URL. + * + * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a + * negative error value. + **/ +int gnutls_pkcs11_copy_x509_privkey(const char* token_url, + gnutls_x509_privkey_t key, const char* label, unsigned int key_usage) +{ + int ret; + pakchois_session_t *pks; + struct pkcs11_url_info info; + ck_rv_t rv; + size_t id_size; + opaque id[20]; + struct ck_attribute a[16]; + ck_object_class_t class = CKO_PRIVATE_KEY; + ck_object_handle_t obj; + ck_key_type_t type; + unsigned int tval = 1; + 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; + + + ret = pkcs11_url_to_info(token_url, &info); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + id_size = sizeof(id); + ret = gnutls_x509_privkey_get_key_id (key, 0, id, &id_size); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = pkcs11_open_session (&pks, &info, SESSION_WRITE|SESSION_LOGIN); + 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_ID; + a[1].value = id; + a[1].value_len = id_size; + a[2].type = CKA_KEY_TYPE; + a[2].value = &type; + a[2].value_len = sizeof(type); + a[3].type = CKA_SENSITIVE; + a[3].value = &tval; + a[3].value_len = sizeof(tval); + + a_val = 4; + + pk = gnutls_x509_privkey_get_pk_algorithm(key); + 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; + + 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; + + 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; + } + default: + gnutls_assert(); + ret = GNUTLS_E_INVALID_REQUEST; + goto cleanup; + } + + rv = pakchois_create_object(pks, a, a_val, &obj); + if (rv != CKR_OK) { + gnutls_assert(); + _gnutls_debug_log("pkcs11: %s\n", pakchois_error(rv)); + ret = GNUTLS_E_PKCS11_ERROR; + goto cleanup; + } + + /* generated! + */ + + 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; + } + default: + gnutls_assert(); + ret = GNUTLS_E_INVALID_REQUEST; + goto cleanup; + } + + ret = 0; + +cleanup: + pakchois_close_session(pks); + + return ret; + +} + +struct delete_data_st { + struct pkcs11_url_info info; + unsigned int deleted; /* how many */ +}; + +static int delete_obj_url(pakchois_session_t *pks, struct token_info *info, void* input) +{ + struct delete_data_st* find_data = input; + struct ck_attribute a[4]; + ck_object_class_t class; + ck_certificate_type_t type = -1; + ck_rv_t rv; + ck_object_handle_t obj; + unsigned long count, a_vals; + int found = 0, ret; + + + if (info == NULL) { /* we don't support multiple calls */ + gnutls_assert(); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } + + /* do not bother reading the token if basic fields do not match + */ + if (pkcs11_token_matches_info( &find_data->info, &info->tinfo) < 0) { + gnutls_assert(); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } + + class = CKO_CERTIFICATE; /* default */ + + if (find_data->info.type[0] != 0) { + class = pkcs11_strtype_to_class(find_data->info.type); + if (class == CKO_CERTIFICATE) + type = CKC_X_509; + + if (class == -1) { + gnutls_assert(); + return GNUTLS_E_INVALID_REQUEST; + } + } + + ret = pkcs11_login(pks, info); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + a_vals = 0; + + /* Find objects with given class and type */ + if (find_data->info.certid_raw_size > 0) { + a[a_vals].type = CKA_ID; + a[a_vals].value = find_data->info.certid_raw; + a[a_vals].value_len = find_data->info.certid_raw_size; + a_vals++; + } + + if (class != -1) { + a[a_vals].type = CKA_CLASS; + a[a_vals].value = &class; + a[a_vals].value_len = sizeof class; + a_vals++; + } + + if (type != -1) { + a[a_vals].type = CKA_CERTIFICATE_TYPE; + a[a_vals].value = &type; + a[a_vals].value_len = sizeof type; + a_vals++; + } + + if (find_data->info.label[0] != 0) { + a[a_vals].type = CKA_LABEL; + a[a_vals].value = find_data->info.label; + a[a_vals].value_len = strlen(find_data->info.label); + a_vals++; + } + + rv = pakchois_find_objects_init(pks, a, a_vals); + if (rv != CKR_OK) { + gnutls_assert(); + _gnutls_debug_log("pk11: FindObjectsInit failed.\n"); + ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + goto cleanup; + } + + while (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK + && count == 1) { + + rv = pakchois_destroy_object(pks, obj); + if (rv != CKR_OK) { + _gnutls_debug_log("pkcs11: Cannot destroy object: %s\n", pakchois_error(rv)); + } else { + find_data->deleted++; + } + + found = 1; + } + + if (found == 0) { + gnutls_assert(); + ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } else { + ret = 0; + } + +cleanup: + pakchois_find_objects_final(pks); + + return ret; +} + + +/** + * gnutls_pkcs11_delete_url: + * @object_url: The URL of the object to delete. + * + * This function will delete objects matching the given URL. + * + * Returns: On success, the number of objects deleted is returned, otherwise a + * negative error value. + **/ +int gnutls_pkcs11_delete_url(const char* object_url) +{ + int ret; + struct delete_data_st find_data; + + memset(&find_data, 0, sizeof(find_data)); + + ret = pkcs11_url_to_info(object_url, &find_data.info); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + ret = _pkcs11_traverse_tokens(delete_obj_url, &find_data, 0, SESSION_WRITE); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + return find_data.deleted; + +} + diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c index c81e67a161..6d47a6504d 100644 --- a/lib/x509/privkey.c +++ b/lib/x509/privkey.c @@ -35,6 +35,7 @@ #include <x509_int.h> #include <gnutls_pk.h> #include <sign.h> +#include <gnutls_mpi.h> static int _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * params); @@ -218,6 +219,20 @@ _gnutls_privkey_decode_pkcs1_rsa_key (const gnutls_datum_t * raw_key, goto error; } + if ((result = _gnutls_x509_read_int (pkey_asn, "exponent1", + &pk_params.params[6])) < 0) + { + gnutls_assert (); + goto error; + } + + if ((result = _gnutls_x509_read_int (pkey_asn, "exponent2", + &pk_params.params[7])) < 0) + { + gnutls_assert (); + goto error; + } + result = _gnutls_pk_fixup (GNUTLS_PK_RSA, GNUTLS_IMPORT, &pk_params); if (result < 0) @@ -232,6 +247,8 @@ _gnutls_privkey_decode_pkcs1_rsa_key (const gnutls_datum_t * raw_key, pkey->params[3] = pk_params.params[3]; pkey->params[4] = pk_params.params[4]; pkey->params[5] = pk_params.params[5]; + pkey->params[6] = pk_params.params[6]; + pkey->params[7] = pk_params.params[7]; pkey->params_size = pk_params.params_nr; return pkey_asn; @@ -465,6 +482,37 @@ gnutls_x509_privkey_import_rsa_raw (gnutls_x509_privkey_t key, const gnutls_datum_t * q, const gnutls_datum_t * u) { + return gnutls_x509_privkey_import_rsa_raw2( key, m, e, d, p, q, u, NULL, NULL); +} + +/** + * gnutls_x509_privkey_import_rsa_raw2: + * @key: The structure to store the parsed key + * @m: holds the modulus + * @e: holds the public exponent + * @d: holds the private exponent + * @p: holds the first prime (p) + * @q: holds the second prime (q) + * @u: holds the coefficient + * + * This function will convert the given RSA raw parameters to the + * native #gnutls_x509_privkey_t format. The output will be stored in + * @key. + * + * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a + * negative error value. + **/ +int +gnutls_x509_privkey_import_rsa_raw2 (gnutls_x509_privkey_t key, + const gnutls_datum_t * m, + const gnutls_datum_t * e, + const gnutls_datum_t * d, + const gnutls_datum_t * p, + const gnutls_datum_t * q, + const gnutls_datum_t * u, + const gnutls_datum_t * e1, + const gnutls_datum_t * e2) +{ int i = 0, ret; size_t siz = 0; @@ -522,15 +570,61 @@ gnutls_x509_privkey_import_rsa_raw (gnutls_x509_privkey_t key, return GNUTLS_E_MPI_SCAN_FAILED; } + if (e1 && e2) + { + siz = e1->size; + if (_gnutls_mpi_scan_nz (&key->params[6], e1->data, siz)) + { + gnutls_assert (); + FREE_RSA_PRIVATE_PARAMS; + return GNUTLS_E_MPI_SCAN_FAILED; + } + + siz = e2->size; + if (_gnutls_mpi_scan_nz (&key->params[7], e2->data, siz)) + { + gnutls_assert (); + FREE_RSA_PRIVATE_PARAMS; + return GNUTLS_E_MPI_SCAN_FAILED; + } + } + else /* calculate e1 and e2 */ + { + bigint_t tmp = _gnutls_mpi_alloc_like(key->params[0]); + if (tmp == NULL) + { + gnutls_assert (); + FREE_RSA_PRIVATE_PARAMS; + return GNUTLS_E_MEMORY_ERROR; + } + + /* [6] = d % p-1, [7] = d % q-1 */ + _gnutls_mpi_sub_ui(tmp, key->params[3], 1); + key->params[6] = _gnutls_mpi_mod(key->params[2]/*d*/, tmp); + + _gnutls_mpi_sub_ui(tmp, key->params[4], 1); + key->params[7] = _gnutls_mpi_mod(key->params[2]/*d*/, tmp); + + _gnutls_mpi_release(&tmp); + + if (key->params[7] == NULL || key->params[6] == NULL) + { + gnutls_assert (); + FREE_RSA_PRIVATE_PARAMS; + return GNUTLS_E_MEMORY_ERROR; + } + } + + if (!key->crippled) { ret = _gnutls_asn1_encode_rsa (&key->key, key->params); if (ret < 0) - { - gnutls_assert (); - FREE_RSA_PRIVATE_PARAMS; - return ret; - } + { + gnutls_assert (); + FREE_RSA_PRIVATE_PARAMS; + return ret; + } } key->params_size = RSA_PRIVATE_PARAMS; @@ -751,6 +845,36 @@ gnutls_x509_privkey_export_rsa_raw (gnutls_x509_privkey_t key, gnutls_datum_t * d, gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * u) { + + return gnutls_x509_privkey_export_rsa_raw2(key, m, e, d, p, q, u, NULL, NULL); +} + +/** + * gnutls_x509_privkey_export_rsa_raw2: + * @key: a structure that holds the rsa parameters + * @m: will hold the modulus + * @e: will hold the public exponent + * @d: will hold the private exponent + * @p: will hold the first prime (p) + * @q: will hold the second prime (q) + * @u: will hold the coefficient + * @e1: will hold the exponent 1 + * @e2: will hold the exponent 2 + * + * This function will export the RSA private key's parameters found + * in the given structure. The new parameters will be allocated using + * gnutls_malloc() and will be stored in the appropriate datum. + * + * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a + * negative error value. + **/ +int +gnutls_x509_privkey_export_rsa_raw2 (gnutls_x509_privkey_t key, + gnutls_datum_t * m, gnutls_datum_t * e, + gnutls_datum_t * d, gnutls_datum_t * p, + gnutls_datum_t * q, gnutls_datum_t * u, + gnutls_datum_t* e1, gnutls_datum_t* e2) +{ int ret; gnutls_pk_params_st pk_params; @@ -824,6 +948,28 @@ gnutls_x509_privkey_export_rsa_raw (gnutls_x509_privkey_t key, goto error; } + /* E1 */ + if (e1) + { + ret = _gnutls_mpi_dprint (key->params[6], e1); + if (ret < 0) + { + gnutls_assert (); + goto error; + } + } + + /* E2 */ + if (e2) + { + ret = _gnutls_mpi_dprint (key->params[7], e2); + if (ret < 0) + { + gnutls_assert (); + goto error; + } + } + gnutls_pk_params_release (&pk_params); return 0; @@ -935,7 +1081,6 @@ _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * params) opaque *m_data, *pube_data, *prie_data; opaque *p1_data, *p2_data, *u_data, *exp1_data, *exp2_data; opaque *all_data = NULL, *p; - bigint_t exp1 = NULL, exp2 = NULL, q1 = NULL, p1 = NULL; opaque null = '\0'; gnutls_pk_params_st pk_params; @@ -961,52 +1106,6 @@ _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * params) goto cleanup; } - q1 = _gnutls_mpi_alloc_like (pk_params.params[4]); - if (q1 == NULL) - { - gnutls_assert (); - result = GNUTLS_E_MEMORY_ERROR; - goto cleanup; - } - - p1 = _gnutls_mpi_alloc_like (pk_params.params[3]); - if (p1 == NULL) - { - gnutls_assert (); - result = GNUTLS_E_MEMORY_ERROR; - goto cleanup; - } - - /* inverse of q mod p */ - _gnutls_mpi_print_lz (pk_params.params[5], NULL, &size[5]); - total += size[5]; - - _gnutls_mpi_sub_ui (p1, pk_params.params[3], 1); - _gnutls_mpi_sub_ui (q1, pk_params.params[4], 1); - - exp1 = _gnutls_mpi_mod (pk_params.params[2], p1); - if (exp1 == NULL) - { - gnutls_assert (); - result = GNUTLS_E_MEMORY_ERROR; - goto cleanup; - } - - exp2 = _gnutls_mpi_mod (pk_params.params[2], q1); - if (exp2 == NULL) - { - gnutls_assert (); - result = GNUTLS_E_MEMORY_ERROR; - goto cleanup; - } - - /* calculate exp's size */ - _gnutls_mpi_print_lz (exp1, NULL, &size[6]); - total += size[6]; - - _gnutls_mpi_print_lz (exp2, NULL, &size[7]); - total += size[7]; - /* Encoding phase. * allocate data enough to hold everything */ @@ -1021,18 +1120,25 @@ _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * params) p = all_data; m_data = p; p += size[0]; + pube_data = p; p += size[1]; + prie_data = p; p += size[2]; + p1_data = p; p += size[3]; + p2_data = p; p += size[4]; + u_data = p; p += size[5]; + exp1_data = p; p += size[6]; + exp2_data = p; _gnutls_mpi_print_lz (pk_params.params[0], m_data, &size[0]); @@ -1041,8 +1147,8 @@ _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * params) _gnutls_mpi_print_lz (pk_params.params[3], p1_data, &size[3]); _gnutls_mpi_print_lz (pk_params.params[4], p2_data, &size[4]); _gnutls_mpi_print_lz (pk_params.params[5], u_data, &size[5]); - _gnutls_mpi_print_lz (exp1, exp1_data, &size[6]); - _gnutls_mpi_print_lz (exp2, exp2_data, &size[7]); + _gnutls_mpi_print_lz (pk_params.params[6], exp1_data, &size[6]); + _gnutls_mpi_print_lz (pk_params.params[7], exp2_data, &size[7]); /* Ok. Now we have the data. Create the asn1 structures */ @@ -1105,34 +1211,31 @@ _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * params) goto cleanup; } - if ((result = asn1_write_value (*c2, "exponent1", - exp1_data, size[6])) != ASN1_SUCCESS) + if ((result = asn1_write_value (*c2, "coefficient", + u_data, size[5])) != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); + goto cleanup; } - if ((result = asn1_write_value (*c2, "exponent2", - exp2_data, size[7])) != ASN1_SUCCESS) + if ((result = asn1_write_value (*c2, "exponent1", + exp1_data, size[6])) != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } - if ((result = asn1_write_value (*c2, "coefficient", - u_data, size[5])) != ASN1_SUCCESS) + if ((result = asn1_write_value (*c2, "exponent2", + exp2_data, size[7])) != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } - _gnutls_mpi_release (&exp1); - _gnutls_mpi_release (&exp2); - _gnutls_mpi_release (&q1); - _gnutls_mpi_release (&p1); gnutls_pk_params_release (&pk_params); gnutls_free (all_data); @@ -1154,10 +1257,6 @@ _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * params) return 0; cleanup: - _gnutls_mpi_release (&exp1); - _gnutls_mpi_release (&exp2); - _gnutls_mpi_release (&q1); - _gnutls_mpi_release (&p1); gnutls_pk_params_release (&pk_params); asn1_delete_structure (c2); gnutls_free (all_data); @@ -1320,6 +1419,12 @@ gnutls_x509_privkey_generate (gnutls_x509_privkey_t key, { case GNUTLS_PK_DSA: ret = _gnutls_dsa_generate_params (key->params, ¶ms_len, bits); + if (params_len != DSA_PRIVATE_PARAMS) + { + gnutls_assert(); + ret = GNUTLS_E_INTERNAL_ERROR; + } + if (ret < 0) { gnutls_assert (); @@ -1341,6 +1446,11 @@ gnutls_x509_privkey_generate (gnutls_x509_privkey_t key, break; case GNUTLS_PK_RSA: ret = _gnutls_rsa_generate_params (key->params, ¶ms_len, bits); + if (params_len != RSA_PRIVATE_PARAMS) + { + gnutls_assert(); + ret = GNUTLS_E_INTERNAL_ERROR; + } if (ret < 0) { gnutls_assert (); diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h index f75a92479d..f4f17adb5f 100644 --- a/lib/x509/x509_int.h +++ b/lib/x509/x509_int.h @@ -72,12 +72,12 @@ typedef struct gnutls_pkcs7_int ASN1_TYPE pkcs7; } gnutls_pkcs7_int; -#define MAX_PRIV_PARAMS_SIZE GNUTLS_MAX_PK_PARAMS /* ok for RSA and DSA */ +#define MAX_PRIV_PARAMS_SIZE GNUTLS_MAX_PK_PARAMS /* ok for RSA and DSA */ /* parameters should not be larger than this limit */ #define DSA_PRIVATE_PARAMS 5 #define DSA_PUBLIC_PARAMS 4 -#define RSA_PRIVATE_PARAMS 6 +#define RSA_PRIVATE_PARAMS 8 #define RSA_PUBLIC_PARAMS 2 #if MAX_PRIV_PARAMS_SIZE - RSA_PRIVATE_PARAMS < 0 @@ -103,7 +103,9 @@ typedef struct gnutls_x509_privkey_int * [4] is prime2 (q) * [5] is coefficient (u == inverse of p mod q) * note that other packages used inverse of q mod p, - * so we need to perform conversions. + * so we need to perform conversions (for libgcrypt only) + * [6] e1 == d mod (p-1) + * [7] e2 == d mod (q-1) * DSA: [0] is p * [1] is q * [2] is g diff --git a/src/certtool-common.h b/src/certtool-common.h index f5db0abd80..79d2300471 100644 --- a/src/certtool-common.h +++ b/src/certtool-common.h @@ -29,6 +29,8 @@ enum ACTION_PKCS11_LIST, ACTION_PKCS11_TOKENS, ACTION_PKCS11_EXPORT_URL, + ACTION_PKCS11_WRITE_URL, + ACTION_PKCS11_DELETE_URL, ACTION_PUBKEY_INFO, }; @@ -39,6 +41,8 @@ void certtool_version (void); void pkcs11_list( FILE*outfile, const char* url, int type); void pkcs11_export(FILE* outfile, const char *pkcs11_url); void pkcs11_token_list(FILE* outfile); +void pkcs11_write(FILE* outfile, const char *pkcs11_url, const char* label, int trusted); +void pkcs11_delete(FILE* outfile, const char *pkcs11_url, int batch); #define PKCS11_TYPE_CRT_ALL 1 #define PKCS11_TYPE_TRUSTED 2 @@ -47,3 +51,13 @@ void pkcs11_token_list(FILE* outfile); extern unsigned char buffer[]; extern const int buffer_size; + +#include <gnutls/x509.h> +#include <gnutls/abstract.h> + +gnutls_x509_privkey_t load_private_key (int mand); +gnutls_x509_crq_t load_request (void); +gnutls_x509_privkey_t load_ca_private_key (void); +gnutls_x509_crt_t load_ca_cert (void); +gnutls_x509_crt_t load_cert (int mand); +gnutls_pubkey_t load_pubkey (int mand); diff --git a/src/certtool-gaa.c b/src/certtool-gaa.c index d353489fec..fae02faa53 100644 --- a/src/certtool-gaa.c +++ b/src/certtool-gaa.c @@ -184,6 +184,10 @@ void gaa_help(void) __gaa_helpsingle(0, "pkcs11-list-all-certs", "", "List all certificates specified by a PKCS#11 URL"); __gaa_helpsingle(0, "pkcs11-list-all", "", "List all objects specified by a PKCS#11 URL"); __gaa_helpsingle(0, "pkcs11-list-tokens", "", "List all available tokens"); + __gaa_helpsingle(0, "pkcs11-write", "URL ", "Writes loaded certificates or private keys to a PKCS11 token."); + __gaa_helpsingle(0, "pkcs11-write-label", "label ", "Sets a label for the write operation."); + __gaa_helpsingle(0, "pkcs11-write-trusted", "", "Marks the certificate to be imported as trusted."); + __gaa_helpsingle(0, "pkcs11-delete-url", "URL ", "Deletes objects matching the URL."); __gaa_helpsingle('d', "debug", "LEVEL ", "specify the debug level. Default is 1."); __gaa_helpsingle('h', "help", "", "shows this help text"); __gaa_helpsingle('v', "version", "", "shows the program's version"); @@ -201,8 +205,12 @@ typedef struct _gaainfo gaainfo; struct _gaainfo { -#line 148 "certtool.gaa" +#line 156 "certtool.gaa" int debug; +#line 151 "certtool.gaa" + int pkcs11_trusted; +#line 148 "certtool.gaa" + char* pkcs11_label; #line 141 "certtool.gaa" int pkcs11_type; #line 138 "certtool.gaa" @@ -311,65 +319,69 @@ static int gaa_error = 0; #define GAA_MULTIPLE_OPTION 3 #define GAA_REST 0 -#define GAA_NB_OPTION 58 +#define GAA_NB_OPTION 62 #define GAAOPTID_version 1 #define GAAOPTID_help 2 #define GAAOPTID_debug 3 -#define GAAOPTID_pkcs11_list_tokens 4 -#define GAAOPTID_pkcs11_list_all 5 -#define GAAOPTID_pkcs11_list_all_certs 6 -#define GAAOPTID_pkcs11_list_trusted 7 -#define GAAOPTID_pkcs11_list_certs 8 -#define GAAOPTID_pkcs11_export_url 9 -#define GAAOPTID_pkcs11_provider 10 -#define GAAOPTID_pkcs_cipher 11 -#define GAAOPTID_template 12 -#define GAAOPTID_infile 13 -#define GAAOPTID_outfile 14 -#define GAAOPTID_disable_quick_random 15 -#define GAAOPTID_bits 16 -#define GAAOPTID_outraw 17 -#define GAAOPTID_outder 18 -#define GAAOPTID_inraw 19 -#define GAAOPTID_inder 20 -#define GAAOPTID_export_ciphers 21 -#define GAAOPTID_hash 22 -#define GAAOPTID_dsa 23 -#define GAAOPTID_pkcs8 24 -#define GAAOPTID_to_p8 25 -#define GAAOPTID_to_p12 26 -#define GAAOPTID_v1 27 -#define GAAOPTID_fix_key 28 -#define GAAOPTID_pubkey_info 29 -#define GAAOPTID_pgp_key_info 30 -#define GAAOPTID_key_info 31 -#define GAAOPTID_smime_to_p7 32 -#define GAAOPTID_p7_info 33 -#define GAAOPTID_p12_info 34 -#define GAAOPTID_no_crq_extensions 35 -#define GAAOPTID_crq_info 36 -#define GAAOPTID_crl_info 37 -#define GAAOPTID_pgp_ring_info 38 -#define GAAOPTID_pgp_certificate_info 39 -#define GAAOPTID_certificate_info 40 -#define GAAOPTID_password 41 -#define GAAOPTID_load_ca_certificate 42 -#define GAAOPTID_load_ca_privkey 43 -#define GAAOPTID_load_certificate 44 -#define GAAOPTID_load_request 45 -#define GAAOPTID_load_pubkey 46 -#define GAAOPTID_load_privkey 47 -#define GAAOPTID_get_dh_params 48 -#define GAAOPTID_generate_dh_params 49 -#define GAAOPTID_verify_crl 50 -#define GAAOPTID_verify_chain 51 -#define GAAOPTID_generate_request 52 -#define GAAOPTID_generate_privkey 53 -#define GAAOPTID_update_certificate 54 -#define GAAOPTID_generate_crl 55 -#define GAAOPTID_generate_proxy 56 -#define GAAOPTID_generate_certificate 57 -#define GAAOPTID_generate_self_signed 58 +#define GAAOPTID_pkcs11_delete_url 4 +#define GAAOPTID_pkcs11_write_trusted 5 +#define GAAOPTID_pkcs11_write_label 6 +#define GAAOPTID_pkcs11_write 7 +#define GAAOPTID_pkcs11_list_tokens 8 +#define GAAOPTID_pkcs11_list_all 9 +#define GAAOPTID_pkcs11_list_all_certs 10 +#define GAAOPTID_pkcs11_list_trusted 11 +#define GAAOPTID_pkcs11_list_certs 12 +#define GAAOPTID_pkcs11_export_url 13 +#define GAAOPTID_pkcs11_provider 14 +#define GAAOPTID_pkcs_cipher 15 +#define GAAOPTID_template 16 +#define GAAOPTID_infile 17 +#define GAAOPTID_outfile 18 +#define GAAOPTID_disable_quick_random 19 +#define GAAOPTID_bits 20 +#define GAAOPTID_outraw 21 +#define GAAOPTID_outder 22 +#define GAAOPTID_inraw 23 +#define GAAOPTID_inder 24 +#define GAAOPTID_export_ciphers 25 +#define GAAOPTID_hash 26 +#define GAAOPTID_dsa 27 +#define GAAOPTID_pkcs8 28 +#define GAAOPTID_to_p8 29 +#define GAAOPTID_to_p12 30 +#define GAAOPTID_v1 31 +#define GAAOPTID_fix_key 32 +#define GAAOPTID_pubkey_info 33 +#define GAAOPTID_pgp_key_info 34 +#define GAAOPTID_key_info 35 +#define GAAOPTID_smime_to_p7 36 +#define GAAOPTID_p7_info 37 +#define GAAOPTID_p12_info 38 +#define GAAOPTID_no_crq_extensions 39 +#define GAAOPTID_crq_info 40 +#define GAAOPTID_crl_info 41 +#define GAAOPTID_pgp_ring_info 42 +#define GAAOPTID_pgp_certificate_info 43 +#define GAAOPTID_certificate_info 44 +#define GAAOPTID_password 45 +#define GAAOPTID_load_ca_certificate 46 +#define GAAOPTID_load_ca_privkey 47 +#define GAAOPTID_load_certificate 48 +#define GAAOPTID_load_request 49 +#define GAAOPTID_load_pubkey 50 +#define GAAOPTID_load_privkey 51 +#define GAAOPTID_get_dh_params 52 +#define GAAOPTID_generate_dh_params 53 +#define GAAOPTID_verify_crl 54 +#define GAAOPTID_verify_chain 55 +#define GAAOPTID_generate_request 56 +#define GAAOPTID_generate_privkey 57 +#define GAAOPTID_update_certificate 58 +#define GAAOPTID_generate_crl 59 +#define GAAOPTID_generate_proxy 60 +#define GAAOPTID_generate_certificate 61 +#define GAAOPTID_generate_self_signed 62 #line 168 "gaa.skel" @@ -562,49 +574,67 @@ struct GAAOPTION_debug int size1; }; -struct GAAOPTION_pkcs11_export_url +struct GAAOPTION_pkcs11_delete_url +{ + char* arg1; + int size1; +}; + +struct GAAOPTION_pkcs11_write_label +{ + char* arg1; + int size1; +}; + +struct GAAOPTION_pkcs11_write { char* arg1; int size1; }; -struct GAAOPTION_pkcs11_provider +struct GAAOPTION_pkcs11_export_url { char* arg1; int size1; }; -struct GAAOPTION_pkcs_cipher +struct GAAOPTION_pkcs11_provider { char* arg1; int size1; }; -struct GAAOPTION_template +struct GAAOPTION_pkcs_cipher { char* arg1; int size1; }; -struct GAAOPTION_infile +struct GAAOPTION_template { char* arg1; int size1; }; -struct GAAOPTION_outfile +struct GAAOPTION_infile { char* arg1; int size1; }; -struct GAAOPTION_bits +struct GAAOPTION_outfile +{ + char* arg1; + int size1; +}; + +struct GAAOPTION_bits { int arg1; int size1; }; -struct GAAOPTION_hash +struct GAAOPTION_hash { char* arg1; int size1; @@ -682,6 +712,9 @@ static int gaa_get_option_num(char *str, int status) { case GAA_LETTER_OPTION: GAA_CHECK1STR("d", GAAOPTID_debug); + GAA_CHECK1STR("", GAAOPTID_pkcs11_delete_url); + GAA_CHECK1STR("", GAAOPTID_pkcs11_write_label); + GAA_CHECK1STR("", GAAOPTID_pkcs11_write); GAA_CHECK1STR("", GAAOPTID_pkcs11_export_url); GAA_CHECK1STR("", GAAOPTID_pkcs11_provider); GAA_CHECK1STR("", GAAOPTID_pkcs_cipher); @@ -701,6 +734,7 @@ static int gaa_get_option_num(char *str, int status) #line 375 "gaa.skel" GAA_CHECK1STR("v", GAAOPTID_version); GAA_CHECK1STR("h", GAAOPTID_help); + GAA_CHECK1STR("", GAAOPTID_pkcs11_write_trusted); GAA_CHECK1STR("", GAAOPTID_pkcs11_list_tokens); GAA_CHECK1STR("", GAAOPTID_pkcs11_list_all); GAA_CHECK1STR("", GAAOPTID_pkcs11_list_all_certs); @@ -748,6 +782,10 @@ static int gaa_get_option_num(char *str, int status) GAA_CHECKSTR("version", GAAOPTID_version); GAA_CHECKSTR("help", GAAOPTID_help); GAA_CHECKSTR("debug", GAAOPTID_debug); + GAA_CHECKSTR("pkcs11-delete-url", GAAOPTID_pkcs11_delete_url); + GAA_CHECKSTR("pkcs11-write-trusted", GAAOPTID_pkcs11_write_trusted); + GAA_CHECKSTR("pkcs11-write-label", GAAOPTID_pkcs11_write_label); + GAA_CHECKSTR("pkcs11-write", GAAOPTID_pkcs11_write); GAA_CHECKSTR("pkcs11-list-tokens", GAAOPTID_pkcs11_list_tokens); GAA_CHECKSTR("pkcs11-list-all", GAAOPTID_pkcs11_list_all); GAA_CHECKSTR("pkcs11-list-all-certs", GAAOPTID_pkcs11_list_all_certs); @@ -816,6 +854,9 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) int OK = 0; int gaa_last_non_option; struct GAAOPTION_debug GAATMP_debug; + struct GAAOPTION_pkcs11_delete_url GAATMP_pkcs11_delete_url; + struct GAAOPTION_pkcs11_write_label GAATMP_pkcs11_write_label; + struct GAAOPTION_pkcs11_write GAATMP_pkcs11_write; struct GAAOPTION_pkcs11_export_url GAATMP_pkcs11_export_url; struct GAAOPTION_pkcs11_provider GAATMP_pkcs11_provider; struct GAAOPTION_pkcs_cipher GAATMP_pkcs_cipher; @@ -853,14 +894,14 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) { case GAAOPTID_version: OK = 0; -#line 153 "certtool.gaa" +#line 161 "certtool.gaa" { certtool_version(); exit(0); ;}; return GAA_OK; break; case GAAOPTID_help: OK = 0; -#line 151 "certtool.gaa" +#line 159 "certtool.gaa" { gaa_help(); exit(0); ;}; return GAA_OK; @@ -870,11 +911,48 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_debug.arg1, gaa_getint, GAATMP_debug.size1); gaa_index++; -#line 149 "certtool.gaa" +#line 157 "certtool.gaa" { gaaval->debug = GAATMP_debug.arg1 ;}; return GAA_OK; break; + case GAAOPTID_pkcs11_delete_url: + OK = 0; + GAA_TESTMOREARGS; + GAA_FILL(GAATMP_pkcs11_delete_url.arg1, gaa_getstr, GAATMP_pkcs11_delete_url.size1); + gaa_index++; +#line 154 "certtool.gaa" +{ gaaval->action = ACTION_PKCS11_DELETE_URL; gaaval->pkcs11_url = GAATMP_pkcs11_delete_url.arg1; ;}; + + return GAA_OK; + break; + case GAAOPTID_pkcs11_write_trusted: + OK = 0; +#line 152 "certtool.gaa" +{ gaaval->pkcs11_trusted = 1; ;}; + + return GAA_OK; + break; + case GAAOPTID_pkcs11_write_label: + OK = 0; + GAA_TESTMOREARGS; + GAA_FILL(GAATMP_pkcs11_write_label.arg1, gaa_getstr, GAATMP_pkcs11_write_label.size1); + gaa_index++; +#line 150 "certtool.gaa" +{ gaaval->pkcs11_label = GAATMP_pkcs11_write_label.arg1; ;}; + + return GAA_OK; + break; + case GAAOPTID_pkcs11_write: + OK = 0; + GAA_TESTMOREARGS; + GAA_FILL(GAATMP_pkcs11_write.arg1, gaa_getstr, GAATMP_pkcs11_write.size1); + gaa_index++; +#line 149 "certtool.gaa" +{ gaaval->action = ACTION_PKCS11_WRITE_URL; gaaval->pkcs11_url = GAATMP_pkcs11_write.arg1; ;}; + + return GAA_OK; + break; case GAAOPTID_pkcs11_list_tokens: OK = 0; #line 146 "certtool.gaa" @@ -1329,13 +1407,14 @@ int gaa(int argc, char **argv, gaainfo *gaaval) if(inited == 0) { -#line 155 "certtool.gaa" +#line 163 "certtool.gaa" { gaaval->bits = 2048; gaaval->pkcs8 = 0; gaaval->privkey = NULL; gaaval->ca=NULL; gaaval->ca_privkey = NULL; gaaval->debug=1; gaaval->request = NULL; gaaval->infile = NULL; gaaval->outfile = NULL; gaaval->cert = NULL; gaaval->incert_format = 0; gaaval->outcert_format = 0; gaaval->action=-1; gaaval->pass = NULL; gaaval->v1_cert = 0; gaaval->export = 0; gaaval->template = NULL; gaaval->hash=NULL; gaaval->fix_key = 0; gaaval->quick_random=1; gaaval->privkey_op = 0; gaaval->pkcs_cipher = "3des"; gaaval->crq_extensions=1; gaaval->pkcs11_provider= NULL; - gaaval->pkcs11_url = NULL; gaaval->pkcs11_type = PKCS11_TYPE_PK; gaaval->pubkey=NULL; ;}; + gaaval->pkcs11_url = NULL; gaaval->pkcs11_type = PKCS11_TYPE_PK; gaaval->pubkey=NULL; gaaval->pkcs11_label = NULL; + gaaval->pkcs11_trusted=0; ;}; } inited = 1; diff --git a/src/certtool-gaa.h b/src/certtool-gaa.h index b96924aa61..8cda5acc1b 100644 --- a/src/certtool-gaa.h +++ b/src/certtool-gaa.h @@ -8,8 +8,12 @@ typedef struct _gaainfo gaainfo; struct _gaainfo { -#line 148 "certtool.gaa" +#line 156 "certtool.gaa" int debug; +#line 151 "certtool.gaa" + int pkcs11_trusted; +#line 148 "certtool.gaa" + char* pkcs11_label; #line 141 "certtool.gaa" int pkcs11_type; #line 138 "certtool.gaa" diff --git a/src/certtool.c b/src/certtool.c index 075f19c840..b646453c50 100644 --- a/src/certtool.c +++ b/src/certtool.c @@ -64,12 +64,6 @@ void verify_crl (void); void pubkey_info (void); void pgp_privkey_info (void); void pgp_ring_info (void); -gnutls_x509_privkey_t load_private_key (int mand); -gnutls_x509_crq_t load_request (void); -gnutls_x509_privkey_t load_ca_private_key (void); -gnutls_x509_crt_t load_ca_cert (void); -gnutls_x509_crt_t load_cert (int mand); -gnutls_pubkey_t load_pubkey (int mand); void certificate_info (void); void pgp_certificate_info (void); void crl_info (void); @@ -1028,6 +1022,12 @@ gaa_parser (int argc, char **argv) case ACTION_PKCS11_EXPORT_URL: pkcs11_export(outfile, info.pkcs11_url); break; + case ACTION_PKCS11_WRITE_URL: + pkcs11_write(outfile, info.pkcs11_url, info.pkcs11_label, info.pkcs11_trusted); + break; + case ACTION_PKCS11_DELETE_URL: + pkcs11_delete(outfile, info.pkcs11_url, batch); + break; #ifdef ENABLE_OPENPGP case ACTION_PGP_INFO: pgp_certificate_info (); diff --git a/src/certtool.gaa b/src/certtool.gaa index 0ce49aaea5..9a835ad3ab 100644 --- a/src/certtool.gaa +++ b/src/certtool.gaa @@ -145,6 +145,14 @@ option (pkcs11-list-all-certs) { $action = ACTION_PKCS11_LIST; $pkcs11_type=PKCS option (pkcs11-list-all) { $action = ACTION_PKCS11_LIST; $pkcs11_type=PKCS11_TYPE_ALL; } "List all objects specified by a PKCS#11 URL" option (pkcs11-list-tokens) { $action = ACTION_PKCS11_TOKENS; } "List all available tokens" +#char* pkcs11_label; +option (pkcs11-write) STR "URL" { $action = ACTION_PKCS11_WRITE_URL; $pkcs11_url = $1; } "Writes loaded certificates or private keys to a PKCS11 token." +option (pkcs11-write-label) STR "label" { $pkcs11_label = $1; } "Sets a label for the write operation." +#int pkcs11_trusted; +option (pkcs11-write-trusted) { $pkcs11_trusted = 1; } "Marks the certificate to be imported as trusted." + +option (pkcs11-delete-url) STR "URL" { $action = ACTION_PKCS11_DELETE_URL; $pkcs11_url = $1; } "Deletes objects matching the URL." + #int debug; option (d, debug) INT "LEVEL" { $debug = $1 } "specify the debug level. Default is 1." @@ -157,4 +165,5 @@ init { $bits = 2048; $pkcs8 = 0; $privkey = NULL; $ca=NULL; $ca_privkey = NULL; $incert_format = 0; $outcert_format = 0; $action=-1; $pass = NULL; $v1_cert = 0; $export = 0; $template = NULL; $hash=NULL; $fix_key = 0; $quick_random=1; $privkey_op = 0; $pkcs_cipher = "3des"; $crq_extensions=1; $pkcs11_provider= NULL; - $pkcs11_url = NULL; $pkcs11_type = PKCS11_TYPE_PK; $pubkey=NULL; } + $pkcs11_url = NULL; $pkcs11_type = PKCS11_TYPE_PK; $pubkey=NULL; $pkcs11_label = NULL; + $pkcs11_trusted=0; } diff --git a/src/crypt-gaa.c b/src/crypt-gaa.c index 8ec3b033ed..3375cf9988 100644 --- a/src/crypt-gaa.c +++ b/src/crypt-gaa.c @@ -389,12 +389,31 @@ static int gaa_getint(char *arg) return tmp; } +static char gaa_getchar(char *arg) +{ + if(strlen(arg) != 1) + { + printf("Option %s: '%s' isn't an character\n", gaa_current_option, arg); + GAAERROR(-1); + } + return arg[0]; +} static char* gaa_getstr(char *arg) { return arg; } - +static float gaa_getfloat(char *arg) +{ + float tmp; + char a; + if(sscanf(arg, "%f%c", &tmp, &a) < 1) + { + printf("Option %s: '%s' isn't a float number\n", gaa_current_option, arg); + GAAERROR(-1); + } + return tmp; +} /* option structures */ struct GAAOPTION_create_conf @@ -615,19 +634,16 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) int gaa(int argc, char **argv, gaainfo *gaaval) { int tmp1, tmp2; - int l; - size_t i, j; + int i, j; char *opt_list; - i = 0; - GAAargv = argv; GAAargc = argc; opt_list = (char*) gaa_malloc(GAA_NB_OPTION + 1); - for(l = 0; l < GAA_NB_OPTION + 1; l++) - opt_list[l] = 0; + for(i = 0; i < GAA_NB_OPTION + 1; i++) + opt_list[i] = 0; /* initialization */ if(inited == 0) { @@ -646,27 +662,27 @@ int gaa(int argc, char **argv, gaainfo *gaaval) gaa_arg_used = gaa_malloc(argc * sizeof(char)); } - for(l = 1; l < argc; l++) - gaa_arg_used[l] = 0; - for(l = 1; l < argc; l++) + for(i = 1; i < argc; i++) + gaa_arg_used[i] = 0; + for(i = 1; i < argc; i++) { - if(gaa_arg_used[l] == 0) + if(gaa_arg_used[i] == 0) { j = 0; - tmp1 = gaa_is_an_argument(GAAargv[l]); + tmp1 = gaa_is_an_argument(GAAargv[i]); switch(tmp1) { case GAA_WORD_OPTION: j++; case GAA_LETTER_OPTION: j++; - tmp2 = gaa_get_option_num(argv[l]+j, tmp1); + tmp2 = gaa_get_option_num(argv[i]+j, tmp1); if(tmp2 == GAA_ERROR_NOMATCH) { - printf("Invalid option '%s'\n", argv[l]+j); + printf("Invalid option '%s'\n", argv[i]+j); return 0; } - switch(gaa_try(tmp2, l+1, gaaval, opt_list)) + switch(gaa_try(tmp2, i+1, gaaval, opt_list)) { case GAA_ERROR_NOTENOUGH_ARGS: printf("'%s': not enough arguments\n",gaa_current_option); @@ -679,18 +695,18 @@ int gaa(int argc, char **argv, gaainfo *gaaval) default: printf("Unknown error\n"); } - gaa_arg_used[l] = 1; + gaa_arg_used[i] = 1; break; case GAA_MULTIPLE_OPTION: - for(j = 1; j < strlen(argv[l]); j++) + for(j = 1; j < strlen(argv[i]); j++) { - tmp2 = gaa_get_option_num(argv[l]+j, tmp1); + tmp2 = gaa_get_option_num(argv[i]+j, tmp1); if(tmp2 == GAA_ERROR_NOMATCH) { - printf("Invalid option '%c'\n", *(argv[l]+j)); + printf("Invalid option '%c'\n", *(argv[i]+j)); return 0; } - switch(gaa_try(tmp2, l+1, gaaval, opt_list)) + switch(gaa_try(tmp2, i+1, gaaval, opt_list)) { case GAA_ERROR_NOTENOUGH_ARGS: printf("'%s': not enough arguments\n",gaa_current_option); @@ -704,7 +720,7 @@ int gaa(int argc, char **argv, gaainfo *gaaval) printf("Unknown error\n"); } } - gaa_arg_used[l] = 1; + gaa_arg_used[i] = 1; break; default: break; } @@ -730,9 +746,9 @@ if(gaa_processing_file == 0) } #endif } - for(l = 1; l < argc; l++) + for(i = 1; i < argc; i++) { - if(gaa_arg_used[l] == 0) + if(gaa_arg_used[i] == 0) { printf("Too many arguments\n"); return 0; @@ -783,7 +799,7 @@ static int gaa_internal_get_next_str(FILE *file, gaa_str_node *tmp_str, int argc len++; a = fgetc( file); - if(a==EOF) return 0; /* a = ' '; */ + if(a==EOF) return 0; //a = ' '; } len += 1; diff --git a/src/pkcs11.c b/src/pkcs11.c index be99641777..c27dd03e25 100644 --- a/src/pkcs11.c +++ b/src/pkcs11.c @@ -44,6 +44,28 @@ static void pkcs11_common(void) } +void pkcs11_delete(FILE* outfile, const char* url, int batch) +{ +int ret; + if (!batch) { + pkcs11_list(outfile, url, PKCS11_TYPE_ALL); + ret = read_yesno("Are you sure you want to delete those objects? (Y/N): "); + if (ret == 0) { + exit(1); + } + } + + ret = gnutls_pkcs11_delete_url(url); + if (ret < 0) { + fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror(ret)); + exit(1); + } + + fprintf(outfile, "\n%d objects deleted\n", ret); + + return; +} + /* lists certificates from a token */ void pkcs11_list( FILE* outfile, const char* url, int type) @@ -340,6 +362,15 @@ size_t size; } return; +} + +void pkcs11_write(FILE* outfile, const char* url, const char* label, int trusted) +{ +gnutls_x509_crt_t xcrt; +gnutls_x509_privkey_t xkey; +int ret; +unsigned int flags = 0; +unsigned int key_usage; } @@ -512,6 +543,10 @@ size_t size; return; + if (xkey == NULL && xcrt == NULL) { + fprintf(stderr, "You must use --load-privkey or --load-certificate to load the file to be copied\n"); + exit (1); + } - + return; } |