|
Packit Service |
2ea82d |
/* libp11, a simple layer on to of PKCS#11 API
|
|
Packit Service |
2ea82d |
* Copyright (C) 2005 Olaf Kirch <okir@lst.de>
|
|
Packit Service |
2ea82d |
* Copyright (C) 2015-2018 MichaĆ Trojnara <Michal.Trojnara@stunnel.org>
|
|
Packit Service |
2ea82d |
*
|
|
Packit Service |
2ea82d |
* This library is free software; you can redistribute it and/or
|
|
Packit Service |
2ea82d |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit Service |
2ea82d |
* License as published by the Free Software Foundation; either
|
|
Packit Service |
2ea82d |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit Service |
2ea82d |
*
|
|
Packit Service |
2ea82d |
* This library is distributed in the hope that it will be useful,
|
|
Packit Service |
2ea82d |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
2ea82d |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
2ea82d |
* Lesser General Public License for more details.
|
|
Packit Service |
2ea82d |
*
|
|
Packit Service |
2ea82d |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
2ea82d |
* License along with this library; if not, write to the Free Software
|
|
Packit Service |
2ea82d |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
#include "libp11-int.h"
|
|
Packit Service |
2ea82d |
#include <string.h>
|
|
Packit Service |
2ea82d |
#include <openssl/buffer.h>
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static int pkcs11_init_slot(PKCS11_CTX *, PKCS11_SLOT *, CK_SLOT_ID);
|
|
Packit Service |
2ea82d |
static void pkcs11_release_slot(PKCS11_CTX *, PKCS11_SLOT *);
|
|
Packit Service |
2ea82d |
static int pkcs11_check_token(PKCS11_CTX *, PKCS11_SLOT *);
|
|
Packit Service |
2ea82d |
static void pkcs11_destroy_token(PKCS11_TOKEN *);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Get slotid from private
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
unsigned long pkcs11_get_slotid_from_slot(PKCS11_SLOT *slot)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
return spriv->id;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Enumerate slots
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
int pkcs11_enumerate_slots(PKCS11_CTX *ctx, PKCS11_SLOT **slotp,
|
|
Packit Service |
2ea82d |
unsigned int *countp)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_CTX_private *cpriv = PRIVCTX(ctx);
|
|
Packit Service |
2ea82d |
CK_SLOT_ID *slotid;
|
|
Packit Service |
2ea82d |
CK_ULONG nslots, n;
|
|
Packit Service |
2ea82d |
PKCS11_SLOT *slots;
|
|
Packit Service |
2ea82d |
size_t alloc_size;
|
|
Packit Service |
2ea82d |
int rv;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
rv = cpriv->method->C_GetSlotList(FALSE, NULL_PTR, &nslots);
|
|
Packit Service |
2ea82d |
CRYPTOKI_checkerr(CKR_F_PKCS11_ENUMERATE_SLOTS, rv);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
alloc_size = nslots * sizeof(CK_SLOT_ID);
|
|
Packit Service |
2ea82d |
if (alloc_size / sizeof(CK_SLOT_ID) != nslots) /* integer overflow */
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
slotid = OPENSSL_malloc(alloc_size);
|
|
Packit Service |
2ea82d |
if (slotid == NULL)
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
rv = cpriv->method->C_GetSlotList(FALSE, slotid, &nslots);
|
|
Packit Service |
2ea82d |
CRYPTOKI_checkerr(CKR_F_PKCS11_ENUMERATE_SLOTS, rv);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
alloc_size = nslots * sizeof(PKCS11_SLOT);
|
|
Packit Service |
2ea82d |
if (alloc_size / sizeof(PKCS11_SLOT) != nslots) /* integer overflow */
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
slots = OPENSSL_malloc(alloc_size);
|
|
Packit Service |
2ea82d |
if (slots == NULL)
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
memset(slots, 0, nslots * sizeof(PKCS11_SLOT));
|
|
Packit Service |
2ea82d |
for (n = 0; n < nslots; n++) {
|
|
Packit Service |
2ea82d |
if (pkcs11_init_slot(ctx, &slots[n], slotid[n])) {
|
|
Packit Service |
2ea82d |
while (n--)
|
|
Packit Service |
2ea82d |
pkcs11_release_slot(ctx, slots + n);
|
|
Packit Service |
2ea82d |
OPENSSL_free(slotid);
|
|
Packit Service |
2ea82d |
OPENSSL_free(slots);
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (slotp)
|
|
Packit Service |
2ea82d |
*slotp = slots;
|
|
Packit Service |
2ea82d |
else
|
|
Packit Service |
2ea82d |
OPENSSL_free(slots);
|
|
Packit Service |
2ea82d |
if (countp)
|
|
Packit Service |
2ea82d |
*countp = nslots;
|
|
Packit Service |
2ea82d |
OPENSSL_free(slotid);
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Find a slot with a token that looks "valuable"
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
PKCS11_SLOT *pkcs11_find_token(PKCS11_CTX *ctx, PKCS11_SLOT *slots,
|
|
Packit Service |
2ea82d |
unsigned int nslots)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_SLOT *slot, *best;
|
|
Packit Service |
2ea82d |
PKCS11_TOKEN *tok;
|
|
Packit Service |
2ea82d |
unsigned int n;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
(void)ctx;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (slots == NULL)
|
|
Packit Service |
2ea82d |
return NULL;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
best = NULL;
|
|
Packit Service |
2ea82d |
for (n = 0, slot = slots; n < nslots; n++, slot++) {
|
|
Packit Service |
2ea82d |
if ((tok = slot->token) != NULL) {
|
|
Packit Service |
2ea82d |
if (best == NULL ||
|
|
Packit Service |
2ea82d |
(tok->initialized > best->token->initialized &&
|
|
Packit Service |
2ea82d |
tok->userPinSet > best->token->userPinSet &&
|
|
Packit Service |
2ea82d |
tok->loginRequired > best->token->loginRequired))
|
|
Packit Service |
2ea82d |
best = slot;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
return best;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Find the next slot with a token that looks "valuable"
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
PKCS11_SLOT *pkcs11_find_next_token(PKCS11_CTX *ctx, PKCS11_SLOT *slots,
|
|
Packit Service |
2ea82d |
unsigned int nslots, PKCS11_SLOT *current)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
int offset;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (slots == NULL)
|
|
Packit Service |
2ea82d |
return NULL;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (current) {
|
|
Packit Service |
2ea82d |
offset = current + 1 - slots;
|
|
Packit Service |
2ea82d |
if (offset < 1 || (unsigned int)offset >= nslots)
|
|
Packit Service |
2ea82d |
return NULL;
|
|
Packit Service |
2ea82d |
} else {
|
|
Packit Service |
2ea82d |
offset = 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
return pkcs11_find_token(ctx, slots + offset, nslots - offset);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Open a session with this slot
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
int pkcs11_open_session(PKCS11_SLOT *slot, int rw, int relogin)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit Service |
2ea82d |
PKCS11_CTX *ctx = SLOT2CTX(slot);
|
|
Packit Service |
2ea82d |
int rv;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (relogin == 0) {
|
|
Packit Service |
2ea82d |
if (spriv->haveSession) {
|
|
Packit Service |
2ea82d |
CRYPTOKI_call(ctx, C_CloseSession(spriv->session));
|
|
Packit Service |
2ea82d |
spriv->haveSession = 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
rv = CRYPTOKI_call(ctx,
|
|
Packit Service |
2ea82d |
C_OpenSession(spriv->id,
|
|
Packit Service |
2ea82d |
CKF_SERIAL_SESSION | (rw ? CKF_RW_SESSION : 0),
|
|
Packit Service |
2ea82d |
NULL, NULL, &spriv->session));
|
|
Packit Service |
2ea82d |
CRYPTOKI_checkerr(CKR_F_PKCS11_OPEN_SESSION, rv);
|
|
Packit Service |
2ea82d |
spriv->haveSession = 1;
|
|
Packit Service |
2ea82d |
spriv->prev_rw = rw;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
int pkcs11_reopen_session(PKCS11_SLOT *slot)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit Service |
2ea82d |
PKCS11_CTX *ctx = SLOT2CTX(slot);
|
|
Packit Service |
2ea82d |
int rv;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
rv = CRYPTOKI_call(ctx,
|
|
Packit Service |
2ea82d |
C_OpenSession(spriv->id,
|
|
Packit Service |
2ea82d |
CKF_SERIAL_SESSION | (spriv->prev_rw ? CKF_RW_SESSION : 0),
|
|
Packit Service |
2ea82d |
NULL, NULL, &spriv->session));
|
|
Packit Service |
2ea82d |
CRYPTOKI_checkerr(CKR_F_PKCS11_REOPEN_SESSION, rv);
|
|
Packit Service |
2ea82d |
spriv->haveSession = 1;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Determines if user is authenticated with token
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
int pkcs11_is_logged_in(PKCS11_SLOT *slot, int so, int *res)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_CTX *ctx = SLOT2CTX(slot);
|
|
Packit Service |
2ea82d |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit Service |
2ea82d |
CK_SESSION_INFO session_info;
|
|
Packit Service |
2ea82d |
int rv;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (spriv->loggedIn) {
|
|
Packit Service |
2ea82d |
*res = 1;
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
if (!spriv->haveSession) {
|
|
Packit Service |
2ea82d |
/* SO gets a r/w session by default,
|
|
Packit Service |
2ea82d |
* user gets a r/o session by default. */
|
|
Packit Service |
2ea82d |
if (PKCS11_open_session(slot, so))
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
rv = CRYPTOKI_call(ctx, C_GetSessionInfo(spriv->session, &session_info));
|
|
Packit Service |
2ea82d |
CRYPTOKI_checkerr(CKR_F_PKCS11_IS_LOGGED_IN, rv);
|
|
Packit Service |
2ea82d |
if (so) {
|
|
Packit Service |
2ea82d |
*res = session_info.state == CKS_RW_SO_FUNCTIONS;
|
|
Packit Service |
2ea82d |
} else {
|
|
Packit Service |
2ea82d |
*res = session_info.state == CKS_RO_USER_FUNCTIONS ||
|
|
Packit Service |
2ea82d |
session_info.state == CKS_RW_USER_FUNCTIONS;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Authenticate with the card. relogin should be set if we automatically
|
|
Packit Service |
2ea82d |
* relogin after a fork.
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
int pkcs11_login(PKCS11_SLOT *slot, int so, const char *pin, int relogin)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_CTX *ctx = SLOT2CTX(slot);
|
|
Packit Service |
2ea82d |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit Service |
2ea82d |
int rv;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (!relogin && spriv->loggedIn)
|
|
Packit Service |
2ea82d |
return 0; /* Nothing to do */
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (!spriv->haveSession) {
|
|
Packit Service |
2ea82d |
/* SO gets a r/w session by default,
|
|
Packit Service |
2ea82d |
* user gets a r/o session by default. */
|
|
Packit Service |
2ea82d |
if (pkcs11_open_session(slot, so, relogin))
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
rv = CRYPTOKI_call(ctx,
|
|
Packit Service |
2ea82d |
C_Login(spriv->session, so ? CKU_SO : CKU_USER,
|
|
Packit Service |
2ea82d |
(CK_UTF8CHAR *) pin, pin ? (unsigned long) strlen(pin) : 0));
|
|
Packit Service |
2ea82d |
if (rv && rv != CKR_USER_ALREADY_LOGGED_IN) /* logged in -> OK */
|
|
Packit Service |
2ea82d |
CRYPTOKI_checkerr(CKR_F_PKCS11_LOGIN, rv);
|
|
Packit Service |
2ea82d |
spriv->loggedIn = 1;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (spriv->prev_pin != pin) {
|
|
Packit Service |
2ea82d |
if (spriv->prev_pin) {
|
|
Packit Service |
2ea82d |
OPENSSL_cleanse(spriv->prev_pin, strlen(spriv->prev_pin));
|
|
Packit Service |
2ea82d |
OPENSSL_free(spriv->prev_pin);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
spriv->prev_pin = OPENSSL_strdup(pin);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
spriv->prev_so = so;
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Authenticate with the card
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
int pkcs11_relogin(PKCS11_SLOT *slot)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
return pkcs11_login(slot, spriv->prev_so, spriv->prev_pin, 1);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Log out
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
int pkcs11_logout(PKCS11_SLOT *slot)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_CTX *ctx = SLOT2CTX(slot);
|
|
Packit Service |
2ea82d |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit Service |
2ea82d |
int rv;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* Calling PKCS11_logout invalidates all cached
|
|
Packit Service |
2ea82d |
* keys we have */
|
|
Packit Service |
2ea82d |
if (slot->token) {
|
|
Packit Service |
2ea82d |
pkcs11_destroy_keys(slot->token, CKO_PRIVATE_KEY);
|
|
Packit Service |
2ea82d |
pkcs11_destroy_keys(slot->token, CKO_PUBLIC_KEY);
|
|
Packit Service |
2ea82d |
pkcs11_destroy_certs(slot->token);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
if (!spriv->haveSession) {
|
|
Packit Service |
2ea82d |
P11err(P11_F_PKCS11_LOGOUT, P11_R_NO_SESSION);
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
rv = CRYPTOKI_call(ctx, C_Logout(spriv->session));
|
|
Packit Service |
2ea82d |
CRYPTOKI_checkerr(CKR_F_PKCS11_LOGOUT, rv);
|
|
Packit Service |
2ea82d |
spriv->loggedIn = 0;
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Initialize the token
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
int pkcs11_init_token(PKCS11_TOKEN *token, const char *pin, const char *label)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_SLOT *slot = TOKEN2SLOT(token);
|
|
Packit Service |
2ea82d |
PKCS11_CTX *ctx = SLOT2CTX(slot);
|
|
Packit Service |
2ea82d |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit Service |
2ea82d |
int rv;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (label == NULL)
|
|
Packit Service |
2ea82d |
label = "PKCS#11 Token";
|
|
Packit Service |
2ea82d |
rv = CRYPTOKI_call(ctx,
|
|
Packit Service |
2ea82d |
C_InitToken(spriv->id,
|
|
Packit Service |
2ea82d |
(CK_UTF8CHAR *) pin, (unsigned long) strlen(pin),
|
|
Packit Service |
2ea82d |
(CK_UTF8CHAR *) label));
|
|
Packit Service |
2ea82d |
CRYPTOKI_checkerr(CKR_F_PKCS11_INIT_TOKEN, rv);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* FIXME: how to update the token?
|
|
Packit Service |
2ea82d |
* PKCS11_CTX_private *cpriv;
|
|
Packit Service |
2ea82d |
* int n;
|
|
Packit Service |
2ea82d |
* cpriv = PRIVCTX(ctx);
|
|
Packit Service |
2ea82d |
* for (n = 0; n < cpriv->nslots; n++) {
|
|
Packit Service |
2ea82d |
* if (pkcs11_check_token(ctx, cpriv->slots + n) < 0)
|
|
Packit Service |
2ea82d |
* return -1;
|
|
Packit Service |
2ea82d |
* }
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Set the User PIN
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
int pkcs11_init_pin(PKCS11_TOKEN *token, const char *pin)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_SLOT *slot = TOKEN2SLOT(token);
|
|
Packit Service |
2ea82d |
PKCS11_CTX *ctx = SLOT2CTX(slot);
|
|
Packit Service |
2ea82d |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit Service |
2ea82d |
int len, rv;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (!spriv->haveSession) {
|
|
Packit Service |
2ea82d |
P11err(P11_F_PKCS11_INIT_PIN, P11_R_NO_SESSION);
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
len = pin ? (int) strlen(pin) : 0;
|
|
Packit Service |
2ea82d |
rv = CRYPTOKI_call(ctx, C_InitPIN(spriv->session, (CK_UTF8CHAR *) pin, len));
|
|
Packit Service |
2ea82d |
CRYPTOKI_checkerr(CKR_F_PKCS11_INIT_PIN, rv);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
return pkcs11_check_token(ctx, TOKEN2SLOT(token));
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Change the User PIN
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
int pkcs11_change_pin(PKCS11_SLOT *slot, const char *old_pin,
|
|
Packit Service |
2ea82d |
const char *new_pin)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_CTX *ctx = SLOT2CTX(slot);
|
|
Packit Service |
2ea82d |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit Service |
2ea82d |
int old_len, new_len, rv;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (!spriv->haveSession) {
|
|
Packit Service |
2ea82d |
P11err(P11_F_PKCS11_CHANGE_PIN, P11_R_NO_SESSION);
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
old_len = old_pin ? (int) strlen(old_pin) : 0;
|
|
Packit Service |
2ea82d |
new_len = new_pin ? (int) strlen(new_pin) : 0;
|
|
Packit Service |
2ea82d |
rv = CRYPTOKI_call(ctx,
|
|
Packit Service |
2ea82d |
C_SetPIN(spriv->session, (CK_UTF8CHAR *) old_pin, old_len,
|
|
Packit Service |
2ea82d |
(CK_UTF8CHAR *) new_pin, new_len));
|
|
Packit Service |
2ea82d |
CRYPTOKI_checkerr(CKR_F_PKCS11_CHANGE_PIN, rv);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
return pkcs11_check_token(ctx, slot);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Seed the random number generator
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
int pkcs11_seed_random(PKCS11_SLOT *slot, const unsigned char *s,
|
|
Packit Service |
2ea82d |
unsigned int s_len)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_CTX *ctx = SLOT2CTX(slot);
|
|
Packit Service |
2ea82d |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit Service |
2ea82d |
int rv;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (!spriv->haveSession && PKCS11_open_session(slot, 0)) {
|
|
Packit Service |
2ea82d |
P11err(P11_F_PKCS11_SEED_RANDOM, P11_R_NO_SESSION);
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
rv = CRYPTOKI_call(ctx,
|
|
Packit Service |
2ea82d |
C_SeedRandom(spriv->session, (CK_BYTE_PTR) s, s_len));
|
|
Packit Service |
2ea82d |
CRYPTOKI_checkerr(CKR_F_PKCS11_SEED_RANDOM, rv);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
return pkcs11_check_token(ctx, slot);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Generate random numbers
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
int pkcs11_generate_random(PKCS11_SLOT *slot, unsigned char *r,
|
|
Packit Service |
2ea82d |
unsigned int r_len)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_CTX *ctx = SLOT2CTX(slot);
|
|
Packit Service |
2ea82d |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit Service |
2ea82d |
int rv;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (!spriv->haveSession && PKCS11_open_session(slot, 0)) {
|
|
Packit Service |
2ea82d |
P11err(P11_F_PKCS11_GENERATE_RANDOM, P11_R_NO_SESSION);
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
rv = CRYPTOKI_call(ctx,
|
|
Packit Service |
2ea82d |
C_GenerateRandom(spriv->session, (CK_BYTE_PTR) r, r_len));
|
|
Packit Service |
2ea82d |
CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_RANDOM, rv);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
return pkcs11_check_token(ctx, slot);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/*
|
|
Packit Service |
2ea82d |
* Helper functions
|
|
Packit Service |
2ea82d |
*/
|
|
Packit Service |
2ea82d |
static int pkcs11_init_slot(PKCS11_CTX *ctx, PKCS11_SLOT *slot, CK_SLOT_ID id)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_SLOT_private *spriv;
|
|
Packit Service |
2ea82d |
CK_SLOT_INFO info;
|
|
Packit Service |
2ea82d |
int rv;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
rv = CRYPTOKI_call(ctx, C_GetSlotInfo(id, &info));
|
|
Packit Service |
2ea82d |
CRYPTOKI_checkerr(CKR_F_PKCS11_INIT_SLOT, rv);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
spriv = OPENSSL_malloc(sizeof(PKCS11_SLOT_private));
|
|
Packit Service |
2ea82d |
if (spriv == NULL)
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
memset(spriv, 0, sizeof(PKCS11_SLOT_private));
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
spriv->parent = ctx;
|
|
Packit Service |
2ea82d |
spriv->id = id;
|
|
Packit Service |
2ea82d |
spriv->forkid = PRIVCTX(ctx)->forkid;
|
|
Packit Service |
2ea82d |
spriv->prev_rw = 0;
|
|
Packit Service |
2ea82d |
spriv->prev_pin = NULL;
|
|
Packit Service |
2ea82d |
spriv->prev_so = 0;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
slot->description = PKCS11_DUP(info.slotDescription);
|
|
Packit Service |
2ea82d |
slot->manufacturer = PKCS11_DUP(info.manufacturerID);
|
|
Packit Service |
2ea82d |
slot->removable = (info.flags & CKF_REMOVABLE_DEVICE) ? 1 : 0;
|
|
Packit Service |
2ea82d |
slot->_private = spriv;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if ((info.flags & CKF_TOKEN_PRESENT) && pkcs11_check_token(ctx, slot))
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
void pkcs11_release_all_slots(PKCS11_CTX *ctx, PKCS11_SLOT *slots,
|
|
Packit Service |
2ea82d |
unsigned int nslots)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
unsigned int i;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
for (i=0; i < nslots; i++)
|
|
Packit Service |
2ea82d |
pkcs11_release_slot(ctx, &slots[i]);
|
|
Packit Service |
2ea82d |
OPENSSL_free(slots);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static void pkcs11_release_slot(PKCS11_CTX *ctx, PKCS11_SLOT *slot)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (spriv) {
|
|
Packit Service |
2ea82d |
if (spriv->prev_pin) {
|
|
Packit Service |
2ea82d |
OPENSSL_cleanse(spriv->prev_pin, strlen(spriv->prev_pin));
|
|
Packit Service |
2ea82d |
OPENSSL_free(spriv->prev_pin);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
CRYPTOKI_call(ctx, C_CloseAllSessions(spriv->id));
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
OPENSSL_free(slot->_private);
|
|
Packit Service |
2ea82d |
OPENSSL_free(slot->description);
|
|
Packit Service |
2ea82d |
OPENSSL_free(slot->manufacturer);
|
|
Packit Service |
2ea82d |
if (slot->token) {
|
|
Packit Service |
2ea82d |
pkcs11_destroy_token(slot->token);
|
|
Packit Service |
2ea82d |
OPENSSL_free(slot->token);
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
memset(slot, 0, sizeof(*slot));
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static int pkcs11_check_token(PKCS11_CTX *ctx, PKCS11_SLOT *slot)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit Service |
2ea82d |
PKCS11_TOKEN_private *tpriv;
|
|
Packit Service |
2ea82d |
CK_TOKEN_INFO info;
|
|
Packit Service |
2ea82d |
int rv;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
if (slot->token) {
|
|
Packit Service |
2ea82d |
pkcs11_destroy_token(slot->token);
|
|
Packit Service |
2ea82d |
} else {
|
|
Packit Service |
2ea82d |
slot->token = OPENSSL_malloc(sizeof(PKCS11_TOKEN));
|
|
Packit Service |
2ea82d |
if (slot->token == NULL)
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
memset(slot->token, 0, sizeof(PKCS11_TOKEN));
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
rv = CRYPTOKI_call(ctx, C_GetTokenInfo(spriv->id, &info));
|
|
Packit Service |
2ea82d |
if (rv == CKR_TOKEN_NOT_PRESENT || rv == CKR_TOKEN_NOT_RECOGNIZED) {
|
|
Packit Service |
2ea82d |
OPENSSL_free(slot->token);
|
|
Packit Service |
2ea82d |
slot->token = NULL;
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
CRYPTOKI_checkerr(CKR_F_PKCS11_CHECK_TOKEN, rv);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* We have a token */
|
|
Packit Service |
2ea82d |
tpriv = OPENSSL_malloc(sizeof(PKCS11_TOKEN_private));
|
|
Packit Service |
2ea82d |
if (tpriv == NULL)
|
|
Packit Service |
2ea82d |
return -1;
|
|
Packit Service |
2ea82d |
memset(tpriv, 0, sizeof(PKCS11_TOKEN_private));
|
|
Packit Service |
2ea82d |
tpriv->parent = slot;
|
|
Packit Service |
2ea82d |
tpriv->prv.keys = NULL;
|
|
Packit Service |
2ea82d |
tpriv->prv.num = 0;
|
|
Packit Service |
2ea82d |
tpriv->pub.keys = NULL;
|
|
Packit Service |
2ea82d |
tpriv->pub.num = 0;
|
|
Packit Service |
2ea82d |
tpriv->ncerts = 0;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
slot->token->label = PKCS11_DUP(info.label);
|
|
Packit Service |
2ea82d |
slot->token->manufacturer = PKCS11_DUP(info.manufacturerID);
|
|
Packit Service |
2ea82d |
slot->token->model = PKCS11_DUP(info.model);
|
|
Packit Service |
2ea82d |
slot->token->serialnr = PKCS11_DUP(info.serialNumber);
|
|
Packit Service |
2ea82d |
slot->token->initialized = (info.flags & CKF_TOKEN_INITIALIZED) ? 1 : 0;
|
|
Packit Service |
2ea82d |
slot->token->loginRequired = (info.flags & CKF_LOGIN_REQUIRED) ? 1 : 0;
|
|
Packit Service |
2ea82d |
slot->token->secureLogin = (info.flags & CKF_PROTECTED_AUTHENTICATION_PATH) ? 1 : 0;
|
|
Packit Service |
2ea82d |
slot->token->userPinSet = (info.flags & CKF_USER_PIN_INITIALIZED) ? 1 : 0;
|
|
Packit Service |
2ea82d |
slot->token->readOnly = (info.flags & CKF_WRITE_PROTECTED) ? 1 : 0;
|
|
Packit Service |
2ea82d |
slot->token->hasRng = (info.flags & CKF_RNG) ? 1 : 0;
|
|
Packit Service |
2ea82d |
slot->token->userPinCountLow = (info.flags & CKF_USER_PIN_COUNT_LOW) ? 1 : 0;
|
|
Packit Service |
2ea82d |
slot->token->userPinFinalTry = (info.flags & CKF_USER_PIN_FINAL_TRY) ? 1 : 0;
|
|
Packit Service |
2ea82d |
slot->token->userPinLocked = (info.flags & CKF_USER_PIN_LOCKED) ? 1 : 0;
|
|
Packit Service |
2ea82d |
slot->token->userPinToBeChanged = (info.flags & CKF_USER_PIN_TO_BE_CHANGED) ? 1 : 0;
|
|
Packit Service |
2ea82d |
slot->token->soPinCountLow = (info.flags & CKF_SO_PIN_COUNT_LOW) ? 1 : 0;
|
|
Packit Service |
2ea82d |
slot->token->soPinFinalTry = (info.flags & CKF_SO_PIN_FINAL_TRY) ? 1 : 0;
|
|
Packit Service |
2ea82d |
slot->token->soPinLocked = (info.flags & CKF_SO_PIN_LOCKED) ? 1 : 0;
|
|
Packit Service |
2ea82d |
slot->token->soPinToBeChanged = (info.flags & CKF_SO_PIN_TO_BE_CHANGED) ? 1 : 0;
|
|
Packit Service |
2ea82d |
slot->token->_private = tpriv;
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
return 0;
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
static void pkcs11_destroy_token(PKCS11_TOKEN *token)
|
|
Packit Service |
2ea82d |
{
|
|
Packit Service |
2ea82d |
pkcs11_destroy_keys(token, CKO_PRIVATE_KEY);
|
|
Packit Service |
2ea82d |
pkcs11_destroy_keys(token, CKO_PUBLIC_KEY);
|
|
Packit Service |
2ea82d |
pkcs11_destroy_certs(token);
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
OPENSSL_free(token->label);
|
|
Packit Service |
2ea82d |
OPENSSL_free(token->manufacturer);
|
|
Packit Service |
2ea82d |
OPENSSL_free(token->model);
|
|
Packit Service |
2ea82d |
OPENSSL_free(token->serialnr);
|
|
Packit Service |
2ea82d |
OPENSSL_free(token->_private);
|
|
Packit Service |
2ea82d |
memset(token, 0, sizeof(*token));
|
|
Packit Service |
2ea82d |
}
|
|
Packit Service |
2ea82d |
|
|
Packit Service |
2ea82d |
/* vim: set noexpandtab: */
|