[pkg-opensc-commit] [libp11] 29/86: Engine cleanup
Eric Dorland
eric at moszumanska.debian.org
Sun Jul 24 21:40:19 UTC 2016
This is an automated email from the git hooks/post-receive script.
eric pushed a commit to branch master
in repository libp11.
commit 32feafd257728c0edf4e6e016e0be06c1376e547
Author: Michał Trojnara <Michal.Trojnara at stunnel.org>
Date: Sun Jan 31 15:35:39 2016 +0100
Engine cleanup
* No more global variables. Local context was moved into a structure.
A pointer to this structure is stored in the ENGINE ex_data.
* Libc memory allocation functions changed to OpenSSL functions.
* URI/ID parser was moved to a separate file.
---
src/Makefile.am | 11 +-
src/eng_back.c | 721 +++++++++++++++++---------------------------------------
src/eng_front.c | 127 ++++++----
src/eng_parse.c | 338 ++++++++++++++++++++++++++
src/engine.h | 41 +++-
5 files changed, 673 insertions(+), 565 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
index 3f9dbb8..7183381 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,10 +21,9 @@ libp11_la_CFLAGS = $(AM_CFLAGS) $(OPENSSL_CFLAGS)
libp11_la_LIBADD = $(OPENSSL_LIBS)
libp11_la_LDFLAGS = $(AM_LDFLAGS) \
-version-info @LIBP11_LT_CURRENT@:@LIBP11_LT_REVISION@:@LIBP11_LT_AGE@ \
- -export-symbols "$(srcdir)/libp11.exports" \
- -no-undefined
+ -export-symbols "$(srcdir)/libp11.exports"
-libpkcs11_la_SOURCES = eng_front.c eng_back.c engine.h pkcs11.exports
+libpkcs11_la_SOURCES = eng_front.c eng_back.c eng_parse.c engine.h pkcs11.exports
if WIN32
libpkcs11_la_SOURCES += pkcs11.rc
else
@@ -32,10 +31,8 @@ dist_noinst_DATA += pkcs11.rc
endif
libpkcs11_la_CFLAGS = $(AM_CFLAGS) $(OPENSSL_EXTRA_CFLAGS) $(OPENSSL_CFLAGS)
libpkcs11_la_LIBADD = libp11.la $(OPENSSL_LIBS)
-libpkcs11_la_LDFLAGS = $(AM_LDFLAGS) \
- -module -shared -avoid-version \
- -export-symbols "$(srcdir)/pkcs11.exports" \
- -no-undefined
+libpkcs11_la_LDFLAGS = $(AM_LDFLAGS) -shared -avoid-version \
+ -export-symbols "$(srcdir)/pkcs11.exports"
if WIN32
# def file required for MS users to build library
diff --git a/src/eng_back.c b/src/eng_back.c
index 352bd5c..d90d160 100644
--- a/src/eng_back.c
+++ b/src/eng_back.c
@@ -1,8 +1,9 @@
/*
- * Copyright (c) 2002 Juha Yrjölä. All rights reserved.
- * Copyright (c) 2001 Markus Friedl.
+ * Copyright (c) 2001 Markus Friedl
+ * Copyright (c) 2002 Juha Yrjölä
* Copyright (c) 2002 Olaf Kirch
* Copyright (c) 2003 Kevin Stefanik
+ * Copyright (c) 2016 Michał Trojnara
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,97 +27,51 @@
*/
#include "engine.h"
-#include "libp11.h"
#include <stdio.h>
#include <string.h>
#include <openssl/crypto.h>
#include <openssl/objects.h>
#include <openssl/engine.h>
-#ifdef _WIN32
-#define strncasecmp strnicmp
-#endif
-
-/** The maximum length of an internally-allocated PIN */
+/* The maximum length of an internally-allocated PIN */
#define MAX_PIN_LENGTH 32
+#define MAX_VALUE_LEN 200
-static PKCS11_CTX *ctx;
-
-/**
- * The PIN used for login. Cache for the get_pin function.
- * 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;
-static int pin_length = 0;
-
-static int verbose = 0;
-
-static char *module = NULL;
-
-static char *init_args = NULL;
+struct st_engine_ctx {
+ PKCS11_CTX *pkcs11_ctx;
+ /*
+ * The PIN used for login. Cache for the get_pin function.
+ * 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.
+ */
+ char *pin;
+ int pin_length;
+ int verbose;
+ char *module;
+ char *init_args;
+};
-int set_module(const char *modulename)
-{
- free (module);
- module = modulename ? strdup(modulename) : NULL;
- return 1;
-}
+/******************************************************************************/
+/* pin handling */
+/******************************************************************************/
/* Free PIN storage in secure way. */
-static void zero_pin(void)
-{
- if (pin != NULL) {
- OPENSSL_cleanse(pin, pin_length);
- free(pin);
- pin = NULL;
- pin_length = 0;
- }
-}
-
-/**
- * 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)
+static void destroy_pin(ENGINE_CTX *ctx)
{
- /* Pre-condition check */
- if (_pin == NULL) {
- errno = EINVAL;
- return 0;
+ if (ctx->pin != NULL) {
+ OPENSSL_cleanse(ctx->pin, ctx->pin_length);
+ OPENSSL_free(ctx->pin);
+ ctx->pin = NULL;
+ ctx->pin_length = 0;
}
-
- /* Copy the PIN. If the string cannot be copied, NULL
- * shall be returned and errno shall be set. */
- zero_pin();
- pin = strdup(_pin);
- if (pin != NULL)
- pin_length = strlen(pin);
-
- return (pin != NULL);
-}
-
-int inc_verbose(void)
-{
- verbose++;
- return 1;
}
/* Get the PIN via asking user interface. The supplied call-back data are
* passed to the user interface implemented by an application. Only the
* application knows how to interpret the call-back data.
* A (strdup'ed) copy of the PIN code will be stored in the pin variable. */
-static int get_pin(UI_METHOD * ui_method, void *callback_data)
+static int get_pin(ENGINE_CTX *ctx, UI_METHOD *ui_method, void *callback_data)
{
UI *ui;
@@ -131,13 +86,14 @@ static int get_pin(UI_METHOD * ui_method, void *callback_data)
if (callback_data != NULL)
UI_add_user_data(ui, callback_data);
- zero_pin();
- pin = (char *)calloc(MAX_PIN_LENGTH, sizeof(char));
- if (pin == NULL)
+ destroy_pin(ctx);
+ ctx->pin = OPENSSL_malloc(MAX_PIN_LENGTH * sizeof(char));
+ if (ctx->pin == NULL)
return 0;
- pin_length = MAX_PIN_LENGTH;
+ memset(ctx->pin, 0, MAX_PIN_LENGTH * sizeof(char));
+ ctx->pin_length = MAX_PIN_LENGTH;
if (!UI_add_input_string(ui, "PKCS#11 token PIN: ",
- UI_INPUT_FLAG_DEFAULT_PWD, pin, 1, MAX_PIN_LENGTH)) {
+ UI_INPUT_FLAG_DEFAULT_PWD, ctx->pin, 1, MAX_PIN_LENGTH)) {
fprintf(stderr, "UI_add_input_string failed\n");
UI_free(ui);
return 0;
@@ -151,43 +107,40 @@ static int get_pin(UI_METHOD * ui_method, void *callback_data)
return 1;
}
-int set_init_args(const char *init_args_orig)
+/******************************************************************************/
+/* initialization/cleanup */
+/******************************************************************************/
+
+ENGINE_CTX *pkcs11_new()
{
- free(init_args);
- init_args = init_args_orig ? strdup(init_args_orig) : NULL;
- return 1;
+ ENGINE_CTX *ctx;
+
+ ctx = OPENSSL_malloc(sizeof(ENGINE_CTX));
+ if (ctx == NULL)
+ return NULL;
+ memset(ctx, 0, sizeof(ENGINE_CTX));
+ ctx->pkcs11_ctx = PKCS11_CTX_new();
+ return ctx;
}
-int pkcs11_finish(ENGINE * engine)
+int pkcs11_finish(ENGINE_CTX *ctx)
{
- /*
- * TODO: Retrieve the libp11 context with:
- * ctx = ENGINE_get_ex_data(e, pkcs11_idx);
- * , free it, and set to NULL with:
- * ENGINE_set_ex_data(e, pkcs11_idx, NULL);
- * instead of using a global context
- */
- (void)engine;
-
if (ctx) {
- PKCS11_CTX_unload(ctx);
- PKCS11_CTX_free(ctx);
- ctx = NULL;
+ if (ctx->pkcs11_ctx) {
+ PKCS11_CTX_unload(ctx->pkcs11_ctx);
+ PKCS11_CTX_free(ctx->pkcs11_ctx);
+ }
+ destroy_pin(ctx);
+ OPENSSL_free(ctx->module);
+ OPENSSL_free(ctx->init_args);
+ OPENSSL_free(ctx);
}
- zero_pin();
return 1;
}
-int pkcs11_init(ENGINE * engine)
+int pkcs11_init(ENGINE_CTX *ctx)
{
- char *mod = module;
-
- /*
- * TODO: Save the libp11 context with:
- * ENGINE_set_ex_data(e, pkcs11_idx, ctx);
- * instead of using a global context
- */
- (void)engine;
+ char *mod = ctx->module;
if (mod == NULL)
mod = getenv("PKCS11_MODULE_PATH");
@@ -195,331 +148,26 @@ int pkcs11_init(ENGINE * engine)
if (mod == NULL)
mod = DEFAULT_PKCS11_MODULE;
#endif
- if (verbose) {
+ if (ctx->verbose) {
fprintf(stderr, "Initializing engine\n");
}
- ctx = PKCS11_CTX_new();
- PKCS11_CTX_init_args(ctx, init_args);
- if (PKCS11_CTX_load(ctx, mod) < 0) {
+
+ PKCS11_CTX_init_args(ctx->pkcs11_ctx, ctx->init_args);
+ if (PKCS11_CTX_load(ctx->pkcs11_ctx, mod) < 0) {
fprintf(stderr, "Unable to load module %s\n", mod);
return 0;
}
return 1;
}
-static int hex_to_bin(const char *in, unsigned char *out, size_t * outlen)
-{
- size_t left, count = 0;
-
- if (in == NULL || *in == '\0') {
- *outlen = 0;
- return 1;
- }
-
- left = *outlen;
-
- while (*in != '\0') {
- int byte = 0, nybbles = 2;
-
- while (nybbles-- && *in && *in != ':') {
- char c;
- 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 {
- fprintf(stderr,
- "hex_to_bin(): invalid char '%c' in hex string\n",
- c);
- *outlen = 0;
- return 0;
- }
- byte |= c;
- }
- if (*in == ':')
- in++;
- if (left <= 0) {
- fprintf(stderr, "hex_to_bin(): hex string too long\n");
- *outlen = 0;
- return 0;
- }
- out[count++] = (unsigned char)byte;
- left--;
- }
-
- *outlen = count;
- return 1;
-}
-
-/* parse string containing slot and id information */
-static int parse_slot_id_string(const char *slot_id, int *slot,
- unsigned char *id, size_t * id_len,
- char **label)
-{
- int n, i;
-
- if (slot_id == NULL)
- return 0;
-
- /* support for several formats */
-#define HEXDIGITS "01234567890ABCDEFabcdef"
-#define DIGITS "0123456789"
-
- /* first: pure hex number (id, slot is undefined) */
- if (strspn(slot_id, HEXDIGITS) == strlen(slot_id)) {
- /* ah, easiest case: only hex. */
- if ((strlen(slot_id) + 1) / 2 > *id_len) {
- fprintf(stderr, "ID string too long!\n");
- return 0;
- }
- *slot = -1;
- return hex_to_bin(slot_id, id, id_len);
- }
-
- /* second: slot:id. slot is an digital int. */
- if (sscanf(slot_id, "%d", &n) == 1) {
- i = strspn(slot_id, DIGITS);
-
- if (slot_id[i] != ':') {
- fprintf(stderr, "Could not parse string!\n");
- return 0;
- }
- i++;
- if (slot_id[i] == 0) {
- *slot = n;
- *id_len = 0;
- return 1;
- }
- if (strspn(slot_id + i, HEXDIGITS) + i != strlen(slot_id)) {
- fprintf(stderr, "Could not parse string!\n");
- return 0;
- }
- /* ah, rest is hex */
- if ((strlen(slot_id) - i + 1) / 2 > *id_len) {
- fprintf(stderr, "ID string too long!\n");
- return 0;
- }
- *slot = n;
- return hex_to_bin(slot_id + i, id, id_len);
- }
-
- /* third: id_<id>, slot is undefined */
- if (strncmp(slot_id, "id_", 3) == 0) {
- if (strspn(slot_id + 3, HEXDIGITS) + 3 != strlen(slot_id)) {
- fprintf(stderr, "Could not parse string!\n");
- return 0;
- }
- /* ah, rest is hex */
- if ((strlen(slot_id) - 3 + 1) / 2 > *id_len) {
- fprintf(stderr, "ID string too long!\n");
- return 0;
- }
- *slot = -1;
- return hex_to_bin(slot_id + 3, id, id_len);
- }
-
- /* label_<label>, slot is undefined */
- if (strncmp(slot_id, "label_", 6) == 0) {
- *slot = -1;
- *label = strdup(slot_id + 6);
- return *label != NULL;
- }
-
- /* last try: it has to be slot_<slot> and then "-id_<cert>" */
-
- if (strncmp(slot_id, "slot_", 5) != 0) {
- fprintf(stderr, "Format not recognized!\n");
- return 0;
- }
-
- /* slot is an digital int. */
- if (sscanf(slot_id + 5, "%d", &n) != 1) {
- fprintf(stderr, "Could not decode slot number!\n");
- return 0;
- }
-
- i = strspn(slot_id + 5, DIGITS);
-
- if (slot_id[i + 5] == 0) {
- *slot = n;
- *id_len = 0;
- return 1;
- }
-
- if (slot_id[i + 5] != '-') {
- fprintf(stderr, "Could not parse string!\n");
- return 0;
- }
-
- i = 5 + i + 1;
-
- /* now followed by "id_" */
- if (strncmp(slot_id + i, "id_", 3) == 0) {
- if (strspn(slot_id + i + 3, HEXDIGITS) + 3 + i != strlen(slot_id)) {
- fprintf(stderr, "Could not parse string!\n");
- return 0;
- }
- /* ah, rest is hex */
- if ((strlen(slot_id) - i - 3 + 1) / 2 > *id_len) {
- fprintf(stderr, "ID string too long!\n");
- return 0;
- }
- *slot = n;
- return hex_to_bin(slot_id + i + 3, id, id_len);
- }
-
- /* ... or "label_" */
- if (strncmp(slot_id + i, "label_", 6) == 0) {
- *slot = n;
- return (*label = strdup(slot_id + i + 6)) != NULL;
- }
-
- fprintf(stderr, "Could not parse string!\n");
- return 0;
-}
-
-static int parse_uri_attr(const char *attr, int attrlen, unsigned char **field,
- size_t *field_len)
-{
- size_t max, outlen = 0;
- unsigned char *out;
- int ret = 1;
-
- if (field_len) {
- out = *field;
- max = *field_len;
- } else {
- out = malloc(attrlen + 1);
- if (out == NULL)
- return 0;
- max = attrlen + 1;
- }
-
- while (ret && attrlen && outlen < max) {
- if (*attr == '%') {
- if (attrlen < 3) {
- ret = 0;
- } else {
- char tmp[3];
- size_t l = 1;
-
- tmp[0] = attr[1];
- tmp[1] = attr[2];
- tmp[2] = 0;
- ret = hex_to_bin(tmp, &out[outlen++], &l);
- attrlen -= 3;
- attr += 3;
- }
-
- } else {
- out[outlen++] = *(attr++);
- attrlen--;
- }
- }
- if (attrlen && outlen == max)
- ret = 0;
-
- if (ret) {
- if (field_len) {
- *field_len = outlen;
- } else {
- out[outlen] = 0;
- *field = out;
- }
- } else {
- if (field_len == NULL)
- free(out);
- }
-
- return ret;
-}
-
-static int parse_pkcs11_uri(const char *uri, PKCS11_TOKEN **p_tok,
- unsigned char *id, size_t *id_len, char *pin, size_t *pin_len,
- char **label)
-{
- PKCS11_TOKEN *tok;
- char *newlabel = NULL;
- const char *end, *p;
- int rv = 1, pin_set = 0;
-
- tok = calloc(1, sizeof(*tok));
- if (tok == NULL) {
- fprintf(stderr, "Could not allocate memory for token info\n");
- return 0;
- }
-
- /* We are only ever invoked if the string starts with 'pkcs11:' */
- end = uri + 6;
- while (rv && end[0] && end[1]) {
- p = end + 1;
- end = strchr(p, ';');
- if (end == NULL)
- end = p + strlen(p);
-
- if (!strncmp(p, "model=", 6)) {
- p += 6;
- rv = parse_uri_attr(p, end - p, (void *)&tok->model, NULL);
- } else if (!strncmp(p, "manufacturer=", 13)) {
- p += 13;
- rv = parse_uri_attr(p, end - p, (void *)&tok->manufacturer, NULL);
- } else if (!strncmp(p, "token=", 6)) {
- p += 6;
- rv = parse_uri_attr(p, end - p, (void *)&tok->label, NULL);
- } else if (!strncmp(p, "serial=", 7)) {
- p += 7;
- rv = parse_uri_attr(p, end - p, (void *)&tok->serialnr, NULL);
- } else if (!strncmp(p, "object=", 7)) {
- p += 7;
- rv = parse_uri_attr(p, end - p, (void *)&newlabel, NULL);
- } else if (!strncmp(p, "id=", 3)) {
- p += 3;
- rv = parse_uri_attr(p, end - p, (void *)&id, id_len);
- } else if (!strncmp(p, "pin-value=", 10)) {
- p += 10;
- rv = parse_uri_attr(p, end - p, (void *)&pin, pin_len);
- pin_set = 1;
- } else if (!strncmp(p, "type=", 5) || !strncmp(p, "object-type=", 12)) {
- p = strchr(p, '=') + 1;
-
- if ((end - p == 4 && !strncmp(p, "cert", 4)) ||
- (end - p == 6 && !strncmp(p, "public", 6)) ||
- (end - p == 7 && !strncmp(p, "private", 7))) {
- /* Actually, just ignore it */
- } else {
- fprintf(stderr, "Unknown object type\n");
- rv = 0;
- }
- } else {
- rv = 0;
- }
- }
-
- if (!pin_set)
- *pin_len = 0;
-
- if (rv) {
- *label = newlabel;
- *p_tok = tok;
- } else {
- free(tok);
- tok = NULL;
- free(newlabel);
- }
-
- return rv;
-}
-
-#define MAX_VALUE_LEN 200
+/******************************************************************************/
+/* certificte handling */
+/******************************************************************************/
/* prototype for OpenSSL ENGINE_load_cert */
/* used by load_cert_ctrl via ENGINE_ctrl for now */
-static X509 *pkcs11_load_cert(ENGINE * engine, const char *s_slot_cert_id)
+static X509 *pkcs11_load_cert(ENGINE_CTX *ctx, const char *s_slot_cert_id)
{
PKCS11_SLOT *slot_list, *slot;
PKCS11_SLOT *found_slot = NULL;
@@ -535,25 +183,19 @@ static X509 *pkcs11_load_cert(ENGINE * engine, const char *s_slot_cert_id)
int slot_nr = -1;
char flags[64];
- /*
- * TODO: Retrieve the libp11 context with:
- * ctx = ENGINE_get_ex_data(e, pkcs11_idx);
- * instead of using a global context
- */
- (void)engine;
-
if (s_slot_cert_id && *s_slot_cert_id) {
if (!strncmp(s_slot_cert_id, "pkcs11:", 7)) {
n = parse_pkcs11_uri(s_slot_cert_id, &match_tok,
cert_id, &cert_id_len,
tmp_pin, &tmp_pin_len, &cert_label);
if (n && tmp_pin_len > 0 && tmp_pin[0] != 0) {
- zero_pin();
- pin = calloc(MAX_PIN_LENGTH, sizeof(char));
- if (pin != NULL) {
- memcpy(pin, tmp_pin, tmp_pin_len);
- pin_length = tmp_pin_len;
+ destroy_pin(ctx);
+ ctx->pin = OPENSSL_malloc(MAX_PIN_LENGTH * sizeof(char));
+ if (ctx->pin != NULL) {
+ memcpy(ctx->pin, tmp_pin, tmp_pin_len);
+ ctx->pin_length = tmp_pin_len;
}
+ memset(ctx->pin, 0, MAX_PIN_LENGTH * sizeof(char));
}
if (!n) {
@@ -575,7 +217,7 @@ static X509 *pkcs11_load_cert(ENGINE * engine, const char *s_slot_cert_id)
return NULL;
}
}
- if (verbose) {
+ if (ctx->verbose) {
fprintf(stderr, "Looking in slot %d for certificate: ",
slot_nr);
if (cert_label == NULL) {
@@ -587,12 +229,12 @@ static X509 *pkcs11_load_cert(ENGINE * engine, const char *s_slot_cert_id)
}
}
- if (PKCS11_enumerate_slots(ctx, &slot_list, &slot_count) < 0) {
+ if (PKCS11_enumerate_slots(ctx->pkcs11_ctx, &slot_list, &slot_count) < 0) {
fprintf(stderr, "Failed to enumerate slots\n");
return NULL;
}
- if (verbose) {
+ if (ctx->verbose) {
fprintf(stderr, "Found %u slot%s\n", slot_count,
(slot_count <= 1) ? "" : "s");
}
@@ -630,7 +272,7 @@ static X509 *pkcs11_load_cert(ENGINE * engine, const char *s_slot_cert_id)
!strcmp(match_tok->model, slot->token->model))) {
found_slot = slot;
}
- if (verbose) {
+ if (ctx->verbose) {
fprintf(stderr, "[%lu] %-25.25s %-16s",
PKCS11_get_slotid_from_slot(slot),
slot->description, flags);
@@ -644,11 +286,11 @@ static X509 *pkcs11_load_cert(ENGINE * engine, const char *s_slot_cert_id)
}
if (match_tok) {
- free(match_tok->model);
- free(match_tok->manufacturer);
- free(match_tok->serialnr);
- free(match_tok->label);
- free(match_tok);
+ OPENSSL_free(match_tok->model);
+ OPENSSL_free(match_tok->manufacturer);
+ OPENSSL_free(match_tok->serialnr);
+ OPENSSL_free(match_tok->label);
+ OPENSSL_free(match_tok);
}
if (found_slot) {
slot = found_slot;
@@ -656,34 +298,34 @@ static X509 *pkcs11_load_cert(ENGINE * engine, const char *s_slot_cert_id)
fprintf(stderr, "Specified object not found\n");
return NULL;
} else if (slot_nr == -1) {
- if (!(slot = PKCS11_find_token(ctx, slot_list, slot_count))) {
+ if (!(slot = PKCS11_find_token(ctx->pkcs11_ctx, slot_list, slot_count))) {
fprintf(stderr, "No tokens found\n");
return NULL;
}
} else {
fprintf(stderr, "Invalid slot number: %d\n", slot_nr);
- PKCS11_release_all_slots(ctx, slot_list, slot_count);
+ PKCS11_release_all_slots(ctx->pkcs11_ctx, slot_list, slot_count);
return NULL;
}
tok = slot->token;
if (tok == NULL) {
fprintf(stderr, "Empty token found\n");
- PKCS11_release_all_slots(ctx, slot_list, slot_count);
+ PKCS11_release_all_slots(ctx->pkcs11_ctx, slot_list, slot_count);
return NULL;
}
- if (verbose) {
+ if (ctx->verbose) {
fprintf(stderr, "Found slot: %s\n", slot->description);
fprintf(stderr, "Found token: %s\n", slot->token->label);
}
/* In several tokens certificates are marked as private. We use the pin-value */
- if (tok->loginRequired && pin) {
+ if (tok->loginRequired && ctx->pin) {
/* Now login in with the (possibly NULL) pin */
- if (PKCS11_login(slot, 0, pin)) {
+ if (PKCS11_login(slot, 0, ctx->pin)) {
/* Login failed, so free the PIN if present */
- zero_pin();
+ destroy_pin(ctx);
fprintf(stderr, "Login failed\n");
return NULL;
}
@@ -691,11 +333,11 @@ static X509 *pkcs11_load_cert(ENGINE * engine, const char *s_slot_cert_id)
if (PKCS11_enumerate_certs(tok, &certs, &cert_count)) {
fprintf(stderr, "Unable to enumerate certificates\n");
- PKCS11_release_all_slots(ctx, slot_list, slot_count);
+ PKCS11_release_all_slots(ctx->pkcs11_ctx, slot_list, slot_count);
return NULL;
}
- if (verbose) {
+ if (ctx->verbose) {
fprintf(stderr, "Found %u cert%s:\n", cert_count,
(cert_count <= 1) ? "" : "s");
}
@@ -719,17 +361,17 @@ static X509 *pkcs11_load_cert(ENGINE * engine, const char *s_slot_cert_id)
if (selected_cert == NULL) {
fprintf(stderr, "Certificate not found.\n");
- PKCS11_release_all_slots(ctx, slot_list, slot_count);
+ PKCS11_release_all_slots(ctx->pkcs11_ctx, slot_list, slot_count);
return NULL;
}
x509 = X509_dup(selected_cert->x509);
if (cert_label != NULL)
- free(cert_label);
+ OPENSSL_free(cert_label);
return x509;
}
-int load_cert_ctrl(ENGINE * e, void *p)
+static int ctrl_load_cert(ENGINE_CTX *ctx, void *p)
{
struct {
const char *s_slot_cert_id;
@@ -739,13 +381,17 @@ int load_cert_ctrl(ENGINE * e, void *p)
if (parms->cert != NULL)
return 0;
- parms->cert = pkcs11_load_cert(e, parms->s_slot_cert_id);
+ parms->cert = pkcs11_load_cert(ctx, parms->s_slot_cert_id);
if (parms->cert == NULL)
return 0;
return 1;
}
+/******************************************************************************/
+/* private and public key handling */
+/******************************************************************************/
+
/*
* Log-into the token if necesary.
*
@@ -755,7 +401,7 @@ int load_cert_ctrl(ENGINE * e, void *p)
* @callback_data are application data to the user interface
* @return 1 on success, 0 on error.
*/
-static int pkcs11_login(PKCS11_SLOT *slot, PKCS11_TOKEN *tok,
+static int pkcs11_login(ENGINE_CTX *ctx, PKCS11_SLOT *slot, PKCS11_TOKEN *tok,
UI_METHOD *ui_method, void *callback_data)
{
if (tok->loginRequired) {
@@ -765,25 +411,26 @@ static int pkcs11_login(PKCS11_SLOT *slot, PKCS11_TOKEN *tok,
if (tok->secureLogin) {
/* Free the PIN if it has already been
* assigned (i.e, cached by get_pin) */
- zero_pin();
- } else if (pin == NULL) {
- pin = (char *)calloc(MAX_PIN_LENGTH, sizeof(char));
- pin_length = MAX_PIN_LENGTH;
- if (pin == NULL) {
+ destroy_pin(ctx);
+ } else if (ctx->pin == NULL) {
+ ctx->pin = OPENSSL_malloc(MAX_PIN_LENGTH * sizeof(char));
+ ctx->pin_length = MAX_PIN_LENGTH;
+ if (ctx->pin == NULL) {
fprintf(stderr, "Could not allocate memory for PIN");
return 0;
}
- if (!get_pin(ui_method, callback_data)) {
- zero_pin();
+ memset(ctx->pin, 0, MAX_PIN_LENGTH * sizeof(char));
+ if (!get_pin(ctx, ui_method, callback_data)) {
+ destroy_pin(ctx);
fprintf(stderr, "No pin code was entered");
return 0;
}
}
/* Now login in with the (possibly NULL) pin */
- if (PKCS11_login(slot, 0, pin)) {
+ if (PKCS11_login(slot, 0, ctx->pin)) {
/* Login failed, so free the PIN if present */
- zero_pin();
+ destroy_pin(ctx);
fprintf(stderr, "Login failed\n");
return 0;
}
@@ -795,17 +442,16 @@ static int pkcs11_login(PKCS11_SLOT *slot, PKCS11_TOKEN *tok,
* 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
+ * seems safer to retain the PIN and perform 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 */
}
return 1;
}
-static EVP_PKEY *pkcs11_load_key(ENGINE * engine, const char *s_slot_key_id,
+static EVP_PKEY *pkcs11_load_key(ENGINE_CTX *ctx, const char *s_slot_key_id,
UI_METHOD * ui_method, void *callback_data, int isPrivate)
{
PKCS11_SLOT *slot_list, *slot;
@@ -823,14 +469,7 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * engine, const char *s_slot_key_id,
size_t tmp_pin_len = sizeof(tmp_pin);
char flags[64];
- /*
- * TODO: Retrieve the libp11 context with:
- * ctx = ENGINE_get_ex_data(e, pkcs11_idx);
- * instead of using a global context
- */
- (void)engine;
-
- if (verbose)
+ if (ctx->verbose)
fprintf(stderr, "Loading %s key \"%s\"\n",
(char *)(isPrivate ? "private" : "public"),
s_slot_key_id);
@@ -841,11 +480,12 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * engine, const char *s_slot_key_id,
tmp_pin, &tmp_pin_len, &key_label);
if (n && tmp_pin_len > 0 && tmp_pin[0] != 0) {
- zero_pin();
- pin = calloc(MAX_PIN_LENGTH, sizeof(char));
- if (pin != NULL) {
- memcpy(pin, tmp_pin, tmp_pin_len);
- pin_length = tmp_pin_len;
+ destroy_pin(ctx);
+ ctx->pin = OPENSSL_malloc(MAX_PIN_LENGTH * sizeof(char));
+ if (ctx->pin != NULL) {
+ memset(ctx->pin, 0, MAX_PIN_LENGTH * sizeof(char));
+ memcpy(ctx->pin, tmp_pin, tmp_pin_len);
+ ctx->pin_length = tmp_pin_len;
}
}
@@ -868,7 +508,7 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * engine, const char *s_slot_key_id,
return NULL;
}
}
- if (verbose) {
+ if (ctx->verbose) {
fprintf(stderr, "Looking in slot %d for key: ",
slot_nr);
if (key_label == NULL) {
@@ -880,12 +520,12 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * engine, const char *s_slot_key_id,
}
}
- if (PKCS11_enumerate_slots(ctx, &slot_list, &slot_count) < 0) {
+ if (PKCS11_enumerate_slots(ctx->pkcs11_ctx, &slot_list, &slot_count) < 0) {
fprintf(stderr, "Failed to enumerate slots\n");
return NULL;
}
- if (verbose) {
+ if (ctx->verbose) {
fprintf(stderr, "Found %u slot%s\n", slot_count,
(slot_count <= 1) ? "" : "s");
}
@@ -923,7 +563,7 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * engine, const char *s_slot_key_id,
!strcmp(match_tok->model, slot->token->model))) {
found_slot = slot;
}
- if (verbose) {
+ if (ctx->verbose) {
fprintf(stderr, "[%lu] %-25.25s %-16s",
PKCS11_get_slotid_from_slot(slot),
slot->description, flags);
@@ -937,11 +577,11 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * engine, const char *s_slot_key_id,
}
if (match_tok) {
- free(match_tok->model);
- free(match_tok->manufacturer);
- free(match_tok->serialnr);
- free(match_tok->label);
- free(match_tok);
+ OPENSSL_free(match_tok->model);
+ OPENSSL_free(match_tok->manufacturer);
+ OPENSSL_free(match_tok->serialnr);
+ OPENSSL_free(match_tok->label);
+ OPENSSL_free(match_tok);
}
if (found_slot) {
slot = found_slot;
@@ -949,20 +589,20 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * engine, const char *s_slot_key_id,
fprintf(stderr, "Specified object not found\n");
return NULL;
} else if (slot_nr == -1) {
- if (!(slot = PKCS11_find_token(ctx, slot_list, slot_count))) {
+ if (!(slot = PKCS11_find_token(ctx->pkcs11_ctx, slot_list, slot_count))) {
fprintf(stderr, "No tokens found\n");
return NULL;
}
} else {
fprintf(stderr, "Invalid slot number: %d\n", slot_nr);
- PKCS11_release_all_slots(ctx, slot_list, slot_count);
+ PKCS11_release_all_slots(ctx->pkcs11_ctx, slot_list, slot_count);
return NULL;
}
tok = slot->token;
if (tok == NULL) {
fprintf(stderr, "Found empty token\n");
- PKCS11_release_all_slots(ctx, slot_list, slot_count);
+ PKCS11_release_all_slots(ctx->pkcs11_ctx, slot_list, slot_count);
return NULL;
}
/* The following check is non-critical to ensure interoperability
@@ -971,11 +611,11 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * engine, const char *s_slot_key_id,
fprintf(stderr, "Found uninitialized token\n");
if (isPrivate && !tok->userPinSet && !tok->readOnly) {
fprintf(stderr, "Found slot without user PIN\n");
- PKCS11_release_all_slots(ctx, slot_list, slot_count);
+ PKCS11_release_all_slots(ctx->pkcs11_ctx, slot_list, slot_count);
return NULL;
}
- if (verbose) {
+ if (ctx->verbose) {
fprintf(stderr, "Found slot: %s\n", slot->description);
fprintf(stderr, "Found token: %s\n", slot->token->label);
}
@@ -985,7 +625,7 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * engine, const char *s_slot_key_id,
return NULL;
}
- if (verbose) {
+ if (ctx->verbose) {
fprintf(stderr, "Found %u certificate%s:\n", cert_count,
(cert_count <= 1) ? "" : "s");
for (n = 0; n < cert_count; n++) {
@@ -1005,7 +645,7 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * engine, const char *s_slot_key_id,
if (isPrivate) {
/* Perform login to the token if required */
- if (!pkcs11_login(slot, tok, ui_method, callback_data)) {
+ if (!pkcs11_login(ctx, slot, tok, ui_method, callback_data)) {
fprintf(stderr, "login to token failed, returning NULL...\n");
return NULL;
}
@@ -1027,7 +667,7 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * engine, const char *s_slot_key_id,
(char *)(isPrivate ? "private" : "public"));
return NULL;
}
- if (verbose)
+ if (ctx->verbose)
fprintf(stderr, "Found %u %s key%s:\n", key_count,
(char *)(isPrivate ? "private" : "public"),
(key_count == 1) ? "" : "s");
@@ -1037,7 +677,7 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * engine, const char *s_slot_key_id,
for (n = 0; n < key_count; n++) {
PKCS11_KEY *k = keys + n;
- if (verbose) {
+ if (ctx->verbose) {
fprintf(stderr, " %2u %c%c %s\n", n + 1,
k->isPrivate ? 'P' : ' ',
k->needLogin ? 'L' : ' ', k->label);
@@ -1066,16 +706,16 @@ static EVP_PKEY *pkcs11_load_key(ENGINE * engine, const char *s_slot_key_id,
PKCS11_get_private_key(selected_key) :
PKCS11_get_public_key(selected_key);
if (key_label != NULL)
- free(key_label);
+ OPENSSL_free(key_label);
return pk;
}
-EVP_PKEY *pkcs11_load_public_key(ENGINE * e, const char *s_key_id,
+EVP_PKEY *pkcs11_load_public_key(ENGINE_CTX *ctx, const char *s_key_id,
UI_METHOD * ui_method, void *callback_data)
{
EVP_PKEY *pk;
- pk = pkcs11_load_key(e, s_key_id, ui_method, callback_data, 0);
+ pk = pkcs11_load_key(ctx, s_key_id, ui_method, callback_data, 0);
if (pk == NULL) {
fprintf(stderr, "PKCS11_load_public_key returned NULL\n");
return NULL;
@@ -1083,12 +723,12 @@ EVP_PKEY *pkcs11_load_public_key(ENGINE * e, const char *s_key_id,
return pk;
}
-EVP_PKEY *pkcs11_load_private_key(ENGINE * e, const char *s_key_id,
+EVP_PKEY *pkcs11_load_private_key(ENGINE_CTX *ctx, const char *s_key_id,
UI_METHOD * ui_method, void *callback_data)
{
EVP_PKEY *pk;
- pk = pkcs11_load_key(e, s_key_id, ui_method, callback_data, 1);
+ pk = pkcs11_load_key(ctx, s_key_id, ui_method, callback_data, 1);
if (pk == NULL) {
fprintf(stderr, "PKCS11_get_private_key returned NULL\n");
return NULL;
@@ -1096,4 +736,81 @@ EVP_PKEY *pkcs11_load_private_key(ENGINE * e, const char *s_key_id,
return pk;
}
+/******************************************************************************/
+/* engine ctrl request handling */
+/******************************************************************************/
+
+static int ctrl_set_module(ENGINE_CTX *ctx, const char *modulename)
+{
+ OPENSSL_free(ctx->module);
+ ctx->module = modulename ? OPENSSL_strdup(modulename) : NULL;
+ 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.
+ */
+static int ctrl_set_pin(ENGINE_CTX *ctx, 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. */
+ destroy_pin(ctx);
+ ctx->pin = OPENSSL_strdup(pin);
+ if (ctx->pin != NULL)
+ ctx->pin_length = strlen(ctx->pin);
+
+ return ctx->pin != NULL;
+}
+
+static int ctrl_inc_verbose(ENGINE_CTX *ctx)
+{
+ ctx->verbose++;
+ return 1;
+}
+
+static int ctrl_set_init_args(ENGINE_CTX *ctx, const char *init_args_orig)
+{
+ OPENSSL_free(ctx->init_args);
+ ctx->init_args = init_args_orig ? OPENSSL_strdup(init_args_orig) : NULL;
+ return 1;
+}
+
+int pkcs11_engine_ctrl(ENGINE_CTX *ctx, int cmd, long i, void *p, void (*f)())
+{
+ (void)i; /* We don't currently take integer parameters */
+ (void)f; /* We don't currently take callback parameters */
+ /*int initialised = ((pkcs11_dso == NULL) ? 0 : 1); */
+ switch (cmd) {
+ case CMD_MODULE_PATH:
+ return ctrl_set_module(ctx, (const char *)p);
+ case CMD_PIN:
+ return ctrl_set_pin(ctx, (const char *)p);
+ case CMD_VERBOSE:
+ return ctrl_inc_verbose(ctx);
+ case CMD_LOAD_CERT_CTRL:
+ return ctrl_load_cert(ctx, p);
+ case CMD_INIT_ARGS:
+ return ctrl_set_init_args(ctx, (const char *)p);
+ default:
+ break;
+ }
+ return 0;
+}
+
/* vim: set noexpandtab: */
diff --git a/src/eng_front.c b/src/eng_front.c
index 95c3470..28510ec 100644
--- a/src/eng_front.c
+++ b/src/eng_front.c
@@ -3,6 +3,7 @@
* project 2000.
* Copied/modified by Kevin Stefanik (kstef at mtppi.org) for the OpenSC
* project 2003.
+ * Copyright (c) 2016 Michał Trojnara
*/
/* ====================================================================
* Copyright (c) 1999-2001 The OpenSSL Project. All rights reserved.
@@ -60,7 +61,6 @@
*/
#include "engine.h"
-#include "libp11.h"
#include <stdio.h>
#include <string.h>
#include <openssl/opensslv.h>
@@ -76,23 +76,13 @@
#define PKCS11_ENGINE_ID "pkcs11"
#define PKCS11_ENGINE_NAME "pkcs11 engine"
-#define CMD_SO_PATH ENGINE_CMD_BASE
-#define CMD_MODULE_PATH (ENGINE_CMD_BASE+1)
-#define CMD_PIN (ENGINE_CMD_BASE+2)
-#define CMD_VERBOSE (ENGINE_CMD_BASE+3)
-#define CMD_QUIET (ENGINE_CMD_BASE+4)
-#define CMD_LOAD_CERT_CTRL (ENGINE_CMD_BASE+5)
-#define CMD_INIT_ARGS (ENGINE_CMD_BASE+6)
-
-static int pkcs11_engine_destroy(ENGINE * e);
-static int pkcs11_engine_ctrl(ENGINE * e, int cmd, long i, void *p,
- void (*f) ());
+static int pkcs11_idx = -1;
/* The definitions for control commands specific to this engine */
/* need to add function to pass in reader id? or user reader:key as key id string? */
-static const ENGINE_CMD_DEFN pkcs11_cmd_defns[] = {
+static const ENGINE_CMD_DEFN engine_cmd_defns[] = {
{CMD_SO_PATH,
"SO_PATH",
"Specifies the path to the 'pkcs11-engine' shared library",
@@ -124,47 +114,98 @@ static const ENGINE_CMD_DEFN pkcs11_cmd_defns[] = {
{0, NULL, NULL, 0}
};
+static ENGINE_CTX *get_ctx(ENGINE *engine)
+{
+ ENGINE_CTX *ctx;
+
+ if (pkcs11_idx < 0) {
+ pkcs11_idx = ENGINE_get_ex_new_index(0, "libpkcs11", NULL, NULL, 0);
+ if (pkcs11_idx < 0)
+ return NULL;
+ ctx = NULL;
+ } else {
+ ctx = ENGINE_get_ex_data(engine, pkcs11_idx);
+ }
+ if (ctx == NULL) {
+ ctx = pkcs11_new();
+ ENGINE_set_ex_data(engine, pkcs11_idx, ctx);
+ }
+ return ctx;
+}
+
/* Destructor */
-static int pkcs11_engine_destroy(ENGINE * e)
+static int engine_destroy(ENGINE *engine)
{
- (void)e;
+ (void)engine;
return 1;
}
-static int pkcs11_engine_ctrl(ENGINE * e, int cmd, long i, void *p,
- void (*f) ())
+static int engine_init(ENGINE *engine)
{
- (void)i; /* We don't currently take integer parameters */
- (void)f; /* We don't currently take callback parameters */
- /*int initialised = ((pkcs11_dso == NULL) ? 0 : 1); */
- switch (cmd) {
- case CMD_MODULE_PATH:
- return set_module((const char *)p);
- case CMD_PIN:
- return set_pin((const char *)p);
- case CMD_VERBOSE:
- return inc_verbose();
- case CMD_LOAD_CERT_CTRL:
- return load_cert_ctrl(e, p);
- case CMD_INIT_ARGS:
- return set_init_args((const char *)p);
- default:
- break;
- }
- return 0;
+ ENGINE_CTX *ctx;
+
+ ctx = get_ctx(engine);
+ if (ctx == NULL)
+ return 0;
+ return pkcs11_init(ctx);
+}
+
+static int engine_finish(ENGINE *engine)
+{
+ ENGINE_CTX *ctx;
+ int rv;
+
+ ctx = get_ctx(engine);
+ if (ctx == NULL)
+ return 0;
+ rv = pkcs11_finish(ctx);
+ ENGINE_set_ex_data(engine, pkcs11_idx, NULL);
+ return rv;
+}
+
+static EVP_PKEY *load_pubkey(ENGINE *engine, const char *s_key_id,
+ UI_METHOD *ui_method, void *callback_data)
+{
+ ENGINE_CTX *ctx;
+
+ ctx = get_ctx(engine);
+ if (ctx == NULL)
+ return 0;
+ return pkcs11_load_public_key(ctx, s_key_id, ui_method, callback_data);
+}
+
+static EVP_PKEY *load_privkey(ENGINE *engine, const char *s_key_id,
+ UI_METHOD *ui_method, void *callback_data)
+{
+ ENGINE_CTX *ctx;
+
+ ctx = get_ctx(engine);
+ if (ctx == NULL)
+ return 0;
+ return pkcs11_load_private_key(ctx, s_key_id, ui_method, callback_data);
+}
+
+static int engine_ctrl(ENGINE *engine, int cmd, long i, void *p, void (*f) ())
+{
+ ENGINE_CTX *ctx;
+
+ ctx = get_ctx(engine);
+ if (ctx == NULL)
+ return 0;
+ return pkcs11_engine_ctrl(ctx, cmd, i, p, f);
}
/* This internal function is used by ENGINE_pkcs11() and possibly by the
* "dynamic" ENGINE support too */
-static int bind_helper(ENGINE * e)
+static int bind_helper(ENGINE *e)
{
if (!ENGINE_set_id(e, PKCS11_ENGINE_ID) ||
- !ENGINE_set_destroy_function(e, pkcs11_engine_destroy) ||
- !ENGINE_set_init_function(e, pkcs11_init) ||
- !ENGINE_set_finish_function(e, pkcs11_finish) ||
- !ENGINE_set_ctrl_function(e, pkcs11_engine_ctrl) ||
- !ENGINE_set_cmd_defns(e, pkcs11_cmd_defns) ||
+ !ENGINE_set_destroy_function(e, engine_destroy) ||
+ !ENGINE_set_init_function(e, engine_init) ||
+ !ENGINE_set_finish_function(e, engine_finish) ||
+ !ENGINE_set_ctrl_function(e, engine_ctrl) ||
+ !ENGINE_set_cmd_defns(e, engine_cmd_defns) ||
!ENGINE_set_name(e, PKCS11_ENGINE_NAME) ||
#ifndef OPENSSL_NO_RSA
!ENGINE_set_RSA(e, PKCS11_get_rsa_method()) ||
@@ -179,8 +220,8 @@ static int bind_helper(ENGINE * e)
!ENGINE_set_EC(e, PKCS11_get_ec_key_method()) ||
#endif /* OPENSSL_NO_EC */
#endif /* OPENSSL_VERSION_NUMBER */
- !ENGINE_set_load_pubkey_function(e, pkcs11_load_public_key) ||
- !ENGINE_set_load_privkey_function(e, pkcs11_load_private_key)) {
+ !ENGINE_set_load_pubkey_function(e, load_pubkey) ||
+ !ENGINE_set_load_privkey_function(e, load_privkey)) {
return 0;
} else {
return 1;
diff --git a/src/eng_parse.c b/src/eng_parse.c
new file mode 100644
index 0000000..db5279f
--- /dev/null
+++ b/src/eng_parse.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2001 Markus Friedl
+ * Copyright (c) 2002 Juha Yrjölä
+ * Copyright (c) 2002 Olaf Kirch
+ * Copyright (c) 2003 Kevin Stefanik
+ * Copyright (c) 2016 Michał Trojnara
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "engine.h"
+#include <stdio.h>
+#include <string.h>
+
+static int hex_to_bin(const char *in, unsigned char *out, size_t * outlen)
+{
+ size_t left, count = 0;
+
+ if (in == NULL || *in == '\0') {
+ *outlen = 0;
+ return 1;
+ }
+
+ left = *outlen;
+
+ while (*in != '\0') {
+ int byte = 0, nybbles = 2;
+
+ while (nybbles-- && *in && *in != ':') {
+ char c;
+ 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 {
+ fprintf(stderr,
+ "hex_to_bin(): invalid char '%c' in hex string\n",
+ c);
+ *outlen = 0;
+ return 0;
+ }
+ byte |= c;
+ }
+ if (*in == ':')
+ in++;
+ if (left <= 0) {
+ fprintf(stderr, "hex_to_bin(): hex string too long\n");
+ *outlen = 0;
+ return 0;
+ }
+ out[count++] = (unsigned char)byte;
+ left--;
+ }
+
+ *outlen = count;
+ return 1;
+}
+
+/* parse string containing slot and id information */
+int parse_slot_id_string(const char *slot_id, int *slot,
+ unsigned char *id, size_t * id_len, char **label)
+{
+ int n, i;
+
+ if (slot_id == NULL)
+ return 0;
+
+ /* support for several formats */
+#define HEXDIGITS "01234567890ABCDEFabcdef"
+#define DIGITS "0123456789"
+
+ /* first: pure hex number (id, slot is undefined) */
+ if (strspn(slot_id, HEXDIGITS) == strlen(slot_id)) {
+ /* ah, easiest case: only hex. */
+ if ((strlen(slot_id) + 1) / 2 > *id_len) {
+ fprintf(stderr, "ID string too long!\n");
+ return 0;
+ }
+ *slot = -1;
+ return hex_to_bin(slot_id, id, id_len);
+ }
+
+ /* second: slot:id. slot is an digital int. */
+ if (sscanf(slot_id, "%d", &n) == 1) {
+ i = strspn(slot_id, DIGITS);
+
+ if (slot_id[i] != ':') {
+ fprintf(stderr, "Could not parse string!\n");
+ return 0;
+ }
+ i++;
+ if (slot_id[i] == 0) {
+ *slot = n;
+ *id_len = 0;
+ return 1;
+ }
+ if (strspn(slot_id + i, HEXDIGITS) + i != strlen(slot_id)) {
+ fprintf(stderr, "Could not parse string!\n");
+ return 0;
+ }
+ /* ah, rest is hex */
+ if ((strlen(slot_id) - i + 1) / 2 > *id_len) {
+ fprintf(stderr, "ID string too long!\n");
+ return 0;
+ }
+ *slot = n;
+ return hex_to_bin(slot_id + i, id, id_len);
+ }
+
+ /* third: id_<id>, slot is undefined */
+ if (strncmp(slot_id, "id_", 3) == 0) {
+ if (strspn(slot_id + 3, HEXDIGITS) + 3 != strlen(slot_id)) {
+ fprintf(stderr, "Could not parse string!\n");
+ return 0;
+ }
+ /* ah, rest is hex */
+ if ((strlen(slot_id) - 3 + 1) / 2 > *id_len) {
+ fprintf(stderr, "ID string too long!\n");
+ return 0;
+ }
+ *slot = -1;
+ return hex_to_bin(slot_id + 3, id, id_len);
+ }
+
+ /* label_<label>, slot is undefined */
+ if (strncmp(slot_id, "label_", 6) == 0) {
+ *slot = -1;
+ *label = strdup(slot_id + 6);
+ return *label != NULL;
+ }
+
+ /* last try: it has to be slot_<slot> and then "-id_<cert>" */
+
+ if (strncmp(slot_id, "slot_", 5) != 0) {
+ fprintf(stderr, "Format not recognized!\n");
+ return 0;
+ }
+
+ /* slot is an digital int. */
+ if (sscanf(slot_id + 5, "%d", &n) != 1) {
+ fprintf(stderr, "Could not decode slot number!\n");
+ return 0;
+ }
+
+ i = strspn(slot_id + 5, DIGITS);
+
+ if (slot_id[i + 5] == 0) {
+ *slot = n;
+ *id_len = 0;
+ return 1;
+ }
+
+ if (slot_id[i + 5] != '-') {
+ fprintf(stderr, "Could not parse string!\n");
+ return 0;
+ }
+
+ i = 5 + i + 1;
+
+ /* now followed by "id_" */
+ if (strncmp(slot_id + i, "id_", 3) == 0) {
+ if (strspn(slot_id + i + 3, HEXDIGITS) + 3 + i != strlen(slot_id)) {
+ fprintf(stderr, "Could not parse string!\n");
+ return 0;
+ }
+ /* ah, rest is hex */
+ if ((strlen(slot_id) - i - 3 + 1) / 2 > *id_len) {
+ fprintf(stderr, "ID string too long!\n");
+ return 0;
+ }
+ *slot = n;
+ return hex_to_bin(slot_id + i + 3, id, id_len);
+ }
+
+ /* ... or "label_" */
+ if (strncmp(slot_id + i, "label_", 6) == 0) {
+ *slot = n;
+ return (*label = strdup(slot_id + i + 6)) != NULL;
+ }
+
+ fprintf(stderr, "Could not parse string!\n");
+ return 0;
+}
+
+static int parse_uri_attr(const char *attr, int attrlen, unsigned char **field,
+ size_t *field_len)
+{
+ size_t max, outlen = 0;
+ unsigned char *out;
+ int ret = 1;
+
+ if (field_len) {
+ out = *field;
+ max = *field_len;
+ } else {
+ out = malloc(attrlen + 1);
+ if (out == NULL)
+ return 0;
+ max = attrlen + 1;
+ }
+
+ while (ret && attrlen && outlen < max) {
+ if (*attr == '%') {
+ if (attrlen < 3) {
+ ret = 0;
+ } else {
+ char tmp[3];
+ size_t l = 1;
+
+ tmp[0] = attr[1];
+ tmp[1] = attr[2];
+ tmp[2] = 0;
+ ret = hex_to_bin(tmp, &out[outlen++], &l);
+ attrlen -= 3;
+ attr += 3;
+ }
+
+ } else {
+ out[outlen++] = *(attr++);
+ attrlen--;
+ }
+ }
+ if (attrlen && outlen == max)
+ ret = 0;
+
+ if (ret) {
+ if (field_len) {
+ *field_len = outlen;
+ } else {
+ out[outlen] = 0;
+ *field = out;
+ }
+ } else {
+ if (field_len == NULL)
+ free(out);
+ }
+
+ return ret;
+}
+
+int parse_pkcs11_uri(const char *uri, PKCS11_TOKEN **p_tok,
+ unsigned char *id, size_t *id_len, char *pin, size_t *pin_len,
+ char **label)
+{
+ PKCS11_TOKEN *tok;
+ char *newlabel = NULL;
+ const char *end, *p;
+ int rv = 1, pin_set = 0;
+
+ tok = calloc(1, sizeof(*tok));
+ if (tok == NULL) {
+ fprintf(stderr, "Could not allocate memory for token info\n");
+ return 0;
+ }
+
+ /* We are only ever invoked if the string starts with 'pkcs11:' */
+ end = uri + 6;
+ while (rv && end[0] && end[1]) {
+ p = end + 1;
+ end = strchr(p, ';');
+ if (end == NULL)
+ end = p + strlen(p);
+
+ if (!strncmp(p, "model=", 6)) {
+ p += 6;
+ rv = parse_uri_attr(p, end - p, (void *)&tok->model, NULL);
+ } else if (!strncmp(p, "manufacturer=", 13)) {
+ p += 13;
+ rv = parse_uri_attr(p, end - p, (void *)&tok->manufacturer, NULL);
+ } else if (!strncmp(p, "token=", 6)) {
+ p += 6;
+ rv = parse_uri_attr(p, end - p, (void *)&tok->label, NULL);
+ } else if (!strncmp(p, "serial=", 7)) {
+ p += 7;
+ rv = parse_uri_attr(p, end - p, (void *)&tok->serialnr, NULL);
+ } else if (!strncmp(p, "object=", 7)) {
+ p += 7;
+ rv = parse_uri_attr(p, end - p, (void *)&newlabel, NULL);
+ } else if (!strncmp(p, "id=", 3)) {
+ p += 3;
+ rv = parse_uri_attr(p, end - p, (void *)&id, id_len);
+ } else if (!strncmp(p, "pin-value=", 10)) {
+ p += 10;
+ rv = parse_uri_attr(p, end - p, (void *)&pin, pin_len);
+ pin_set = 1;
+ } else if (!strncmp(p, "type=", 5) || !strncmp(p, "object-type=", 12)) {
+ p = strchr(p, '=') + 1;
+
+ if ((end - p == 4 && !strncmp(p, "cert", 4)) ||
+ (end - p == 6 && !strncmp(p, "public", 6)) ||
+ (end - p == 7 && !strncmp(p, "private", 7))) {
+ /* Actually, just ignore it */
+ } else {
+ fprintf(stderr, "Unknown object type\n");
+ rv = 0;
+ }
+ } else {
+ rv = 0;
+ }
+ }
+
+ if (!pin_set)
+ *pin_len = 0;
+
+ if (rv) {
+ *label = newlabel;
+ *p_tok = tok;
+ } else {
+ free(tok);
+ tok = NULL;
+ free(newlabel);
+ }
+
+ return rv;
+}
+/* vim: set noexpandtab: */
diff --git a/src/engine.h b/src/engine.h
index 3261a22..bd57479 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -1,7 +1,8 @@
/*
- * Copyright (c) 2002 Juha Yrjölä. All rights reserved.
- * Copyright (c) 2001 Markus Friedl.
+ * Copyright (c) 2001 Markus Friedl
+ * Copyright (c) 2002 Juha Yrjölä
* Copyright (c) 2003 Kevin Stefanik
+ * Copyright (c) 2016 Michał Trojnara
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,34 +32,48 @@
#include "config.h"
#endif
+#include "libp11.h"
#include <stdio.h>
#include <string.h>
#include <openssl/crypto.h>
#include <openssl/objects.h>
#include <openssl/engine.h>
-int set_module(const char *modulename);
+#define CMD_SO_PATH ENGINE_CMD_BASE
+#define CMD_MODULE_PATH (ENGINE_CMD_BASE+1)
+#define CMD_PIN (ENGINE_CMD_BASE+2)
+#define CMD_VERBOSE (ENGINE_CMD_BASE+3)
+#define CMD_QUIET (ENGINE_CMD_BASE+4)
+#define CMD_LOAD_CERT_CTRL (ENGINE_CMD_BASE+5)
+#define CMD_INIT_ARGS (ENGINE_CMD_BASE+6)
-int set_pin(const char *pin);
+typedef struct st_engine_ctx ENGINE_CTX; /* opaque */
-int set_init_args(const char *init_args_orig);
+/* defined in eng_back.c */
-int load_cert_ctrl(ENGINE * e, void *p);
+ENGINE_CTX *pkcs11_new();
-int inc_verbose(void);
+int pkcs11_init(ENGINE_CTX *ctx);
-int pkcs11_finish(ENGINE * engine);
+int pkcs11_finish(ENGINE_CTX *ctx);
-int pkcs11_init(ENGINE * engine);
+int pkcs11_engine_ctrl(ENGINE_CTX *ctx, int cmd, long i, void *p, void (*f)());
-int pkcs11_rsa_finish(RSA * rsa);
-
-EVP_PKEY *pkcs11_load_public_key(ENGINE * e, const char *s_key_id,
+EVP_PKEY *pkcs11_load_public_key(ENGINE_CTX *ctx, const char *s_key_id,
UI_METHOD * ui_method, void *callback_data);
-EVP_PKEY *pkcs11_load_private_key(ENGINE * e, const char *s_key_id,
+EVP_PKEY *pkcs11_load_private_key(ENGINE_CTX *ctx, const char *s_key_id,
UI_METHOD * ui_method, void *callback_data);
+/* defined in eng_parse.c */
+
+int parse_pkcs11_uri(const char *uri, PKCS11_TOKEN **p_tok,
+ unsigned char *id, size_t *id_len, char *pin, size_t *pin_len,
+ char **label);
+
+int parse_slot_id_string(const char *slot_id, int *slot,
+ unsigned char *id, size_t * id_len, char **label);
+
#endif
/* vim: set noexpandtab: */
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-opensc/libp11.git
More information about the pkg-opensc-commit
mailing list