Commit 52385c1a authored by Daniel Salzman's avatar Daniel Salzman

Merge branch 'fix-confdb-pkcs11' into 'master'

PKCS 11 duplicate module loading prevention



See merge request !553
parents 6d3472c1 7f2e3b61
......@@ -129,6 +129,8 @@ libdnssec_la_SOURCES = \
lib/nsec/bitmap.c \
lib/nsec/hash.c \
lib/nsec/nsec.c \
lib/p11/p11.c \
lib/p11/p11.h \
lib/random.c \
lib/sign/der.c \
lib/sign/der.h \
......
......@@ -18,6 +18,7 @@
#include <gnutls/pkcs11.h>
#include "crypto.h"
#include "p11/p11.h"
#include "shared.h"
_public_
......@@ -35,6 +36,7 @@ void dnssec_crypto_cleanup(void)
gnutls_global_deinit();
#ifdef ENABLE_PKCS11
gnutls_pkcs11_deinit();
p11_cleanup();
#endif
}
......
......@@ -91,7 +91,10 @@ enum dnssec_error {
DNSSEC_KEYSTORE_INVALID_BACKEND,
DNSSEC_KEYSTORE_INVALID_CONFIG,
DNSSEC_KEYSTORE_FAILED_TO_LOAD_P11_MODULE,
DNSSEC_P11_FAILED_TO_LOAD_MODULE,
DNSSEC_P11_TOO_MANY_MODULES,
DNSSEC_P11_TOKEN_NOT_AVAILABLE,
DNSSEC_ERROR_MAX = -1001
};
......
......@@ -68,7 +68,10 @@ static const error_message_t ERROR_MESSAGES[] = {
{ DNSSEC_KEYSTORE_INVALID_BACKEND, "invalid KASP keystore backend" },
{ DNSSEC_KEYSTORE_INVALID_CONFIG, "invalid KASP keystore configuration" },
{ DNSSEC_KEYSTORE_FAILED_TO_LOAD_P11_MODULE, "failed to load PKCS #11 module" },
{ DNSSEC_P11_FAILED_TO_LOAD_MODULE, "failed to load PKCS #11 module" },
{ DNSSEC_P11_TOO_MANY_MODULES, "too many PKCS #11 modules loaded" },
{ DNSSEC_P11_TOKEN_NOT_AVAILABLE, "PKCS #11 token not available" },
{ 0 }
};
......
......@@ -23,6 +23,7 @@
#include "keyid_gnutls.h"
#include "keystore.h"
#include "keystore/internal.h"
#include "p11/p11.h"
#include "pem.h"
#include "shared.h"
......@@ -81,6 +82,63 @@ static int key_url(const char *token_uri, const char *key_id, char **url_ptr)
return DNSSEC_EOK;
}
/**
* Parse configuration string. Accepted format: "<pkcs11-url> <module-path>"
*/
static int parse_config(const char *config, char **uri_ptr, char **module_ptr)
{
const char *space = strchr(config, ' ');
if (!space) {
return DNSSEC_KEYSTORE_INVALID_CONFIG;
}
char *url = strndup(config, space - config);
char *module = strdup(space + 1);
if (!url || !module) {
free(url);
free(module);
return DNSSEC_ENOMEM;
}
*uri_ptr = url;
*module_ptr = module;
return DNSSEC_EOK;
}
/*!
* Load PKCS #11 module and check if the token is available.
*/
static int safe_open(const char *config, char **url_ptr)
{
char *url = NULL;
char *module = NULL;
int r = parse_config(config, &url, &module);
if (r != DNSSEC_EOK) {
return r;
}
r = p11_load_module(module);
free(module);
if (r != GNUTLS_E_SUCCESS) {
free(url);
return DNSSEC_P11_FAILED_TO_LOAD_MODULE;
}
unsigned int flags = 0;
r = gnutls_pkcs11_token_get_flags(url, &flags);
if (r != GNUTLS_E_SUCCESS) {
free(url);
return DNSSEC_P11_TOKEN_NOT_AVAILABLE;
}
*url_ptr = url;
return DNSSEC_EOK;
}
/* -- internal API --------------------------------------------------------- */
static void disable_pkcs11_callbacks(void)
......@@ -115,51 +173,22 @@ static int pkcs11_ctx_free(void *ctx)
static int pkcs11_init(void *ctx, const char *config)
{
return DNSSEC_NOT_IMPLEMENTED_ERROR;
}
/**
* Parse configuration string. Accepted format: "<pkcs11-url> <module-path>"
*/
static int parse_config(const char *config, char **uri_ptr, char **module_ptr)
{
const char *space = strchr(config, ' ');
if (!space) {
return DNSSEC_KEYSTORE_INVALID_CONFIG;
}
char *url = strndup(config, space - config);
char *module = strdup(space + 1);
/*
* Current keystore initialization is idempotent. We don't really
* initialize the token because don't want to wipe the data. We just
* check that the token is available the same way pkcs11_open() does.
*/
if (!url || !module) {
free(url);
free(module);
return DNSSEC_ENOMEM;
}
*uri_ptr = url;
*module_ptr = module;
_cleanup_free_ char *url = NULL;
return DNSSEC_EOK;
return safe_open(config, &url);
}
static int pkcs11_open(void *_ctx, const char *config)
{
pkcs11_ctx_t *ctx = _ctx;
char *module = NULL;
int r = parse_config(config, &ctx->url, &module);
if (r != DNSSEC_EOK) {
return r;
}
r = gnutls_pkcs11_add_provider(module, NULL);
free(module);
if (r != GNUTLS_E_SUCCESS) {
return DNSSEC_KEYSTORE_FAILED_TO_LOAD_P11_MODULE;
}
return DNSSEC_EOK;
return safe_open(config, &ctx->url);
}
static int pkcs11_close(void *_ctx)
......@@ -213,7 +242,7 @@ static int pkcs11_list_keys(void *_ctx, dnssec_list_t **list)
int r = gnutls_pkcs11_obj_list_import_url4(&objects, &count, ctx->url, flags);
if (r != GNUTLS_E_SUCCESS) {
dnssec_list_free(ids);
return DNSSEC_ERROR; // TODO
return DNSSEC_P11_TOKEN_NOT_AVAILABLE;
}
for (unsigned i = 0; i < count; i++) {
......
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "p11/p11.h"
#include "error.h"
#include <assert.h>
#include <gnutls/pkcs11.h>
#include <stdlib.h>
#include <string.h>
#define PKCS11_MODULES_MAX 16
static char *pkcs11_modules[PKCS11_MODULES_MAX] = { 0 };
static int pkcs11_modules_count = 0;
int p11_load_module(const char *module)
{
for (int i = 0; i < pkcs11_modules_count; i++) {
if (strcmp(pkcs11_modules[i], module) == 0) {
return DNSSEC_EOK;
}
}
assert(pkcs11_modules_count <= PKCS11_MODULES_MAX);
if (pkcs11_modules_count == PKCS11_MODULES_MAX) {
return DNSSEC_P11_TOO_MANY_MODULES;
}
char *copy = strdup(module);
if (!copy) {
return DNSSEC_ENOMEM;
}
int r = gnutls_pkcs11_add_provider(module, NULL);
if (r != GNUTLS_E_SUCCESS) {
free(copy);
return DNSSEC_P11_FAILED_TO_LOAD_MODULE;
}
pkcs11_modules[pkcs11_modules_count] = copy;
pkcs11_modules_count += 1;
return DNSSEC_EOK;
}
void p11_cleanup(void)
{
for (int i = 0; i < pkcs11_modules_count; i++) {
free(pkcs11_modules[i]);
pkcs11_modules[i] = NULL;
}
pkcs11_modules_count = 0;
}
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
/*!
* Load PKCS11 module unless the module was already loaded.
*
* Duplicates are detected based on the module path.
*/
int p11_load_module(const char *name);
/*!
* Clenaup list of loaded modules.
*
* Should be called when the library is deinitialized to prevent memory leaks.
*/
void p11_cleanup(void);
......@@ -448,7 +448,7 @@ int main(int argc, char *argv[])
// key store access
r = dnssec_keystore_init(store, config);
ok(r == DNSSEC_NOT_IMPLEMENTED_ERROR, "dnssec_keystore_init(), not implemented");
ok(r == DNSSEC_EOK, "dnssec_keystore_init()");
r = dnssec_keystore_open(store, config);
ok(r == DNSSEC_EOK, "dnssec_keystore_open()");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment