From: Nikos Mavrogiannopoulos Date: Mon, 10 May 2010 14:26:24 +0000 (+0200) Subject: Added ability to export certificates from PKCS #11 tokens. X-Git-Tag: gnutls_2_11_3~307 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bbcdf1b0c3365174999b763fd6f6822ddc910f5a;p=thirdparty%2Fgnutls.git Added ability to export certificates from PKCS #11 tokens. Added ability to list trusted certificates, or only certificates with a corresponding private key or just all. --- diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c index 1913420f0f..85d4bd6d24 100644 --- a/lib/gnutls_errors.c +++ b/lib/gnutls_errors.c @@ -274,6 +274,17 @@ static const gnutls_error_entry error_algorithms[] = { ERROR_ENTRY (N_("Error interfacing with /dev/crypto"), GNUTLS_E_CRYPTODEV_IOCTL_ERROR, 1), + ERROR_ENTRY (N_("PKCS #11 error."), + GNUTLS_E_PKCS11_ERROR, 1), + ERROR_ENTRY (N_("PKCS #11 initialization error."), + GNUTLS_E_PKCS11_LOAD_ERROR, 1), + ERROR_ENTRY (N_("Error in parsing."), + GNUTLS_E_PARSING_ERROR, 1), + ERROR_ENTRY (N_("PKCS #11 error in PIN."), + GNUTLS_E_PKCS11_PIN_ERROR, 1), + ERROR_ENTRY (N_("PKCS #11 error"), + GNUTLS_E_PKCS11_ERROR, 1), + {NULL, NULL, 0, 0} }; diff --git a/lib/gnutls_str.c b/lib/gnutls_str.c index 2efe4c643f..4c8aca36f7 100644 --- a/lib/gnutls_str.c +++ b/lib/gnutls_str.c @@ -442,34 +442,34 @@ _gnutls_hex2bin (const opaque * hex_data, int hex_size, opaque * bin_data, opaque hex2_data[3]; unsigned long val; - /* FIXME: we don't handle whitespace. - */ - hex_size /= 2; + hex2_data[2] = 0; - if (*bin_size < (size_t) hex_size) + for (i = j = 0; i < hex_size;) { - gnutls_assert (); - return GNUTLS_E_SHORT_MEMORY_BUFFER; - } + if (!isxdigit(hex_data[i])) /* skip non-hex such as the ':' in 00:FF */ + { + i++; + continue; + } + + if (j > *bin_size) { + gnutls_assert(); + return GNUTLS_E_SHORT_MEMORY_BUFFER; + } - for (i = j = 0; j < hex_size; j++) - { - - if (!isxdigit(hex_data[i])) /* skip non-hex such as the ':' in 00:FF */ - continue; - - hex2_data[0] = hex_data[i]; - hex2_data[1] = hex_data[i + 1]; - hex2_data[2] = 0; - i+=2; - val = strtoul ((char *) hex2_data, NULL, 16); - if (val == ULONG_MAX) - { - gnutls_assert (); - return GNUTLS_E_SRP_PWD_PARSING_ERROR; - } - bin_data[j] = val; + hex2_data[0] = hex_data[i]; + hex2_data[1] = hex_data[i + 1]; + i+=2; + + val = strtoul ((char *) hex2_data, NULL, 16); + if (val == ULONG_MAX) { + gnutls_assert (); + return GNUTLS_E_PARSING_ERROR; + } + bin_data[j] = val; + j++; } + *bin_size = j; return 0; } diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 91aa0a4248..9a129e3ccf 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -1728,8 +1728,16 @@ extern "C" #define GNUTLS_E_CRYPTODEV_IOCTL_ERROR -211 #define GNUTLS_E_CRYPTODEV_DEVICE_ERROR -212 +/* PKCS11 related */ +#define GNUTLS_E_PKCS11_ERROR -300 +#define GNUTLS_E_PKCS11_LOAD_ERROR -301 +#define GNUTLS_E_PARSING_ERROR -302 +#define GNUTLS_E_PKCS11_PIN_ERROR -303 + #define GNUTLS_E_UNIMPLEMENTED_FEATURE -1250 + + #define GNUTLS_E_APPLICATION_ERROR_MAX -65000 #define GNUTLS_E_APPLICATION_ERROR_MIN -65500 diff --git a/lib/includes/gnutls/pkcs11.h b/lib/includes/gnutls/pkcs11.h index 092333a14c..924879f50d 100644 --- a/lib/includes/gnutls/pkcs11.h +++ b/lib/includes/gnutls/pkcs11.h @@ -18,13 +18,6 @@ #include #include -/** - * @brief PKCS#11 error - */ -#define GNUTLS_E_PKCS11_ERROR (GNUTLS_E_APPLICATION_ERROR_MIN+529) -#define GNUTLS_E_PKCS11_LOAD_ERROR 1821 -#define GNUTLS_E_PARSING_ERROR 1822 -#define GNUTLS_E_PKCS11_PIN_ERROR 1823 #define GNUTLS_PKCS11_MAX_PIN_LEN 32 @@ -121,7 +114,7 @@ void gnutls_pkcs11_deinit (void); * @param data Data to use when calling callback. * @return gnutls status. */ -void gnutls_pkcs11_set_pin_function (const gnutls_pkcs11_pin_callback_t callback, void * const data); +void gnutls_pkcs11_set_pin_function (gnutls_pkcs11_pin_callback_t callback, void * const data); /** * @brief Add PKCS#11 provider. diff --git a/lib/pkcs11.c b/lib/pkcs11.c index c49e628fd9..2112b3fd1f 100644 --- a/lib/pkcs11.c +++ b/lib/pkcs11.c @@ -29,8 +29,8 @@ #define MAX_PROVIDERS 16 #define ID_SIZE 128 +#define LABEL_SIZE 128 -typedef int (*find_func_t)(pakchois_session_t *pks, struct ck_token_info* tinfo, void* input); struct gnutls_pkcs11_provider_s { pakchois_module_t *module; @@ -38,15 +38,17 @@ struct gnutls_pkcs11_provider_s { ck_slot_id_t *slots; }; + struct pkcs11_url_info { /* everything here is null terminated strings */ - opaque id[ID_SIZE]; + opaque id[ID_SIZE*3+1]; /* hex with delimiters */ opaque type[16]; /* cert/key etc. */ opaque manufacturer[sizeof (((struct ck_token_info *)NULL)->manufacturer_id)+1]; opaque token[sizeof (((struct ck_token_info *)NULL)->label)+1]; opaque serial[sizeof (((struct ck_token_info *)NULL)->serial_number)+1]; opaque model[sizeof (((struct ck_token_info *)NULL)->model)+1]; + opaque label[LABEL_SIZE+1]; }; struct gnutls_pkcs11_crt_st { @@ -57,7 +59,7 @@ struct gnutls_pkcs11_crt_st { struct url_find_data_st { gnutls_pkcs11_crt_t crt; - char certid_raw[ID_SIZE/2]; + char certid_raw[ID_SIZE]; size_t certid_raw_size; }; @@ -69,6 +71,15 @@ struct crt_find_data_st { struct pkcs11_url_info info; }; +struct token_info { + struct ck_token_info tinfo; + struct ck_slot_info sinfo; + ck_slot_id_t sid; + struct gnutls_pkcs11_provider_s* prov; +}; + +typedef int (*find_func_t)(pakchois_session_t *pks, struct token_info* tinfo, void* input); + static struct gnutls_pkcs11_provider_s providers[MAX_PROVIDERS]; static int active_providers = 0; @@ -109,7 +120,7 @@ int gnutls_pkcs11_add_provider (const char * name, const char * params) goto fail; } - _gnutls_debug_log("p11: loaded provider '%s' with %d slots\n", name, providers[active_providers-1].nslots); + _gnutls_debug_log("p11: loaded provider '%s' with %d slots\n", name, (int)providers[active_providers-1].nslots); return 0; @@ -228,8 +239,7 @@ static int unescape_string (char* output, const char* input, size_t* size, char static int pkcs11_url_to_info(const char* url, struct pkcs11_url_info* info) { int ret; -char* p1; -char* hexid = NULL; +char* p1, *p2; size_t l; memset( info, 0, sizeof(*info)); @@ -259,6 +269,16 @@ size_t l; } } + if ((p1=strstr(url, "object="))!= NULL) { + p1+=sizeof("object=")-1; + l=sizeof (info->label); + + ret = unescape_string(info->label, p1, &l, ';'); + if (ret < 0) { + goto cleanup; + } + } + if ((p1=strstr(url, "serial="))!= NULL) { p1+=sizeof("serial=")-1; l=sizeof (info->serial); @@ -283,30 +303,25 @@ size_t l; if (((p1=strstr(url, ";id="))!= NULL) || ((p1=strstr(url, ":id="))!= NULL)) { p1+=sizeof(";id=")-1; - hexid = gnutls_strdup(p1); - if (hexid == NULL) { - goto cleanup; - } - if ((p1=strchr(hexid, ';'))!= NULL) { - *p1 = 0; + if ((p2=strchr(p1, ';'))== NULL) { + l = strlen(p1); } else { - ret = GNUTLS_E_PARSING_ERROR; - goto cleanup; + l = p2 - p1; } - - l = sizeof(info->id); - ret = _gnutls_hex2bin(hexid, strlen(hexid), info->id, &l); - if (ret < 0) { + + if (l > sizeof(info->id)-1) { gnutls_assert(); - return ret; + ret = GNUTLS_E_PARSING_ERROR; } + + memcpy(info->id, p1, l); + info->id[l] = 0; } ret = 0; cleanup: - gnutls_free(hexid); return ret; @@ -371,6 +386,15 @@ static int pkcs11_info_to_url(const struct pkcs11_url_info* info, char** url) init = 1; } + if (info->serial[0]) { + ret = append(&str, info->serial, "serial", init); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + init = 1; + } + if (info->model[0]) { ret = append(&str, info->model, "model", init); if (ret < 0) { @@ -380,6 +404,7 @@ static int pkcs11_info_to_url(const struct pkcs11_url_info* info, char** url) init = 1; } + if (info->manufacturer[0]) { ret = append(&str, info->manufacturer, "manufacturer", init); if (ret < 0) { @@ -389,15 +414,15 @@ static int pkcs11_info_to_url(const struct pkcs11_url_info* info, char** url) init = 1; } - if (info->serial[0]) { - ret = append(&str, info->serial, "serial", init); + if (info->label[0]) { + ret = append(&str, info->label, "object", init); if (ret < 0) { gnutls_assert(); goto cleanup; } init = 1; } - + ret = _gnutls_string_append_printf(&str, ";id=%s", info->id); if (ret < 0) { gnutls_assert(); @@ -443,86 +468,6 @@ static void terminate_string(unsigned char *str, size_t len) ptr[1] = '\0'; } -static int pk11_login(struct gnutls_pkcs11_provider_s *prov, ck_slot_id_t slot_id, - pakchois_session_t *pks, struct ck_slot_info *sinfo, struct ck_token_info* tinfo) -{ - int attempt = 0; - ck_rv_t rv; - - if (pakchois_get_token_info(prov->module, slot_id, tinfo) != CKR_OK) { - gnutls_assert(); - _gnutls_debug_log("pk11: GetTokenInfo failed\n"); - return GNUTLS_E_PKCS11_ERROR; - } - - if ((tinfo->flags & CKF_LOGIN_REQUIRED) == 0) { - _gnutls_debug_log("pk11: No login required.\n"); - return 0; - } - - /* For a token with a "protected" (out-of-band) authentication - * path, calling login with a NULL username is all that is - * required. */ - if (tinfo->flags & CKF_PROTECTED_AUTHENTICATION_PATH) { - if (pakchois_login(pks, CKU_USER, NULL, 0) == CKR_OK) { - return 0; - } - else { - gnutls_assert(); - _gnutls_debug_log("pk11: Protected login failed.\n"); - return GNUTLS_E_PKCS11_ERROR; - } - } - - /* Otherwise, PIN entry is necessary for login, so fail if there's - * no callback. */ - if (!pin_func) { - gnutls_assert(); - _gnutls_debug_log("pk11: No pin callback but login required.\n"); - return GNUTLS_E_PKCS11_PIN_ERROR; - } - - terminate_string(sinfo->slot_description, sizeof sinfo->slot_description); - - do { - char pin[GNUTLS_PKCS11_MAX_PIN_LEN]; - unsigned int flags = 0; - - /* If login has been attempted once already, check the token - * status again, the flags might change. */ - if (attempt) { - if (pakchois_get_token_info(prov->module, slot_id, - tinfo) != CKR_OK) { - _gnutls_debug_log("pk11: GetTokenInfo failed\n"); - gnutls_assert(); - return GNUTLS_E_PKCS11_ERROR; - } - } - - if (tinfo->flags & CKF_USER_PIN_COUNT_LOW) - flags |= GNUTLS_PKCS11_PIN_COUNT_LOW; - if (tinfo->flags & CKF_USER_PIN_FINAL_TRY) - flags |= GNUTLS_PKCS11_PIN_FINAL_TRY; - - terminate_string(tinfo->label, sizeof tinfo->label); - - if (pin_func(pin_data, attempt++, - (char *)sinfo->slot_description, - (char *)tinfo->label, flags, pin, sizeof(pin))) { - return GNUTLS_E_PKCS11_PIN_ERROR; - } - - rv = pakchois_login(pks, CKU_USER, (unsigned char *)pin, strlen(pin)); - - /* Try to scrub the pin off the stack. Clever compilers will - * probably optimize this away, oh well. */ - memset(pin, 0, sizeof pin); - } while (rv == CKR_PIN_INCORRECT); - - _gnutls_debug_log("pk11: Login result = %lu\n", rv); - - return (rv == CKR_OK || rv == CKR_USER_ALREADY_LOGGED_IN) ? 0 : GNUTLS_E_PKCS11_ERROR; -} static int traverse_tokens (find_func_t find_func, void* input) { @@ -533,24 +478,31 @@ static int traverse_tokens (find_func_t find_func, void* input) for (x=0;xinfo.token, sizeof(crt->info.token), "%s", tinfo->label); snprintf(crt->info.model, sizeof(crt->info.model), "%s", tinfo->model); snprintf(crt->info.serial, sizeof(crt->info.serial), "%s", tinfo->serial_number); + + memcpy(crt->info.label, label->data, label->size); + crt->info.label[label->size] = 0; + strcpy(crt->info.type, "cert"); s = _gnutls_bin2hex(id->data, id->size, crt->info.id, sizeof(crt->info.id), ":"); @@ -613,10 +569,10 @@ static int pkcs11_crt_import(gnutls_pkcs11_crt_t crt, const gnutls_datum_t* data } -static int find_url(pakchois_session_t *pks, struct ck_token_info *tinfo, void* input) +static int find_cert_url(pakchois_session_t *pks, struct token_info *info, void* input) { struct url_find_data_st* find_data = input; - struct ck_attribute a[3]; + struct ck_attribute a[4]; ck_object_class_t class; ck_certificate_type_t type; ck_rv_t rv; @@ -624,9 +580,10 @@ static int find_url(pakchois_session_t *pks, struct ck_token_info *tinfo, void* unsigned long count; int found = 0, ret; unsigned char value[8192], subject[8192]; - char certid_tmp[ID_SIZE/2]; + char certid_tmp[ID_SIZE]; + char label_tmp[LABEL_SIZE]; - if (tinfo == NULL) { /* we don't support multiple calls */ + if (info == NULL) { /* we don't support multiple calls */ gnutls_assert(); return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } @@ -634,22 +591,22 @@ static int find_url(pakchois_session_t *pks, struct ck_token_info *tinfo, 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, tinfo->manufacturer_id) != 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, tinfo->label) != 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, tinfo->model) != 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, tinfo->serial_number) != 0) + if (strcmp(find_data->crt->info.serial, info->tinfo.serial_number) != 0) return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } @@ -691,18 +648,25 @@ static int find_url(pakchois_session_t *pks, struct ck_token_info *tinfo, void* a[1].type = CKA_ID; a[1].value = certid_tmp; a[1].value_len = sizeof(certid_tmp); - a[2].type = CKA_SUBJECT; - a[2].value = subject; - a[2].value_len = sizeof subject; + a[2].type = CKA_LABEL; + a[2].value = label_tmp; + a[2].value_len = sizeof(label_tmp); if (pakchois_get_attribute_value(pks, obj, a, 3) == CKR_OK) { +char buf[512]; +char buf2[512]; +fprintf(stderr, "val: %d, certid: %d\n", a[1].value_len, find_data->certid_raw_size); +fprintf(stderr, "fcertid: %s, gcertid: %s\n", _gnutls_bin2hex (a[1].value, a[1].value_len, buf, + sizeof (buf), NULL), _gnutls_bin2hex (a[1].value, a[1].value_len, buf2, + sizeof (buf2), NULL)); if (a[1].value_len == find_data->certid_raw_size && memcmp(certid_tmp, find_data->certid_raw, find_data->certid_raw_size)==0) { gnutls_datum_t id = { a[1].value, a[1].value_len }; gnutls_datum_t data = { a[0].value, a[0].value_len }; + gnutls_datum_t label = { a[2].value, a[2].value_len }; - ret = pkcs11_crt_import(find_data->crt, &data, &id, tinfo); + ret = pkcs11_crt_import(find_data->crt, &data, &id, &label, &info->tinfo); if (ret < 0) { gnutls_assert(); goto cleanup; @@ -734,7 +698,6 @@ int gnutls_pkcs11_crt_import_url (gnutls_pkcs11_crt_t cert, const char * url) { int ret; struct url_find_data_st find_data; - size_t size; /* fill in the find data structure */ find_data.crt = cert; @@ -747,14 +710,13 @@ int gnutls_pkcs11_crt_import_url (gnutls_pkcs11_crt_t cert, const char * url) find_data.certid_raw_size = sizeof(find_data.certid_raw); - size = find_data.certid_raw_size; - ret = _gnutls_hex2bin(cert->info.id, sizeof cert->info.id, find_data.certid_raw, &size); + ret = _gnutls_hex2bin(cert->info.id, strlen(cert->info.id), find_data.certid_raw, &find_data.certid_raw_size); if (ret < 0) { gnutls_assert(); return ret; } - - ret = traverse_tokens(find_url, &find_data); +fprintf(stderr, "hex2bin: %d, %d\n", ret, find_data.certid_raw_size); + ret = traverse_tokens(find_cert_url, &find_data); if (ret < 0) { gnutls_assert(); return ret; @@ -781,12 +743,192 @@ gnutls_certificate_type_t gnutls_pkcs11_crt_get_type (gnutls_pkcs11_crt_t certif return certificate->type; } +struct pkey_list { + gnutls_string *key_ids; + size_t key_ids_size; +}; + +static int pk11_login(pakchois_session_t *pks, struct token_info *info) +{ + struct ck_token_info tinfo; + int attempt = 0; + ck_rv_t rv; + + if (pakchois_get_token_info(info->prov->module, info->sid, &info->tinfo) != CKR_OK) { + gnutls_assert(); + _gnutls_debug_log( "pk11: GetTokenInfo failed\n"); + return GNUTLS_E_PKCS11_ERROR; + } + + /* force login on HW tokens. Some tokens will not list private keys + * if login has not been performed. + */ + if (!(info->sinfo.flags & CKF_HW_SLOT) && (tinfo.flags & CKF_LOGIN_REQUIRED) == 0) { + gnutls_assert(); + _gnutls_debug_log( "pk11: No login required.\n"); + return 0; + } + + /* For a token with a "protected" (out-of-band) authentication + * path, calling login with a NULL username is all that is + * required. */ + if (tinfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) { + if (pakchois_login(pks, CKU_USER, NULL, 0) == CKR_OK) { + return 0; + } + else { + gnutls_assert(); + _gnutls_debug_log( "pk11: Protected login failed.\n"); + return GNUTLS_E_PKCS11_ERROR; + } + } + + /* Otherwise, PIN entry is necessary for login, so fail if there's + * no callback. */ + if (!pin_func) { + gnutls_assert(); + _gnutls_debug_log("pk11: No pin callback but login required.\n"); + return GNUTLS_E_PKCS11_ERROR; + } + + terminate_string(info->sinfo.slot_description, sizeof info->sinfo.slot_description); + + do { + char pin[GNUTLS_PKCS11_MAX_PIN_LEN]; + unsigned int flags = 0; + + /* If login has been attempted once already, check the token + * status again, the flags might change. */ + if (attempt) { + if (pakchois_get_token_info(info->prov->module, info->sid, + &info->tinfo) != CKR_OK) { + gnutls_assert(); + _gnutls_debug_log( "pk11: GetTokenInfo failed\n"); + return GNUTLS_E_PKCS11_ERROR; + } + } + + if (info->tinfo.flags & CKF_USER_PIN_COUNT_LOW) + flags |= GNUTLS_PKCS11_PIN_COUNT_LOW; + if (info->tinfo.flags & CKF_USER_PIN_FINAL_TRY) + flags |= GNUTLS_PKCS11_PIN_FINAL_TRY; + + terminate_string(info->tinfo.label, sizeof info->tinfo.label); + + if (pin_func(pin_data, attempt++, + (char *)info->sinfo.slot_description, + (char *)info->tinfo.label, flags, pin, sizeof(pin))) { + gnutls_assert(); + return GNUTLS_E_PKCS11_PIN_ERROR; + } + + rv = pakchois_login(pks, CKU_USER, (unsigned char *)pin, strlen(pin)); + + /* Try to scrub the pin off the stack. Clever compilers will + * probably optimize this away, oh well. */ + memset(pin, 0, sizeof pin); + } while (rv == CKR_PIN_INCORRECT); + + _gnutls_debug_log("pk11: Login result = %lu\n", rv); + + return (rv == CKR_OK || rv == CKR_USER_ALREADY_LOGGED_IN) ? 0 : GNUTLS_E_PKCS11_ERROR; +} + + +static int find_privkeys(pakchois_session_t *pks, struct token_info* info, struct pkey_list *list) +{ + struct ck_attribute a[3]; + ck_object_class_t class; + ck_rv_t rv; + ck_object_handle_t obj; + unsigned long count, current; + char certid_tmp[ID_SIZE]; + int ret; + + class = CKO_PRIVATE_KEY; + + ret = pk11_login(pks, info); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + /* Find an object with private key class and a certificate ID + * which matches the certificate. */ + /* FIXME: also match the cert subject. */ + a[0].type = CKA_CLASS; + a[0].value = &class; + a[0].value_len = sizeof class; + + rv = pakchois_find_objects_init(pks, a, 1); + if (rv != CKR_OK) { + gnutls_assert(); + return GNUTLS_E_PKCS11_ERROR; + } + + list->key_ids_size = 0; + while (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK + && count == 1) { + list->key_ids_size++; + } + + pakchois_find_objects_final(pks); + + if (list->key_ids_size == 0) { + gnutls_assert(); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } + + list->key_ids = gnutls_malloc(sizeof(gnutls_string)*list->key_ids_size); + if (list->key_ids == NULL) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + + /* actual search */ + a[0].type = CKA_CLASS; + a[0].value = &class; + a[0].value_len = sizeof class; + + rv = pakchois_find_objects_init(pks, a, 1); + if (rv != CKR_OK) { + gnutls_assert(); + return GNUTLS_E_PKCS11_ERROR; + } + + current = 0; + while (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK + && count == 1) { + + a[0].type = CKA_ID; + a[0].value = certid_tmp; + a[0].value_len = sizeof(certid_tmp); + + _gnutls_string_init(&list->key_ids[current], gnutls_malloc, gnutls_realloc, gnutls_free); + + if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK) { + _gnutls_string_append_data(&list->key_ids[current], a[0].value, a[0].value_len); + current++; + } + + if (current > list->key_ids_size) + break; + } + + pakchois_find_objects_final(pks); + + list->key_ids_size = current-1; + + return 0; +} + /* Recover certificate list from tokens */ -static int find_crts(pakchois_session_t *pks, struct ck_token_info *tinfo, void* input) + +static int find_crts(pakchois_session_t *pks, struct token_info *info, void* input) { struct crt_find_data_st* find_data = input; - struct ck_attribute a[3]; + struct ck_attribute a[4]; ck_object_class_t class; ck_certificate_type_t type; bool trusted; @@ -794,10 +936,12 @@ static int find_crts(pakchois_session_t *pks, struct ck_token_info *tinfo, void* ck_object_handle_t obj; unsigned long count; unsigned char value[8192], subject[8192]; - char certid_tmp[ID_SIZE/2]; + char certid_tmp[ID_SIZE]; + char label_tmp[LABEL_SIZE]; int ret, i; + struct pkey_list plist; /* private key holder */ - if (tinfo == NULL) { /* final call */ + if (info == NULL) { /* final call */ if (find_data->current <= *find_data->n_list) ret = 0; else @@ -811,22 +955,22 @@ static int find_crts(pakchois_session_t *pks, struct ck_token_info *tinfo, void* /* 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, tinfo->manufacturer_id) != 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, tinfo->label) != 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, tinfo->model) != 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, tinfo->serial_number) != 0) + if (strcmp(find_data->info.serial, info->tinfo.serial_number) != 0) return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } @@ -837,6 +981,20 @@ static int find_crts(pakchois_session_t *pks, struct ck_token_info *tinfo, void* } } + memset(&plist, 0, sizeof(plist)); + if (find_data->flags==GNUTLS_PKCS11_CRT_ATTR_WITH_PK) { + ret = find_privkeys(pks, info, &plist); + if (ret < 0) { + gnutls_assert(); + return ret; + } + + if (plist.key_ids_size == 0) { + gnutls_assert(); + return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; + } + } + /* Find objects with cert class and X.509 cert type. */ class = CKO_CERTIFICATE; type = CKC_X_509; @@ -874,20 +1032,24 @@ static int find_crts(pakchois_session_t *pks, struct ck_token_info *tinfo, void* a[1].type = CKA_ID; a[1].value = certid_tmp; a[1].value_len = sizeof(certid_tmp); - a[2].type = CKA_SUBJECT; - a[2].value = subject; - a[2].value_len = sizeof subject; + a[2].type = CKA_LABEL; + a[2].value = label_tmp; + a[2].value_len = sizeof label_tmp; if (pakchois_get_attribute_value(pks, obj, a, 3) == CKR_OK) { gnutls_datum_t data = { a[0].value, a[0].value_len }; gnutls_datum_t id = { a[1].value, a[1].value_len }; - + gnutls_datum_t label = { a[2].value, a[2].value_len }; + /* XXX check also ID with find_data->info.id */ if (find_data->flags == GNUTLS_PKCS11_CRT_ATTR_WITH_PK) { - gnutls_assert(); - /* XXX verify that certificate has a corresponding private key */ - //not yet + for (i=0;icurrent < *find_data->n_list) { @@ -897,8 +1059,8 @@ static int find_crts(pakchois_session_t *pks, struct ck_token_info *tinfo, void* gnutls_assert(); goto fail; } - - ret = pkcs11_crt_import(find_data->p_list[find_data->current], &data, &id, tinfo); + + ret = pkcs11_crt_import(find_data->p_list[find_data->current], &data, &id, &label, &info->tinfo); if (ret < 0) { gnutls_assert(); goto fail; @@ -919,6 +1081,12 @@ static int find_crts(pakchois_session_t *pks, struct ck_token_info *tinfo, void* fail: pakchois_find_objects_final(pks); + if (plist.key_ids != NULL) { + for (i=0;icurrent;i++) { gnutls_pkcs11_crt_deinit(find_data->p_list[i]); } @@ -1020,58 +1188,6 @@ cleanup: #if 0 #define KEYTYPE_IS_DSA(kt) (kt == CKK_DSA) -static int pk11_find_pkey(ne_ssl_pkcs11_provider *prov, - pakchois_session_t *pks, - unsigned char *certid, unsigned long cid_len) -{ - struct ck_attribute a[3]; - ck_object_class_t class; - ck_rv_t rv; - ck_object_handle_t obj; - unsigned long count; - int found = 0; - - class = CKO_PRIVATE_KEY; - - /* Find an object with private key class and a certificate ID - * which matches the certificate. */ - /* FIXME: also match the cert subject. */ - a[0].type = CKA_CLASS; - a[0].value = &class; - a[0].value_len = sizeof class; - a[1].type = CKA_ID; - a[1].value = certid; - a[1].value_len = cid_len; - - rv = pakchois_find_objects_init(pks, a, 2); - if (rv != CKR_OK) { - NE_DEBUG(NE_DBG_SSL, "pk11: FindObjectsInit failed.\n"); - /* TODO: error propagation */ - return 0; - } - - rv = pakchois_find_objects(pks, &obj, 1, &count); - if (rv == CKR_OK && count == 1) { - NE_DEBUG(NE_DBG_SSL, "pk11: Found private key.\n"); - - a[0].type = CKA_KEY_TYPE; - a[0].value = &prov->keytype; - a[0].value_len = sizeof prov->keytype; - - if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK - && (prov->keytype == CKK_RSA || KEYTYPE_IS_DSA(prov->keytype))) { - found = 1; - prov->privkey = obj; - } - else { - NE_DEBUG(NE_DBG_SSL, "pk11: Could not determine key type.\n"); - } - } - - pakchois_find_objects_final(pks); - - return found; -} static int find_client_cert(ne_ssl_pkcs11_provider *prov, pakchois_session_t *pks) diff --git a/src/certtool-common.h b/src/certtool-common.h index 07be84c5fc..f0132d402f 100644 --- a/src/certtool-common.h +++ b/src/certtool-common.h @@ -1,3 +1,6 @@ +#include +#include + enum { ACTION_SELF_SIGNED, @@ -24,11 +27,18 @@ enum ACTION_RING_INFO, ACTION_REQUEST, ACTION_PKCS11_LIST, + ACTION_PKCS11_EXPORT_URL, }; #define TYPE_CRT 1 #define TYPE_CRQ 2 void certtool_version (void); -void pkcs11_list( const char* url); +void pkcs11_list( const char* url, int type); +void pkcs11_export(FILE* outfile, const char *pkcs11_url); +void print_certificate_info (gnutls_x509_crt_t crt, FILE * out, + unsigned int); +#define PKCS11_TYPE_ALL 1 +#define PKCS11_TYPE_TRUSTED 2 +#define PKCS11_TYPE_PK 3 diff --git a/src/certtool-gaa.c b/src/certtool-gaa.c index b0bfd3f73c..19828a1707 100644 --- a/src/certtool-gaa.c +++ b/src/certtool-gaa.c @@ -161,9 +161,6 @@ void gaa_help(void) __gaa_helpsingle(0, "v1", "", "Generate an X.509 version 1 certificate (no extensions)."); __gaa_helpsingle(0, "to-p12", "", "Generate a PKCS #12 structure."); __gaa_helpsingle(0, "to-p8", "", "Generate a PKCS #8 key structure."); - __gaa_helpsingle(0, "pkcs11-provider", "Library ", "Specify the pkcs11 provider library"); - __gaa_helpsingle(0, "pkcs11-url", "URL ", "Specify a pkcs11 URL"); - __gaa_helpsingle(0, "pkcs11-list", "", "List objects specified by a PKCS#11 URL"); __gaa_helpsingle('8', "pkcs8", "", "Use PKCS #8 format for private keys."); __gaa_helpsingle(0, "dsa", "", "Use DSA keys."); __gaa_helpsingle(0, "hash", "STR ", "Hash algorithm to use for signing (MD5,SHA1,RMD160,SHA256,SHA384,SHA512)."); @@ -178,6 +175,11 @@ void gaa_help(void) __gaa_helpsingle(0, "infile", "FILE ", "Input file."); __gaa_helpsingle(0, "template", "FILE ", "Template file to use for non interactive operation."); __gaa_helpsingle(0, "pkcs-cipher", "CIPHER ", "Cipher to use for pkcs operations (3des,aes-128,aes-192,aes-256,rc2-40)."); + __gaa_helpsingle(0, "pkcs11-provider", "Library ", "Specify the pkcs11 provider library"); + __gaa_helpsingle(0, "pkcs11-export-url", "URL ", "Export data specified a pkcs11 URL"); + __gaa_helpsingle(0, "pkcs11-list", "", "List objects specified by a PKCS#11 URL"); + __gaa_helpsingle(0, "pkcs11-list-trusted", "", "List objects marked as trusted, specified by a PKCS#11 URL"); + __gaa_helpsingle(0, "pkcs11-list-all", "", "List all objects specified by a PKCS#11 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"); @@ -195,36 +197,38 @@ typedef struct _gaainfo gaainfo; struct _gaainfo { -#line 139 "certtool.gaa" +#line 142 "certtool.gaa" int debug; -#line 135 "certtool.gaa" +#line 137 "certtool.gaa" + int pkcs11_type; +#line 134 "certtool.gaa" + char* pkcs11_url; +#line 131 "certtool.gaa" + char* pkcs11_provider; +#line 128 "certtool.gaa" char *pkcs_cipher; -#line 132 "certtool.gaa" +#line 125 "certtool.gaa" char *template; -#line 129 "certtool.gaa" +#line 122 "certtool.gaa" char *infile; -#line 126 "certtool.gaa" +#line 119 "certtool.gaa" char *outfile; -#line 123 "certtool.gaa" +#line 116 "certtool.gaa" int quick_random; -#line 120 "certtool.gaa" +#line 113 "certtool.gaa" int bits; -#line 116 "certtool.gaa" +#line 109 "certtool.gaa" int outcert_format; -#line 112 "certtool.gaa" +#line 105 "certtool.gaa" int incert_format; -#line 109 "certtool.gaa" +#line 102 "certtool.gaa" int export; -#line 106 "certtool.gaa" +#line 99 "certtool.gaa" char *hash; -#line 103 "certtool.gaa" +#line 96 "certtool.gaa" int dsa; -#line 100 "certtool.gaa" +#line 93 "certtool.gaa" int pkcs8; -#line 95 "certtool.gaa" - char* pkcs11_url; -#line 92 "certtool.gaa" - char* pkcs11_provider; #line 85 "certtool.gaa" int v1_cert; #line 82 "certtool.gaa" @@ -301,59 +305,61 @@ static int gaa_error = 0; #define GAA_MULTIPLE_OPTION 3 #define GAA_REST 0 -#define GAA_NB_OPTION 52 +#define GAA_NB_OPTION 54 #define GAAOPTID_version 1 #define GAAOPTID_help 2 #define GAAOPTID_debug 3 -#define GAAOPTID_pkcs_cipher 4 -#define GAAOPTID_template 5 -#define GAAOPTID_infile 6 -#define GAAOPTID_outfile 7 -#define GAAOPTID_disable_quick_random 8 -#define GAAOPTID_bits 9 -#define GAAOPTID_outraw 10 -#define GAAOPTID_outder 11 -#define GAAOPTID_inraw 12 -#define GAAOPTID_inder 13 -#define GAAOPTID_export_ciphers 14 -#define GAAOPTID_hash 15 -#define GAAOPTID_dsa 16 -#define GAAOPTID_pkcs8 17 -#define GAAOPTID_pkcs11_list 18 -#define GAAOPTID_pkcs11_url 19 -#define GAAOPTID_pkcs11_provider 20 -#define GAAOPTID_to_p8 21 -#define GAAOPTID_to_p12 22 -#define GAAOPTID_v1 23 -#define GAAOPTID_fix_key 24 -#define GAAOPTID_pgp_key_info 25 -#define GAAOPTID_key_info 26 -#define GAAOPTID_smime_to_p7 27 -#define GAAOPTID_p7_info 28 -#define GAAOPTID_p12_info 29 -#define GAAOPTID_no_crq_extensions 30 -#define GAAOPTID_crq_info 31 -#define GAAOPTID_crl_info 32 -#define GAAOPTID_pgp_ring_info 33 -#define GAAOPTID_pgp_certificate_info 34 -#define GAAOPTID_certificate_info 35 -#define GAAOPTID_password 36 -#define GAAOPTID_load_ca_certificate 37 -#define GAAOPTID_load_ca_privkey 38 -#define GAAOPTID_load_certificate 39 -#define GAAOPTID_load_request 40 -#define GAAOPTID_load_privkey 41 -#define GAAOPTID_get_dh_params 42 -#define GAAOPTID_generate_dh_params 43 -#define GAAOPTID_verify_crl 44 -#define GAAOPTID_verify_chain 45 -#define GAAOPTID_generate_request 46 -#define GAAOPTID_generate_privkey 47 -#define GAAOPTID_update_certificate 48 -#define GAAOPTID_generate_crl 49 -#define GAAOPTID_generate_proxy 50 -#define GAAOPTID_generate_certificate 51 -#define GAAOPTID_generate_self_signed 52 +#define GAAOPTID_pkcs11_list_all 4 +#define GAAOPTID_pkcs11_list_trusted 5 +#define GAAOPTID_pkcs11_list 6 +#define GAAOPTID_pkcs11_export_url 7 +#define GAAOPTID_pkcs11_provider 8 +#define GAAOPTID_pkcs_cipher 9 +#define GAAOPTID_template 10 +#define GAAOPTID_infile 11 +#define GAAOPTID_outfile 12 +#define GAAOPTID_disable_quick_random 13 +#define GAAOPTID_bits 14 +#define GAAOPTID_outraw 15 +#define GAAOPTID_outder 16 +#define GAAOPTID_inraw 17 +#define GAAOPTID_inder 18 +#define GAAOPTID_export_ciphers 19 +#define GAAOPTID_hash 20 +#define GAAOPTID_dsa 21 +#define GAAOPTID_pkcs8 22 +#define GAAOPTID_to_p8 23 +#define GAAOPTID_to_p12 24 +#define GAAOPTID_v1 25 +#define GAAOPTID_fix_key 26 +#define GAAOPTID_pgp_key_info 27 +#define GAAOPTID_key_info 28 +#define GAAOPTID_smime_to_p7 29 +#define GAAOPTID_p7_info 30 +#define GAAOPTID_p12_info 31 +#define GAAOPTID_no_crq_extensions 32 +#define GAAOPTID_crq_info 33 +#define GAAOPTID_crl_info 34 +#define GAAOPTID_pgp_ring_info 35 +#define GAAOPTID_pgp_certificate_info 36 +#define GAAOPTID_certificate_info 37 +#define GAAOPTID_password 38 +#define GAAOPTID_load_ca_certificate 39 +#define GAAOPTID_load_ca_privkey 40 +#define GAAOPTID_load_certificate 41 +#define GAAOPTID_load_request 42 +#define GAAOPTID_load_privkey 43 +#define GAAOPTID_get_dh_params 44 +#define GAAOPTID_generate_dh_params 45 +#define GAAOPTID_verify_crl 46 +#define GAAOPTID_verify_chain 47 +#define GAAOPTID_generate_request 48 +#define GAAOPTID_generate_privkey 49 +#define GAAOPTID_update_certificate 50 +#define GAAOPTID_generate_crl 51 +#define GAAOPTID_generate_proxy 52 +#define GAAOPTID_generate_certificate 53 +#define GAAOPTID_generate_self_signed 54 #line 168 "gaa.skel" @@ -546,49 +552,49 @@ struct GAAOPTION_debug int size1; }; -struct GAAOPTION_pkcs_cipher +struct GAAOPTION_pkcs11_export_url { char* arg1; int size1; }; -struct GAAOPTION_template +struct GAAOPTION_pkcs11_provider { char* arg1; int size1; }; -struct GAAOPTION_infile +struct GAAOPTION_pkcs_cipher { char* arg1; int size1; }; -struct GAAOPTION_outfile +struct GAAOPTION_template { char* arg1; int size1; }; -struct GAAOPTION_bits +struct GAAOPTION_infile { - int arg1; + char* arg1; int size1; }; -struct GAAOPTION_hash +struct GAAOPTION_outfile { char* arg1; int size1; }; -struct GAAOPTION_pkcs11_url +struct GAAOPTION_bits { - char* arg1; + int arg1; int size1; }; -struct GAAOPTION_pkcs11_provider +struct GAAOPTION_hash { char* arg1; int size1; @@ -660,14 +666,14 @@ static int gaa_get_option_num(char *str, int status) { case GAA_LETTER_OPTION: GAA_CHECK1STR("d", GAAOPTID_debug); + GAA_CHECK1STR("", GAAOPTID_pkcs11_export_url); + GAA_CHECK1STR("", GAAOPTID_pkcs11_provider); GAA_CHECK1STR("", GAAOPTID_pkcs_cipher); GAA_CHECK1STR("", GAAOPTID_template); GAA_CHECK1STR("", GAAOPTID_infile); GAA_CHECK1STR("", GAAOPTID_outfile); GAA_CHECK1STR("", GAAOPTID_bits); GAA_CHECK1STR("", GAAOPTID_hash); - GAA_CHECK1STR("", GAAOPTID_pkcs11_url); - GAA_CHECK1STR("", GAAOPTID_pkcs11_provider); GAA_CHECK1STR("", GAAOPTID_password); GAA_CHECK1STR("", GAAOPTID_load_ca_certificate); GAA_CHECK1STR("", GAAOPTID_load_ca_privkey); @@ -678,6 +684,9 @@ 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_list_all); + GAA_CHECK1STR("", GAAOPTID_pkcs11_list_trusted); + GAA_CHECK1STR("", GAAOPTID_pkcs11_list); GAA_CHECK1STR("", GAAOPTID_disable_quick_random); GAA_CHECK1STR("", GAAOPTID_outraw); GAA_CHECK1STR("", GAAOPTID_outder); @@ -686,7 +695,6 @@ static int gaa_get_option_num(char *str, int status) GAA_CHECK1STR("", GAAOPTID_export_ciphers); GAA_CHECK1STR("", GAAOPTID_dsa); GAA_CHECK1STR("8", GAAOPTID_pkcs8); - GAA_CHECK1STR("", GAAOPTID_pkcs11_list); GAA_CHECK1STR("", GAAOPTID_to_p8); GAA_CHECK1STR("", GAAOPTID_to_p12); GAA_CHECK1STR("", GAAOPTID_v1); @@ -720,6 +728,11 @@ 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-list-all", GAAOPTID_pkcs11_list_all); + GAA_CHECKSTR("pkcs11-list-trusted", GAAOPTID_pkcs11_list_trusted); + GAA_CHECKSTR("pkcs11-list", GAAOPTID_pkcs11_list); + GAA_CHECKSTR("pkcs11-export-url", GAAOPTID_pkcs11_export_url); + GAA_CHECKSTR("pkcs11-provider", GAAOPTID_pkcs11_provider); GAA_CHECKSTR("pkcs-cipher", GAAOPTID_pkcs_cipher); GAA_CHECKSTR("template", GAAOPTID_template); GAA_CHECKSTR("infile", GAAOPTID_infile); @@ -734,9 +747,6 @@ static int gaa_get_option_num(char *str, int status) GAA_CHECKSTR("hash", GAAOPTID_hash); GAA_CHECKSTR("dsa", GAAOPTID_dsa); GAA_CHECKSTR("pkcs8", GAAOPTID_pkcs8); - GAA_CHECKSTR("pkcs11-list", GAAOPTID_pkcs11_list); - GAA_CHECKSTR("pkcs11-url", GAAOPTID_pkcs11_url); - GAA_CHECKSTR("pkcs11-provider", GAAOPTID_pkcs11_provider); GAA_CHECKSTR("to-p8", GAAOPTID_to_p8); GAA_CHECKSTR("to-p12", GAAOPTID_to_p12); GAA_CHECKSTR("v1", GAAOPTID_v1); @@ -782,14 +792,14 @@ 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_export_url GAATMP_pkcs11_export_url; + struct GAAOPTION_pkcs11_provider GAATMP_pkcs11_provider; struct GAAOPTION_pkcs_cipher GAATMP_pkcs_cipher; struct GAAOPTION_template GAATMP_template; struct GAAOPTION_infile GAATMP_infile; struct GAAOPTION_outfile GAATMP_outfile; struct GAAOPTION_bits GAATMP_bits; struct GAAOPTION_hash GAATMP_hash; - struct GAAOPTION_pkcs11_url GAATMP_pkcs11_url; - struct GAAOPTION_pkcs11_provider GAATMP_pkcs11_provider; struct GAAOPTION_password GAATMP_password; struct GAAOPTION_load_ca_certificate GAATMP_load_ca_certificate; struct GAAOPTION_load_ca_privkey GAATMP_load_ca_privkey; @@ -818,14 +828,14 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) { case GAAOPTID_version: OK = 0; -#line 144 "certtool.gaa" +#line 147 "certtool.gaa" { certtool_version(); exit(0); ;}; return GAA_OK; break; case GAAOPTID_help: OK = 0; -#line 142 "certtool.gaa" +#line 145 "certtool.gaa" { gaa_help(); exit(0); ;}; return GAA_OK; @@ -835,9 +845,50 @@ 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 140 "certtool.gaa" +#line 143 "certtool.gaa" { gaaval->debug = GAATMP_debug.arg1 ;}; + return GAA_OK; + break; + case GAAOPTID_pkcs11_list_all: + OK = 0; +#line 140 "certtool.gaa" +{ gaaval->action = ACTION_PKCS11_LIST; gaaval->pkcs11_type=PKCS11_TYPE_ALL; ;}; + + return GAA_OK; + break; + case GAAOPTID_pkcs11_list_trusted: + OK = 0; +#line 139 "certtool.gaa" +{ gaaval->action = ACTION_PKCS11_LIST; gaaval->pkcs11_type=PKCS11_TYPE_TRUSTED; ;}; + + return GAA_OK; + break; + case GAAOPTID_pkcs11_list: + OK = 0; +#line 138 "certtool.gaa" +{ gaaval->action = ACTION_PKCS11_LIST; gaaval->pkcs11_type=PKCS11_TYPE_PK; ;}; + + return GAA_OK; + break; + case GAAOPTID_pkcs11_export_url: + OK = 0; + GAA_TESTMOREARGS; + GAA_FILL(GAATMP_pkcs11_export_url.arg1, gaa_getstr, GAATMP_pkcs11_export_url.size1); + gaa_index++; +#line 135 "certtool.gaa" +{ gaaval->action = ACTION_PKCS11_EXPORT_URL; gaaval->pkcs11_url = GAATMP_pkcs11_export_url.arg1; ;}; + + return GAA_OK; + break; + case GAAOPTID_pkcs11_provider: + OK = 0; + GAA_TESTMOREARGS; + GAA_FILL(GAATMP_pkcs11_provider.arg1, gaa_getstr, GAATMP_pkcs11_provider.size1); + gaa_index++; +#line 132 "certtool.gaa" +{ gaaval->pkcs11_provider = GAATMP_pkcs11_provider.arg1 ;}; + return GAA_OK; break; case GAAOPTID_pkcs_cipher: @@ -845,7 +896,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_pkcs_cipher.arg1, gaa_getstr, GAATMP_pkcs_cipher.size1); gaa_index++; -#line 136 "certtool.gaa" +#line 129 "certtool.gaa" { gaaval->pkcs_cipher = GAATMP_pkcs_cipher.arg1 ;}; return GAA_OK; @@ -855,7 +906,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_template.arg1, gaa_getstr, GAATMP_template.size1); gaa_index++; -#line 133 "certtool.gaa" +#line 126 "certtool.gaa" { gaaval->template = GAATMP_template.arg1 ;}; return GAA_OK; @@ -865,7 +916,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_infile.arg1, gaa_getstr, GAATMP_infile.size1); gaa_index++; -#line 130 "certtool.gaa" +#line 123 "certtool.gaa" { gaaval->infile = GAATMP_infile.arg1 ;}; return GAA_OK; @@ -875,14 +926,14 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_outfile.arg1, gaa_getstr, GAATMP_outfile.size1); gaa_index++; -#line 127 "certtool.gaa" +#line 120 "certtool.gaa" { gaaval->outfile = GAATMP_outfile.arg1 ;}; return GAA_OK; break; case GAAOPTID_disable_quick_random: OK = 0; -#line 124 "certtool.gaa" +#line 117 "certtool.gaa" { gaaval->quick_random = 0; ;}; return GAA_OK; @@ -892,42 +943,42 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_bits.arg1, gaa_getint, GAATMP_bits.size1); gaa_index++; -#line 121 "certtool.gaa" +#line 114 "certtool.gaa" { gaaval->bits = GAATMP_bits.arg1 ;}; return GAA_OK; break; case GAAOPTID_outraw: OK = 0; -#line 118 "certtool.gaa" +#line 111 "certtool.gaa" { gaaval->outcert_format=1 ;}; return GAA_OK; break; case GAAOPTID_outder: OK = 0; -#line 117 "certtool.gaa" +#line 110 "certtool.gaa" { gaaval->outcert_format=1 ;}; return GAA_OK; break; case GAAOPTID_inraw: OK = 0; -#line 114 "certtool.gaa" +#line 107 "certtool.gaa" { gaaval->incert_format=1 ;}; return GAA_OK; break; case GAAOPTID_inder: OK = 0; -#line 113 "certtool.gaa" +#line 106 "certtool.gaa" { gaaval->incert_format=1 ;}; return GAA_OK; break; case GAAOPTID_export_ciphers: OK = 0; -#line 110 "certtool.gaa" +#line 103 "certtool.gaa" { gaaval->export=1 ;}; return GAA_OK; @@ -937,50 +988,23 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_hash.arg1, gaa_getstr, GAATMP_hash.size1); gaa_index++; -#line 107 "certtool.gaa" +#line 100 "certtool.gaa" { gaaval->hash = GAATMP_hash.arg1 ;}; return GAA_OK; break; case GAAOPTID_dsa: OK = 0; -#line 104 "certtool.gaa" +#line 97 "certtool.gaa" { gaaval->dsa=1 ;}; return GAA_OK; break; case GAAOPTID_pkcs8: OK = 0; -#line 101 "certtool.gaa" +#line 94 "certtool.gaa" { gaaval->pkcs8=1 ;}; - return GAA_OK; - break; - case GAAOPTID_pkcs11_list: - OK = 0; -#line 98 "certtool.gaa" -{ gaaval->action = ACTION_PKCS11_LIST ;}; - - return GAA_OK; - break; - case GAAOPTID_pkcs11_url: - OK = 0; - GAA_TESTMOREARGS; - GAA_FILL(GAATMP_pkcs11_url.arg1, gaa_getstr, GAATMP_pkcs11_url.size1); - gaa_index++; -#line 96 "certtool.gaa" -{ gaaval->pkcs11_url = GAATMP_pkcs11_url.arg1 ;}; - - return GAA_OK; - break; - case GAAOPTID_pkcs11_provider: - OK = 0; - GAA_TESTMOREARGS; - GAA_FILL(GAATMP_pkcs11_provider.arg1, gaa_getstr, GAATMP_pkcs11_provider.size1); - gaa_index++; -#line 93 "certtool.gaa" -{ gaaval->pkcs11_provider = GAATMP_pkcs11_provider.arg1 ;}; - return GAA_OK; break; case GAAOPTID_to_p8: @@ -1249,13 +1273,13 @@ int gaa(int argc, char **argv, gaainfo *gaaval) if(inited == 0) { -#line 146 "certtool.gaa" +#line 149 "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_url = NULL; gaaval->pkcs11_type = PKCS11_TYPE_PK; ;}; } inited = 1; diff --git a/src/certtool-gaa.h b/src/certtool-gaa.h index 28e3cce57c..8e00cb9a7d 100644 --- a/src/certtool-gaa.h +++ b/src/certtool-gaa.h @@ -8,36 +8,38 @@ typedef struct _gaainfo gaainfo; struct _gaainfo { -#line 139 "certtool.gaa" +#line 142 "certtool.gaa" int debug; -#line 135 "certtool.gaa" +#line 137 "certtool.gaa" + int pkcs11_type; +#line 134 "certtool.gaa" + char* pkcs11_url; +#line 131 "certtool.gaa" + char* pkcs11_provider; +#line 128 "certtool.gaa" char *pkcs_cipher; -#line 132 "certtool.gaa" +#line 125 "certtool.gaa" char *template; -#line 129 "certtool.gaa" +#line 122 "certtool.gaa" char *infile; -#line 126 "certtool.gaa" +#line 119 "certtool.gaa" char *outfile; -#line 123 "certtool.gaa" +#line 116 "certtool.gaa" int quick_random; -#line 120 "certtool.gaa" +#line 113 "certtool.gaa" int bits; -#line 116 "certtool.gaa" +#line 109 "certtool.gaa" int outcert_format; -#line 112 "certtool.gaa" +#line 105 "certtool.gaa" int incert_format; -#line 109 "certtool.gaa" +#line 102 "certtool.gaa" int export; -#line 106 "certtool.gaa" +#line 99 "certtool.gaa" char *hash; -#line 103 "certtool.gaa" +#line 96 "certtool.gaa" int dsa; -#line 100 "certtool.gaa" +#line 93 "certtool.gaa" int pkcs8; -#line 95 "certtool.gaa" - char* pkcs11_url; -#line 92 "certtool.gaa" - char* pkcs11_provider; #line 85 "certtool.gaa" int v1_cert; #line 82 "certtool.gaa" diff --git a/src/certtool.c b/src/certtool.c index b65386e027..bf12195aca 100644 --- a/src/certtool.c +++ b/src/certtool.c @@ -71,8 +71,6 @@ void certificate_info (void); void pgp_certificate_info (void); void crl_info (void); void privkey_info (void); -static void print_certificate_info (gnutls_x509_crt_t crt, FILE * out, - unsigned int); static void gaa_parser (int argc, char **argv); void generate_self_signed (void); void generate_request (void); @@ -1028,7 +1026,10 @@ gaa_parser (int argc, char **argv) generate_pkcs8 (); break; case ACTION_PKCS11_LIST: - pkcs11_list(info.pkcs11_url); + pkcs11_list(info.pkcs11_url, info.pkcs11_type); + break; + case ACTION_PKCS11_EXPORT_URL: + pkcs11_export(outfile, info.pkcs11_url); break; #ifdef ENABLE_OPENPGP case ACTION_PGP_INFO: @@ -1370,7 +1371,7 @@ print_hex_datum (gnutls_datum_t * dat) } -static void +void print_certificate_info (gnutls_x509_crt_t crt, FILE * out, unsigned int all) { gnutls_datum_t cinfo; diff --git a/src/certtool.gaa b/src/certtool.gaa index 53d3ac169a..fec590e7f1 100644 --- a/src/certtool.gaa +++ b/src/certtool.gaa @@ -89,13 +89,6 @@ option (to-p12) { $action = ACTION_TO_PKCS12; } "Generate a PKCS #12 structure." option (to-p8) { $action = ACTION_GENERATE_PKCS8; } "Generate a PKCS #8 key structure." -#char* pkcs11_provider; -option (pkcs11-provider) STR "Library" { $pkcs11_provider = $1 } "Specify the pkcs11 provider library" - -#char* pkcs11_url; -option (pkcs11-url) STR "URL" { $pkcs11_url = $1 } "Specify a pkcs11 URL" - -option (pkcs11-list) { $action = ACTION_PKCS11_LIST } "List objects specified by a PKCS#11 URL" #int pkcs8; option (8, pkcs8) { $pkcs8=1 } "Use PKCS #8 format for private keys." @@ -135,6 +128,16 @@ option (template) STR "FILE" { $template = $1 } "Template file to use for non in #char *pkcs_cipher; option (pkcs-cipher) STR "CIPHER" { $pkcs_cipher = $1 } "Cipher to use for pkcs operations (3des,aes-128,aes-192,aes-256,rc2-40)." +#char* pkcs11_provider; +option (pkcs11-provider) STR "Library" { $pkcs11_provider = $1 } "Specify the pkcs11 provider library" + +#char* pkcs11_url; +option (pkcs11-export-url) STR "URL" { $action = ACTION_PKCS11_EXPORT_URL; $pkcs11_url = $1; } "Export data specified a pkcs11 URL" + +#int pkcs11_type; +option (pkcs11-list) { $action = ACTION_PKCS11_LIST; $pkcs11_type=PKCS11_TYPE_PK; } "List objects specified by a PKCS#11 URL" +option (pkcs11-list-trusted) { $action = ACTION_PKCS11_LIST; $pkcs11_type=PKCS11_TYPE_TRUSTED; } "List objects marked as trusted, specified by a PKCS#11 URL" +option (pkcs11-list-all) { $action = ACTION_PKCS11_LIST; $pkcs11_type=PKCS11_TYPE_ALL; } "List all objects specified by a PKCS#11 URL" #int debug; option (d, debug) INT "LEVEL" { $debug = $1 } "specify the debug level. Default is 1." @@ -148,4 +151,4 @@ 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_url = NULL; $pkcs11_type = PKCS11_TYPE_PK; } diff --git a/src/pkcs11.c b/src/pkcs11.c index fc3953d5dc..b27cf0e01d 100644 --- a/src/pkcs11.c +++ b/src/pkcs11.c @@ -6,20 +6,56 @@ #include #include #include "certtool-common.h" +#include "certtool-cfg.h" +#include -void pkcs11_list( const char* url) +#define MIN(x,y) ((x)<(y))?(x):(y) + +static int pin_callback(void* user, int attempt, const char *slot_descr, + const char *token_label, unsigned int flags, char* pin, size_t pin_max) +{ +const char* password; + + printf("PIN required for token '%s' in slot '%s'\n", token_label, slot_descr); + if (flags & GNUTLS_PKCS11_PIN_FINAL_TRY) + printf("*** This is the final try before locking!\n"); + if (flags & GNUTLS_PKCS11_PIN_COUNT_LOW) + printf("*** Only few tries left before locking!\n"); + + password = get_pass(); + if (password==NULL) { + fprintf(stderr, "No password given\n"); + exit(1); + } + memcpy(pin, password, MIN(pin_max,strlen(password))); + + return 0; +} + +static void pkcs11_common(void) +{ + + gnutls_pkcs11_set_pin_function (pin_callback, NULL); + +} + +/* lists certificates from a token + */ +void pkcs11_list( const char* url, int type) { gnutls_pkcs11_crt_t *crt_list; unsigned int crt_list_size = 0; int ret; char* output; -int i; +int i, flags; + + pkcs11_common(); if (url == NULL) url = "pkcs11:"; ret = gnutls_pkcs11_crt_list_import( NULL, &crt_list_size, url, GNUTLS_PKCS11_CRT_ATTR_ALL); - if (ret != 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { + if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) { fprintf(stderr, "Error in crt_list_import (1): %s\n", gnutls_strerror(ret)); exit(1); } @@ -35,7 +71,15 @@ int i; exit(1); } - ret = gnutls_pkcs11_crt_list_import( crt_list, &crt_list_size, url, GNUTLS_PKCS11_CRT_ATTR_ALL); + if (type == PKCS11_TYPE_TRUSTED) { + flags = GNUTLS_PKCS11_CRT_ATTR_TRUSTED; + } else if (type == PKCS11_TYPE_PK) { + flags = GNUTLS_PKCS11_CRT_ATTR_WITH_PK; + } else { + flags = GNUTLS_PKCS11_CRT_ATTR_ALL; + } + + ret = gnutls_pkcs11_crt_list_import( crt_list, &crt_list_size, url, flags); if (ret < 0) { fprintf(stderr, "Error in crt_list_import: %s\n", gnutls_strerror(ret)); exit(1); @@ -48,3 +92,49 @@ int i; return; } + +void pkcs11_export(FILE* outfile, const char* url) +{ +gnutls_pkcs11_crt_t crt; +gnutls_x509_crt_t xcrt; +int ret; + + pkcs11_common(); + + if (url == NULL) + url = "pkcs11:"; + + ret = gnutls_pkcs11_crt_init(&crt); + if (ret < 0) { + fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_crt_import_url( crt, url); + if (ret < 0) { + fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_crt_init(&xcrt); + if (ret < 0) { + fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_crt_import_pkcs11(xcrt, crt); + if (ret < 0) { + fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, gnutls_strerror(ret)); + exit(1); + } + + print_certificate_info(xcrt, outfile, 1); + + gnutls_x509_crt_deinit(xcrt); + gnutls_pkcs11_crt_deinit(crt); + + return; + + + +}