4d2f92f055
Resolves: rhbz#1507402
285 lines
9.2 KiB
Diff
285 lines
9.2 KiB
Diff
diff --git a/lib/includes/gnutls/pkcs11.h b/lib/includes/gnutls/pkcs11.h
|
|
index c3db2181a..52f7898b4 100644
|
|
--- a/lib/includes/gnutls/pkcs11.h
|
|
+++ b/lib/includes/gnutls/pkcs11.h
|
|
@@ -65,6 +65,7 @@ typedef struct gnutls_pkcs11_obj_st *gnutls_pkcs11_obj_t;
|
|
|
|
#define GNUTLS_PKCS11_FLAG_MANUAL 0 /* Manual loading of libraries */
|
|
#define GNUTLS_PKCS11_FLAG_AUTO 1 /* Automatically load libraries by reading /etc/gnutls/pkcs11.conf */
|
|
+#define GNUTLS_PKCS11_FLAG_AUTO_TRUSTED (1<<1) /* Automatically load trusted libraries by reading /etc/gnutls/pkcs11.conf */
|
|
|
|
/* pkcs11.conf format:
|
|
* load = /lib/xxx-pkcs11.so
|
|
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
|
|
index 43a6b1321..16c582c6f 100644
|
|
--- a/lib/libgnutls.map
|
|
+++ b/lib/libgnutls.map
|
|
@@ -1241,6 +1241,7 @@ GNUTLS_PRIVATE_3_4 {
|
|
_gnutls_mpi_log;
|
|
_gnutls_mpi_release;
|
|
# Internal symbols needed by tests/:
|
|
+ _gnutls_pkcs11_token_get_url;
|
|
_gnutls_pkcs12_string_to_key;
|
|
_gnutls_bin2hex;
|
|
_gnutls_mac_to_entry;
|
|
diff --git a/lib/pkcs11.c b/lib/pkcs11.c
|
|
index e014a6b5f..e6e37c60c 100644
|
|
--- a/lib/pkcs11.c
|
|
+++ b/lib/pkcs11.c
|
|
@@ -108,7 +108,8 @@ struct find_cert_st {
|
|
|
|
static struct gnutls_pkcs11_provider_st providers[MAX_PROVIDERS];
|
|
static unsigned int active_providers = 0;
|
|
-static unsigned int providers_initialized = 0;
|
|
+
|
|
+static init_level_t providers_initialized = PROV_UNINITIALIZED;
|
|
static unsigned int pkcs11_forkid = 0;
|
|
|
|
static int _gnutls_pkcs11_reinit(void);
|
|
@@ -116,6 +117,8 @@ static int _gnutls_pkcs11_reinit(void);
|
|
gnutls_pkcs11_token_callback_t _gnutls_token_func;
|
|
void *_gnutls_token_data;
|
|
|
|
+static int auto_load(unsigned trusted);
|
|
+
|
|
int pkcs11_rv_to_err(ck_rv_t rv)
|
|
{
|
|
switch (rv) {
|
|
@@ -232,7 +235,8 @@ pkcs11_add_module(const char* name, struct ck_function_list *module, unsigned cu
|
|
/* initially check if this module is a duplicate */
|
|
for (i = 0; i < active_providers; i++) {
|
|
/* already loaded, skip the rest */
|
|
- if (module == providers[i].module) {
|
|
+ if (module == providers[i].module ||
|
|
+ memcmp(&info, &providers[i].info, sizeof(info)) == 0) {
|
|
_gnutls_debug_log("p11: module %s is already loaded.\n", name);
|
|
return GNUTLS_E_INT_RET_0;
|
|
}
|
|
@@ -261,7 +265,7 @@ pkcs11_add_module(const char* name, struct ck_function_list *module, unsigned cu
|
|
* The output value of the callback will be returned if it is
|
|
* a negative one (indicating failure).
|
|
*/
|
|
-int _gnutls_pkcs11_check_init(void *priv, pkcs11_reinit_function cb)
|
|
+int _gnutls_pkcs11_check_init(init_level_t req_level, void *priv, pkcs11_reinit_function cb)
|
|
{
|
|
int ret;
|
|
|
|
@@ -269,7 +273,7 @@ int _gnutls_pkcs11_check_init(void *priv, pkcs11_reinit_function cb)
|
|
if (ret != 0)
|
|
return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR);
|
|
|
|
- if (providers_initialized != 0) {
|
|
+ if (providers_initialized >= req_level) {
|
|
ret = 0;
|
|
|
|
if (_gnutls_detect_fork(pkcs11_forkid)) {
|
|
@@ -288,10 +292,16 @@ int _gnutls_pkcs11_check_init(void *priv, pkcs11_reinit_function cb)
|
|
|
|
gnutls_mutex_unlock(&_gnutls_pkcs11_mutex);
|
|
return ret;
|
|
- }
|
|
+ } else if (providers_initialized < req_level &&
|
|
+ (req_level == PROV_INIT_TRUSTED)) {
|
|
+ _gnutls_debug_log("Initializing needed PKCS #11 modules\n");
|
|
+ ret = auto_load(1);
|
|
|
|
- _gnutls_debug_log("Initializing PKCS #11 modules\n");
|
|
- ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_AUTO, NULL);
|
|
+ providers_initialized = PROV_INIT_TRUSTED;
|
|
+ } else {
|
|
+ _gnutls_debug_log("Initializing all PKCS #11 modules\n");
|
|
+ ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_AUTO, NULL);
|
|
+ }
|
|
|
|
gnutls_mutex_unlock(&_gnutls_pkcs11_mutex);
|
|
|
|
@@ -742,13 +752,13 @@ static void compat_load(const char *configfile)
|
|
return;
|
|
}
|
|
|
|
-static int auto_load(void)
|
|
+static int auto_load(unsigned trusted)
|
|
{
|
|
struct ck_function_list **modules;
|
|
int i, ret;
|
|
char* name;
|
|
|
|
- modules = p11_kit_modules_load_and_initialize(0);
|
|
+ modules = p11_kit_modules_load_and_initialize(trusted?P11_KIT_MODULE_TRUSTED:0);
|
|
if (modules == NULL) {
|
|
gnutls_assert();
|
|
_gnutls_debug_log
|
|
@@ -817,15 +827,21 @@ gnutls_pkcs11_init(unsigned int flags, const char *deprecated_config_file)
|
|
if (flags == GNUTLS_PKCS11_FLAG_MANUAL) {
|
|
/* if manual configuration is requested then don't
|
|
* bother loading any other providers */
|
|
- providers_initialized = 1;
|
|
+ providers_initialized = PROV_INIT_MANUAL;
|
|
return 0;
|
|
} else if (flags & GNUTLS_PKCS11_FLAG_AUTO) {
|
|
if (deprecated_config_file == NULL)
|
|
- ret = auto_load();
|
|
+ ret = auto_load(0);
|
|
|
|
compat_load(deprecated_config_file);
|
|
|
|
- providers_initialized = 1;
|
|
+ providers_initialized = PROV_INIT_ALL;
|
|
+
|
|
+ return ret;
|
|
+ } else if (flags & GNUTLS_PKCS11_FLAG_AUTO_TRUSTED) {
|
|
+ ret = auto_load(1);
|
|
+
|
|
+ providers_initialized = PROV_INIT_TRUSTED;
|
|
|
|
return ret;
|
|
}
|
|
@@ -918,7 +934,7 @@ void gnutls_pkcs11_deinit(void)
|
|
p11_kit_module_release(providers[i].module);
|
|
}
|
|
active_providers = 0;
|
|
- providers_initialized = 0;
|
|
+ providers_initialized = PROV_UNINITIALIZED;
|
|
|
|
gnutls_pkcs11_set_pin_function(NULL, NULL);
|
|
gnutls_pkcs11_set_token_function(NULL, NULL);
|
|
@@ -2177,11 +2193,18 @@ find_token_modname_cb(struct ck_function_list *module, struct pkcs11_session_inf
|
|
return 0;
|
|
}
|
|
|
|
+/* Internal symbol used by tests */
|
|
+int
|
|
+_gnutls_pkcs11_token_get_url(unsigned int seq,
|
|
+ gnutls_pkcs11_url_type_t detailed, char **url,
|
|
+ unsigned flags);
|
|
+
|
|
/**
|
|
- * gnutls_pkcs11_token_get_url:
|
|
+ * _gnutls_pkcs11_token_get_url:
|
|
* @seq: sequence number starting from 0
|
|
* @detailed: non zero if a detailed URL is required
|
|
* @url: will contain an allocated url
|
|
+ * @flags: zero or 1. When 1 no initialization is performed.
|
|
*
|
|
* This function will return the URL for each token available
|
|
* in system. The url has to be released using gnutls_free()
|
|
@@ -2190,16 +2213,18 @@ find_token_modname_cb(struct ck_function_list *module, struct pkcs11_session_inf
|
|
* %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE if the sequence number
|
|
* exceeds the available tokens, otherwise a negative error value.
|
|
*
|
|
- * Since: 2.12.0
|
|
**/
|
|
int
|
|
-gnutls_pkcs11_token_get_url(unsigned int seq,
|
|
- gnutls_pkcs11_url_type_t detailed, char **url)
|
|
+_gnutls_pkcs11_token_get_url(unsigned int seq,
|
|
+ gnutls_pkcs11_url_type_t detailed, char **url,
|
|
+ unsigned flags)
|
|
{
|
|
int ret;
|
|
struct find_token_num tn;
|
|
|
|
- PKCS11_CHECK_INIT;
|
|
+ if (!(flags & 1)) {
|
|
+ PKCS11_CHECK_INIT;
|
|
+ }
|
|
|
|
memset(&tn, 0, sizeof(tn));
|
|
tn.seq = seq;
|
|
@@ -2224,6 +2249,28 @@ gnutls_pkcs11_token_get_url(unsigned int seq,
|
|
}
|
|
|
|
/**
|
|
+ * gnutls_pkcs11_token_get_url:
|
|
+ * @seq: sequence number starting from 0
|
|
+ * @detailed: non zero if a detailed URL is required
|
|
+ * @url: will contain an allocated url
|
|
+ *
|
|
+ * This function will return the URL for each token available
|
|
+ * in system. The url has to be released using gnutls_free()
|
|
+ *
|
|
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
|
|
+ * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE if the sequence number
|
|
+ * exceeds the available tokens, otherwise a negative error value.
|
|
+ *
|
|
+ * Since: 2.12.0
|
|
+ **/
|
|
+int
|
|
+gnutls_pkcs11_token_get_url(unsigned int seq,
|
|
+ gnutls_pkcs11_url_type_t detailed, char **url)
|
|
+{
|
|
+ return _gnutls_pkcs11_token_get_url(seq, detailed, url, 0);
|
|
+}
|
|
+
|
|
+/**
|
|
* gnutls_pkcs11_token_get_info:
|
|
* @url: should contain a PKCS 11 URL
|
|
* @ttype: Denotes the type of information requested
|
|
@@ -3173,7 +3220,11 @@ gnutls_pkcs11_obj_list_import_url4(gnutls_pkcs11_obj_t ** p_list,
|
|
int ret;
|
|
struct find_obj_data_st priv;
|
|
|
|
- PKCS11_CHECK_INIT;
|
|
+ if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED) {
|
|
+ PKCS11_CHECK_INIT_TRUSTED;
|
|
+ } else {
|
|
+ PKCS11_CHECK_INIT;
|
|
+ }
|
|
|
|
memset(&priv, 0, sizeof(priv));
|
|
|
|
diff --git a/lib/pkcs11_int.h b/lib/pkcs11_int.h
|
|
index 2c2de3463..de9afbdee 100644
|
|
--- a/lib/pkcs11_int.h
|
|
+++ b/lib/pkcs11_int.h
|
|
@@ -82,7 +82,15 @@ struct gnutls_pkcs11_privkey_st {
|
|
* directly. It can be provided a callback function to run when a reinitialization
|
|
* occurs. */
|
|
typedef int (*pkcs11_reinit_function)(void *priv);
|
|
-int _gnutls_pkcs11_check_init(void *priv, pkcs11_reinit_function cb);
|
|
+
|
|
+typedef enum init_level_t {
|
|
+ PROV_UNINITIALIZED = 0,
|
|
+ PROV_INIT_MANUAL,
|
|
+ PROV_INIT_TRUSTED,
|
|
+ PROV_INIT_ALL
|
|
+} init_level_t;
|
|
+
|
|
+int _gnutls_pkcs11_check_init(init_level_t req_level, void *priv, pkcs11_reinit_function cb);
|
|
|
|
#define FIX_KEY_USAGE(pk, usage) \
|
|
if (usage == 0) { \
|
|
@@ -93,12 +101,17 @@ int _gnutls_pkcs11_check_init(void *priv, pkcs11_reinit_function cb);
|
|
}
|
|
|
|
#define PKCS11_CHECK_INIT \
|
|
- ret = _gnutls_pkcs11_check_init(NULL, NULL); \
|
|
+ ret = _gnutls_pkcs11_check_init(PROV_INIT_MANUAL, NULL, NULL); \
|
|
+ if (ret < 0) \
|
|
+ return gnutls_assert_val(ret)
|
|
+
|
|
+#define PKCS11_CHECK_INIT_TRUSTED \
|
|
+ ret = _gnutls_pkcs11_check_init(PROV_INIT_TRUSTED, NULL, NULL); \
|
|
if (ret < 0) \
|
|
return gnutls_assert_val(ret)
|
|
|
|
#define PKCS11_CHECK_INIT_RET(x) \
|
|
- ret = _gnutls_pkcs11_check_init(NULL, NULL); \
|
|
+ ret = _gnutls_pkcs11_check_init(PROV_INIT_MANUAL, NULL, NULL); \
|
|
if (ret < 0) \
|
|
return gnutls_assert_val(x)
|
|
|
|
diff --git a/lib/pkcs11_privkey.c b/lib/pkcs11_privkey.c
|
|
index 34fe47a38..afe831ee9 100644
|
|
--- a/lib/pkcs11_privkey.c
|
|
+++ b/lib/pkcs11_privkey.c
|
|
@@ -36,7 +36,7 @@
|
|
/* In case of a fork, it will invalidate the open session
|
|
* in the privkey and start another */
|
|
#define PKCS11_CHECK_INIT_PRIVKEY(k) \
|
|
- ret = _gnutls_pkcs11_check_init(k, reopen_privkey_session); \
|
|
+ ret = _gnutls_pkcs11_check_init(PROV_INIT_MANUAL, k, reopen_privkey_session); \
|
|
if (ret < 0) \
|
|
return gnutls_assert_val(ret)
|
|
|