summaryrefslogtreecommitdiffstats
path: root/src/libdnssec/p11/p11.c
blob: c3af544984e82a7feb88e7f9dff8d1c7a4199c5c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*  Copyright (C) 2018 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 <https://www.gnu.org/licenses/>.
 */

#include <assert.h>
#include <gnutls/pkcs11.h>
#include <stdlib.h>
#include <string.h>

#include "libdnssec/p11/p11.h"
#include "libdnssec/error.h"

#ifdef ENABLE_PKCS11

#define PKCS11_MODULES_MAX 16

static char *pkcs11_modules[PKCS11_MODULES_MAX] = { 0 };
static int pkcs11_modules_count = 0;

static int map_result(int gnutls_result)
{
	return gnutls_result == GNUTLS_E_SUCCESS ? DNSSEC_EOK : DNSSEC_ERROR;
}

int p11_init(void)
{
	int r = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
	return map_result(r);
}

int p11_reinit(void)
{
	int r = gnutls_pkcs11_reinit();
	return map_result(r);
}

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;

	gnutls_pkcs11_deinit();
}

#else

int p11_init(void)
{
	return DNSSEC_EOK;
}

int p11_reinit(void)
{
	return DNSSEC_EOK;
}

int p11_load_module(const char *module)
{
	return DNSSEC_NOT_IMPLEMENTED_ERROR;
}

void p11_cleanup(void)
{
	// this function intentionally left blank
}

#endif