manipulating tokens purely from PKCS #11.
* Version 2.11.5 (unreleased)
+** p11tool: Introduced. It allows manipulating pkcs 11 tokens.
+
** gnutls-cli: Print channel binding only in verbose mode.
Before it printed it after the 'Compression:' output, thus breaking
Emacs starttls.el string searches.
** API and ABI modifications:
-No changes since last version.
+gnutls_pkcs11_token_init: New function
+gnutls_pkcs11_token_set_pin: New function
* Version 2.11.4 (released 2010-10-15)
auth_dh_common.c gnutls_helper.c gnutls_supplemental.c \
crypto.c random.c ext_signature.c cryptodev.c system.c \
crypto-api.c ext_safe_renegotiation.c gnutls_privkey.c \
- pkcs11.c pkcs11_privkey.c gnutls_pubkey.c pkcs11_write.c locks.c
+ pkcs11.c pkcs11_privkey.c gnutls_pubkey.c pkcs11_write.c locks.c \
+ pkcs11_secret.c
if ENABLE_NETTLE
const unsigned retry);
/* flags */
-#define GNUTLS_PKCS11_PIN_FINAL_TRY (1<<0)
-#define GNUTLS_PKCS11_PIN_COUNT_LOW (1<<1)
+typedef enum
+{
+ GNUTLS_PKCS11_PIN_USER = (1<<0),
+ GNUTLS_PKCS11_PIN_SO = (1<<1),
+ GNUTLS_PKCS11_PIN_FINAL_TRY = (1<<2),
+ GNUTLS_PKCS11_PIN_COUNT_LOW = (1<<3)
+} gnutls_pkcs11_pin_flag_t;
typedef int (*gnutls_pkcs11_pin_callback_t) (void *userdata, int attempt,
const char *token_url,
const char *token_label,
- unsigned int flags, char *pin,
+ unsigned int flags /*gnutls_pkcs11_pin_flag_t*/,
+ char *pin,
size_t pin_max);
struct gnutls_pkcs11_obj_st;
int gnutls_pkcs11_delete_url (const char *object_url, unsigned int flags
/* GNUTLS_PKCS11_OBJ_FLAG_* */ );
+int gnutls_pkcs11_copy_secret_key (const char *token_url, gnutls_datum_t* key,
+ const char *label,
+ unsigned int key_usage /* GNUTLS_KEY_* */,
+ unsigned int flags
+ /* GNUTLS_PKCS11_OBJ_FLAG_* */ );
+
typedef enum
{
GNUTLS_PKCS11_OBJ_ID_HEX = 1,
GNUTLS_PKCS11_OBJ_DATA
} gnutls_pkcs11_obj_type_t;
+int
+gnutls_pkcs11_token_init (const char *token_url,
+ const char* so_pin,
+ const char *label);
+
+int
+gnutls_pkcs11_token_set_pin (const char *token_url,
+ const char* oldpin, const char* newpin, unsigned int flags/*gnutls_pkcs11_pin_flag_t*/);
+
int gnutls_pkcs11_token_get_url (unsigned int seq,
gnutls_pkcs11_url_type_t detailed,
char **url);
gnutls_cipher_decrypt2;
gnutls_openpgp_privkey_sec_param;
gnutls_x509_privkey_sec_param;
-
gnutls_session_channel_binding;
+ gnutls_pkcs11_copy_secret_key;
+ gnutls_pkcs11_token_init;
+ gnutls_pkcs11_token_set_pin;
} GNUTLS_2_10;
GNUTLS_PRIVATE {
}
int
-pkcs11_open_session (pakchois_session_t ** _pks,
- struct pkcs11_url_info *info, unsigned int flags)
+pkcs11_find_slot (pakchois_module_t** module, ck_slot_id_t *slot,
+ struct pkcs11_url_info *info, struct token_info* _tinfo)
{
- ck_rv_t rv;
- int x, z, ret;
- pakchois_session_t *pks = NULL;
+ int x, z;
for (x = 0; x < active_providers; x++)
{
{
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;
+ continue;
}
tinfo.sid = providers[x].slots[z];
tinfo.prov = &providers[x];
(providers[x].module, providers[x].slots[z],
&tinfo.sinfo) != CKR_OK)
{
- goto next;
+ continue;
}
/* XXX make wrapper for token_info? */
if (pkcs11_token_matches_info (info, &tinfo.tinfo,
&providers[x].info) < 0)
{
- goto next;
- }
-
- if (flags & SESSION_LOGIN)
- {
- ret = pkcs11_login (pks, &tinfo);
- if (ret < 0)
- {
- gnutls_assert ();
- pakchois_close_session (pks);
- return ret;
- }
+ continue;
}
/* ok found */
- *_pks = pks;
+ *module = providers[x].module;
+ *slot = providers[x].slots[z];
+
+ if (_tinfo != NULL)
+ memcpy(_tinfo, &tinfo, sizeof(tinfo));
+
return 0;
+ }
+ }
- next:
+ gnutls_assert();
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+}
+
+int
+pkcs11_open_session (pakchois_session_t ** _pks,
+ struct pkcs11_url_info *info, unsigned int flags)
+{
+ ck_rv_t rv;
+ int ret;
+ pakchois_session_t *pks = NULL;
+ pakchois_module_t *module;
+ ck_slot_id_t slot;
+ struct token_info tinfo;
+
+ ret = pkcs11_find_slot(&module, &slot, info, &tinfo);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ return ret;
+ }
+
+ rv = pakchois_open_session (module,
+ slot,
+ ((flags & SESSION_WRITE)
+ ? CKF_RW_SESSION : 0) |
+ CKF_SERIAL_SESSION, NULL, NULL, &pks);
+ if (rv != CKR_OK)
+ {
+ gnutls_assert();
+ return pkcs11_rv_to_err (rv);
+ }
+
+ if (flags & SESSION_LOGIN)
+ {
+ ret = pkcs11_login (pks, &tinfo, (flags & SESSION_SO)?1:0);
+ if (ret < 0)
+ {
+ gnutls_assert ();
pakchois_close_session (pks);
+ return ret;
}
}
- return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ /* ok found */
+ *_pks = pks;
+ return 0;
}
ret = GNUTLS_E_PKCS11_ERROR;
- 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],
&info.tinfo) != CKR_OK)
{
- goto next;
+ continue;
}
info.sid = providers[x].slots[z];
info.prov = &providers[x];
(providers[x].module, providers[x].slots[z],
&info.sinfo) != CKR_OK)
{
- goto next;
+ continue;
}
/* XXX make wrapper for token_info? */
fix_strings (&info);
+ 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 (flags & SESSION_LOGIN)
{
- ret = pkcs11_login (pks, &info);
+ ret = pkcs11_login (pks, &info, (flags & SESSION_SO)?1:0);
if (ret < 0)
{
gnutls_assert ();
ret = find_func (pks, &info, &providers[x].info, input);
- next:
-
if (ret == 0)
{
found = 1;
size_t key_ids_size;
};
-int
-pkcs11_login (pakchois_session_t * pks, const struct token_info *info)
+int pkcs11_login (pakchois_session_t * pks,
+ const struct token_info *info, int so)
{
int attempt = 0, ret;
ck_rv_t rv;
struct pkcs11_url_info uinfo;
- if ((info->tinfo.flags & CKF_LOGIN_REQUIRED) == 0)
+ if (so == 0 && (info->tinfo.flags & CKF_LOGIN_REQUIRED) == 0)
{
gnutls_assert ();
_gnutls_debug_log ("pk11: No login required.\n");
* required. */
if (info->tinfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
{
- if (pakchois_login (pks, CKU_USER, NULL, 0) == CKR_OK)
+ if (pakchois_login (pks, (so==0)?CKU_USER:CKU_SO, NULL, 0) == CKR_OK)
{
return 0;
}
}
flags = 0;
- 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;
+ if (so == 0)
+ {
+ flags |= GNUTLS_PKCS11_PIN_USER;
+ 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;
+ }
+ else
+ {
+ flags |= GNUTLS_PKCS11_PIN_SO;
+ if (tinfo.flags & CKF_SO_PIN_COUNT_LOW)
+ flags |= GNUTLS_PKCS11_PIN_COUNT_LOW;
+ if (tinfo.flags & CKF_SO_PIN_FINAL_TRY)
+ flags |= GNUTLS_PKCS11_PIN_FINAL_TRY;
+ }
ret = pin_func (pin_data, attempt++,
(char *) token_url,
}
pin_len = strlen (pin);
- rv = pakchois_login (pks, CKU_USER, (unsigned char *) pin, pin_len);
+ rv = pakchois_login (pks, (so==0)?CKU_USER:CKU_SO,
+ (unsigned char *) pin, pin_len);
/* Try to scrub the pin off the stack. Clever compilers will
* probably optimize this away, oh well. */
int pkcs11_rv_to_err (ck_rv_t rv);
int pkcs11_url_to_info (const char *url, struct pkcs11_url_info *info);
+int
+pkcs11_find_slot (pakchois_module_t** module, ck_slot_id_t *slot,
+ struct pkcs11_url_info *info, struct token_info* _tinfo);
int pkcs11_get_info (struct pkcs11_url_info *info,
gnutls_pkcs11_obj_info_t itype, void *output,
size_t * output_size);
-int pkcs11_login (pakchois_session_t * pks, const struct token_info *info);
+int pkcs11_login (pakchois_session_t * pks,
+ const struct token_info *info, int admin);
extern gnutls_pkcs11_token_callback_t token_func;
extern void *token_data;
int pkcs11_info_to_url (const struct pkcs11_url_info *info,
gnutls_pkcs11_url_type_t detailed, char **url);
-#define SESSION_WRITE 1
-#define SESSION_LOGIN 2
+#define SESSION_WRITE (1<<0)
+#define SESSION_LOGIN (1<<1)
+#define SESSION_SO (1<<2) /* security officer session */
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,
--- /dev/null
+/*
+ * 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
+ * @key: The raw key
+ * @key_size: the size of the key
+ * @label: A name to be used for the stored data
+ * @key_usage: One of GNUTLS_KEY_*
+ * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_*
+ *
+ * This function will copy a raw secret (symmetric) key into a PKCS #11
+ * token specified by a URL. The key can be marked as sensitive or not.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ * negative error value.
+ **/
+int gnutls_pkcs11_copy_secret_key (const char *token_url, gnutls_datum_t* key,
+ const char *label,
+ unsigned int key_usage,
+ unsigned int flags
+ /* GNUTLS_PKCS11_OBJ_FLAG_* */ )
+{
+ int ret;
+ pakchois_session_t *pks;
+ struct pkcs11_url_info info;
+ ck_rv_t rv;
+ struct ck_attribute a[8];
+ ck_object_class_t class = CKO_SECRET_KEY;
+ 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 | pkcs11_obj_flags_to_int (flags));
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ /* FIXME: copy key usage flags */
+
+ a[0].type = CKA_CLASS;
+ a[0].value = &class;
+ a[0].value_len = sizeof (class);
+ a[1].type = CKA_VALUE;
+ a[1].value = key->data;
+ a[1].value_len = key->size;
+ a[2].type = CKA_TOKEN;
+ a[2].value = &tval;
+ a[2].value_len = sizeof (tval);
+ a[3].type = CKA_PRIVATE;
+ a[3].value = &tval;
+ a[3].value_len = sizeof (tval);
+
+ a_val = 4;
+
+ if (label)
+ {
+ a[a_val].type = CKA_LABEL;
+ a[a_val].value = (void *) label;
+ a[a_val].value_len = strlen (label);
+ a_val++;
+ }
+
+ if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE)
+ tval = 1;
+ else
+ tval = 0;
+
+ a[a_val].type = CKA_SENSITIVE;
+ a[a_val].value = &tval;
+ a[a_val].value_len = sizeof (tval);
+ a_val++;
+
+ rv = pakchois_create_object (pks, a, a_val, &obj);
+ if (rv != CKR_OK)
+ {
+ gnutls_assert ();
+ _gnutls_debug_log ("pkcs11: %s\n", pakchois_error (rv));
+ ret = pkcs11_rv_to_err (rv);
+ goto cleanup;
+ }
+
+ /* generated!
+ */
+
+ ret = 0;
+
+cleanup:
+ pakchois_close_session (pks);
+
+ return ret;
+
+}
+
a[a_val].value_len = sizeof (type);
a_val++;
+ a[a_val].type = CKA_TOKEN;
+ a[a_val].value = &tval;
+ a[a_val].value_len = sizeof (tval);
+ a_val++;
+
+ a[a_val].type = CKA_PRIVATE;
+ a[a_val].value = &tval;
+ a[a_val].value_len = sizeof (tval);
+ a_val++;
+
if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE)
tval = 1;
else
return find_data.deleted;
}
+
+/**
+ * gnutls_pkcs11_token_init:
+ * @token_url: A PKCS #11 URL specifying a token
+ * @so_pin: Security Officer's PIN
+ * @label: A name to be used for the token
+ *
+ * This function will initialize (format) a token. If the token is
+ * at a factory defaults state the security officer's PIN given will be
+ * set to be the default. Otherwise it should match the officer's PIN.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ * negative error value.
+ **/
+int
+gnutls_pkcs11_token_init (const char *token_url,
+ const char* so_pin,
+ const char *label)
+{
+ int ret;
+ struct pkcs11_url_info info;
+ ck_rv_t rv;
+ pakchois_module_t *module;
+ ck_slot_id_t slot;
+ char flabel[32];
+
+ ret = pkcs11_url_to_info (token_url, &info);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ ret = pkcs11_find_slot(&module, &slot, &info, NULL);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ return ret;
+ }
+
+ /* so it seems memset has other uses than zeroing! */
+ memset(flabel, ' ', sizeof(flabel));
+ if (label != NULL)
+ memcpy(flabel, label, strlen(label));
+
+ rv = pakchois_init_token(module, slot, (char*)so_pin, strlen(so_pin), flabel);
+ if (rv != CKR_OK)
+ {
+ gnutls_assert ();
+ _gnutls_debug_log ("pkcs11: %s\n", pakchois_error (rv));
+ return pkcs11_rv_to_err (rv);
+ }
+
+ return 0;
+
+}
+
+/**
+ * gnutls_pkcs11_token_set_pin:
+ * @token_url: A PKCS #11 URL specifying a token
+ * @oldpin: old user's PIN
+ * @newpin: new user's PIN
+ * @flags: one of gnutls_pkcs11_pin_flag_t
+ *
+ * This function will modify or set a user's PIN for the given token.
+ * If it is called to set a user pin for first time the oldpin must
+ * be NULL.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ * negative error value.
+ **/
+int
+gnutls_pkcs11_token_set_pin (const char *token_url,
+ const char* oldpin,
+ const char* newpin,
+ unsigned int flags)
+{
+ int ret;
+ pakchois_session_t *pks;
+ struct pkcs11_url_info info;
+ ck_rv_t rv;
+ unsigned int ses_flags;
+
+ ret = pkcs11_url_to_info (token_url, &info);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ if (((flags & GNUTLS_PKCS11_PIN_USER) && oldpin == NULL) ||
+ (flags & GNUTLS_PKCS11_PIN_SO))
+ ses_flags = SESSION_WRITE|SESSION_LOGIN|SESSION_SO;
+ else
+ ses_flags = SESSION_WRITE|SESSION_LOGIN;
+
+ ret = pkcs11_open_session (&pks, &info, ses_flags);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ return ret;
+ }
+
+ if (oldpin == NULL)
+ {
+ rv = pakchois_init_pin(pks, (char*)newpin, strlen(newpin));
+ if (rv != CKR_OK)
+ {
+ gnutls_assert ();
+ _gnutls_debug_log ("pkcs11: %s\n", pakchois_error (rv));
+ ret = pkcs11_rv_to_err (rv);
+ goto finish;
+ }
+ }
+ else
+ {
+ rv = pakchois_set_pin(pks,
+ (char*)oldpin, strlen(oldpin),
+ (char*)newpin, strlen(newpin));
+ if (rv != CKR_OK)
+ {
+ gnutls_assert ();
+ _gnutls_debug_log ("pkcs11: %s\n", pakchois_error (rv));
+ ret = pkcs11_rv_to_err (rv);
+ goto finish;
+ }
+ }
+
+ ret = 0;
+
+finish:
+ pakchois_close_session (pks);
+ return ret;
+
+}
exit(0);
ret =
- gnutls_pkcs11_token_init (url, so_pin, pin, label);
+ gnutls_pkcs11_token_init (url, so_pin, label);
+ if (ret < 0)
+ {
+ fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
+ gnutls_strerror (ret));
+ exit (1);
+ }
+
+ ret =
+ gnutls_pkcs11_token_set_pin (url, NULL, pin, GNUTLS_PKCS11_PIN_USER);
if (ret < 0)
{
fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,