While implementing the new unit testing framework cmocka, it was found that the BIND 9 code doesn't compile when assertions are disabled or replaced with any function (such as mock_assert() from cmocka unit testing framework) that's not directly recognized as assertion by the compiler. This made the compiler to complain about blocks of code that was recognized as unreachable before, but now it isn't. The changes in this commit include: * assigns default values to couple of local variables, * moves some return statements around INSIST assertions, * adds __builtin_unreachable(); annotations after some INSIST assertions, * fixes one broken assertion (= instead of ==) (cherry picked from commitfbd2e47f51) (cherry picked from commitb222783ae9)
1401 lines
33 KiB
C
1401 lines
33 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
#include <inttypes.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <isc/log.h>
|
|
#include <isc/mem.h>
|
|
#include <isc/once.h>
|
|
#include <isc/platform.h>
|
|
#include <isc/print.h>
|
|
#include <isc/stdio.h>
|
|
#include <isc/string.h>
|
|
#include <isc/thread.h>
|
|
#include <isc/util.h>
|
|
|
|
#include <dst/result.h>
|
|
|
|
#include <pk11/pk11.h>
|
|
#include <pk11/internal.h>
|
|
#include <pk11/result.h>
|
|
#include <pk11/site.h>
|
|
|
|
#include <pkcs11/cryptoki.h>
|
|
#include <pkcs11/pkcs11.h>
|
|
#include <pkcs11/eddsa.h>
|
|
|
|
/* was 32 octets, Petr Spacek suggested 1024, SoftHSMv2 uses 256... */
|
|
#ifndef PINLEN
|
|
#define PINLEN 256
|
|
#endif
|
|
|
|
#ifndef PK11_NO_LOGERR
|
|
#define PK11_NO_LOGERR 1
|
|
#endif
|
|
|
|
LIBISC_EXTERNAL_DATA bool pk11_verbose_init = false;
|
|
|
|
static isc_once_t once = ISC_ONCE_INIT;
|
|
static isc_mem_t *pk11_mctx = NULL;
|
|
static int32_t allocsize = 0;
|
|
static bool initialized = false;
|
|
|
|
typedef struct pk11_session pk11_session_t;
|
|
typedef struct pk11_token pk11_token_t;
|
|
typedef ISC_LIST(pk11_session_t) pk11_sessionlist_t;
|
|
|
|
struct pk11_session {
|
|
unsigned int magic;
|
|
CK_SESSION_HANDLE session;
|
|
ISC_LINK(pk11_session_t) link;
|
|
pk11_token_t *token;
|
|
};
|
|
|
|
struct pk11_token {
|
|
unsigned int magic;
|
|
unsigned int operations;
|
|
ISC_LINK(pk11_token_t) link;
|
|
CK_SLOT_ID slotid;
|
|
pk11_sessionlist_t sessions;
|
|
bool logged;
|
|
char name[32];
|
|
char manuf[32];
|
|
char model[16];
|
|
char serial[16];
|
|
char pin[PINLEN + 1];
|
|
};
|
|
static ISC_LIST(pk11_token_t) tokens;
|
|
|
|
static pk11_token_t *rand_token;
|
|
static pk11_token_t *best_rsa_token;
|
|
static pk11_token_t *best_dsa_token;
|
|
static pk11_token_t *best_dh_token;
|
|
static pk11_token_t *digest_token;
|
|
static pk11_token_t *best_ec_token;
|
|
static pk11_token_t *best_gost_token;
|
|
static pk11_token_t *aes_token;
|
|
|
|
static isc_result_t free_all_sessions(void);
|
|
static isc_result_t free_session_list(pk11_sessionlist_t *slist);
|
|
static isc_result_t setup_session(pk11_session_t *sp,
|
|
pk11_token_t *token,
|
|
bool rw);
|
|
static void scan_slots(void);
|
|
static isc_result_t token_login(pk11_session_t *sp);
|
|
static char *percent_decode(char *x, size_t *len);
|
|
static bool pk11strcmp(const char *x, size_t lenx,
|
|
const char *y, size_t leny);
|
|
static CK_ATTRIBUTE *push_attribute(pk11_object_t *obj,
|
|
isc_mem_t *mctx,
|
|
size_t len);
|
|
|
|
static isc_mutex_t alloclock;
|
|
static isc_mutex_t sessionlock;
|
|
|
|
static pk11_sessionlist_t actives;
|
|
|
|
static CK_C_INITIALIZE_ARGS pk11_init_args = {
|
|
NULL_PTR, /* CreateMutex */
|
|
NULL_PTR, /* DestroyMutex */
|
|
NULL_PTR, /* LockMutex */
|
|
NULL_PTR, /* UnlockMutex */
|
|
CKF_OS_LOCKING_OK, /* flags */
|
|
NULL_PTR, /* pReserved */
|
|
};
|
|
|
|
#ifndef PK11_LIB_LOCATION
|
|
#define PK11_LIB_LOCATION "unknown_provider"
|
|
#endif
|
|
|
|
#ifndef WIN32
|
|
static const char *lib_name = PK11_LIB_LOCATION;
|
|
#else
|
|
static const char *lib_name = PK11_LIB_LOCATION ".dll";
|
|
#endif
|
|
|
|
void
|
|
pk11_set_lib_name(const char *name) {
|
|
lib_name = name;
|
|
}
|
|
|
|
const char *
|
|
pk11_get_lib_name(void) {
|
|
return (lib_name);
|
|
}
|
|
|
|
static void
|
|
initialize(void) {
|
|
char *pk11_provider;
|
|
|
|
RUNTIME_CHECK(isc_mutex_init(&alloclock) == ISC_R_SUCCESS);
|
|
RUNTIME_CHECK(isc_mutex_init(&sessionlock) == ISC_R_SUCCESS);
|
|
|
|
pk11_provider = getenv("PKCS11_PROVIDER");
|
|
if (pk11_provider != NULL)
|
|
lib_name = pk11_provider;
|
|
}
|
|
|
|
void *
|
|
pk11_mem_get(size_t size) {
|
|
void *ptr;
|
|
|
|
LOCK(&alloclock);
|
|
if (pk11_mctx != NULL)
|
|
ptr = isc_mem_get(pk11_mctx, size);
|
|
else {
|
|
ptr = malloc(size);
|
|
if (ptr != NULL)
|
|
allocsize += (int)size;
|
|
}
|
|
UNLOCK(&alloclock);
|
|
|
|
if (ptr != NULL)
|
|
memset(ptr, 0, size);
|
|
return (ptr);
|
|
}
|
|
|
|
void
|
|
pk11_mem_put(void *ptr, size_t size) {
|
|
if (ptr != NULL)
|
|
memset(ptr, 0, size);
|
|
LOCK(&alloclock);
|
|
if (pk11_mctx != NULL)
|
|
isc_mem_put(pk11_mctx, ptr, size);
|
|
else {
|
|
if (ptr != NULL)
|
|
allocsize -= (int)size;
|
|
free(ptr);
|
|
}
|
|
UNLOCK(&alloclock);
|
|
}
|
|
|
|
isc_result_t
|
|
pk11_initialize(isc_mem_t *mctx, const char *engine) {
|
|
isc_result_t result = ISC_R_SUCCESS;
|
|
CK_RV rv;
|
|
|
|
RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
|
|
|
|
LOCK(&sessionlock);
|
|
LOCK(&alloclock);
|
|
if ((mctx != NULL) && (pk11_mctx == NULL) && (allocsize == 0))
|
|
isc_mem_attach(mctx, &pk11_mctx);
|
|
UNLOCK(&alloclock);
|
|
if (initialized) {
|
|
goto unlock;
|
|
} else {
|
|
initialized = true;
|
|
}
|
|
|
|
ISC_LIST_INIT(tokens);
|
|
ISC_LIST_INIT(actives);
|
|
|
|
if (engine != NULL)
|
|
lib_name = engine;
|
|
|
|
/* Initialize the CRYPTOKI library */
|
|
rv = pkcs_C_Initialize((CK_VOID_PTR) &pk11_init_args);
|
|
|
|
if (rv == 0xfe) {
|
|
result = PK11_R_NOPROVIDER;
|
|
fprintf(stderr, "Can't load PKCS#11 provider: %s\n",
|
|
pk11_get_load_error_message());
|
|
goto unlock;
|
|
}
|
|
if (rv != CKR_OK) {
|
|
result = PK11_R_INITFAILED;
|
|
goto unlock;
|
|
}
|
|
|
|
scan_slots();
|
|
#ifdef PKCS11CRYPTO
|
|
if (rand_token == NULL) {
|
|
result = PK11_R_NORANDOMSERVICE;
|
|
goto unlock;
|
|
}
|
|
if (digest_token == NULL) {
|
|
result = PK11_R_NODIGESTSERVICE;
|
|
goto unlock;
|
|
}
|
|
#if defined(AES_CC)
|
|
if (aes_token == NULL) {
|
|
result = PK11_R_NOAESSERVICE;
|
|
goto unlock;
|
|
}
|
|
#endif
|
|
#endif /* PKCS11CRYPTO */
|
|
unlock:
|
|
UNLOCK(&sessionlock);
|
|
return (result);
|
|
}
|
|
|
|
isc_result_t
|
|
pk11_finalize(void) {
|
|
pk11_token_t *token, *next;
|
|
isc_result_t ret;
|
|
|
|
ret = free_all_sessions();
|
|
(void) pkcs_C_Finalize(NULL_PTR);
|
|
token = ISC_LIST_HEAD(tokens);
|
|
while (token != NULL) {
|
|
next = ISC_LIST_NEXT(token, link);
|
|
ISC_LIST_UNLINK(tokens, token, link);
|
|
if (token == rand_token)
|
|
rand_token = NULL;
|
|
if (token == best_rsa_token)
|
|
best_rsa_token = NULL;
|
|
if (token == best_dsa_token)
|
|
best_dsa_token = NULL;
|
|
if (token == best_dh_token)
|
|
best_dh_token = NULL;
|
|
if (token == digest_token)
|
|
digest_token = NULL;
|
|
if (token == best_ec_token)
|
|
best_ec_token = NULL;
|
|
if (token == best_gost_token)
|
|
best_gost_token = NULL;
|
|
if (token == aes_token)
|
|
aes_token = NULL;
|
|
pk11_mem_put(token, sizeof(*token));
|
|
token = next;
|
|
}
|
|
if (pk11_mctx != NULL)
|
|
isc_mem_detach(&pk11_mctx);
|
|
initialized = false;
|
|
return (ret);
|
|
}
|
|
|
|
isc_result_t
|
|
pk11_rand_bytes(unsigned char *buf, int num) {
|
|
isc_result_t ret;
|
|
CK_RV rv;
|
|
pk11_context_t ctx;
|
|
|
|
ret = pk11_get_session(&ctx, OP_RAND, false, false,
|
|
false, NULL, 0);
|
|
if ((ret != ISC_R_SUCCESS) &&
|
|
(ret != PK11_R_NODIGESTSERVICE) &&
|
|
(ret != PK11_R_NOAESSERVICE))
|
|
return (ret);
|
|
RUNTIME_CHECK(ctx.session != CK_INVALID_HANDLE);
|
|
rv = pkcs_C_GenerateRandom(ctx.session,
|
|
(CK_BYTE_PTR) buf, (CK_ULONG) num);
|
|
pk11_return_session(&ctx);
|
|
if (rv == CKR_OK)
|
|
return (ISC_R_SUCCESS);
|
|
else
|
|
return (DST_R_CRYPTOFAILURE);
|
|
}
|
|
|
|
#define SEEDSIZE 1024
|
|
|
|
static CK_BYTE seed[SEEDSIZE];
|
|
|
|
void
|
|
pk11_rand_seed_fromfile(const char *randomfile) {
|
|
pk11_context_t ctx;
|
|
FILE *stream = NULL;
|
|
size_t cc = 0;
|
|
isc_result_t ret;
|
|
|
|
ret = pk11_get_session(&ctx, OP_RAND, false, false,
|
|
false, NULL, 0);
|
|
if ((ret != ISC_R_SUCCESS) &&
|
|
(ret != PK11_R_NODIGESTSERVICE) &&
|
|
(ret != PK11_R_NOAESSERVICE))
|
|
return;
|
|
RUNTIME_CHECK(ctx.session != CK_INVALID_HANDLE);
|
|
ret = isc_stdio_open(randomfile, "r", &stream);
|
|
if (ret != ISC_R_SUCCESS)
|
|
goto cleanup;
|
|
ret = isc_stdio_read(seed, 1, SEEDSIZE, stream, &cc);
|
|
if (ret!= ISC_R_SUCCESS)
|
|
goto cleanup;
|
|
ret = isc_stdio_close(stream);
|
|
stream = NULL;
|
|
if (ret!= ISC_R_SUCCESS)
|
|
goto cleanup;
|
|
(void) pkcs_C_SeedRandom(ctx.session, seed, (CK_ULONG) cc);
|
|
|
|
cleanup:
|
|
if (stream != NULL)
|
|
(void) isc_stdio_close(stream);
|
|
pk11_return_session(&ctx);
|
|
}
|
|
|
|
isc_result_t
|
|
pk11_get_session(pk11_context_t *ctx, pk11_optype_t optype,
|
|
bool need_services, bool rw,
|
|
bool logon, const char *pin, CK_SLOT_ID slot)
|
|
{
|
|
pk11_token_t *token = NULL;
|
|
pk11_sessionlist_t *freelist;
|
|
pk11_session_t *sp;
|
|
isc_result_t ret;
|
|
#ifdef PKCS11CRYPTO
|
|
isc_result_t service_ret = ISC_R_SUCCESS;
|
|
#else
|
|
UNUSED(need_services);
|
|
#endif
|
|
|
|
memset(ctx, 0, sizeof(pk11_context_t));
|
|
ctx->handle = NULL;
|
|
ctx->session = CK_INVALID_HANDLE;
|
|
|
|
ret = pk11_initialize(NULL, NULL);
|
|
#ifdef PKCS11CRYPTO
|
|
if (ret == PK11_R_NORANDOMSERVICE ||
|
|
ret == PK11_R_NODIGESTSERVICE ||
|
|
ret == PK11_R_NOAESSERVICE) {
|
|
if (need_services)
|
|
return (ret);
|
|
service_ret = ret;
|
|
}
|
|
else
|
|
#endif /* PKCS11CRYPTO */
|
|
if (ret != ISC_R_SUCCESS)
|
|
return (ret);
|
|
|
|
LOCK(&sessionlock);
|
|
/* wait for initialization to finish */
|
|
UNLOCK(&sessionlock);
|
|
|
|
switch(optype) {
|
|
#ifdef PKCS11CRYPTO
|
|
case OP_RAND:
|
|
token = rand_token;
|
|
break;
|
|
case OP_DIGEST:
|
|
token = digest_token;
|
|
break;
|
|
case OP_AES:
|
|
token = aes_token;
|
|
break;
|
|
case OP_ANY:
|
|
for (token = ISC_LIST_HEAD(tokens);
|
|
token != NULL;
|
|
token = ISC_LIST_NEXT(token, link))
|
|
if (token->slotid == slot)
|
|
break;
|
|
break;
|
|
#endif
|
|
default:
|
|
for (token = ISC_LIST_HEAD(tokens);
|
|
token != NULL;
|
|
token = ISC_LIST_NEXT(token, link))
|
|
if (token->slotid == slot)
|
|
break;
|
|
#ifdef PKCS11CRYPTO
|
|
if ((token == NULL) ||
|
|
((token->operations & (1 << optype)) == 0))
|
|
return (ISC_R_NOTFOUND);
|
|
#endif
|
|
break;
|
|
}
|
|
if (token == NULL)
|
|
return (ISC_R_NOTFOUND);
|
|
|
|
/* Override the token's PIN */
|
|
if (logon && pin != NULL && *pin != '\0') {
|
|
if (strlen(pin) > PINLEN)
|
|
return (ISC_R_RANGE);
|
|
/*
|
|
* We want to zero out the old pin before
|
|
* overwriting with a new one.
|
|
*/
|
|
memset(token->pin, 0, sizeof(token->pin));
|
|
strlcpy(token->pin, pin, sizeof(token->pin));
|
|
}
|
|
|
|
freelist = &token->sessions;
|
|
|
|
LOCK(&sessionlock);
|
|
sp = ISC_LIST_HEAD(*freelist);
|
|
if (sp != NULL) {
|
|
ISC_LIST_UNLINK(*freelist, sp, link);
|
|
ISC_LIST_APPEND(actives, sp, link);
|
|
UNLOCK(&sessionlock);
|
|
if (logon)
|
|
ret = token_login(sp);
|
|
ctx->handle = sp;
|
|
ctx->session = sp->session;
|
|
return (ret);
|
|
}
|
|
UNLOCK(&sessionlock);
|
|
|
|
sp = pk11_mem_get(sizeof(*sp));
|
|
if (sp == NULL)
|
|
return (ISC_R_NOMEMORY);
|
|
sp->magic = SES_MAGIC;
|
|
sp->token = token;
|
|
sp->session = CK_INVALID_HANDLE;
|
|
ISC_LINK_INIT(sp, link);
|
|
ret = setup_session(sp, token, rw);
|
|
if ((ret == ISC_R_SUCCESS) && logon)
|
|
ret = token_login(sp);
|
|
LOCK(&sessionlock);
|
|
ISC_LIST_APPEND(actives, sp, link);
|
|
UNLOCK(&sessionlock);
|
|
ctx->handle = sp;
|
|
ctx->session = sp->session;
|
|
#ifdef PKCS11CRYPTO
|
|
if (ret == ISC_R_SUCCESS)
|
|
ret = service_ret;
|
|
#endif
|
|
return (ret);
|
|
}
|
|
|
|
void
|
|
pk11_return_session(pk11_context_t *ctx) {
|
|
pk11_session_t *sp = (pk11_session_t *) ctx->handle;
|
|
|
|
if (sp == NULL)
|
|
return;
|
|
ctx->handle = NULL;
|
|
ctx->session = CK_INVALID_HANDLE;
|
|
|
|
LOCK(&sessionlock);
|
|
ISC_LIST_UNLINK(actives, sp, link);
|
|
UNLOCK(&sessionlock);
|
|
if (sp->session == CK_INVALID_HANDLE) {
|
|
pk11_mem_put(sp, sizeof(*sp));
|
|
return;
|
|
}
|
|
|
|
LOCK(&sessionlock);
|
|
ISC_LIST_APPEND(sp->token->sessions, sp, link);
|
|
UNLOCK(&sessionlock);
|
|
}
|
|
|
|
static isc_result_t
|
|
free_all_sessions(void) {
|
|
pk11_token_t *token;
|
|
isc_result_t ret = ISC_R_SUCCESS;
|
|
isc_result_t oret;
|
|
|
|
for (token = ISC_LIST_HEAD(tokens);
|
|
token != NULL;
|
|
token = ISC_LIST_NEXT(token, link)) {
|
|
oret = free_session_list(&token->sessions);
|
|
if (oret != ISC_R_SUCCESS)
|
|
ret = oret;
|
|
}
|
|
if (!ISC_LIST_EMPTY(actives)) {
|
|
ret = ISC_R_ADDRINUSE;
|
|
oret = free_session_list(&actives);
|
|
if (oret != ISC_R_SUCCESS)
|
|
ret = oret;
|
|
}
|
|
return (ret);
|
|
}
|
|
|
|
static isc_result_t
|
|
free_session_list(pk11_sessionlist_t *slist) {
|
|
pk11_session_t *sp;
|
|
CK_RV rv;
|
|
isc_result_t ret;
|
|
|
|
ret = ISC_R_SUCCESS;
|
|
LOCK(&sessionlock);
|
|
while (!ISC_LIST_EMPTY(*slist)) {
|
|
sp = ISC_LIST_HEAD(*slist);
|
|
ISC_LIST_UNLINK(*slist, sp, link);
|
|
UNLOCK(&sessionlock);
|
|
if (sp->session != CK_INVALID_HANDLE) {
|
|
rv = pkcs_C_CloseSession(sp->session);
|
|
if (rv != CKR_OK)
|
|
ret = DST_R_CRYPTOFAILURE;
|
|
}
|
|
LOCK(&sessionlock);
|
|
pk11_mem_put(sp, sizeof(*sp));
|
|
}
|
|
UNLOCK(&sessionlock);
|
|
|
|
return (ret);
|
|
}
|
|
|
|
static isc_result_t
|
|
setup_session(pk11_session_t *sp, pk11_token_t *token,
|
|
bool rw)
|
|
{
|
|
CK_RV rv;
|
|
CK_FLAGS flags = CKF_SERIAL_SESSION;
|
|
|
|
if (rw)
|
|
flags += CKF_RW_SESSION;
|
|
|
|
rv = pkcs_C_OpenSession(token->slotid, flags, NULL_PTR,
|
|
NULL_PTR, &sp->session);
|
|
if (rv != CKR_OK)
|
|
return (DST_R_CRYPTOFAILURE);
|
|
return (ISC_R_SUCCESS);
|
|
}
|
|
|
|
static isc_result_t
|
|
token_login(pk11_session_t *sp) {
|
|
CK_RV rv;
|
|
pk11_token_t *token = sp->token;
|
|
isc_result_t ret = ISC_R_SUCCESS;
|
|
|
|
LOCK(&sessionlock);
|
|
if (!token->logged) {
|
|
rv = pkcs_C_Login(sp->session, CKU_USER,
|
|
(CK_UTF8CHAR_PTR) token->pin,
|
|
(CK_ULONG) strlen(token->pin));
|
|
if (rv != CKR_OK) {
|
|
ret = ISC_R_NOPERM;
|
|
#if PK11_NO_LOGERR
|
|
pk11_error_fatalcheck(__FILE__, __LINE__,
|
|
"pkcs_C_Login", rv);
|
|
#endif
|
|
} else
|
|
token->logged = true;
|
|
}
|
|
UNLOCK(&sessionlock);
|
|
return (ret);
|
|
}
|
|
|
|
#define PK11_TRACE(fmt) \
|
|
if (pk11_verbose_init) fprintf(stderr, fmt)
|
|
#define PK11_TRACE1(fmt, arg) \
|
|
if (pk11_verbose_init) fprintf(stderr, fmt, arg)
|
|
#define PK11_TRACE2(fmt, arg1, arg2) \
|
|
if (pk11_verbose_init) fprintf(stderr, fmt, arg1, arg2)
|
|
#define PK11_TRACEM(mech) \
|
|
if (pk11_verbose_init) fprintf(stderr, #mech ": 0x%lx\n", rv)
|
|
|
|
static void
|
|
scan_slots(void) {
|
|
CK_MECHANISM_INFO mechInfo;
|
|
CK_TOKEN_INFO tokenInfo;
|
|
CK_RV rv;
|
|
CK_SLOT_ID slot;
|
|
CK_SLOT_ID_PTR slotList;
|
|
CK_ULONG slotCount;
|
|
pk11_token_t *token;
|
|
unsigned int i;
|
|
bool bad;
|
|
|
|
slotCount = 0;
|
|
PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, NULL_PTR, &slotCount));
|
|
PK11_TRACE1("slotCount=%lu\n", slotCount);
|
|
/* it's not an error if we didn't find any providers */
|
|
if (slotCount == 0)
|
|
return;
|
|
slotList = pk11_mem_get(sizeof(CK_SLOT_ID) * slotCount);
|
|
RUNTIME_CHECK(slotList != NULL);
|
|
PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, slotList, &slotCount));
|
|
|
|
for (i = 0; i < slotCount; i++) {
|
|
slot = slotList[i];
|
|
PK11_TRACE2("slot#%u=0x%lx\n", i, slot);
|
|
|
|
rv = pkcs_C_GetTokenInfo(slot, &tokenInfo);
|
|
if (rv != CKR_OK)
|
|
continue;
|
|
token = pk11_mem_get(sizeof(*token));
|
|
RUNTIME_CHECK(token != NULL);
|
|
token->magic = TOK_MAGIC;
|
|
token->slotid = slot;
|
|
ISC_LINK_INIT(token, link);
|
|
ISC_LIST_INIT(token->sessions);
|
|
memmove(token->name, tokenInfo.label, 32);
|
|
memmove(token->manuf, tokenInfo.manufacturerID, 32);
|
|
memmove(token->model, tokenInfo.model, 16);
|
|
memmove(token->serial, tokenInfo.serialNumber, 16);
|
|
ISC_LIST_APPEND(tokens, token, link);
|
|
if ((tokenInfo.flags & CKF_RNG) == 0) {
|
|
PK11_TRACE("no CKF_RNG\n");
|
|
goto try_rsa;
|
|
}
|
|
token->operations |= 1 << OP_RAND;
|
|
if (rand_token == NULL)
|
|
rand_token = token;
|
|
|
|
try_rsa:
|
|
bad = false;
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
|
|
&mechInfo);
|
|
if ((rv != CKR_OK) ||
|
|
((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_RSA_PKCS_KEY_PAIR_GEN);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5_RSA_PKCS,
|
|
&mechInfo);
|
|
if ((rv != CKR_OK) ||
|
|
((mechInfo.flags & CKF_SIGN) == 0) ||
|
|
((mechInfo.flags & CKF_VERIFY) == 0)) {
|
|
#if !defined(PK11_MD5_DISABLE) && !defined(PK11_RSA_PKCS_REPLACE)
|
|
bad = true;
|
|
#endif
|
|
PK11_TRACEM(CKM_MD5_RSA_PKCS);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA1_RSA_PKCS,
|
|
&mechInfo);
|
|
if ((rv != CKR_OK) ||
|
|
((mechInfo.flags & CKF_SIGN) == 0) ||
|
|
((mechInfo.flags & CKF_VERIFY) == 0)) {
|
|
#ifndef PK11_RSA_PKCS_REPLACE
|
|
bad = true;
|
|
#endif
|
|
PK11_TRACEM(CKM_SHA1_RSA_PKCS);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256_RSA_PKCS,
|
|
&mechInfo);
|
|
if ((rv != CKR_OK) ||
|
|
((mechInfo.flags & CKF_SIGN) == 0) ||
|
|
((mechInfo.flags & CKF_VERIFY) == 0)) {
|
|
#ifndef PK11_RSA_PKCS_REPLACE
|
|
bad = true;
|
|
#endif
|
|
PK11_TRACEM(CKM_SHA256_RSA_PKCS);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512_RSA_PKCS,
|
|
&mechInfo);
|
|
if ((rv != CKR_OK) ||
|
|
((mechInfo.flags & CKF_SIGN) == 0) ||
|
|
((mechInfo.flags & CKF_VERIFY) == 0)) {
|
|
#ifndef PK11_RSA_PKCS_REPLACE
|
|
bad = true;
|
|
#endif
|
|
PK11_TRACEM(CKM_SHA512_RSA_PKCS);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_RSA_PKCS, &mechInfo);
|
|
if ((rv != CKR_OK) ||
|
|
((mechInfo.flags & CKF_SIGN) == 0) ||
|
|
((mechInfo.flags & CKF_VERIFY) == 0)) {
|
|
#ifdef PK11_RSA_PKCS_REPLACE
|
|
bad = true;
|
|
#endif
|
|
PK11_TRACEM(CKM_RSA_PKCS);
|
|
}
|
|
if (bad)
|
|
goto try_dsa;
|
|
token->operations |= 1 << OP_RSA;
|
|
if (best_rsa_token == NULL)
|
|
best_rsa_token = token;
|
|
|
|
try_dsa:
|
|
bad = false;
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_PARAMETER_GEN,
|
|
&mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_GENERATE) == 0)) {
|
|
#ifndef PK11_DSA_PARAMETER_GEN_SKIP
|
|
bad = true;
|
|
#endif
|
|
PK11_TRACEM(CKM_DSA_PARAMETER_GEN);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_KEY_PAIR_GEN,
|
|
&mechInfo);
|
|
if ((rv != CKR_OK) ||
|
|
((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_DSA_PARAMETER_GEN);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_SHA1, &mechInfo);
|
|
if ((rv != CKR_OK) ||
|
|
((mechInfo.flags & CKF_SIGN) == 0) ||
|
|
((mechInfo.flags & CKF_VERIFY) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_DSA_SHA1);
|
|
}
|
|
if (bad)
|
|
goto try_dh;
|
|
#ifndef PK11_DSA_DISABLE
|
|
token->operations |= 1 << OP_DSA;
|
|
if (best_dsa_token == NULL)
|
|
best_dsa_token = token;
|
|
#endif
|
|
|
|
try_dh:
|
|
bad = false;
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_DH_PKCS_PARAMETER_GEN,
|
|
&mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_GENERATE) == 0)) {
|
|
PK11_TRACEM(CKM_DH_PKCS_PARAMETER_GEN);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_DH_PKCS_KEY_PAIR_GEN,
|
|
&mechInfo);
|
|
if ((rv != CKR_OK) ||
|
|
((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) {
|
|
#ifndef PK11_DH_PKCS_PARAMETER_GEN_SKIP
|
|
bad = true;
|
|
#endif
|
|
PK11_TRACEM(CKM_DH_PKCS_KEY_PAIR_GEN);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_DH_PKCS_DERIVE,
|
|
&mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DERIVE) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_DH_PKCS_DERIVE);
|
|
}
|
|
if (bad)
|
|
goto try_digest;
|
|
#ifndef PK11_DH_DISABLE
|
|
token->operations |= 1 << OP_DH;
|
|
if (best_dh_token == NULL)
|
|
best_dh_token = token;
|
|
#endif
|
|
|
|
try_digest:
|
|
bad = false;
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5, &mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
|
|
#ifndef PK11_MD5_DISABLE
|
|
bad = true;
|
|
#endif
|
|
PK11_TRACEM(CKM_MD5);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA_1, &mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_SHA_1);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA224, &mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_SHA224);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256, &mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_SHA256);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA384, &mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_SHA384);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512, &mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_SHA512);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5_HMAC, &mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) {
|
|
#if !defined(PK11_MD5_DISABLE) && !defined(PK11_MD5_HMAC_REPLACE)
|
|
bad = true;
|
|
#endif
|
|
PK11_TRACEM(CKM_MD5_HMAC);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA_1_HMAC, &mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) {
|
|
#ifndef PK11_SHA_1_HMAC_REPLACE
|
|
bad = true;
|
|
#endif
|
|
PK11_TRACEM(CKM_SHA_1_HMAC);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA224_HMAC, &mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) {
|
|
#ifndef PK11_SHA224_HMAC_REPLACE
|
|
bad = true;
|
|
#endif
|
|
PK11_TRACEM(CKM_SHA224_HMAC);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256_HMAC, &mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) {
|
|
#ifndef PK11_SHA256_HMAC_REPLACE
|
|
bad = true;
|
|
#endif
|
|
PK11_TRACEM(CKM_SHA256_HMAC);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA384_HMAC, &mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) {
|
|
#ifndef PK11_SHA384_HMAC_REPLACE
|
|
bad = true;
|
|
#endif
|
|
PK11_TRACEM(CKM_SHA384_HMAC);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512_HMAC, &mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) {
|
|
#ifndef PK11_SHA512_HMAC_REPLACE
|
|
bad = true;
|
|
#endif
|
|
PK11_TRACEM(CKM_SHA512_HMAC);
|
|
}
|
|
if (!bad) {
|
|
token->operations |= 1 << OP_DIGEST;
|
|
if (digest_token == NULL)
|
|
digest_token = token;
|
|
}
|
|
|
|
/* ECDSA requires digest */
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_EC_KEY_PAIR_GEN,
|
|
&mechInfo);
|
|
if ((rv != CKR_OK) ||
|
|
((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_EC_KEY_PAIR_GEN);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_ECDSA, &mechInfo);
|
|
if ((rv != CKR_OK) ||
|
|
((mechInfo.flags & CKF_SIGN) == 0) ||
|
|
((mechInfo.flags & CKF_VERIFY) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_ECDSA);
|
|
}
|
|
if (bad)
|
|
goto try_gost;
|
|
token->operations |= 1 << OP_EC;
|
|
if (best_ec_token == NULL)
|
|
best_ec_token = token;
|
|
|
|
try_gost:
|
|
bad = false;
|
|
/* does GOST require digest too? */
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_GOSTR3411, &mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_GOSTR3411);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_GOSTR3410_KEY_PAIR_GEN,
|
|
&mechInfo);
|
|
if ((rv != CKR_OK) ||
|
|
((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_GOSTR3410_KEY_PAIR_GEN);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot,
|
|
CKM_GOSTR3410_WITH_GOSTR3411,
|
|
&mechInfo);
|
|
if ((rv != CKR_OK) ||
|
|
((mechInfo.flags & CKF_SIGN) == 0) ||
|
|
((mechInfo.flags & CKF_VERIFY) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_GOSTR3410_WITH_GOSTR3411);
|
|
}
|
|
if (bad)
|
|
goto try_eddsa;
|
|
token->operations |= 1 << OP_GOST;
|
|
if (best_gost_token == NULL)
|
|
best_gost_token = token;
|
|
|
|
try_eddsa:
|
|
#if defined(CKM_EDDSA_KEY_PAIR_GEN) && defined(CKM_EDDSA) && defined(CKK_EDDSA)
|
|
bad = false;
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_EDDSA_KEY_PAIR_GEN,
|
|
&mechInfo);
|
|
if ((rv != CKR_OK) ||
|
|
((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_EDDSA_KEY_PAIR_GEN);
|
|
}
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_EDDSA, &mechInfo);
|
|
if ((rv != CKR_OK) ||
|
|
((mechInfo.flags & CKF_SIGN) == 0) ||
|
|
((mechInfo.flags & CKF_VERIFY) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_EDDSA);
|
|
}
|
|
if (bad)
|
|
goto try_aes;
|
|
|
|
try_aes:
|
|
#endif
|
|
bad = false;
|
|
rv = pkcs_C_GetMechanismInfo(slot, CKM_AES_ECB, &mechInfo);
|
|
if ((rv != CKR_OK) || ((mechInfo.flags & CKF_ENCRYPT) == 0)) {
|
|
bad = true;
|
|
PK11_TRACEM(CKM_AES_ECB);
|
|
}
|
|
if (bad)
|
|
continue;
|
|
token->operations |= 1 << OP_AES;
|
|
if (aes_token == NULL)
|
|
aes_token = token;
|
|
}
|
|
|
|
if (slotList != NULL) {
|
|
pk11_mem_put(slotList, sizeof(CK_SLOT_ID) * slotCount);
|
|
}
|
|
}
|
|
|
|
CK_SLOT_ID
|
|
pk11_get_best_token(pk11_optype_t optype) {
|
|
pk11_token_t *token = NULL;
|
|
|
|
switch (optype) {
|
|
case OP_RAND:
|
|
token = rand_token;
|
|
break;
|
|
case OP_RSA:
|
|
token = best_rsa_token;
|
|
break;
|
|
case OP_DSA:
|
|
token = best_dsa_token;
|
|
break;
|
|
case OP_DH:
|
|
token = best_dh_token;
|
|
break;
|
|
case OP_DIGEST:
|
|
token = digest_token;
|
|
break;
|
|
case OP_EC:
|
|
token = best_ec_token;
|
|
break;
|
|
case OP_GOST:
|
|
token = best_gost_token;
|
|
break;
|
|
case OP_AES:
|
|
token = aes_token;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (token == NULL)
|
|
return (0);
|
|
return (token->slotid);
|
|
}
|
|
|
|
unsigned int
|
|
pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt) {
|
|
unsigned int bitcnt, i;
|
|
CK_BYTE top;
|
|
|
|
if (bytecnt == 0)
|
|
return (0);
|
|
bitcnt = bytecnt * 8;
|
|
for (i = 0; i < bytecnt; i++) {
|
|
top = data[i];
|
|
if (top == 0) {
|
|
bitcnt -= 8;
|
|
continue;
|
|
}
|
|
if (top & 0x80)
|
|
return (bitcnt);
|
|
if (top & 0x40)
|
|
return (bitcnt - 1);
|
|
if (top & 0x20)
|
|
return (bitcnt - 2);
|
|
if (top & 0x10)
|
|
return (bitcnt - 3);
|
|
if (top & 0x08)
|
|
return (bitcnt - 4);
|
|
if (top & 0x04)
|
|
return (bitcnt - 5);
|
|
if (top & 0x02)
|
|
return (bitcnt - 6);
|
|
if (top & 0x01)
|
|
return (bitcnt - 7);
|
|
break;
|
|
}
|
|
INSIST(0);
|
|
ISC_UNREACHABLE();
|
|
}
|
|
|
|
CK_ATTRIBUTE *
|
|
pk11_attribute_first(const pk11_object_t *obj) {
|
|
return (obj->repr);
|
|
}
|
|
|
|
CK_ATTRIBUTE *
|
|
pk11_attribute_next(const pk11_object_t *obj, CK_ATTRIBUTE *attr) {
|
|
CK_ATTRIBUTE *next;
|
|
|
|
next = attr + 1;
|
|
if ((next - obj->repr) >= obj->attrcnt)
|
|
return (NULL);
|
|
return (next);
|
|
}
|
|
|
|
CK_ATTRIBUTE *
|
|
pk11_attribute_bytype(const pk11_object_t *obj, CK_ATTRIBUTE_TYPE type) {
|
|
CK_ATTRIBUTE *attr;
|
|
|
|
for(attr = pk11_attribute_first(obj);
|
|
attr != NULL;
|
|
attr = pk11_attribute_next(obj, attr))
|
|
if (attr->type == type)
|
|
return (attr);
|
|
return (NULL);
|
|
}
|
|
|
|
static char *
|
|
percent_decode(char *x, size_t *len) {
|
|
char *p, *c;
|
|
unsigned char v;
|
|
|
|
INSIST(len != NULL);
|
|
|
|
for (p = c = x; p[0] != '\0'; p++, c++) {
|
|
switch (p[0]) {
|
|
case '%':
|
|
v = 0;
|
|
switch (p[1]) {
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
v = (p[1] - '0') << 4;
|
|
break;
|
|
case 'A':
|
|
case 'B':
|
|
case 'C':
|
|
case 'D':
|
|
case 'E':
|
|
case 'F':
|
|
v = (p[1] - 'A' + 10) << 4;
|
|
break;
|
|
case 'a':
|
|
case 'b':
|
|
case 'c':
|
|
case 'd':
|
|
case 'e':
|
|
case 'f':
|
|
v = (p[1] - 'a' + 10) << 4;
|
|
break;
|
|
default:
|
|
return (NULL);
|
|
}
|
|
switch (p[2]) {
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
v |= (p[2] - '0') & 0x0f;
|
|
break;
|
|
case 'A':
|
|
case 'B':
|
|
case 'C':
|
|
case 'D':
|
|
case 'E':
|
|
case 'F':
|
|
v = (p[2] - 'A' + 10) & 0x0f;
|
|
break;
|
|
case 'a':
|
|
case 'b':
|
|
case 'c':
|
|
case 'd':
|
|
case 'e':
|
|
case 'f':
|
|
v = (p[2] - 'a' + 10) & 0x0f;
|
|
break;
|
|
default:
|
|
return (NULL);
|
|
}
|
|
p += 2;
|
|
*c = (char) v;
|
|
(*len)++;
|
|
break;
|
|
default:
|
|
*c = *p;
|
|
(*len)++;
|
|
}
|
|
}
|
|
return (x);
|
|
}
|
|
|
|
static bool
|
|
pk11strcmp(const char *x, size_t lenx, const char *y, size_t leny) {
|
|
char buf[32];
|
|
|
|
INSIST((leny == 32) || (leny == 16));
|
|
|
|
memset(buf, ' ', 32);
|
|
if (lenx > leny)
|
|
lenx = leny;
|
|
memmove(buf, x, lenx);
|
|
return (memcmp(buf, y, leny) == 0);
|
|
}
|
|
|
|
static CK_ATTRIBUTE *
|
|
push_attribute(pk11_object_t *obj, isc_mem_t *mctx, size_t len) {
|
|
CK_ATTRIBUTE *old = obj->repr;
|
|
CK_ATTRIBUTE *attr;
|
|
CK_BYTE cnt = obj->attrcnt;
|
|
|
|
obj->repr = isc_mem_get(mctx, (cnt + 1) * sizeof(*attr));
|
|
if (obj->repr == NULL) {
|
|
obj->repr = old;
|
|
return (NULL);
|
|
}
|
|
memset(obj->repr, 0, (cnt + 1) * sizeof(*attr));
|
|
memmove(obj->repr, old, cnt * sizeof(*attr));
|
|
attr = obj->repr + cnt;
|
|
attr->ulValueLen = (CK_ULONG) len;
|
|
attr->pValue = isc_mem_get(mctx, len);
|
|
if (attr->pValue == NULL) {
|
|
memset(obj->repr, 0, (cnt + 1) * sizeof(*attr));
|
|
isc_mem_put(mctx, obj->repr, (cnt + 1) * sizeof(*attr));
|
|
obj->repr = old;
|
|
return (NULL);
|
|
}
|
|
memset(attr->pValue, 0, len);
|
|
if (old != NULL) {
|
|
memset(old, 0, cnt * sizeof(*attr));
|
|
isc_mem_put(mctx, old, cnt * sizeof(*attr));
|
|
}
|
|
obj->attrcnt++;
|
|
return (attr);
|
|
}
|
|
|
|
#define DST_RET(a) { ret = a; goto err; }
|
|
|
|
isc_result_t
|
|
pk11_parse_uri(pk11_object_t *obj, const char *label,
|
|
isc_mem_t *mctx, pk11_optype_t optype)
|
|
{
|
|
CK_ATTRIBUTE *attr;
|
|
pk11_token_t *token = NULL;
|
|
char *uri, *p, *a, *na, *v;
|
|
size_t len, l;
|
|
FILE *stream = NULL;
|
|
char pin[PINLEN + 1];
|
|
bool gotpin = false;
|
|
isc_result_t ret;
|
|
|
|
/* get values to work on */
|
|
len = strlen(label) + 1;
|
|
uri = isc_mem_get(mctx, len);
|
|
if (uri == NULL)
|
|
return (ISC_R_NOMEMORY);
|
|
memmove(uri, label, len);
|
|
|
|
/* get the URI scheme */
|
|
p = strchr(uri, ':');
|
|
if (p == NULL)
|
|
DST_RET(PK11_R_NOPROVIDER);
|
|
*p++ = '\0';
|
|
if (strcmp(uri, "pkcs11") != 0)
|
|
DST_RET(PK11_R_NOPROVIDER);
|
|
|
|
/* get attributes */
|
|
for (na = p; na != NULL;) {
|
|
a = na;
|
|
p = strchr(a, ';');
|
|
if (p == NULL) {
|
|
/* last attribute */
|
|
na = NULL;
|
|
} else {
|
|
*p++ = '\0';
|
|
na = p;
|
|
}
|
|
p = strchr(a, '=');
|
|
if (p != NULL) {
|
|
*p++ = '\0';
|
|
v = p;
|
|
} else
|
|
v = a;
|
|
l = 0;
|
|
v = percent_decode(v, &l);
|
|
if (v == NULL)
|
|
DST_RET(PK11_R_NOPROVIDER);
|
|
if ((a == v) || (strcmp(a, "object") == 0)) {
|
|
/* object: CKA_LABEL */
|
|
attr = pk11_attribute_bytype(obj, CKA_LABEL);
|
|
if (attr != NULL)
|
|
DST_RET(PK11_R_NOPROVIDER);
|
|
attr = push_attribute(obj, mctx, l);
|
|
if (attr == NULL)
|
|
DST_RET(ISC_R_NOMEMORY);
|
|
attr->type = CKA_LABEL;
|
|
memmove(attr->pValue, v, l);
|
|
} else if (strcmp(a, "token") == 0) {
|
|
/* token: CK_TOKEN_INFO label */
|
|
if (token == NULL)
|
|
for (token = ISC_LIST_HEAD(tokens);
|
|
token != NULL;
|
|
token = ISC_LIST_NEXT(token, link))
|
|
if (pk11strcmp(v, l, token->name, 32))
|
|
break;
|
|
} else if (strcmp(a, "manufacturer") == 0) {
|
|
/* manufacturer: CK_TOKEN_INFO manufacturerID */
|
|
if (token == NULL)
|
|
for (token = ISC_LIST_HEAD(tokens);
|
|
token != NULL;
|
|
token = ISC_LIST_NEXT(token, link))
|
|
if (pk11strcmp(v, l, token->manuf, 32))
|
|
break;
|
|
} else if (strcmp(a, "serial") == 0) {
|
|
/* serial: CK_TOKEN_INFO serialNumber */
|
|
if (token == NULL)
|
|
for (token = ISC_LIST_HEAD(tokens);
|
|
token != NULL;
|
|
token = ISC_LIST_NEXT(token, link))
|
|
if (pk11strcmp(v, l, token->serial, 16))
|
|
break;
|
|
} else if (strcmp(a, "model") == 0) {
|
|
/* model: CK_TOKEN_INFO model */
|
|
if (token == NULL)
|
|
for (token = ISC_LIST_HEAD(tokens);
|
|
token != NULL;
|
|
token = ISC_LIST_NEXT(token, link))
|
|
if (pk11strcmp(v, l, token->model, 16))
|
|
break;
|
|
} else if (strcmp(a, "library-manufacturer") == 0) {
|
|
/* ignored */
|
|
} else if (strcmp(a, "library-description") == 0) {
|
|
/* ignored */
|
|
} else if (strcmp(a, "library-version") == 0) {
|
|
/* ignored */
|
|
} else if (strcmp(a, "object-type") == 0) {
|
|
/* object-type: CKA_CLASS */
|
|
/* only private makes sense */
|
|
if (strcmp(v, "private") != 0)
|
|
DST_RET(PK11_R_NOPROVIDER);
|
|
} else if (strcmp(a, "id") == 0) {
|
|
/* id: CKA_ID */
|
|
attr = pk11_attribute_bytype(obj, CKA_ID);
|
|
if (attr != NULL)
|
|
DST_RET(PK11_R_NOPROVIDER);
|
|
attr = push_attribute(obj, mctx, l);
|
|
if (attr == NULL)
|
|
DST_RET(ISC_R_NOMEMORY);
|
|
attr->type = CKA_ID;
|
|
memmove(attr->pValue, v, l);
|
|
} else if (strcmp(a, "pin-source") == 0) {
|
|
/* pin-source: PIN */
|
|
ret = isc_stdio_open(v, "r", &stream);
|
|
if (ret != ISC_R_SUCCESS)
|
|
goto err;
|
|
memset(pin, 0, PINLEN + 1);
|
|
ret = isc_stdio_read(pin, 1, PINLEN + 1, stream, &l);
|
|
if ((ret != ISC_R_SUCCESS) && (ret != ISC_R_EOF))
|
|
goto err;
|
|
if (l > PINLEN)
|
|
DST_RET(ISC_R_RANGE);
|
|
ret = isc_stdio_close(stream);
|
|
stream = NULL;
|
|
if (ret != ISC_R_SUCCESS)
|
|
goto err;
|
|
gotpin = true;
|
|
} else
|
|
DST_RET(PK11_R_NOPROVIDER);
|
|
}
|
|
|
|
if ((pk11_attribute_bytype(obj, CKA_LABEL) == NULL) &&
|
|
(pk11_attribute_bytype(obj, CKA_ID) == NULL))
|
|
DST_RET(ISC_R_NOTFOUND);
|
|
|
|
if (token == NULL) {
|
|
if (optype == OP_RSA)
|
|
token = best_rsa_token;
|
|
else if (optype == OP_DSA)
|
|
token = best_dsa_token;
|
|
else if (optype == OP_DH)
|
|
token = best_dh_token;
|
|
else if (optype == OP_EC)
|
|
token = best_ec_token;
|
|
}
|
|
if (token == NULL)
|
|
DST_RET(ISC_R_NOTFOUND);
|
|
obj->slot = token->slotid;
|
|
if (gotpin) {
|
|
memmove(token->pin, pin, PINLEN + 1);
|
|
obj->reqlogon = true;
|
|
}
|
|
|
|
ret = ISC_R_SUCCESS;
|
|
|
|
err:
|
|
if (stream != NULL)
|
|
(void) isc_stdio_close(stream);
|
|
isc_mem_put(mctx, uri, len);
|
|
return (ret);
|
|
}
|
|
|
|
void
|
|
pk11_error_fatalcheck(const char *file, int line,
|
|
const char *funcname, CK_RV rv)
|
|
{
|
|
isc_error_fatal(file, line, "%s: Error = 0x%.8lX\n", funcname, rv);
|
|
}
|
|
|
|
void
|
|
pk11_dump_tokens(void) {
|
|
pk11_token_t *token;
|
|
bool first;
|
|
|
|
printf("DEFAULTS\n");
|
|
printf("\trand_token=%p\n", rand_token);
|
|
printf("\tbest_rsa_token=%p\n", best_rsa_token);
|
|
printf("\tbest_dsa_token=%p\n", best_dsa_token);
|
|
printf("\tbest_dh_token=%p\n", best_dh_token);
|
|
printf("\tdigest_token=%p\n", digest_token);
|
|
printf("\tbest_ec_token=%p\n", best_ec_token);
|
|
printf("\tbest_gost_token=%p\n", best_gost_token);
|
|
printf("\taes_token=%p\n", aes_token);
|
|
|
|
for (token = ISC_LIST_HEAD(tokens);
|
|
token != NULL;
|
|
token = ISC_LIST_NEXT(token, link)) {
|
|
printf("\nTOKEN\n");
|
|
printf("\taddress=%p\n", token);
|
|
printf("\tslotID=%lu\n", token->slotid);
|
|
printf("\tlabel=%.32s\n", token->name);
|
|
printf("\tmanufacturerID=%.32s\n", token->manuf);
|
|
printf("\tmodel=%.16s\n", token->model);
|
|
printf("\tserialNumber=%.16s\n", token->serial);
|
|
printf("\tsupported operations=0x%x (", token->operations);
|
|
first = true;
|
|
if (token->operations & (1 << OP_RAND)) {
|
|
if (!first)
|
|
printf(",");
|
|
first = false;
|
|
printf("RAND");
|
|
}
|
|
if (token->operations & (1 << OP_RSA)) {
|
|
first = false;
|
|
printf("RSA");
|
|
}
|
|
if (token->operations & (1 << OP_DSA)) {
|
|
if (!first)
|
|
printf(",");
|
|
first = false;
|
|
printf("DSA");
|
|
}
|
|
if (token->operations & (1 << OP_DH)) {
|
|
if (!first)
|
|
printf(",");
|
|
first = false;
|
|
printf("DH");
|
|
}
|
|
if (token->operations & (1 << OP_DIGEST)) {
|
|
if (!first)
|
|
printf(",");
|
|
first = false;
|
|
printf("DIGEST");
|
|
}
|
|
if (token->operations & (1 << OP_EC)) {
|
|
if (!first)
|
|
printf(",");
|
|
first = false;
|
|
printf("EC");
|
|
}
|
|
if (token->operations & (1 << OP_AES)) {
|
|
if (!first)
|
|
printf(",");
|
|
first = false;
|
|
printf("AES");
|
|
}
|
|
printf(")\n");
|
|
}
|
|
}
|