Added support for selecting keys by slot and by key ID; and added newlines to some error messages

git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@1216 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
sth 2003-06-24 09:11:01 +00:00
parent 127f94ad37
commit 24b517cda5
5 changed files with 175 additions and 21 deletions

20
src/sslengines/README Normal file
View File

@ -0,0 +1,20 @@
engine-pkcs11
-------------
This is an OpenSSL engine for making certificate requests for
a key that resides on an smart card. When the certificate
request has to be signed, the smart card is contacted through
the opensc-pkcs11 lib for creating the signature.
Usage:
- start the OpenSSL tool: openssl
- at the prompt, enter: engine dynamic -pre SO_PATH:engine_pkcs11.so -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD
(for Windows, use "engine_pkcs11" instead of "engine_pkcs11.so")
- at the prompt, enter: req -engine pkcs11 -new -key <key> -keyform engine -out req.pem -text
In the last line, <key> has the format [S<slotNumber>-]keyID, in which
- the optional slotNumber indicates which pkcs11 slot to take (starting from 0, which is also the default)
- keyID is the key ID in hex notation
Examples: 45 -> private key with ID = 0x45 in the first 'suited' slot
S2-46 -> private key with ID = 0x46 in the third slot

View File

@ -55,11 +55,11 @@ char* get_pin(UI_METHOD* ui_method, char* sc_pin, int maxlen) {
UI* ui;
ui=UI_new();
UI_set_method(ui,ui_method);
if(!UI_add_input_string(ui, "SmartCard Password: ", 0, sc_pin, 1, maxlen)) {
fprintf(stderr, "UI_add_input_string failed");
if(!UI_add_input_string(ui, "SmartCard PIN: ", 0, sc_pin, 1, maxlen)) {
fprintf(stderr, "UI_add_input_string failed\n");
UI_free(ui); return NULL; }
if(!UI_process(ui)) {
fprintf(stderr, "UI_process failed"); return NULL;}
fprintf(stderr, "UI_process failed\n"); return NULL;}
UI_free(ui);
return sc_pin;
@ -78,11 +78,11 @@ int pkcs11_init(ENGINE *engine) {
int r=0;
if(!quiet)
fprintf(stderr,"initializing engine");
fprintf(stderr,"initializing engine\n");
ctx = PKCS11_CTX_new();
if (PKCS11_CTX_load(ctx, module) < 0) {
fprintf(stderr, "unable to load module");
fprintf(stderr, "unable to load module\n");
return 0;
}
@ -98,24 +98,120 @@ pkcs11_rsa_finish(RSA* rsa) {
}
static int hex2byte(const char *hex)
{
int b = 0;
if (hex[0]>='0' && hex[0]<='9')
b = hex[0] - '0';
else if (hex[0]>='a'&&hex[0]<='f')
b = hex[0] - 'a' + 10;
else if (hex[0]>='A'&&hex[0]<='F')
b = hex[0] - 'A' + 10;
else
return -1;
b *= 16;
if (hex[1]>='0' && hex[1]<='9')
return b + hex[1] - '0';
else if (hex[1]>='a'&&hex[1]<='f')
return b + hex[1] - 'a' + 10;
else if (hex[1]>='A'&&hex[1]<='F')
return b + hex[1] - 'A' + 10;
return -1;
}
EVP_PKEY *pkcs11_load_key(ENGINE *e, const char *s_key_id,
static int hex_to_bin(const char *in, unsigned char *out, size_t *outlen)
{
int err = 0;
size_t left, count = 0;
if (in == NULL || *in == '\0') {
*outlen = 0;
return 1;
}
left = *outlen;
while (*in != '\0') {
int byte = 0, nybbles = 2;
char c;
while (nybbles-- && *in && *in != ':') {
byte <<= 4;
c = *in++;
if ('0' <= c && c <= '9')
c -= '0';
else
if ('a' <= c && c <= 'f')
c = c - 'a' + 10;
else
if ('A' <= c && c <= 'F')
c = c - 'A' + 10;
else {
printf("hex_to_bin(): invalid char '%c' in hex string\n", c);
*outlen = 0;
return 0;
}
byte |= c;
}
if (*in == ':')
in++;
if (left <= 0) {
printf("hex_to_bin(): hex string too long");
*outlen = 0;
return 0;
}
out[count++] = (unsigned char) byte;
left--;
c++;
}
out:
*outlen = count;
return 1;
}
EVP_PKEY *pkcs11_load_key(ENGINE *e, const char *s_slot_key_id,
UI_METHOD *ui_method, void *callback_data, int private) {
PKCS11_SLOT *slot_list, *slot;
PKCS11_TOKEN *tok;
PKCS11_KEY *keys;
PKCS11_KEY *keys, *selected_key = NULL;
PKCS11_CERT *certs;
EVP_PKEY *pk;
unsigned int count, n, m;
unsigned char key_id[100];
const char *s_key_id;
int key_id_len = sizeof(key_id);
int slot_nr = -1;
char flags[64];
int logged_in = 0;
/* if(pin) {free(pin); pin=NULL;} // keep cached key? */
/* Format of s_slot_key_id: [S<slotNr>-]keyID or NULL,
with slotNr in decimal (0 = first slot, ...), and keyID in hex.
E.g. "S0-45" or "46" */
s_key_id = s_slot_key_id;
if (s_slot_key_id != NULL &&
(s_slot_key_id[0] == 's' || s_slot_key_id[0] == 'S')) {
for (n = 1; s_slot_key_id[n] != '\0' && n < 8; n++) {
if (s_slot_key_id[n] == '-') {
char tmp[8];
s_key_id += (n + 1);
memcpy(tmp, s_slot_key_id + 1, n - 1);
tmp[n - 1] = '\0';
printf("tmp=%s\n", tmp);
slot_nr = atoi(tmp);
}
}
}
if (!hex_to_bin(s_key_id, key_id, &key_id_len))
fail("Invalid key ID\n");
if (PKCS11_enumerate_slots(ctx, &slot_list, &count) < 0)
fail("failed to enumerate slots");
fail("failed to enumerate slots\n");
printf("Found %u slot%s\n", count, (count <= 1)? "" : "s");
again:
@ -146,15 +242,21 @@ again:
printf("\n");
}
if (!(slot = PKCS11_find_token(ctx)))
fail("didn't find any tokens");
if (slot_nr == -1) {
if (!(slot = PKCS11_find_token(ctx)))
fail("didn't find any tokens\n");
}
else if (slot_nr >= 0 && slot_nr < count)
slot = slot_list + slot_nr;
else {
printf("Invalid slot number: %d\n", slot_nr);
return NULL;
}
tok = slot->token;
if (!tok->initialized) {
printf("Found uninitialized token; \n");
return NULL;
}
if (private && !tok->userPinSet && !tok->readOnly) {
@ -166,7 +268,7 @@ again:
printf("Found token: %s\n", slot->token->label);
if (PKCS11_enumerate_certs(tok, &certs, &count))
fail("unable to enumerate certificates");
fail("unable to enumerate certificates\n");
printf("Found %u certificate%s:\n", count, (count <= 1)? "" : "s");
for (n = 0; n < count; n++) {
@ -186,7 +288,7 @@ again:
while (1) {
if (PKCS11_enumerate_keys(tok, &keys, &count))
fail("unable to enumerate keys");
fail("unable to enumerate keys\n");
if (count)
break;
if (logged_in || !tok->loginRequired)
@ -196,7 +298,7 @@ again:
get_pin(ui_method,pin,12);
}
if (PKCS11_login(slot, 0, pin))
fail("Card login failed");
fail("Card login failed\n");
logged_in++;
}
@ -213,17 +315,29 @@ again:
k->private? 'P' : ' ',
k->needLogin? 'L' : ' ',
k->label);
if (key_id_len != 0 && k->id_len == key_id_len &&
memcmp(k->id, key_id, key_id_len) == 0) {
printf(" ID = %s\n", s_key_id);
selected_key = k;
}
}
if (count == 0)
return NULL;
if (selected_key == NULL) {
if (s_key_id != NULL) {
printf("No key with ID \"%s\" found.\n", s_key_id);
return NULL;
}
else /* Take the first key that was found */
selected_key = &keys[0];
}
if(private) {
pk = PKCS11_get_private_key(&keys[0]);
pk = PKCS11_get_private_key(selected_key);
} else {
/*pk = PKCS11_get_public_key(&keys[0]);
need a get_public_key? */
pk = PKCS11_get_private_key(&keys[0]);
pk = PKCS11_get_private_key(selected_key);
}
return pk;
@ -234,7 +348,7 @@ EVP_PKEY *pkcs11_load_public_key(ENGINE *e, const char *s_key_id,
EVP_PKEY *pk;
pk=pkcs11_load_key(e, s_key_id, ui_method, callback_data, 0);
if (pk == NULL)
fail("PKCS11_load_public_key returned NULL");
fail("PKCS11_load_public_key returned NULL\n");
return pk;
}
@ -243,6 +357,6 @@ EVP_PKEY *pkcs11_load_private_key(ENGINE *e, const char *s_key_id,
EVP_PKEY* pk;
pk=pkcs11_load_key(e, s_key_id, ui_method, callback_data, 1);
if (pk == NULL)
fail("PKCS11_get_private_key returned NULL");
fail("PKCS11_get_private_key returned NULL\n");
return pk;
}

View File

@ -128,6 +128,7 @@ pkcs11_init_cert(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
PKCS11_CERT_private *kpriv;
PKCS11_CERT *cert;
char label[256], data[2048];
unsigned char id[256];
CK_CERTIFICATE_TYPE cert_type;
size_t size;
@ -158,6 +159,11 @@ pkcs11_init_cert(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
cert->x509 = d2i_X509(NULL, &p, size);
}
cert->id_len = sizeof(id);
if (!pkcs11_getattr_var(token, obj, CKA_ID, id, &cert->id_len)) {
cert->id = (unsigned char *) malloc(cert->id_len);
memcpy(cert->id, id, cert->id_len);
}
/* Initialize internal information */
kpriv->id_len = sizeof(kpriv->id);
@ -184,6 +190,8 @@ pkcs11_destroy_certs(PKCS11_TOKEN *token)
if (cert->x509)
X509_free(cert->x509);
OPENSSL_free(cert->label);
if (cert->id)
free(cert->id);
}
if (priv->certs)
OPENSSL_free(priv->certs);

View File

@ -254,6 +254,7 @@ pkcs11_init_key(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
PKCS11_KEY_private *kpriv;
PKCS11_KEY *key;
char label[256];
unsigned char id[256];
CK_KEY_TYPE key_type;
PKCS11_KEY_ops *ops;
size_t size;
@ -283,6 +284,11 @@ pkcs11_init_key(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
if (!pkcs11_getattr_s(token, obj, CKA_LABEL, label, sizeof(label)))
key->label = BUF_strdup(label);
key->id_len = sizeof(id);
if (!pkcs11_getattr_var(token, obj, CKA_ID, id, &key->id_len)) {
key->id = (unsigned char *) malloc(key->id_len);
memcpy(key->id, id, key->id_len);
}
key->private = (type == CKO_PRIVATE_KEY);
/* Initialize internal information */
@ -310,6 +316,8 @@ pkcs11_destroy_keys(PKCS11_TOKEN *token)
if (key->evp_key)
EVP_PKEY_free(key->evp_key);
OPENSSL_free(key->label);
if (key->id)
free(key->id);
}
if (priv->keys)
OPENSSL_free(priv->keys);

View File

@ -115,6 +115,8 @@ ERR_PUT_error(ERR_LIB_PKCS11,(f),(r),__FILE__,__LINE__)
/* PKCS11 key object (public or private) */
typedef struct PKCS11_key_st {
char * label;
unsigned char * id;
int id_len;
unsigned char private; /* private key present? */
unsigned char needLogin; /* login to read private key? */
EVP_PKEY * evp_key; /* initially NULL, need to call PKCS11_load_key */
@ -124,6 +126,8 @@ typedef struct PKCS11_key_st {
/* PKCS11 certificate object */
typedef struct PKCS11_cert_st {
char * label;
unsigned char * id;
int id_len;
X509 * x509;
void * _private;
} PKCS11_CERT;