- do not use key enumeration as a test of login status, as this will
  not work for all PKCS#11 libraries
 
- replace magic number used for PIN length with a constant

- add documentation for set_pin, as well as testing for NULL input
  and checking for strdup failure

- made the global variable 'pin' static (TODO check if other global
  variables can be declared static)

- if a PIN is allocated, then check for NULL

- if a PIN is to be freed, then whiten the memory first

- if the token has a secure authentication path, then the PIN shoud be
  NULL (as per PKCS#11 v2, p. 126)

- replaced some fprintf statements with 'fail' (TODO all
  fprintf calls should be replaced with log functions)

Patch supplied by Geoff Elgey <Geoff.Elgey@quest.com>


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@2488 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
nils 2005-08-16 10:58:16 +00:00
parent d6e5facb0d
commit 305b68f10b
1 changed files with 87 additions and 25 deletions

View File

@ -38,8 +38,19 @@
#define fail(msg) { fprintf(stderr,msg); return NULL;}
/** The maximum length of an internally-allocated PIN */
#define MAX_PIN_LENGTH 12
PKCS11_CTX *ctx;
char *pin = NULL;
/**
* The PIN used for login. May be assigend by set_pin function, or by the
* get_pin function (using an external UI). The memory for this PIN is always
* owned internally, and may be freed as necessary. Before freeing, the PIN
* must be whitened, to prevent security holes.
*/
static char *pin = NULL;
int verbose = 0;
#if defined(_WIN32)
@ -62,10 +73,32 @@ int set_module(const char *modulename)
return 1;
}
/**
* Set the PIN used for login. A copy of the PIN shall be made.
*
* If the PIN cannot be assigned, the value 0 shall be returned
* and errno shall be set as follows:
*
* EINVAL - a NULL PIN was supplied
* ENOMEM - insufficient memory to copy the PIN
*
* @param _pin the pin to use for login. Must not be NULL.
*
* @return 1 on success, 0 on failure.
*/
int set_pin(const char *_pin)
{
/* Pre-condition check */
if (_pin == NULL) {
errno = EINVAL;
return 0;
}
/* Copy the PIN. If the string cannot be copied, NULL
shall be returned and errno shall be set. */
pin = strdup(_pin);
return 1;
return (pin != NULL);
}
int inc_verbose()
@ -104,6 +137,7 @@ int pkcs11_finish(ENGINE * engine)
PKCS11_CTX_free(ctx);
}
if (pin != NULL) {
OPENSSL_cleanse(pin, strlen(pin));
free(pin);
pin = NULL;
}
@ -377,7 +411,6 @@ EVP_PKEY *pkcs11_load_key(ENGINE * e, const char *s_slot_key_id,
size_t key_id_len = sizeof(key_id);
int slot_nr = -1;
char flags[64];
int logged_in = 0;
/* Parse s_slot_key_id: [slot_<slotNr>][-][id_<keyID>] or NULL,
with slotNr in decimal (0 = first slot, ...), and keyID in hex.
@ -521,31 +554,60 @@ EVP_PKEY *pkcs11_load_key(ENGINE * e, const char *s_slot_key_id,
}
}
while (1) {
if (PKCS11_enumerate_keys(tok, &keys, &count))
fail("unable to enumerate keys\n");
if (count)
break;
if (logged_in || !tok->loginRequired)
break;
if (pin == NULL) {
pin = (char *) calloc(12, sizeof(char));
if (!tok->secureLogin)
get_pin(ui_method, callback_data, pin, 12);
}
if (PKCS11_login(slot, 0, pin)) {
if(pin != NULL) {
free(pin);
/* Perform login to the token if required */
if (tok->loginRequired) {
/* If the token has a secure login (i.e., an external keypad),
then use a NULL pin. Otherwise, check if a PIN exists. If
not, allocate and obtain a new PIN. */
if (tok->secureLogin) {
/* Free the PIN if it has already been
assigned (i.e, via set_pin */
if (pin != NULL) {
OPENSSL_cleanse(pin, strlen(pin));
free (pin);
pin = NULL;
}
fail("Login failed\n");
}
logged_in++;
}
}
else if (pin == NULL) {
pin = (char *) calloc(MAX_PIN_LENGTH, sizeof(char));
if (pin == NULL) {
fail("Could not allocate memory for PIN");
}
get_pin(ui_method, callback_data, pin, MAX_PIN_LENGTH);
}
/* Now login in with the (possibly NULL) pin */
if (PKCS11_login(slot, 0, pin)) {
/* Login failed, so free the PIN if present */
if(pin != NULL) {
OPENSSL_cleanse(pin, strlen(pin));
free(pin);
pin = NULL;
}
fail("Login failed\n");
}
/* Login successful, PIN retained in case further logins are
required. This will occur on subsequent calls to the
pkcs11_load_key function. Subsequent login calls should be
relatively fast (the token should maintain its own login
state), although there may still be a slight performance
penalty. We could maintain state noting that successful
login has been performed, but this state may not be updated
if the token is removed and reinserted between calls. It
seems safer to retain the PIN and peform a login on each
call to pkcs11_load_key, even if this may not be strictly
necessary. */
/* TODO when does PIN get freed after successful login? */
/* TODO confirm that multiple login attempts do not introduce
significant performance penalties */
}
/* Make sure there is at least one private key on the token */
if (PKCS11_enumerate_keys(tok, &keys, &count)) {
fail("unable to enumerate keys\n");
}
if (count == 0) {
fprintf(stderr,"No keys found.\n");
return NULL;
fail("No keys found.\n");
}
if(verbose) {