diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:33:12 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:33:12 +0000 |
commit | 36082a2fe36ecd800d784ae44c14f1f18c66a7e9 (patch) | |
tree | 6c68e0c0097987aff85a01dabddd34b862309a7c /tests/pkcs11 | |
parent | Initial commit. (diff) | |
download | gnutls28-upstream.tar.xz gnutls28-upstream.zip |
Adding upstream version 3.7.9.upstream/3.7.9upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
40 files changed, 10960 insertions, 0 deletions
diff --git a/tests/pkcs11/gnutls_pcert_list_import_x509_file.c b/tests/pkcs11/gnutls_pcert_list_import_x509_file.c new file mode 100644 index 0000000..a4602a4 --- /dev/null +++ b/tests/pkcs11/gnutls_pcert_list_import_x509_file.c @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2018 Nikos Mavrogiannopoulos + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> + +#include "../utils.h" +#include "softhsm.h" + +/* Tests whether gnutls_x509_crt_list_import_url() will return a well + * sorted chain, out of values written to softhsm token. + */ + +#define CONFIG_NAME "softhsm-import-url" +#define CONFIG CONFIG_NAME".config" + +#include "../test-chains.h" + +#define PIN "123456" + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +static int comp_cert(gnutls_pcert_st *pcert, unsigned i) +{ + int ret; + gnutls_datum_t data; + gnutls_x509_crt_t crt2; + + if (debug) + success("comparing cert %d\n", i); + + ret = gnutls_x509_crt_init(&crt2); + if (ret < 0) + return -1; + + data.data = (void*)nc_good2[i]; + data.size = strlen(nc_good2[i]); + ret = gnutls_x509_crt_import(crt2, &data, GNUTLS_X509_FMT_PEM); + if (ret < 0) + return -1; + + if (!gnutls_x509_crt_equals2(crt2, &pcert->cert)) { + return -1; + } + + gnutls_x509_crt_deinit(crt2); + + return 0; +} + +static void load_cert(const char *url, unsigned i) +{ + int ret; + gnutls_datum_t data; + gnutls_x509_crt_t crt; + char name[64]; + + ret = gnutls_x509_crt_init(&crt); + if (ret < 0) + fail("error: %s\n", gnutls_strerror(ret)); + + data.data = (void*)nc_good2[i]; + data.size = strlen(nc_good2[i]); + ret = gnutls_x509_crt_import(crt, &data, GNUTLS_X509_FMT_PEM); + if (ret < 0) + fail("error[%d]: %s\n", i, gnutls_strerror(ret)); + + snprintf(name, sizeof(name), "cert-%d", i); + ret = gnutls_pkcs11_copy_x509_crt(url, crt, name, GNUTLS_PKCS11_OBJ_FLAG_LOGIN|GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE); + if (ret < 0) + fail("error[%d]: %s\n", i, gnutls_strerror(ret)); + + success("written cert-%d\n", i); + + gnutls_x509_crt_deinit(crt); +} + +static void load_chain(const char *url) +{ + load_cert(url, 1); + load_cert(url, 0); + load_cert(url, 4); + load_cert(url, 2); + load_cert(url, 3); +} + +static void write_certs(const char *file) +{ + FILE *fp = fopen(file, "w"); + assert(fp != NULL); + fwrite(nc_good2[0], strlen(nc_good2[0]), 1, fp); + fwrite(nc_good2[4], strlen(nc_good2[4]), 1, fp); + fwrite(nc_good2[1], strlen(nc_good2[1]), 1, fp); + fwrite(nc_good2[2], strlen(nc_good2[2]), 1, fp); + fwrite(nc_good2[3], strlen(nc_good2[3]), 1, fp); + fclose(fp); +} + +void doit(void) +{ + char buf[512]; + int ret; + const char *lib, *bin; + unsigned int i; + gnutls_pcert_st pcerts[16]; + unsigned int pcerts_size; + char file[TMPNAME_SIZE]; + + if (gnutls_fips140_mode_enabled()) + exit(77); + + track_temp_files(); + bin = softhsm_bin(); + + lib = softhsm_lib(); + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin "PIN" --pin "PIN, bin); + system(buf); + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret < 0) { + fprintf(stderr, "add_provider: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + /* initialize softhsm token */ + ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test"); + if (ret < 0) { + fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); + } + + ret = gnutls_pkcs11_token_set_pin(SOFTHSM_URL, NULL, PIN, GNUTLS_PIN_USER); + if (ret < 0) { + fail("gnutls_pkcs11_token_set_pin: %s\n", gnutls_strerror(ret)); + } + + load_chain(SOFTHSM_URL); + gnutls_pkcs11_set_pin_function(NULL, NULL); + + success("import from URI\n"); + pcerts_size = 2; + ret = gnutls_pcert_list_import_x509_file(pcerts, &pcerts_size, SOFTHSM_URL";object=cert-0", + GNUTLS_X509_FMT_PEM, pin_func, NULL, 0); + assert(ret == GNUTLS_E_SHORT_MEMORY_BUFFER); + + pcerts_size = sizeof(pcerts)/sizeof(pcerts[0]); + ret = gnutls_pcert_list_import_x509_file(pcerts, &pcerts_size, SOFTHSM_URL";object=cert-0", + GNUTLS_X509_FMT_PEM, pin_func, NULL, 0); + if (ret < 0) + fail("cannot load certs: %s\n", gnutls_strerror(ret)); + + assert(pcerts_size == 5); + + for (i=0;i<pcerts_size;i++) + assert(comp_cert(&pcerts[i], i)>=0); + + for (i=0;i<pcerts_size;i++) + gnutls_pcert_deinit(&pcerts[i]); + + /* Try testing importing from file + */ + success("import from file\n"); + get_tmpname(file); + + write_certs(file); + + pcerts_size = 2; + ret = gnutls_pcert_list_import_x509_file(pcerts, &pcerts_size, file, + GNUTLS_X509_FMT_PEM, pin_func, NULL, 0); + assert(ret == GNUTLS_E_SHORT_MEMORY_BUFFER); + + pcerts_size = sizeof(pcerts)/sizeof(pcerts[0]); + ret = gnutls_pcert_list_import_x509_file(pcerts, &pcerts_size, file, + GNUTLS_X509_FMT_PEM, pin_func, NULL, 0); + if (ret < 0) + fail("cannot load certs: %s\n", gnutls_strerror(ret)); + + assert(pcerts_size == 5); + + for (i=0;i<pcerts_size;i++) + assert(comp_cert(&pcerts[i], i)>=0); + + for (i=0;i<pcerts_size;i++) + gnutls_pcert_deinit(&pcerts[i]); + + gnutls_global_deinit(); + delete_temp_files(); + + remove(CONFIG); +} + diff --git a/tests/pkcs11/gnutls_x509_crt_list_import_url.c b/tests/pkcs11/gnutls_x509_crt_list_import_url.c new file mode 100644 index 0000000..e395180 --- /dev/null +++ b/tests/pkcs11/gnutls_x509_crt_list_import_url.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2018 Nikos Mavrogiannopoulos + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> + +#include "../utils.h" +#include "softhsm.h" + +/* Tests whether gnutls_x509_crt_list_import_url() will return a well + * sorted chain, out of values written to softhsm token. + */ + +#define CONFIG_NAME "x509-crt-list-import-url" +#define CONFIG CONFIG_NAME".config" + +#include "../test-chains.h" + +#define PIN "123456" + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +static void comp_cert(gnutls_x509_crt_t crt1, unsigned i) +{ + int ret; + gnutls_datum_t data; + gnutls_x509_crt_t crt2; + + ret = gnutls_x509_crt_init(&crt2); + if (ret < 0) + fail("error: %s\n", gnutls_strerror(ret)); + + data.data = (void*)nc_good2[i]; + data.size = strlen(nc_good2[i]); + ret = gnutls_x509_crt_import(crt2, &data, GNUTLS_X509_FMT_PEM); + if (ret < 0) + fail("error[%d]: %s\n", i, gnutls_strerror(ret)); + + if (!gnutls_x509_crt_equals(crt1, crt2)) { + fail("certificate doesn't match chain at %d\n", i); + } + + gnutls_x509_crt_deinit(crt2); +} + +static void load_cert(const char *url, unsigned i) +{ + int ret; + gnutls_datum_t data; + gnutls_x509_crt_t crt; + char name[64]; + + ret = gnutls_x509_crt_init(&crt); + if (ret < 0) + fail("error: %s\n", gnutls_strerror(ret)); + + data.data = (void*)nc_good2[i]; + data.size = strlen(nc_good2[i]); + ret = gnutls_x509_crt_import(crt, &data, GNUTLS_X509_FMT_PEM); + if (ret < 0) + fail("error[%d]: %s\n", i, gnutls_strerror(ret)); + + snprintf(name, sizeof(name), "cert-%d", i); + ret = gnutls_pkcs11_copy_x509_crt(url, crt, name, GNUTLS_PKCS11_OBJ_FLAG_LOGIN|GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE); + if (ret < 0) + fail("error[%d]: %s\n", i, gnutls_strerror(ret)); + + success("written cert-%d\n", i); + + gnutls_x509_crt_deinit(crt); +} + +static void load_chain(const char *url) +{ + load_cert(url, 1); + load_cert(url, 0); + load_cert(url, 4); + load_cert(url, 2); + load_cert(url, 3); +} + +void doit(void) +{ + char buf[512]; + int ret; + const char *lib, *bin; + gnutls_x509_crt_t *crts; + unsigned int crts_size, i; + + if (gnutls_fips140_mode_enabled()) + exit(77); + + bin = softhsm_bin(); + + lib = softhsm_lib(); + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin "PIN" --pin "PIN, bin); + system(buf); + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret < 0) { + fprintf(stderr, "add_provider: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + /* initialize softhsm token */ + ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test"); + if (ret < 0) { + fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); + } + + ret = gnutls_pkcs11_token_set_pin(SOFTHSM_URL, NULL, PIN, GNUTLS_PIN_USER); + if (ret < 0) { + fail("gnutls_pkcs11_token_set_pin: %s\n", gnutls_strerror(ret)); + } + + load_chain(SOFTHSM_URL); + gnutls_pkcs11_set_pin_function(NULL, NULL); + + /* try importing without login */ + ret = gnutls_x509_crt_list_import_url(&crts, &crts_size, SOFTHSM_URL";object=cert-0", + pin_func, NULL, 0); + if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) + fail("cannot load certs: %s\n", gnutls_strerror(ret)); + + /* try importing with login */ + ret = gnutls_x509_crt_list_import_url(&crts, &crts_size, SOFTHSM_URL";object=cert-0", + pin_func, NULL, GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) + fail("cannot load certs: %s\n", gnutls_strerror(ret)); + + assert(crts_size == 5); + + for (i=0;i<crts_size;i++) + comp_cert(crts[i], i); + + for (i=0;i<crts_size;i++) + gnutls_x509_crt_deinit(crts[i]); + gnutls_free(crts); + + gnutls_global_deinit(); + delete_temp_files(); + + remove(CONFIG); +} + diff --git a/tests/pkcs11/list-objects.c b/tests/pkcs11/list-objects.c new file mode 100644 index 0000000..ab30cd5 --- /dev/null +++ b/tests/pkcs11/list-objects.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2016-2017 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> +#include <getopt.h> +#define P11_KIT_FUTURE_UNSTABLE_API +#include <p11-kit/p11-kit.h> +#include "cert-common.h" + +/* lists the registered PKCS#11 modules by p11-kit. + */ + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static const char *opt_pin; + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, opt_pin); + return 0; + } + return -1; +} + +int main(int argc, char **argv) +{ + int ret; + unsigned i; + int opt; + char *url, *mod; + unsigned flags; + unsigned obj_flags = 0; + int attrs = GNUTLS_PKCS11_OBJ_ATTR_ALL; + gnutls_pkcs11_obj_t *crt_list; + unsigned int crt_list_size = 0; + const char *envvar; + + ret = gnutls_global_init(); + if (ret != 0) { + fprintf(stderr, "error at %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + + gnutls_global_set_log_function(tls_log_func); + + while((opt = getopt(argc, argv, "o:t:")) != -1) { + switch(opt) { + case 'o': + mod = strdup(optarg); + p11_kit_override_system_files(NULL, NULL, mod, mod, NULL); + break; + case 't': + /* specify the object type to list */ + if (strcmp(optarg, "all") == 0) + attrs = GNUTLS_PKCS11_OBJ_ATTR_ALL; + else if (strcmp(optarg, "privkey") == 0) + attrs = GNUTLS_PKCS11_OBJ_ATTR_PRIVKEY; + else { + fprintf(stderr, "Unknown object type %s\n", optarg); + exit(1); + } + break; + default: + fprintf(stderr, "Unknown option %c\n", (char)opt); + exit(1); + } + } + + if (optind == argc) { + fprintf(stderr, "specify URL\n"); + exit(1); + } + url = argv[optind]; + + envvar = getenv("GNUTLS_PIN"); + if (envvar && *envvar != '\0') { + opt_pin = envvar; + obj_flags |= GNUTLS_PKCS11_OBJ_FLAG_LOGIN; + gnutls_pkcs11_set_pin_function(pin_func, NULL); + } + + ret = gnutls_pkcs11_token_get_flags(url, &flags); + if (ret < 0) { + flags = 0; + } + + ret = + gnutls_pkcs11_obj_list_import_url2(&crt_list, &crt_list_size, + url, attrs, obj_flags); + if (ret != 0) { + fprintf(stderr, "error at %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + + for (i = 0; i < crt_list_size; i++) { + char *output; + + ret = + gnutls_pkcs11_obj_export_url(crt_list[i], 0, + &output); + if (ret != 0) { + fprintf(stderr, "error at %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + + fprintf(stdout, "%s\n", output); + gnutls_free(output); + gnutls_pkcs11_obj_deinit(crt_list[i]); + } + gnutls_free(crt_list); + + gnutls_global_deinit(); +} diff --git a/tests/pkcs11/list-tokens.c b/tests/pkcs11/list-tokens.c new file mode 100644 index 0000000..39cd730 --- /dev/null +++ b/tests/pkcs11/list-tokens.c @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2016-2017 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> +#include <getopt.h> +#include <assert.h> +#define P11_KIT_FUTURE_UNSTABLE_API +#include <p11-kit/p11-kit.h> +#include "cert-common.h" + +/* lists the registered PKCS#11 modules by p11-kit. + */ + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +int +_gnutls_pkcs11_token_get_url(unsigned int seq, + gnutls_pkcs11_url_type_t detailed, char **url, + unsigned flags); + +int main(int argc, char **argv) +{ + int ret; + unsigned i; + int opt; + char *url, *mod; + gnutls_x509_trust_list_t tl; + gnutls_x509_crt_t crt; + gnutls_pkcs11_privkey_t key; + unsigned flag = 1; + unsigned int status; + + ret = gnutls_global_init(); + if (ret != 0) { + fprintf(stderr, "error at %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + + gnutls_global_set_log_function(tls_log_func); + //gnutls_global_set_log_level(4711); + + while((opt = getopt(argc, argv, "s:o:mvatdp")) != -1) { + switch(opt) { + case 'o': + mod = strdup(optarg); + p11_kit_override_system_files(NULL, NULL, mod, mod, NULL); + break; + case 'm': + /* initialize manually - i.e., do no module loading */ + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fprintf(stderr, "error at %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + break; + case 's': + /* load module */ + ret = gnutls_pkcs11_add_provider(optarg, NULL); + if (ret != 0) { + fprintf(stderr, "error at %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + break; + case 'd': + /* when call _gnutls_pkcs11_token_get_url() do proper initialization + * if none done */ + flag = 0; + break; + case 'p': + /* do private key operations */ + assert(gnutls_pkcs11_privkey_init(&key) >= 0); + gnutls_pkcs11_privkey_import_url(key, "pkcs11:", 0); + gnutls_pkcs11_privkey_deinit(key); + break; + case 'a': + /* initialize auto - i.e., do module loading */ + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_AUTO, NULL); + if (ret != 0) { + fprintf(stderr, "error at %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + break; + case 't': + /* do trusted module loading */ + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_AUTO_TRUSTED, NULL); + if (ret != 0) { + fprintf(stderr, "error at %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + break; + case 'v': + /* do verification which should trigger trusted module loading */ + assert(gnutls_x509_crt_init(&crt) >= 0); + assert(gnutls_x509_crt_import(crt, &ca3_cert, GNUTLS_X509_FMT_PEM) >= 0); + + assert(gnutls_x509_trust_list_init(&tl, 0) >= 0); + assert(gnutls_x509_trust_list_add_system_trust(tl, 0, 0) >= 0); + gnutls_x509_trust_list_verify_crt2(tl, &crt, 1, NULL, 0, 0, &status, NULL); + gnutls_x509_trust_list_deinit(tl, 1); + gnutls_x509_crt_deinit(crt); + break; + default: + fprintf(stderr, "Unknown option %c\n", (char)opt); + exit(1); + } + } + + + for (i=0;;i++) { + ret = _gnutls_pkcs11_token_get_url(i, 0, &url, flag); + if (ret < 0) + break; + printf("%s\n", url); + free(url); + } + + /* try whether these URIs are operational */ + for (i=0;;i++) { + unsigned tflags; + + ret = _gnutls_pkcs11_token_get_url(i, 0, &url, flag); + if (ret < 0) + break; + ret = gnutls_pkcs11_token_get_flags(url, &tflags); + if (ret < 0) { + fprintf(stderr, "cannot get token %s flags: %s\n", url, gnutls_strerror(ret)); + exit(1); + } + free(url); + } + + gnutls_global_deinit(); +} diff --git a/tests/pkcs11/pkcs11-cert-import-url-exts.c b/tests/pkcs11/pkcs11-cert-import-url-exts.c new file mode 100644 index 0000000..bf806b1 --- /dev/null +++ b/tests/pkcs11/pkcs11-cert-import-url-exts.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <assert.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/x509-ext.h> + +#include "utils.h" + +/* Tests the certificate extension override in "trusted" PKCS#11 modules */ + +#ifdef _WIN32 +# define P11LIB "libpkcs11mock1.dll" +#else +# define P11LIB "libpkcs11mock1.so" +#endif + +static time_t mytime(time_t * t) +{ + time_t then = 1424466893; + + if (t) + *t = then; + + return then; +} + +void doit(void) +{ + int ret; + gnutls_x509_crt_t crt, ocrt; + unsigned keyusage; + const char *lib; + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + lib = getenv("P11MOCKLIB1"); + if (lib == NULL) + lib = P11LIB; + + gnutls_global_set_time_function(mytime); + if (debug) { + gnutls_global_set_log_level(4711); + success("loading lib %s\n", lib); + } + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, "trusted"); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + assert(gnutls_x509_crt_init(&crt)>=0); + assert(gnutls_x509_crt_init(&ocrt)>=0); + + /* check high level certificate functions */ + ret = gnutls_x509_crt_import_url(crt, "pkcs11:type=cert;object=cert1", 0); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_crt_import_url(ocrt, "pkcs11:type=cert;object=cert1", GNUTLS_PKCS11_OBJ_FLAG_OVERWRITE_TRUSTMOD_EXT); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_crt_equals(crt, ocrt); + if (ret != 0) { + fail("exported certificates are equal!\n"); + } + + ret = gnutls_x509_crt_get_ca_status(ocrt, NULL); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + if (ret == 0) { + fail("overridden cert is not a CA!\n"); + exit(1); + } + + ret = gnutls_x509_crt_get_key_usage(ocrt, &keyusage, NULL); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + if (keyusage != (GNUTLS_KEY_KEY_ENCIPHERMENT|GNUTLS_KEY_ENCIPHER_ONLY|GNUTLS_KEY_KEY_CERT_SIGN)) { + fail("Extension does not have the expected key usage!\n"); + } + + gnutls_x509_crt_deinit(crt); + gnutls_x509_crt_deinit(ocrt); + if (debug) + printf("done\n\n\n"); + + gnutls_global_deinit(); +} diff --git a/tests/pkcs11/pkcs11-cert-import-url4-exts.c b/tests/pkcs11/pkcs11-cert-import-url4-exts.c new file mode 100644 index 0000000..f9fe82f --- /dev/null +++ b/tests/pkcs11/pkcs11-cert-import-url4-exts.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <assert.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/x509-ext.h> + +#include "utils.h" + +/* Tests the certificate extension override in "trusted" PKCS#11 modules */ + +#ifdef _WIN32 +# define P11LIB "libpkcs11mock1.dll" +#else +# define P11LIB "libpkcs11mock1.so" +#endif + +static time_t mytime(time_t * t) +{ + time_t then = 1424466893; + + if (t) + *t = then; + + return then; +} + +void doit(void) +{ + int ret; + gnutls_x509_crt_t crt, ocrt; + unsigned keyusage; + const char *lib; + gnutls_pkcs11_obj_t *plist; + unsigned int plist_size; + gnutls_pkcs11_obj_t *plist2; + unsigned int plist2_size, i; + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + lib = getenv("P11MOCKLIB1"); + if (lib == NULL) + lib = P11LIB; + + gnutls_global_set_time_function(mytime); + if (debug) { + gnutls_global_set_log_level(4711); + success("loading lib %s\n", lib); + } + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, "trusted"); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + assert(gnutls_x509_crt_init(&crt)>=0); + assert(gnutls_x509_crt_init(&ocrt)>=0); + + /* check low level certificate import functions */ + ret = gnutls_pkcs11_obj_list_import_url4(&plist, &plist_size, "pkcs11:type=cert;object=cert1", 0); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_obj_list_import_url4(&plist2, &plist2_size, "pkcs11:type=cert;object=cert1", GNUTLS_PKCS11_OBJ_FLAG_OVERWRITE_TRUSTMOD_EXT); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + if (plist2_size != 1 || plist_size != 1) { + fail("could not import certs %d, %d\n", plist_size, plist2_size); + } + + ret = gnutls_x509_crt_import_pkcs11(crt, plist[0]); + if (ret != 0) { + fail("could not import cert!\n"); + } + + ret = gnutls_x509_crt_import_pkcs11(ocrt, plist2[0]); + if (ret != 0) { + fail("could not import cert!\n"); + } + + for (i=0;i<plist_size;i++) + gnutls_pkcs11_obj_deinit(plist[i]); + for (i=0;i<plist2_size;i++) + gnutls_pkcs11_obj_deinit(plist2[i]); + gnutls_free(plist); + gnutls_free(plist2); + + ret = gnutls_x509_crt_equals(crt, ocrt); + if (ret != 0) { + fail("exported certificates are equal!\n"); + } + + ret = gnutls_x509_crt_get_ca_status(ocrt, NULL); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + if (ret == 0) { + fail("overridden cert is not a CA!\n"); + exit(1); + } + + ret = gnutls_x509_crt_get_key_usage(ocrt, &keyusage, NULL); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + if (keyusage != (GNUTLS_KEY_KEY_ENCIPHERMENT|GNUTLS_KEY_ENCIPHER_ONLY|GNUTLS_KEY_KEY_CERT_SIGN)) { + fail("Extension does not have the expected key usage!\n"); + } + + gnutls_x509_crt_deinit(crt); + gnutls_x509_crt_deinit(ocrt); + if (debug) + printf("done\n\n\n"); + + gnutls_global_deinit(); +} diff --git a/tests/pkcs11/pkcs11-chainverify.c b/tests/pkcs11/pkcs11-chainverify.c new file mode 100644 index 0000000..0ad2efe --- /dev/null +++ b/tests/pkcs11/pkcs11-chainverify.c @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2008-2014 Free Software Foundation, Inc. + * + * Author: Simon Josefsson, Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> + +#include "../utils.h" +#include "softhsm.h" +#include "../test-chains.h" + +#define CONFIG "softhsm-chainverify.config" + +#define DEFAULT_THEN 1256803113 +static time_t then = DEFAULT_THEN; + +/* GnuTLS internally calls time() to find out the current time when + verifying certificates. To avoid a time bomb, we hard code the + current time. This should work fine on systems where the library + call to time is resolved at run-time. */ +static time_t mytime(time_t * t) +{ + if (t) + *t = then; + + return then; +} + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, "1234"); + return 0; + } + return -1; +} + +void doit(void) +{ + int exit_val = 0; + size_t i; + int ret; + const char *lib, *bin; + gnutls_typed_vdata_st vdata[2]; + char buf[128]; + + if (gnutls_fips140_mode_enabled()) + exit(77); + + /* The overloading of time() seems to work in linux (ELF?) + * systems only. Disable it on windows. + */ +#ifdef _WIN32 + exit(77); +#endif + + bin = softhsm_bin(); + + lib = softhsm_lib(); + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + gnutls_global_set_time_function(mytime); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin 1234 --pin 1234", bin); + system(buf); + + ret = gnutls_pkcs11_add_provider(lib, "trusted"); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + for (i = 0; chains[i].chain; i++) { + gnutls_x509_trust_list_t tl; + unsigned int verify_status; + gnutls_x509_crt_t certs[MAX_CHAIN]; + gnutls_x509_crt_t ca; + gnutls_datum_t tmp; + size_t j; + + gnutls_x509_trust_list_iter_t get_ca_iter; + gnutls_datum_t get_ca_datum_test; + gnutls_datum_t get_ca_datum; + gnutls_x509_crt_t get_ca_crt; + + if (debug) + printf("Chain '%s' (%d)...\n", chains[i].name, + (int) i); + + if (chains[i].notfips && gnutls_fips140_mode_enabled()) { + if (debug) + printf("Skipping in FIPS mode...\n"); + continue; + } + + for (j = 0; chains[i].chain[j]; j++) { + if (debug > 2) + printf("\tAdding certificate %d...", + (int) j); + + ret = gnutls_x509_crt_init(&certs[j]); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_init[%d,%d]: %s\n", + (int) i, (int) j, + gnutls_strerror(ret)); + exit(1); + } + + tmp.data = (unsigned char *) chains[i].chain[j]; + tmp.size = strlen(chains[i].chain[j]); + + ret = + gnutls_x509_crt_import(certs[j], &tmp, + GNUTLS_X509_FMT_PEM); + if (debug > 2) + printf("done\n"); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_import[%s,%d]: %s\n", + chains[i].name, (int) j, + gnutls_strerror(ret)); + exit(1); + } + + gnutls_x509_crt_print(certs[j], + GNUTLS_CRT_PRINT_ONELINE, + &tmp); + if (debug) + printf("\tCertificate %d: %.*s\n", (int) j, + tmp.size, tmp.data); + gnutls_free(tmp.data); + } + + if (debug > 2) + printf("\tAdding CA certificate..."); + + ret = gnutls_x509_crt_init(&ca); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + tmp.data = (unsigned char *) *chains[i].ca; + tmp.size = strlen(*chains[i].ca); + + ret = + gnutls_x509_crt_import(ca, &tmp, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + if (debug > 2) + printf("done\n"); + + gnutls_x509_crt_print(ca, GNUTLS_CRT_PRINT_ONELINE, &tmp); + if (debug) + printf("\tCA Certificate: %.*s\n", tmp.size, + tmp.data); + gnutls_free(tmp.data); + + if (debug) + printf("\tVerifying..."); + + /* initialize softhsm token */ + ret = gnutls_pkcs11_token_init(SOFTHSM_URL, "1234", "test"); + if (ret < 0) { + fail("gnutls_pkcs11_token_init\n"); + exit(1); + } + + /* write CA certificate to softhsm */ + ret = gnutls_pkcs11_copy_x509_crt(SOFTHSM_URL, ca, "test-ca", GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED| + GNUTLS_PKCS11_OBJ_FLAG_MARK_CA| + GNUTLS_PKCS11_OBJ_FLAG_LOGIN_SO); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_crt: %s\n", gnutls_strerror(ret)); + } + + gnutls_x509_trust_list_init(&tl, 0); + + ret = gnutls_x509_trust_list_add_trust_file(tl, SOFTHSM_URL, NULL, 0, 0, 0); + if (ret < 0) { + fail("gnutls_x509_trust_list_add_trust_file: %s\n", gnutls_strerror(ret)); + exit(1); + } + + if (ret < 1) { + fail("gnutls_x509_trust_list_add_trust_file returned zero!\n"); + exit(1); + } + + /* test trust list iteration */ + get_ca_iter = NULL; + while (gnutls_x509_trust_list_iter_get_ca(tl, &get_ca_iter, &get_ca_crt) == 0) { + ret = gnutls_x509_crt_export2(get_ca_crt, GNUTLS_X509_FMT_PEM, &get_ca_datum_test); + if (ret < 0) { + fail("gnutls_x509_crt_export2: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_crt_export2(ca, GNUTLS_X509_FMT_PEM, &get_ca_datum); + if (ret < 0) { + fail("gnutls_x509_crt_export2: %s\n", gnutls_strerror(ret)); + exit(1); + } + + if (get_ca_datum_test.size != get_ca_datum.size || + memcmp(get_ca_datum_test.data, get_ca_datum.data, get_ca_datum.size) != 0) { + fail("gnutls_x509_trist_list_iter_get_ca: Unexpected certificate (%u != %u):\n\n%s\n\nvs.\n\n%s", get_ca_datum.size, get_ca_datum_test.size, get_ca_datum.data, get_ca_datum_test.data); + exit(1); + } + + gnutls_free(get_ca_datum.data); + gnutls_free(get_ca_datum_test.data); + gnutls_x509_crt_deinit(get_ca_crt); + } + + vdata[0].type = GNUTLS_DT_KEY_PURPOSE_OID; + vdata[0].data = (void *)chains[i].purpose; + + if (chains[i].expected_time != 0) + then = chains[i].expected_time; + else + then = DEFAULT_THEN; + + /* make sure that the two functions don't diverge */ + ret = gnutls_x509_trust_list_verify_crt2(tl, certs, j, + vdata, + chains[i].purpose==NULL?0:1, + chains[i].verify_flags, + &verify_status, NULL); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_list_verify[%d,%d]: %s\n", + (int) i, (int) j, gnutls_strerror(ret)); + exit(1); + } + + if (verify_status != chains[i].expected_verify_result) { + gnutls_datum_t out1, out2; + gnutls_certificate_verification_status_print + (verify_status, GNUTLS_CRT_X509, &out1, 0); + gnutls_certificate_verification_status_print(chains + [i]. + expected_verify_result, + GNUTLS_CRT_X509, + &out2, + 0); + fail("chain[%s]:\nverify_status: %d: %s\nexpected: %d: %s\n", chains[i].name, verify_status, out1.data, chains[i].expected_verify_result, out2.data); + gnutls_free(out1.data); + gnutls_free(out2.data); + +#if 0 + j = 0; + do { + fprintf(stderr, "%s\n", + chains[i].chain[j]); + } + while (chains[i].chain[++j] != NULL); +#endif + + if (!debug) + exit(1); + } else if (debug) + printf("done\n"); + + if (debug) + printf("\tCleanup..."); + + gnutls_x509_trust_list_deinit(tl, 0); + gnutls_x509_crt_deinit(ca); + for (j = 0; chains[i].chain[j]; j++) + gnutls_x509_crt_deinit(certs[j]); + + if (debug) + printf("done\n\n\n"); + } + + gnutls_global_deinit(); + + if (debug) + printf("Exit status...%d\n", exit_val); + remove(CONFIG); + + exit(exit_val); +} diff --git a/tests/pkcs11/pkcs11-combo.c b/tests/pkcs11/pkcs11-combo.c new file mode 100644 index 0000000..43189c4 --- /dev/null +++ b/tests/pkcs11/pkcs11-combo.c @@ -0,0 +1,431 @@ +/* + * Copyright (C) 2014 Red Hat + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/x509-ext.h> + +/* Tests whether the combination of a trust module + additional CAs + * in a trust list would work. + */ + +#include "../utils.h" +#include "../test-chains.h" +#include "softhsm.h" + +#define NAME "softhsm-combo" +#define CONFIG NAME".config" + +/* These CAs have the same DN */ +static const char *ca_list[MAX_CHAIN] = { +"-----BEGIN CERTIFICATE-----\n" +"MIIHSjCCBjKgAwIBAgIKYRHt9wABAAAAFTANBgkqhkiG9w0BAQUFADBSMQswCQYD\n" +"VQQGEwJVUzEaMBgGA1UEChMRSW50ZWwgQ29ycG9yYXRpb24xJzAlBgNVBAMTHklu\n" +"dGVsIEludHJhbmV0IEJhc2ljIFBvbGljeSBDQTAeFw0xMzAyMDQyMTUyMThaFw0x\n" +"ODA1MjQxOTU5MzlaMFYxCzAJBgNVBAYTAlVTMRowGAYDVQQKExFJbnRlbCBDb3Jw\n" +"b3JhdGlvbjErMCkGA1UEAxMiSW50ZWwgSW50cmFuZXQgQmFzaWMgSXNzdWluZyBD\n" +"QSAyQjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALn3ogjraWSmK5Wb\n" +"/4e9mENA1F36FBVemaG7L93ZhRRXq4UV0PQM5/4TOe9KAaOlX+a2cuULeeUtN9Rk\n" +"V/nHAVzSWlqc/NTMJfuI/1AD7ICNejQFYLxDMXGjR7eAHtiMz0iTMp9u6YTw4WXh\n" +"WffqTPiqUZ6DEWsMic9dM9yw/JqzycKClLcTD1OCvtw7Fx4tNTu6/ngrYJcTo29e\n" +"BBh/DupgtgnYPYuExEkHmucb4VIDdjfRkPo/BdNqrUSYfYqnUDj5mH+hPzIgppsZ\n" +"Rw0S5PUZGuC1f+Zok+4vZPR+hGG3Pdm2LTUEWSnurlhyfBoM+0yxeHsmL9aHU7zt\n" +"EIzVmKUCAwEAAaOCBBwwggQYMBIGCSsGAQQBgjcVAQQFAgMCAAIwIwYJKwYBBAGC\n" +"NxUCBBYEFMqHyYZOx6LYwRwZ+5vjOyIl9hENMB0GA1UdDgQWBBQ4Y3b6tgU6qVlP\n" +"SoeNoIO3fpE6CzAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC\n" +"AYYwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBRp6zCRHAOAgE4RFYhG\n" +"pOJBmtNpHzCCAaIGA1UdHwSCAZkwggGVMIIBkaCCAY2gggGJhlFodHRwOi8vd3d3\n" +"LmludGVsLmNvbS9yZXBvc2l0b3J5L0NSTC9JbnRlbCUyMEludHJhbmV0JTIwQmFz\n" +"aWMlMjBQb2xpY3klMjBDQSgxKS5jcmyGWmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuaW50\n" +"ZWwuY29tL3JlcG9zaXRvcnkvQ1JML0ludGVsJTIwSW50cmFuZXQlMjBCYXNpYyUy\n" +"MFBvbGljeSUyMENBKDEpLmNybIaB12xkYXA6Ly8vQ049SW50ZWwlMjBJbnRyYW5l\n" +"dCUyMEJhc2ljJTIwUG9saWN5JTIwQ0EoMSksQ049bWNzaWJwY2EsQ049Q0RQLENO\n" +"PVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3Vy\n" +"YXRpb24sREM9Y29ycCxEQz1pbnRlbCxEQz1jb20/Y2VydGlmaWNhdGVSZXZvY2F0\n" +"aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MIIB\n" +"uQYIKwYBBQUHAQEEggGrMIIBpzBmBggrBgEFBQcwAoZaaHR0cDovL3d3dy5pbnRl\n" +"bC5jb20vcmVwb3NpdG9yeS9jZXJ0aWZpY2F0ZXMvSW50ZWwlMjBJbnRyYW5ldCUy\n" +"MEJhc2ljJTIwUG9saWN5JTIwQ0EoMSkuY3J0MG8GCCsGAQUFBzAChmNodHRwOi8v\n" +"Y2VydGlmaWNhdGVzLmludGVsLmNvbS9yZXBvc2l0b3J5L2NlcnRpZmljYXRlcy9J\n" +"bnRlbCUyMEludHJhbmV0JTIwQmFzaWMlMjBQb2xpY3klMjBDQSgxKS5jcnQwgcsG\n" +"CCsGAQUFBzAChoG+bGRhcDovLy9DTj1JbnRlbCUyMEludHJhbmV0JTIwQmFzaWMl\n" +"MjBQb2xpY3klMjBDQSxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIwU2VydmljZXMs\n" +"Q049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1jb3JwLERDPWludGVsLERD\n" +"PWNvbT9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9Y2VydGlmaWNhdGlv\n" +"bkF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAQEAsj8cHt2jSAmnIGulE9jXooAc\n" +"qH2xehlI+ko/al+nDnBzbjDYYjVS52XitYg8JGo6j72ijiGlGb/03FcQJRBZmUH6\n" +"znktx2rGTm4IdjL8quhvHthlzXXCozL8GMeeOuZ5rzHlhapKx764a5RuZtyx89uS\n" +"9cECon6oLGesXjFJ8Xrq6ecHZrQwJUpmvZalwvloKACAWqBh8yV12WDnUNZhtp8N\n" +"8rqeJZoy/lXGnTxsSSodO/5Y/CxYJM4W6u4WgvXNJSjO/0qWvb64S+pVLjBzwI+Y\n" +"X6oLqmBovRp1lGPOLjkXZi3EKDR8DmzhtpJq2677RtYowewnFedQ+exH9cXoJw==\n" +"-----END CERTIFICATE-----", +"-----BEGIN CERTIFICATE-----\n" +"MIIHSjCCBjKgAwIBAgIKYRXxrQABAAAAETANBgkqhkiG9w0BAQUFADBSMQswCQYD\n" +"VQQGEwJVUzEaMBgGA1UEChMRSW50ZWwgQ29ycG9yYXRpb24xJzAlBgNVBAMTHklu\n" +"dGVsIEludHJhbmV0IEJhc2ljIFBvbGljeSBDQTAeFw0wOTA1MTUxODQyNDVaFw0x\n" +"NTA1MTUxODUyNDVaMFYxCzAJBgNVBAYTAlVTMRowGAYDVQQKExFJbnRlbCBDb3Jw\n" +"b3JhdGlvbjErMCkGA1UEAxMiSW50ZWwgSW50cmFuZXQgQmFzaWMgSXNzdWluZyBD\n" +"QSAyQjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbJOXtXYgfyoch6\n" +"ip5SSjijOXvpIjBxbTl5EGH/VYHmpM2O6SRlKh/uy77QS9m84sRWCJLr8cWwX9oH\n" +"qSmIylgcWvDpVNHx4v506DTTrbK0sbYRQYXRajOzJKeTt7NLeLrngyl45FrI9VAT\n" +"3yqp/2BCG1dUwcBha3dB2UbTkFOMt9o/gqoL6KvgswYMs/oGc/OIjeozdYuhnBT2\n" +"YlT9Ge5pfhOJWXh4DJbxnTmWwRUKq0MXFn0S00KQ/BZOTkc/5DibUmbmMrYi8ra4\n" +"Z2bpnoTq0WNA99O2Lk8IgmkqPdi6HwZwKCE/x01qwP8zo76rvN8sbW9pj2WzS1WF\n" +"tSDPeZECAwEAAaOCBBwwggQYMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYE\n" +"FPwbdyds7Cm03lobLKmI6q59npi+MAsGA1UdDwQEAwIBhjASBgkrBgEEAYI3FQEE\n" +"BQIDAQABMCMGCSsGAQQBgjcVAgQWBBRT1n27C6cZL4QFHaUX2nFSCPxhtTAZBgkr\n" +"BgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAfBgNVHSMEGDAWgBRp6zCRHAOAgE4RFYhG\n" +"pOJBmtNpHzCCAaIGA1UdHwSCAZkwggGVMIIBkaCCAY2gggGJhlFodHRwOi8vd3d3\n" +"LmludGVsLmNvbS9yZXBvc2l0b3J5L0NSTC9JbnRlbCUyMEludHJhbmV0JTIwQmFz\n" +"aWMlMjBQb2xpY3klMjBDQSgxKS5jcmyGWmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuaW50\n" +"ZWwuY29tL3JlcG9zaXRvcnkvQ1JML0ludGVsJTIwSW50cmFuZXQlMjBCYXNpYyUy\n" +"MFBvbGljeSUyMENBKDEpLmNybIaB12xkYXA6Ly8vQ049SW50ZWwlMjBJbnRyYW5l\n" +"dCUyMEJhc2ljJTIwUG9saWN5JTIwQ0EoMSksQ049bWNzaWJwY2EsQ049Q0RQLENO\n" +"PVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3Vy\n" +"YXRpb24sREM9Y29ycCxEQz1pbnRlbCxEQz1jb20/Y2VydGlmaWNhdGVSZXZvY2F0\n" +"aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MIIB\n" +"uQYIKwYBBQUHAQEEggGrMIIBpzBmBggrBgEFBQcwAoZaaHR0cDovL3d3dy5pbnRl\n" +"bC5jb20vcmVwb3NpdG9yeS9jZXJ0aWZpY2F0ZXMvSW50ZWwlMjBJbnRyYW5ldCUy\n" +"MEJhc2ljJTIwUG9saWN5JTIwQ0EoMSkuY3J0MG8GCCsGAQUFBzAChmNodHRwOi8v\n" +"Y2VydGlmaWNhdGVzLmludGVsLmNvbS9yZXBvc2l0b3J5L2NlcnRpZmljYXRlcy9J\n" +"bnRlbCUyMEludHJhbmV0JTIwQmFzaWMlMjBQb2xpY3klMjBDQSgxKS5jcnQwgcsG\n" +"CCsGAQUFBzAChoG+bGRhcDovLy9DTj1JbnRlbCUyMEludHJhbmV0JTIwQmFzaWMl\n" +"MjBQb2xpY3klMjBDQSxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIwU2VydmljZXMs\n" +"Q049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1jb3JwLERDPWludGVsLERD\n" +"PWNvbT9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9Y2VydGlmaWNhdGlv\n" +"bkF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAQEArlAkrJXyMCssqAJT3PqnY7wt\n" +"sirq1fTMrVrHdmkpBKDXBQnDcTW1zfZtOPV/QDm3UsFwDBbGq+j/7U9qZ1zYHkv+\n" +"wrBpeFM6dlca/sgegGGAhYnQQwmlSzNXCKHMBltMjT61X8rVjyt1XJnucgat9rnT\n" +"2j8pztqoViVnORsGfT6DDB/bz/6bFKw4FMp1wDaJI7dKh5NUggvH36owTWI7JUvq\n" +"yJ8OI2qmjXrlqGexfwvltIkEk8xzuMIHWQoR8sERL2qf3nb2VYq1s1LbH5uCkZ0l\n" +"w/xgwFbbwjaGJ3TFOmkVKYU77nXSkfK9EXae0UZRU0WmX4t5NNt8jiL56TPpsw==\n" +"-----END CERTIFICATE-----\n", +"-----BEGIN CERTIFICATE-----\n" +"MIIHIzCCBgugAwIBAgIKYRok3wABAAAADDANBgkqhkiG9w0BAQUFADBSMQswCQYD\n" +"VQQGEwJVUzEaMBgGA1UEChMRSW50ZWwgQ29ycG9yYXRpb24xJzAlBgNVBAMTHklu\n" +"dGVsIEludHJhbmV0IEJhc2ljIFBvbGljeSBDQTAeFw0wNjA1MjQxOTU2MDFaFw0x\n" +"MjA1MjQyMDA2MDFaMFYxCzAJBgNVBAYTAlVTMRowGAYDVQQKExFJbnRlbCBDb3Jw\n" +"b3JhdGlvbjErMCkGA1UEAxMiSW50ZWwgSW50cmFuZXQgQmFzaWMgSXNzdWluZyBD\n" +"QSAyQjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANE2pFSB0XqXoRWF\n" +"N7bzDesBAcTGEqcr6GVA+sMcJ5Vt17S8vGesmO2RgP6I49Q58nIhUnT054arUlOx\n" +"NKYbAEiVyGOK5zV2mZS4oW2UazfcpsV1uuO3j02UbzX+qcxQdNqoAHxwoB4nRJuU\n" +"Ijio45jWAssDbD8IKHZpmqRI5wUzbibkWnTZEc0YFO6iF40sNtqVr+uInP07PkQn\n" +"1Ttkyw6isa5Dhcyq6lTVOjnlj29bFYbZxN1uuDnTpUMVeov8oQv5wLyLrDVd1sMg\n" +"Njr2oofepZ8KjF3DKCkfsUekCHA9Pr2K/4hStd/nSwvIdNjCjfznqYadkB6wQ99a\n" +"hTX4uJkCAwEAAaOCA/UwggPxMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYE\n" +"FJunwCR+/af8p76CGTyhUZc3l/4DMAsGA1UdDwQEAwIBhjAQBgkrBgEEAYI3FQEE\n" +"AwIBADAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAfBgNVHSMEGDAWgBRp6zCR\n" +"HAOAgE4RFYhGpOJBmtNpHzCCAaIGA1UdHwSCAZkwggGVMIIBkaCCAY2gggGJhlFo\n" +"dHRwOi8vd3d3LmludGVsLmNvbS9yZXBvc2l0b3J5L0NSTC9JbnRlbCUyMEludHJh\n" +"bmV0JTIwQmFzaWMlMjBQb2xpY3klMjBDQSgxKS5jcmyGWmh0dHA6Ly9jZXJ0aWZp\n" +"Y2F0ZXMuaW50ZWwuY29tL3JlcG9zaXRvcnkvQ1JML0ludGVsJTIwSW50cmFuZXQl\n" +"MjBCYXNpYyUyMFBvbGljeSUyMENBKDEpLmNybIaB12xkYXA6Ly8vQ049SW50ZWwl\n" +"MjBJbnRyYW5ldCUyMEJhc2ljJTIwUG9saWN5JTIwQ0EoMSksQ049bWNzaWJwY2Es\n" +"Q049Q0RQLENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENO\n" +"PUNvbmZpZ3VyYXRpb24sREM9Y29ycCxEQz1pbnRlbCxEQz1jb20/Y2VydGlmaWNh\n" +"dGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlv\n" +"blBvaW50MIIBuQYIKwYBBQUHAQEEggGrMIIBpzBmBggrBgEFBQcwAoZaaHR0cDov\n" +"L3d3dy5pbnRlbC5jb20vcmVwb3NpdG9yeS9jZXJ0aWZpY2F0ZXMvSW50ZWwlMjBJ\n" +"bnRyYW5ldCUyMEJhc2ljJTIwUG9saWN5JTIwQ0EoMSkuY3J0MG8GCCsGAQUFBzAC\n" +"hmNodHRwOi8vY2VydGlmaWNhdGVzLmludGVsLmNvbS9yZXBvc2l0b3J5L2NlcnRp\n" +"ZmljYXRlcy9JbnRlbCUyMEludHJhbmV0JTIwQmFzaWMlMjBQb2xpY3klMjBDQSgx\n" +"KS5jcnQwgcsGCCsGAQUFBzAChoG+bGRhcDovLy9DTj1JbnRlbCUyMEludHJhbmV0\n" +"JTIwQmFzaWMlMjBQb2xpY3klMjBDQSxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIw\n" +"U2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1jb3JwLERD\n" +"PWludGVsLERDPWNvbT9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9Y2Vy\n" +"dGlmaWNhdGlvbkF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAQEAe3SmN0lsGF0h\n" +"zq+NANnUD4YJS31UqreVm4kJv07+9CTBtlB0AVqJ2RcjRosdQmrbhx7R0WwcXSdR\n" +"QnRGhaoDVRNehKiz3Grp6ehJr9LInhCp6WtOeKRlOSb2xgRDJCtzCi07TuAb9h2I\n" +"urpmndeA4NEbPYL1GYEBpKYawUcFCq5yTv0YgZXy53DdBDv9ygRWYGEk7/gPgvCu\n" +"2O1GNs9n25goy+3/aMkHnUyl3MOtiooXJR7eKOEgTPHNe42LQ9KuUz5SoZQN8vSL\n" +"r49IRDC4dgMkGvsC5h0+ftixQ66ni6QJe6SNcpSZrpW5vBE9J+vtDI0gTyq2SYPo\n" +"0fiS3V8p4g==\n" +"-----END CERTIFICATE-----\n", +NULL}; + +/* GnuTLS internally calls time() to find out the current time when + verifying certificates. To avoid a time bomb, we hard code the + current time. This should work fine on systems where the library + call to time is resolved at run-time. */ +static time_t mytime(time_t * t) +{ + time_t then = 1256803113; + + if (t) + *t = then; + + return then; +} + +#define PIN "1234" + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +void doit(void) +{ + char buf[128]; + int exit_val = 0; + int ret; + unsigned j; + const char *lib, *bin; + gnutls_x509_crt_t issuer = NULL; + gnutls_x509_trust_list_t tl; + gnutls_x509_crt_t certs[MAX_CHAIN]; + gnutls_x509_crt_t end, ca; + unsigned verify_status = 0; + gnutls_datum_t tmp; + + if (gnutls_fips140_mode_enabled()) + exit(77); + + /* The overloading of time() seems to work in linux (ELF?) + * systems only. Disable it on windows. + */ +#ifdef _WIN32 + exit(77); +#endif + bin = softhsm_bin(); + + lib = softhsm_lib(); + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + gnutls_global_set_time_function(mytime); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin "PIN" --pin "PIN, bin); + system(buf); + + ret = gnutls_pkcs11_add_provider(lib, "trusted"); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + for (j = 0; ca_list[j]; j++) { + if (debug > 2) + printf("\tAdding certificate %d...", + (int) j); + + ret = gnutls_x509_crt_init(&certs[j]); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_init[%d,%d]: %s\n", + (int) 3, (int) j, + gnutls_strerror(ret)); + exit(1); + } + + tmp.data = (unsigned char *) ca_list[j]; + tmp.size = strlen(ca_list[j]); + + ret = + gnutls_x509_crt_import(certs[j], &tmp, + GNUTLS_X509_FMT_PEM); + if (debug > 2) + printf("done\n"); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_import[%d]: %s\n", + (int) j, + gnutls_strerror(ret)); + exit(1); + } + + gnutls_x509_crt_print(certs[j], + GNUTLS_CRT_PRINT_ONELINE, + &tmp); + if (debug) + printf("\tCertificate %d: %.*s\n", (int) j, + tmp.size, tmp.data); + gnutls_free(tmp.data); + } + + if (debug > 2) + printf("\tAdding end certificate..."); + + ret = gnutls_x509_crt_init(&end); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + tmp.data = (unsigned char *) v1_root_check[0]; + tmp.size = strlen(v1_root_check[0]); + + ret = + gnutls_x509_crt_import(end, &tmp, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + gnutls_x509_crt_print(end, GNUTLS_CRT_PRINT_ONELINE, &tmp); + if (debug) + printf("\tEnd Certificate: %.*s\n", tmp.size, + tmp.data); + gnutls_free(tmp.data); + + ret = gnutls_x509_crt_init(&ca); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + tmp.data = (unsigned char *) v1_root_check[1]; + tmp.size = strlen(v1_root_check[1]); + + ret = + gnutls_x509_crt_import(ca, &tmp, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + gnutls_x509_crt_print(end, GNUTLS_CRT_PRINT_ONELINE, &tmp); + if (debug) + printf("\tCA Certificate: %.*s\n", tmp.size, + tmp.data); + gnutls_free(tmp.data); + + if (debug > 2) + printf("done\n"); + + + if (debug) + printf("\tChecking presence and verification..."); + + /* initialize softhsm token */ + ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test"); + if (ret < 0) { + fail("gnutls_pkcs11_token_init\n"); + exit(1); + } + + /* write CA certificate to softhsm */ + for (j = 0; ca_list[j]; j++) { + char name[64]; + snprintf(name, sizeof(name), "test-ca%d", j); + ret = gnutls_pkcs11_copy_x509_crt(SOFTHSM_URL, certs[j], name, GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED|GNUTLS_PKCS11_OBJ_FLAG_LOGIN_SO); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_crt: %s\n", gnutls_strerror(ret)); + exit(1); + } + } + + gnutls_x509_trust_list_init(&tl, 0); + + ret = gnutls_x509_trust_list_add_trust_file(tl, SOFTHSM_URL, NULL, 0, 0, 0); + if (ret < 0) { + fail("gnutls_x509_trust_list_add_trust_file\n"); + exit(1); + } + + ret = gnutls_x509_trust_list_add_cas(tl, &ca, 1, 0); + if (ret < 0) { + fail("gnutls_x509_trust_list_add_cas\n"); + exit(1); + } + + /* extract the issuer of the certificate */ + ret = gnutls_x509_trust_list_get_issuer(tl, end, &issuer, GNUTLS_TL_GET_COPY); + if (ret < 0) { + fail("gnutls_x509_trust_list_get_issuer should have succeeded\n"); + exit(1); + } + gnutls_x509_crt_deinit(issuer); + + ret = gnutls_pkcs11_crt_is_known(SOFTHSM_URL, ca, GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED); + if (ret != 0) { + fail("gnutls_pkcs11_crt_is_known should have failed!\n"); + exit(1); + } + + ret = gnutls_x509_trust_list_verify_crt2(tl, &end, 1, + NULL, 0, + GNUTLS_VERIFY_DISABLE_TIME_CHECKS, &verify_status, NULL); + if (ret < 0) { + fail("gnutls_x509_trust_list_verify_crt2 should have succeeded\n"); + exit(1); + } + + if (verify_status != 0) { + fail("verification should have succeeded: %.2x\n", verify_status); + exit(1); + } + + if (debug) + printf("\tCleanup..."); + + gnutls_x509_trust_list_deinit(tl, 0); + gnutls_x509_crt_deinit(ca); + gnutls_x509_crt_deinit(end); + for (j = 0; ca_list[j]; j++) { + gnutls_x509_crt_deinit(certs[j]); + } + if (debug) + printf("done\n\n\n"); + + gnutls_global_deinit(); + + if (debug) + printf("Exit status...%d\n", exit_val); + remove(CONFIG); + + exit(exit_val); +} diff --git a/tests/pkcs11/pkcs11-ec-privkey-test.c b/tests/pkcs11/pkcs11-ec-privkey-test.c new file mode 100644 index 0000000..782ba00 --- /dev/null +++ b/tests/pkcs11/pkcs11-ec-privkey-test.c @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2015 Nikos Mavrogiannopoulos + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> + +#include "../utils.h" +#include "softhsm.h" + +#define CONFIG_NAME "softhsm-privkey-ecdsa-test" +#define CONFIG CONFIG_NAME".config" + +/* Tests whether signing with PKCS#11 may produce signed (invalid) + * INTEGER values in DSASignatureValue. */ + + +#include "../cert-common.h" + +#define PIN "1234" + +static const gnutls_datum_t testdata = {(void*)"test test", 9}; + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +int _gnutls_decode_ber_rs_raw(const gnutls_datum_t * sig_value, gnutls_datum_t *r, gnutls_datum_t *s); + +void doit(void) +{ + char buf[128]; + int ret, pk; + const char *lib, *bin; + gnutls_x509_crt_t crt; + gnutls_x509_privkey_t key; + gnutls_datum_t tmp, sig; + gnutls_privkey_t pkey; + gnutls_pubkey_t pubkey; + gnutls_pubkey_t pubkey2; + gnutls_pubkey_t pubkey3; + gnutls_pubkey_t pubkey4; + unsigned i; + + if (gnutls_fips140_mode_enabled()) + exit(77); + + bin = softhsm_bin(); + + lib = softhsm_lib(); + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin "PIN" --pin "PIN, bin); + system(buf); + + ret = gnutls_pkcs11_add_provider(lib, "trusted"); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_crt_init(&crt); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_x509_crt_import(crt, &server_ecc_cert, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + if (debug) { + gnutls_x509_crt_print(crt, + GNUTLS_CRT_PRINT_ONELINE, + &tmp); + + printf("\tCertificate: %.*s\n", + tmp.size, tmp.data); + gnutls_free(tmp.data); + } + + ret = gnutls_x509_privkey_init(&key); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_privkey_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_x509_privkey_import(key, &server_ecc_key, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_privkey_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + /* initialize softhsm token */ + ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test"); + if (ret < 0) { + fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_token_set_pin(SOFTHSM_URL, NULL, PIN, GNUTLS_PIN_USER); + if (ret < 0) { + fail("gnutls_pkcs11_token_set_pin: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_copy_x509_crt(SOFTHSM_URL, crt, "cert", + GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE|GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_crt: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_copy_x509_privkey(SOFTHSM_URL, key, "cert", GNUTLS_KEY_DIGITAL_SIGNATURE|GNUTLS_KEY_KEY_ENCIPHERMENT, + GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE|GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE|GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_privkey: %s\n", gnutls_strerror(ret)); + exit(1); + } + + /* Write pubkey to the card too */ + assert(gnutls_pubkey_init(&pubkey) == 0); + assert(gnutls_pubkey_import_x509(pubkey, crt, 0) == 0); + + ret = gnutls_pkcs11_copy_pubkey(SOFTHSM_URL, pubkey, "cert", NULL, + GNUTLS_KEY_DIGITAL_SIGNATURE | + GNUTLS_KEY_KEY_ENCIPHERMENT, 0); + if (ret < 0) { + fail("gnutls_pkcs11_copy_pubkey: %s\n", + gnutls_strerror(ret)); + } + + gnutls_x509_crt_deinit(crt); + gnutls_x509_privkey_deinit(key); + gnutls_pubkey_deinit(pubkey); + gnutls_pkcs11_set_pin_function(NULL, NULL); + + assert(gnutls_privkey_init(&pkey) == 0); + + ret = gnutls_privkey_import_pkcs11_url(pkey, SOFTHSM_URL";object=cert;object-type=private;pin-value="PIN); + if (ret < 0) { + fprintf(stderr, "error in %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + + /* Try to read the public key with public key URI */ + assert(gnutls_pubkey_init(&pubkey3) == 0); + + + ret = + gnutls_pubkey_import_pkcs11_url(pubkey3, + SOFTHSM_URL + ";object=cert;object-type=public;pin-value=" + PIN, 0); + if (ret < 0) { + fail("error in gnutls_pubkey_import_pkcs11_url: %s\n", gnutls_strerror(ret)); + } + + /* Try to read the public key with certificate URI */ + assert(gnutls_pubkey_init(&pubkey4) == 0); + + ret = + gnutls_pubkey_import_pkcs11_url(pubkey4, + SOFTHSM_URL + ";object=cert;object-type=cert;pin-value=" + PIN, 0); + if (ret < 0) { + fail("error in gnutls_pubkey_import_pkcs11_url: %s\n", gnutls_strerror(ret)); + } + + assert(gnutls_pubkey_init(&pubkey) == 0); + assert(gnutls_pubkey_import_privkey(pubkey, pkey, 0, 0) == 0); + + pk = gnutls_pubkey_get_pk_algorithm(pubkey, NULL); + + assert(gnutls_pubkey_init(&pubkey2) == 0); + assert(gnutls_pubkey_import_x509_raw(pubkey2, &server_ecc_cert, GNUTLS_X509_FMT_PEM, 0) == 0); + + for (i=0;i<100;i++) { + gnutls_datum_t r = {NULL, 0}; + gnutls_datum_t s = {NULL, 0}; + + /* check whether privkey and pubkey are operational + * by signing and verifying */ + assert(gnutls_privkey_sign_data(pkey, GNUTLS_DIG_SHA256, 0, &testdata, &sig) == 0); + + assert(_gnutls_decode_ber_rs_raw(&sig, &r, &s) == 0); + if (r.data[0] >= 0x80) { + fail("gnutls_privkey_sign_data resulted to a signed value for R\n"); + } + + if (s.data[0] >= 0x80) { + fail("gnutls_privkey_sign_data resulted to a signed value for S\n"); + } + + /* verify against the raw pubkey */ + assert(gnutls_pubkey_verify_data2(pubkey2, gnutls_pk_to_sign(pk, GNUTLS_DIG_SHA256), 0, &testdata, &sig) == 0); + + /* verify against the pubkey in PKCS #11 */ + assert(gnutls_pubkey_verify_data2(pubkey, gnutls_pk_to_sign(pk, GNUTLS_DIG_SHA256), 0, &testdata, &sig) == 0); + + gnutls_free(sig.data); + gnutls_free(r.data); + gnutls_free(s.data); + } + + gnutls_pubkey_deinit(pubkey4); + gnutls_pubkey_deinit(pubkey3); + gnutls_pubkey_deinit(pubkey2); + gnutls_pubkey_deinit(pubkey); + gnutls_privkey_deinit(pkey); + + gnutls_global_deinit(); + + remove(CONFIG); +} + diff --git a/tests/pkcs11/pkcs11-eddsa-privkey-test.c b/tests/pkcs11/pkcs11-eddsa-privkey-test.c new file mode 100644 index 0000000..ebbfe52 --- /dev/null +++ b/tests/pkcs11/pkcs11-eddsa-privkey-test.c @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos, Simo Sorce + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> + +#include "../utils.h" +#include "softhsm.h" + +#define CONFIG_NAME "softhsm-privkey-eddsa-test" +#define CONFIG CONFIG_NAME".config" + +/* Tests whether signing with PKCS#11 and EDDSA would + * generate valid signatures */ + +#include "../cert-common.h" + +#define PIN "1234" + +static const gnutls_datum_t testdata = { (void *)"test test", 9 }; + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void *userdata, int attempt, const char *url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +#define myfail(fmt, ...) \ + fail("%s (iter %d): "fmt, gnutls_sign_get_name(sigalgo), i, ##__VA_ARGS__) + +static unsigned verify_eddsa_presence(void) +{ + unsigned i; + unsigned long mechanism; + int ret; + + i = 0; + do { + ret = gnutls_pkcs11_token_get_mechanism("pkcs11:", i++, &mechanism); + if (ret >= 0 && mechanism == 0x1057 /* CKM_EDDSA */) + return 1; + } while(ret>=0); + + return 0; +} + +void doit(void) +{ + char buf[128]; + int ret; + const char *lib, *bin; + gnutls_x509_crt_t crt; + gnutls_x509_privkey_t key; + gnutls_datum_t tmp, sig; + gnutls_privkey_t pkey; + gnutls_pubkey_t pubkey; + gnutls_pubkey_t pubkey2; + gnutls_pubkey_t pubkey3; + gnutls_pubkey_t pubkey4; + unsigned i, sigalgo; + + bin = softhsm_bin(); + + lib = softhsm_lib(); + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + } + + if (gnutls_fips140_mode_enabled()) { + gnutls_global_deinit(); + return; + } + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), + "%s --init-token --slot 0 --label test --so-pin " PIN " --pin " + PIN, bin); + system(buf); + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret < 0) { + fail("gnutls_x509_crt_init: %s\n", gnutls_strerror(ret)); + } + + if (verify_eddsa_presence() == 0) { + fprintf(stderr, "Skipping test as no EDDSA mech is supported\n"); + exit(77); + } + + ret = gnutls_x509_crt_init(&crt); + if (ret < 0) + fail("gnutls_x509_crt_init: %s\n", gnutls_strerror(ret)); + + ret = + gnutls_x509_crt_import(crt, &server_ca3_eddsa_cert, + GNUTLS_X509_FMT_PEM); + if (ret < 0) + fail("gnutls_x509_crt_import: %s\n", gnutls_strerror(ret)); + + if (debug) { + gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &tmp); + + printf("\tCertificate: %.*s\n", tmp.size, tmp.data); + gnutls_free(tmp.data); + } + + ret = gnutls_x509_privkey_init(&key); + if (ret < 0) { + fail("gnutls_x509_privkey_init: %s\n", gnutls_strerror(ret)); + } + + ret = + gnutls_x509_privkey_import(key, &server_ca3_eddsa_key, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fail("gnutls_x509_privkey_import: %s\n", gnutls_strerror(ret)); + } + + /* initialize softhsm token */ + ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test"); + if (ret < 0) { + fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); + } + + ret = + gnutls_pkcs11_token_set_pin(SOFTHSM_URL, NULL, PIN, + GNUTLS_PIN_USER); + if (ret < 0) { + fail("gnutls_pkcs11_token_set_pin: %s\n", gnutls_strerror(ret)); + } + + ret = gnutls_pkcs11_copy_x509_crt(SOFTHSM_URL, crt, "cert", + GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE | + GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_crt: %s\n", gnutls_strerror(ret)); + } + + ret = + gnutls_pkcs11_copy_x509_privkey(SOFTHSM_URL, key, "cert", + GNUTLS_KEY_DIGITAL_SIGNATURE | + GNUTLS_KEY_KEY_ENCIPHERMENT, + GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE + | + GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE + | GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_privkey: %s\n", + gnutls_strerror(ret)); + } + + /* Write pubkey to the card too */ + assert(gnutls_pubkey_init(&pubkey) == 0); + assert(gnutls_pubkey_import_x509(pubkey, crt, 0) == 0); + + ret = gnutls_pkcs11_copy_pubkey(SOFTHSM_URL, pubkey, "cert", NULL, + GNUTLS_KEY_DIGITAL_SIGNATURE | + GNUTLS_KEY_KEY_ENCIPHERMENT, 0); + if (ret < 0) { + fail("gnutls_pkcs11_copy_pubkey: %s\n", + gnutls_strerror(ret)); + } + + gnutls_x509_crt_deinit(crt); + gnutls_x509_privkey_deinit(key); + gnutls_pubkey_deinit(pubkey); + gnutls_pkcs11_set_pin_function(NULL, NULL); + + assert(gnutls_privkey_init(&pkey) == 0); + + ret = + gnutls_privkey_import_pkcs11_url(pkey, + SOFTHSM_URL + ";object=cert;object-type=private;pin-value=" + PIN); + if (ret < 0) { + fail("error in gnutls_privkey_import_pkcs11_url: %s\n", gnutls_strerror(ret)); + } + + /* Try to read the public key with public key URI */ + assert(gnutls_pubkey_init(&pubkey3) == 0); + + + ret = + gnutls_pubkey_import_pkcs11_url(pubkey3, + SOFTHSM_URL + ";object=cert;object-type=public;pin-value=" + PIN, 0); + if (ret < 0) { + fail("error in gnutls_pubkey_import_pkcs11_url: %s\n", gnutls_strerror(ret)); + } + + /* Try to read the public key with certificate URI */ + assert(gnutls_pubkey_init(&pubkey4) == 0); + + ret = + gnutls_pubkey_import_pkcs11_url(pubkey4, + SOFTHSM_URL + ";object=cert;object-type=cert;pin-value=" + PIN, 0); + if (ret < 0) { + fail("error in gnutls_pubkey_import_pkcs11_url: %s\n", gnutls_strerror(ret)); + } + + assert(gnutls_pubkey_init(&pubkey) == 0); + assert(gnutls_pubkey_import_privkey(pubkey, pkey, 0, 0) == 0); + + assert(gnutls_pubkey_init(&pubkey2) == 0); + assert(gnutls_pubkey_import_x509_raw + (pubkey2, &server_ca3_eddsa_cert, GNUTLS_X509_FMT_PEM, 0) == 0); + + /* this is the algorithm supported by the certificate */ + sigalgo = GNUTLS_SIGN_EDDSA_ED25519; + + for (i = 0; i < 20; i++) { + /* check whether privkey and pubkey are operational + * by signing and verifying */ + ret = + gnutls_privkey_sign_data2(pkey, sigalgo, 0, + &testdata, &sig); + if (ret < 0) + myfail("Error signing data %s\n", gnutls_strerror(ret)); + + /* verify against the pubkey in PKCS #11 */ + ret = + gnutls_pubkey_verify_data2(pubkey, sigalgo, 0, + &testdata, &sig); + if (ret < 0) + myfail("Error verifying data1: %s\n", + gnutls_strerror(ret)); + + /* verify against the raw pubkey */ + ret = + gnutls_pubkey_verify_data2(pubkey2, sigalgo, 0, + &testdata, &sig); + if (ret < 0) + myfail("Error verifying data2: %s\n", + gnutls_strerror(ret)); + + gnutls_free(sig.data); + } + + /* TODO is there any sensible way to check the pubkeys are the same? */ + gnutls_pubkey_deinit(pubkey4); + gnutls_pubkey_deinit(pubkey3); + gnutls_pubkey_deinit(pubkey2); + gnutls_pubkey_deinit(pubkey); + gnutls_privkey_deinit(pkey); + + gnutls_global_deinit(); + + remove(CONFIG); +} diff --git a/tests/pkcs11/pkcs11-get-exts.c b/tests/pkcs11/pkcs11-get-exts.c new file mode 100644 index 0000000..1d236a6 --- /dev/null +++ b/tests/pkcs11/pkcs11-get-exts.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <assert.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/x509-ext.h> + +#include "utils.h" + +/* Tests the gnutls_pkcs11_obj_get_exts API */ + +#ifdef _WIN32 +# define P11LIB "libpkcs11mock1.dll" +#else +# define P11LIB "libpkcs11mock1.so" +#endif + +void doit(void) +{ + int ret; + const char *lib; + gnutls_x509_ext_st *exts; + unsigned int exts_size, i; + gnutls_pkcs11_obj_t obj; + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + lib = getenv("P11MOCKLIB1"); + if (lib == NULL) + lib = P11LIB; + + if (debug) { + gnutls_global_set_log_level(4711); + success("loading lib %s\n", lib); + } + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + assert(gnutls_pkcs11_obj_init(&obj)>=0); + + /* check extensions */ + ret = gnutls_pkcs11_obj_import_url(obj, "pkcs11:type=cert;object=cert1", 0); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_obj_get_exts(obj, &exts, &exts_size, 0); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + if (exts_size != 2) { + fail("the expected extensions were not found (found %d)!\n", exts_size); + exit(1); + } + + if (strcmp(exts[0].oid, "2.5.29.19") != 0) { + fail("Found OID for %d: %s\n", 0, exts[0].oid); + } + + { + unsigned ca; + int pathlen; + ret = gnutls_x509_ext_import_basic_constraints(&exts[0].data, &ca, &pathlen); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + if (debug) + success("ca: %d/%d\n", ca, pathlen); + if (ca != 1) { + fail("Extension does not set the CA constraint!\n"); + } + } + + if (strcmp(exts[1].oid, "2.5.29.15") != 0) { + fail("Found OID for %d: %s\n", 1, exts[1].oid); + } + + { + unsigned keyusage; + ret = gnutls_x509_ext_import_key_usage(&exts[1].data, &keyusage); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + if (debug) + success("usage: %x\n", keyusage); + if (keyusage != (GNUTLS_KEY_KEY_ENCIPHERMENT|GNUTLS_KEY_ENCIPHER_ONLY|GNUTLS_KEY_KEY_CERT_SIGN)) { + fail("Extension does not have the expected key usage!\n"); + } + } + + for (i=0;i<exts_size;i++) + gnutls_x509_ext_deinit(&exts[i]); + gnutls_free(exts); + + gnutls_pkcs11_obj_deinit(obj); + if (debug) + printf("done\n\n\n"); + + gnutls_global_deinit(); +} diff --git a/tests/pkcs11/pkcs11-get-issuer.c b/tests/pkcs11/pkcs11-get-issuer.c new file mode 100644 index 0000000..b4df717 --- /dev/null +++ b/tests/pkcs11/pkcs11-get-issuer.c @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2008-2014 Free Software Foundation, Inc. + * + * Author: Simon Josefsson, Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/x509-ext.h> + +#include "../utils.h" +#include "../test-chains.h" +#include "softhsm.h" + +#define CONFIG "softhsm-issuer.config" + +/* GnuTLS internally calls time() to find out the current time when + verifying certificates. To avoid a time bomb, we hard code the + current time. This should work fine on systems where the library + call to time is resolved at run-time. */ +static time_t mytime(time_t * t) +{ + time_t then = 1256803113; + + if (t) + *t = then; + + return then; +} + +#define PIN "1234" + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +void doit(void) +{ + char buf[128]; + int exit_val = 0; + int ret; + unsigned j; + const char *lib, *bin; + gnutls_x509_crt_t issuer = NULL; + gnutls_x509_trust_list_t tl; + gnutls_x509_crt_t certs[MAX_CHAIN]; + gnutls_x509_crt_t ca; + gnutls_datum_t tmp; + int idx = -1; + + if (gnutls_fips140_mode_enabled()) + exit(77); + + /* The overloading of time() seems to work in linux (ELF?) + * systems only. Disable it on windows. + */ +#ifdef _WIN32 + exit(77); +#endif + for (j=0;;j++) { + if (chains[j].name == NULL) + break; + if (strcmp(chains[j].name, "verisign.com v1 ok") == 0) { + idx = j; + break; + } + } + + if (idx == -1) { + fail("could not find proper chain\n"); + exit(1); + } + + bin = softhsm_bin(); + + lib = softhsm_lib(); + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + gnutls_global_set_time_function(mytime); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + /* write softhsm.config */ + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin "PIN" --pin "PIN, bin); + system(buf); + + ret = gnutls_pkcs11_add_provider(lib, "trusted"); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + for (j = 0; chains[idx].chain[j]; j++) { + if (debug > 2) + printf("\tAdding certificate %d...", + (int) j); + + ret = gnutls_x509_crt_init(&certs[j]); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_init[%d,%d]: %s\n", + (int) 3, (int) j, + gnutls_strerror(ret)); + exit(1); + } + + tmp.data = (unsigned char *) chains[idx].chain[j]; + tmp.size = strlen(chains[idx].chain[j]); + + ret = + gnutls_x509_crt_import(certs[j], &tmp, + GNUTLS_X509_FMT_PEM); + if (debug > 2) + printf("done\n"); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_import[%s,%d]: %s\n", + chains[idx].name, (int) j, + gnutls_strerror(ret)); + exit(1); + } + + gnutls_x509_crt_print(certs[j], + GNUTLS_CRT_PRINT_ONELINE, + &tmp); + if (debug) + printf("\tCertificate %d: %.*s\n", (int) j, + tmp.size, tmp.data); + gnutls_free(tmp.data); + } + + if (debug > 2) + printf("\tAdding CA certificate..."); + + ret = gnutls_x509_crt_init(&ca); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + tmp.data = (unsigned char *) *chains[idx].ca; + tmp.size = strlen(*chains[idx].ca); + + ret = + gnutls_x509_crt_import(ca, &tmp, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + if (debug > 2) + printf("done\n"); + + gnutls_x509_crt_print(ca, GNUTLS_CRT_PRINT_ONELINE, &tmp); + if (debug) + printf("\tCA Certificate: %.*s\n", tmp.size, + tmp.data); + gnutls_free(tmp.data); + + if (debug) + printf("\tVerifying..."); + + /* initialize softhsm token */ + ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test"); + if (ret < 0) { + fail("gnutls_pkcs11_token_init\n"); + exit(1); + } + + /* write CA certificate to softhsm */ + ret = gnutls_pkcs11_copy_x509_crt(SOFTHSM_URL, ca, "test-ca", GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED|GNUTLS_PKCS11_OBJ_FLAG_LOGIN_SO); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_crt: %s\n", gnutls_strerror(ret)); + exit(1); + } + + gnutls_x509_trust_list_init(&tl, 0); + + ret = gnutls_x509_trust_list_add_trust_file(tl, SOFTHSM_URL, NULL, 0, 0, 0); + if (ret < 0) { + fail("gnutls_x509_trust_list_add_trust_file\n"); + exit(1); + } + + /* extract the issuer of the certificate */ + issuer = NULL; + ret = gnutls_x509_trust_list_get_issuer(tl, certs[2], &issuer, GNUTLS_TL_GET_COPY); + if (ret < 0) { + fail("error in gnutls_x509_trust_list_get_issuer\n"); + exit(1); + } + if (issuer == NULL) { + fail("error in gnutls_x509_trust_list_get_issuer return value\n"); + exit(1); + } + gnutls_x509_crt_deinit(issuer); + + /* extract the issuer of the certificate using the non-thread-safe approach */ + issuer = NULL; + ret = gnutls_x509_trust_list_get_issuer(tl, certs[2], &issuer, 0); + if (ret < 0) { + fail("error in gnutls_x509_trust_list_get_issuer\n"); + exit(1); + } + if (issuer == NULL) { + fail("error in gnutls_x509_trust_list_get_issuer return value\n"); + exit(1); + } + + /* extract (again) the issuer of the certificate - check for any leaks */ + ret = gnutls_x509_trust_list_get_issuer(tl, certs[2], &issuer, 0); + if (ret < 0) { + fail("error in gnutls_x509_trust_list_get_issuer\n"); + exit(1); + } + + /* Check gnutls_x509_trust_list_get_raw_issuer_by_dn */ + ret = gnutls_x509_crt_get_raw_issuer_dn(certs[2], &tmp); + if (ret < 0) { + fail("error in gnutls_x509_crt_get_raw_issuer_dn: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_trust_list_get_issuer_by_dn(tl, &tmp, &issuer, 0); + gnutls_free(tmp.data); + if (ret < 0) { + fail("error in gnutls_x509_trust_list_get_issuer\n"); + exit(1); + } + if (issuer == NULL) { + fail("error in gnutls_x509_trust_list_get_issuer_by_dn return value\n"); + exit(1); + } + gnutls_x509_crt_deinit(issuer); + + if (debug) + printf("\tCleanup..."); + + gnutls_x509_trust_list_deinit(tl, 0); + gnutls_x509_crt_deinit(ca); + for (j = 0; chains[idx].chain[j]; j++) + gnutls_x509_crt_deinit(certs[j]); + if (debug) + printf("done\n\n\n"); + + gnutls_global_deinit(); + + if (debug) + printf("Exit status...%d\n", exit_val); + remove(CONFIG); + + exit(exit_val); +} diff --git a/tests/pkcs11/pkcs11-get-raw-issuer-exts.c b/tests/pkcs11/pkcs11-get-raw-issuer-exts.c new file mode 100644 index 0000000..dec3088 --- /dev/null +++ b/tests/pkcs11/pkcs11-get-raw-issuer-exts.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <assert.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/x509-ext.h> + +#include "utils.h" + +/* Tests the certificate extension override in "trusted" PKCS#11 modules + * when used with gnutls_pkcs11_get_raw_issuer(). + */ + +#ifdef _WIN32 +# define P11LIB "libpkcs11mock1.dll" +#else +# define P11LIB "libpkcs11mock1.so" +#endif + +static time_t mytime(time_t * t) +{ + time_t then = 1424466893; + + if (t) + *t = then; + + return then; +} + +void doit(void) +{ + int ret; + gnutls_x509_crt_t crt, ocrt; + unsigned keyusage; + const char *lib; + gnutls_datum_t issuer = {NULL, 0}; + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + lib = getenv("P11MOCKLIB1"); + if (lib == NULL) + lib = P11LIB; + + gnutls_global_set_time_function(mytime); + if (debug) { + gnutls_global_set_log_level(4711); + success("loading lib %s\n", lib); + } + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, "trusted"); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + assert(gnutls_x509_crt_init(&crt)>=0); + assert(gnutls_x509_crt_init(&ocrt)>=0); + + /* check high level certificate functions */ + ret = gnutls_x509_crt_import_url(crt, "pkcs11:type=cert;object=cert1", 0); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_get_raw_issuer("pkcs11:", crt, &issuer, GNUTLS_X509_FMT_DER, GNUTLS_PKCS11_OBJ_FLAG_OVERWRITE_TRUSTMOD_EXT); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_crt_equals2(crt, &issuer); + if (ret != 0) { + fail("exported certificates are equal!\n"); + } + + ret = gnutls_x509_crt_import(ocrt, &issuer, GNUTLS_X509_FMT_DER); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_crt_get_ca_status(ocrt, NULL); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + if (ret == 0) { + fail("overridden cert is not a CA!\n"); + exit(1); + } + + ret = gnutls_x509_crt_get_key_usage(ocrt, &keyusage, NULL); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + if (keyusage != (GNUTLS_KEY_KEY_ENCIPHERMENT|GNUTLS_KEY_ENCIPHER_ONLY|GNUTLS_KEY_KEY_CERT_SIGN)) { + fail("Extension does not have the expected key usage!\n"); + } + + gnutls_x509_crt_deinit(crt); + gnutls_x509_crt_deinit(ocrt); + gnutls_free(issuer.data); + if (debug) + printf("done\n\n\n"); + + gnutls_global_deinit(); +} diff --git a/tests/pkcs11/pkcs11-import-url-privkey.c b/tests/pkcs11/pkcs11-import-url-privkey.c new file mode 100644 index 0000000..ded8c9a --- /dev/null +++ b/tests/pkcs11/pkcs11-import-url-privkey.c @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/x509-ext.h> + +#include "utils.h" +#include "pkcs11-mock-ext.h" + +/* Tests the private key import for sensitive keys in the common case and in + * some problematic cases. */ + +#ifdef ALL_CAPS_URI +#define PURI "PKCS11:" +#else +#define PURI "pkcs11:" +#endif + +#ifdef _WIN32 +# define P11LIB "libpkcs11mock1.dll" +#else +# include <dlfcn.h> +# define P11LIB "libpkcs11mock1.so" +#endif + +void doit(void) +{ + int ret; + const char *lib; + gnutls_pkcs11_obj_t *obj_list; + unsigned int obj_list_size = 0; + unsigned int i; + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + lib = getenv("P11MOCKLIB1"); + if (lib == NULL) + lib = P11LIB; + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_obj_list_import_url4(&obj_list, &obj_list_size, PURI, GNUTLS_PKCS11_OBJ_FLAG_PRIVKEY); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + for (i=0;i<obj_list_size;i++) + gnutls_pkcs11_obj_deinit(obj_list[i]); + gnutls_free(obj_list); + obj_list_size = 0; + +#ifndef _WIN32 + { + void *dl; + unsigned int *pflags; + + dl = dlopen(lib, RTLD_NOW); + if (dl == NULL) { + fail("could not dlopen %s\n", lib); + exit(1); + } + + pflags = dlsym(dl, "pkcs11_mock_flags"); + if (pflags == NULL) { + fail("could find pkcs11_mock_flags\n"); + exit(1); + } + + *pflags = MOCK_FLAG_BROKEN_GET_ATTRIBUTES; + + ret = gnutls_pkcs11_obj_list_import_url4(&obj_list, &obj_list_size, PURI, GNUTLS_PKCS11_OBJ_FLAG_PRIVKEY); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + for (i=0;i<obj_list_size;i++) + gnutls_pkcs11_obj_deinit(obj_list[i]); + gnutls_free(obj_list); + obj_list_size = 0; + } +#endif + + if (debug) + printf("done\n\n\n"); + + gnutls_global_deinit(); +} diff --git a/tests/pkcs11/pkcs11-import-with-pin.c b/tests/pkcs11/pkcs11-import-with-pin.c new file mode 100644 index 0000000..79cf187 --- /dev/null +++ b/tests/pkcs11/pkcs11-import-with-pin.c @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> + +#include "../utils.h" +#include "softhsm.h" + +/* Tests whether a protected object is imported with PIN obtained using + * pin-value or pin-source. */ + +#define CONFIG_NAME "softhsm-import-with-pin" +#define CONFIG CONFIG_NAME".config" + +#include "../cert-common.h" + +#define PIN "1234" + +static const gnutls_datum_t testdata = {(void*)"test test", 9}; + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +static void write_pin(const char *file, const char *pin) +{ + FILE *fp = fopen(file, "w"); + assert(fp != NULL); + fputs(pin, fp); + fclose(fp); +} + +void doit(void) +{ + char buf[512]; + int ret; + const char *lib, *bin; + gnutls_x509_privkey_t key; + gnutls_datum_t sig; + gnutls_privkey_t pkey; + char file[TMPNAME_SIZE]; + + if (gnutls_fips140_mode_enabled()) + exit(77); + + bin = softhsm_bin(); + + lib = softhsm_lib(); + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin "PIN" --pin "PIN, bin); + system(buf); + + ret = gnutls_pkcs11_add_provider(lib, "trusted"); + if (ret < 0) { + fprintf(stderr, "add_provider: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_privkey_init(&key); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_privkey_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_x509_privkey_import(key, &server_key, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_privkey_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + /* initialize softhsm token */ + ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test"); + if (ret < 0) { + fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_token_set_pin(SOFTHSM_URL, NULL, PIN, GNUTLS_PIN_USER); + if (ret < 0) { + fail("gnutls_pkcs11_token_set_pin: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_copy_x509_privkey(SOFTHSM_URL, key, "cert", GNUTLS_KEY_DIGITAL_SIGNATURE|GNUTLS_KEY_KEY_ENCIPHERMENT, + GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE|GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE|GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_privkey: %s\n", gnutls_strerror(ret)); + exit(1); + } + + gnutls_x509_privkey_deinit(key); + gnutls_pkcs11_set_pin_function(NULL, NULL); + + assert(gnutls_privkey_init(&pkey) == 0); + + /* Test 1 + * Try importing with wrong pin-value */ + ret = gnutls_privkey_import_pkcs11_url(pkey, SOFTHSM_URL";object=cert;object-type=private;pin-value=XXXX"); + if (ret != GNUTLS_E_PKCS11_PIN_ERROR) { + fprintf(stderr, "unexpected error in %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + gnutls_privkey_deinit(pkey); + assert(gnutls_privkey_init(&pkey) == 0); + + /* Test 2 + * Try importing with pin-value */ + ret = gnutls_privkey_import_pkcs11_url(pkey, SOFTHSM_URL";object=cert;object-type=private;pin-value="PIN); + if (ret < 0) { + fprintf(stderr, "error in %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + + /* check whether privkey is operational by signing */ + assert(gnutls_privkey_sign_data(pkey, GNUTLS_DIG_SHA256, 0, &testdata, &sig) == 0); + gnutls_free(sig.data); + gnutls_privkey_deinit(pkey); + + /* Test 3 + * Try importing with wrong pin-source */ + track_temp_files(); + get_tmpname(file); + + write_pin(file, "XXXX"); + + assert(gnutls_privkey_init(&pkey) == 0); + snprintf(buf, sizeof(buf), "%s;object=cert;object-type=private;pin-source=%s", SOFTHSM_URL, file); + ret = gnutls_privkey_import_pkcs11_url(pkey, buf); + if (ret != GNUTLS_E_PKCS11_PIN_ERROR) { + fprintf(stderr, "error in %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + + gnutls_privkey_deinit(pkey); + + /* Test 4 + * Try importing with pin-source */ + write_pin(file, PIN); + + assert(gnutls_privkey_init(&pkey) == 0); + snprintf(buf, sizeof(buf), "%s;object=cert;object-type=private;pin-source=%s", SOFTHSM_URL, file); + ret = gnutls_privkey_import_pkcs11_url(pkey, buf); + if (ret < 0) { + fprintf(stderr, "error in %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + + /* check whether privkey is operational by signing */ + assert(gnutls_privkey_sign_data(pkey, GNUTLS_DIG_SHA256, 0, &testdata, &sig) == 0); + gnutls_free(sig.data); + gnutls_privkey_deinit(pkey); + + gnutls_global_deinit(); + delete_temp_files(); + + remove(CONFIG); +} + diff --git a/tests/pkcs11/pkcs11-is-known.c b/tests/pkcs11/pkcs11-is-known.c new file mode 100644 index 0000000..95b9c56 --- /dev/null +++ b/tests/pkcs11/pkcs11-is-known.c @@ -0,0 +1,656 @@ +/* + * Copyright (C) 2008-2014 Free Software Foundation, Inc. + * + * Author: Simon Josefsson, Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/x509-ext.h> +#include <assert.h> + +#include "../utils.h" +#include "softhsm.h" + +#define MAX_CHAIN 16 + +#define OBJ_URL SOFTHSM_URL";object=test-ca0;object-type=cert" +#define CONFIG "softhsm-issuer2.config" + +/* These CAs have the same DN */ +static const char *ca_list[MAX_CHAIN] = { +"-----BEGIN CERTIFICATE-----\n" +"MIIHSjCCBjKgAwIBAgIKYRHt9wABAAAAFTANBgkqhkiG9w0BAQUFADBSMQswCQYD\n" +"VQQGEwJVUzEaMBgGA1UEChMRSW50ZWwgQ29ycG9yYXRpb24xJzAlBgNVBAMTHklu\n" +"dGVsIEludHJhbmV0IEJhc2ljIFBvbGljeSBDQTAeFw0xMzAyMDQyMTUyMThaFw0x\n" +"ODA1MjQxOTU5MzlaMFYxCzAJBgNVBAYTAlVTMRowGAYDVQQKExFJbnRlbCBDb3Jw\n" +"b3JhdGlvbjErMCkGA1UEAxMiSW50ZWwgSW50cmFuZXQgQmFzaWMgSXNzdWluZyBD\n" +"QSAyQjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALn3ogjraWSmK5Wb\n" +"/4e9mENA1F36FBVemaG7L93ZhRRXq4UV0PQM5/4TOe9KAaOlX+a2cuULeeUtN9Rk\n" +"V/nHAVzSWlqc/NTMJfuI/1AD7ICNejQFYLxDMXGjR7eAHtiMz0iTMp9u6YTw4WXh\n" +"WffqTPiqUZ6DEWsMic9dM9yw/JqzycKClLcTD1OCvtw7Fx4tNTu6/ngrYJcTo29e\n" +"BBh/DupgtgnYPYuExEkHmucb4VIDdjfRkPo/BdNqrUSYfYqnUDj5mH+hPzIgppsZ\n" +"Rw0S5PUZGuC1f+Zok+4vZPR+hGG3Pdm2LTUEWSnurlhyfBoM+0yxeHsmL9aHU7zt\n" +"EIzVmKUCAwEAAaOCBBwwggQYMBIGCSsGAQQBgjcVAQQFAgMCAAIwIwYJKwYBBAGC\n" +"NxUCBBYEFMqHyYZOx6LYwRwZ+5vjOyIl9hENMB0GA1UdDgQWBBQ4Y3b6tgU6qVlP\n" +"SoeNoIO3fpE6CzAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC\n" +"AYYwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBRp6zCRHAOAgE4RFYhG\n" +"pOJBmtNpHzCCAaIGA1UdHwSCAZkwggGVMIIBkaCCAY2gggGJhlFodHRwOi8vd3d3\n" +"LmludGVsLmNvbS9yZXBvc2l0b3J5L0NSTC9JbnRlbCUyMEludHJhbmV0JTIwQmFz\n" +"aWMlMjBQb2xpY3klMjBDQSgxKS5jcmyGWmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuaW50\n" +"ZWwuY29tL3JlcG9zaXRvcnkvQ1JML0ludGVsJTIwSW50cmFuZXQlMjBCYXNpYyUy\n" +"MFBvbGljeSUyMENBKDEpLmNybIaB12xkYXA6Ly8vQ049SW50ZWwlMjBJbnRyYW5l\n" +"dCUyMEJhc2ljJTIwUG9saWN5JTIwQ0EoMSksQ049bWNzaWJwY2EsQ049Q0RQLENO\n" +"PVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3Vy\n" +"YXRpb24sREM9Y29ycCxEQz1pbnRlbCxEQz1jb20/Y2VydGlmaWNhdGVSZXZvY2F0\n" +"aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MIIB\n" +"uQYIKwYBBQUHAQEEggGrMIIBpzBmBggrBgEFBQcwAoZaaHR0cDovL3d3dy5pbnRl\n" +"bC5jb20vcmVwb3NpdG9yeS9jZXJ0aWZpY2F0ZXMvSW50ZWwlMjBJbnRyYW5ldCUy\n" +"MEJhc2ljJTIwUG9saWN5JTIwQ0EoMSkuY3J0MG8GCCsGAQUFBzAChmNodHRwOi8v\n" +"Y2VydGlmaWNhdGVzLmludGVsLmNvbS9yZXBvc2l0b3J5L2NlcnRpZmljYXRlcy9J\n" +"bnRlbCUyMEludHJhbmV0JTIwQmFzaWMlMjBQb2xpY3klMjBDQSgxKS5jcnQwgcsG\n" +"CCsGAQUFBzAChoG+bGRhcDovLy9DTj1JbnRlbCUyMEludHJhbmV0JTIwQmFzaWMl\n" +"MjBQb2xpY3klMjBDQSxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIwU2VydmljZXMs\n" +"Q049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1jb3JwLERDPWludGVsLERD\n" +"PWNvbT9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9Y2VydGlmaWNhdGlv\n" +"bkF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAQEAsj8cHt2jSAmnIGulE9jXooAc\n" +"qH2xehlI+ko/al+nDnBzbjDYYjVS52XitYg8JGo6j72ijiGlGb/03FcQJRBZmUH6\n" +"znktx2rGTm4IdjL8quhvHthlzXXCozL8GMeeOuZ5rzHlhapKx764a5RuZtyx89uS\n" +"9cECon6oLGesXjFJ8Xrq6ecHZrQwJUpmvZalwvloKACAWqBh8yV12WDnUNZhtp8N\n" +"8rqeJZoy/lXGnTxsSSodO/5Y/CxYJM4W6u4WgvXNJSjO/0qWvb64S+pVLjBzwI+Y\n" +"X6oLqmBovRp1lGPOLjkXZi3EKDR8DmzhtpJq2677RtYowewnFedQ+exH9cXoJw==\n" +"-----END CERTIFICATE-----", +"-----BEGIN CERTIFICATE-----\n" +"MIIHSjCCBjKgAwIBAgIKYRXxrQABAAAAETANBgkqhkiG9w0BAQUFADBSMQswCQYD\n" +"VQQGEwJVUzEaMBgGA1UEChMRSW50ZWwgQ29ycG9yYXRpb24xJzAlBgNVBAMTHklu\n" +"dGVsIEludHJhbmV0IEJhc2ljIFBvbGljeSBDQTAeFw0wOTA1MTUxODQyNDVaFw0x\n" +"NTA1MTUxODUyNDVaMFYxCzAJBgNVBAYTAlVTMRowGAYDVQQKExFJbnRlbCBDb3Jw\n" +"b3JhdGlvbjErMCkGA1UEAxMiSW50ZWwgSW50cmFuZXQgQmFzaWMgSXNzdWluZyBD\n" +"QSAyQjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbJOXtXYgfyoch6\n" +"ip5SSjijOXvpIjBxbTl5EGH/VYHmpM2O6SRlKh/uy77QS9m84sRWCJLr8cWwX9oH\n" +"qSmIylgcWvDpVNHx4v506DTTrbK0sbYRQYXRajOzJKeTt7NLeLrngyl45FrI9VAT\n" +"3yqp/2BCG1dUwcBha3dB2UbTkFOMt9o/gqoL6KvgswYMs/oGc/OIjeozdYuhnBT2\n" +"YlT9Ge5pfhOJWXh4DJbxnTmWwRUKq0MXFn0S00KQ/BZOTkc/5DibUmbmMrYi8ra4\n" +"Z2bpnoTq0WNA99O2Lk8IgmkqPdi6HwZwKCE/x01qwP8zo76rvN8sbW9pj2WzS1WF\n" +"tSDPeZECAwEAAaOCBBwwggQYMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYE\n" +"FPwbdyds7Cm03lobLKmI6q59npi+MAsGA1UdDwQEAwIBhjASBgkrBgEEAYI3FQEE\n" +"BQIDAQABMCMGCSsGAQQBgjcVAgQWBBRT1n27C6cZL4QFHaUX2nFSCPxhtTAZBgkr\n" +"BgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAfBgNVHSMEGDAWgBRp6zCRHAOAgE4RFYhG\n" +"pOJBmtNpHzCCAaIGA1UdHwSCAZkwggGVMIIBkaCCAY2gggGJhlFodHRwOi8vd3d3\n" +"LmludGVsLmNvbS9yZXBvc2l0b3J5L0NSTC9JbnRlbCUyMEludHJhbmV0JTIwQmFz\n" +"aWMlMjBQb2xpY3klMjBDQSgxKS5jcmyGWmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuaW50\n" +"ZWwuY29tL3JlcG9zaXRvcnkvQ1JML0ludGVsJTIwSW50cmFuZXQlMjBCYXNpYyUy\n" +"MFBvbGljeSUyMENBKDEpLmNybIaB12xkYXA6Ly8vQ049SW50ZWwlMjBJbnRyYW5l\n" +"dCUyMEJhc2ljJTIwUG9saWN5JTIwQ0EoMSksQ049bWNzaWJwY2EsQ049Q0RQLENO\n" +"PVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3Vy\n" +"YXRpb24sREM9Y29ycCxEQz1pbnRlbCxEQz1jb20/Y2VydGlmaWNhdGVSZXZvY2F0\n" +"aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MIIB\n" +"uQYIKwYBBQUHAQEEggGrMIIBpzBmBggrBgEFBQcwAoZaaHR0cDovL3d3dy5pbnRl\n" +"bC5jb20vcmVwb3NpdG9yeS9jZXJ0aWZpY2F0ZXMvSW50ZWwlMjBJbnRyYW5ldCUy\n" +"MEJhc2ljJTIwUG9saWN5JTIwQ0EoMSkuY3J0MG8GCCsGAQUFBzAChmNodHRwOi8v\n" +"Y2VydGlmaWNhdGVzLmludGVsLmNvbS9yZXBvc2l0b3J5L2NlcnRpZmljYXRlcy9J\n" +"bnRlbCUyMEludHJhbmV0JTIwQmFzaWMlMjBQb2xpY3klMjBDQSgxKS5jcnQwgcsG\n" +"CCsGAQUFBzAChoG+bGRhcDovLy9DTj1JbnRlbCUyMEludHJhbmV0JTIwQmFzaWMl\n" +"MjBQb2xpY3klMjBDQSxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIwU2VydmljZXMs\n" +"Q049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1jb3JwLERDPWludGVsLERD\n" +"PWNvbT9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9Y2VydGlmaWNhdGlv\n" +"bkF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAQEArlAkrJXyMCssqAJT3PqnY7wt\n" +"sirq1fTMrVrHdmkpBKDXBQnDcTW1zfZtOPV/QDm3UsFwDBbGq+j/7U9qZ1zYHkv+\n" +"wrBpeFM6dlca/sgegGGAhYnQQwmlSzNXCKHMBltMjT61X8rVjyt1XJnucgat9rnT\n" +"2j8pztqoViVnORsGfT6DDB/bz/6bFKw4FMp1wDaJI7dKh5NUggvH36owTWI7JUvq\n" +"yJ8OI2qmjXrlqGexfwvltIkEk8xzuMIHWQoR8sERL2qf3nb2VYq1s1LbH5uCkZ0l\n" +"w/xgwFbbwjaGJ3TFOmkVKYU77nXSkfK9EXae0UZRU0WmX4t5NNt8jiL56TPpsw==\n" +"-----END CERTIFICATE-----\n", +"-----BEGIN CERTIFICATE-----\n" +"MIIHIzCCBgugAwIBAgIKYRok3wABAAAADDANBgkqhkiG9w0BAQUFADBSMQswCQYD\n" +"VQQGEwJVUzEaMBgGA1UEChMRSW50ZWwgQ29ycG9yYXRpb24xJzAlBgNVBAMTHklu\n" +"dGVsIEludHJhbmV0IEJhc2ljIFBvbGljeSBDQTAeFw0wNjA1MjQxOTU2MDFaFw0x\n" +"MjA1MjQyMDA2MDFaMFYxCzAJBgNVBAYTAlVTMRowGAYDVQQKExFJbnRlbCBDb3Jw\n" +"b3JhdGlvbjErMCkGA1UEAxMiSW50ZWwgSW50cmFuZXQgQmFzaWMgSXNzdWluZyBD\n" +"QSAyQjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANE2pFSB0XqXoRWF\n" +"N7bzDesBAcTGEqcr6GVA+sMcJ5Vt17S8vGesmO2RgP6I49Q58nIhUnT054arUlOx\n" +"NKYbAEiVyGOK5zV2mZS4oW2UazfcpsV1uuO3j02UbzX+qcxQdNqoAHxwoB4nRJuU\n" +"Ijio45jWAssDbD8IKHZpmqRI5wUzbibkWnTZEc0YFO6iF40sNtqVr+uInP07PkQn\n" +"1Ttkyw6isa5Dhcyq6lTVOjnlj29bFYbZxN1uuDnTpUMVeov8oQv5wLyLrDVd1sMg\n" +"Njr2oofepZ8KjF3DKCkfsUekCHA9Pr2K/4hStd/nSwvIdNjCjfznqYadkB6wQ99a\n" +"hTX4uJkCAwEAAaOCA/UwggPxMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYE\n" +"FJunwCR+/af8p76CGTyhUZc3l/4DMAsGA1UdDwQEAwIBhjAQBgkrBgEEAYI3FQEE\n" +"AwIBADAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAfBgNVHSMEGDAWgBRp6zCR\n" +"HAOAgE4RFYhGpOJBmtNpHzCCAaIGA1UdHwSCAZkwggGVMIIBkaCCAY2gggGJhlFo\n" +"dHRwOi8vd3d3LmludGVsLmNvbS9yZXBvc2l0b3J5L0NSTC9JbnRlbCUyMEludHJh\n" +"bmV0JTIwQmFzaWMlMjBQb2xpY3klMjBDQSgxKS5jcmyGWmh0dHA6Ly9jZXJ0aWZp\n" +"Y2F0ZXMuaW50ZWwuY29tL3JlcG9zaXRvcnkvQ1JML0ludGVsJTIwSW50cmFuZXQl\n" +"MjBCYXNpYyUyMFBvbGljeSUyMENBKDEpLmNybIaB12xkYXA6Ly8vQ049SW50ZWwl\n" +"MjBJbnRyYW5ldCUyMEJhc2ljJTIwUG9saWN5JTIwQ0EoMSksQ049bWNzaWJwY2Es\n" +"Q049Q0RQLENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENO\n" +"PUNvbmZpZ3VyYXRpb24sREM9Y29ycCxEQz1pbnRlbCxEQz1jb20/Y2VydGlmaWNh\n" +"dGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlv\n" +"blBvaW50MIIBuQYIKwYBBQUHAQEEggGrMIIBpzBmBggrBgEFBQcwAoZaaHR0cDov\n" +"L3d3dy5pbnRlbC5jb20vcmVwb3NpdG9yeS9jZXJ0aWZpY2F0ZXMvSW50ZWwlMjBJ\n" +"bnRyYW5ldCUyMEJhc2ljJTIwUG9saWN5JTIwQ0EoMSkuY3J0MG8GCCsGAQUFBzAC\n" +"hmNodHRwOi8vY2VydGlmaWNhdGVzLmludGVsLmNvbS9yZXBvc2l0b3J5L2NlcnRp\n" +"ZmljYXRlcy9JbnRlbCUyMEludHJhbmV0JTIwQmFzaWMlMjBQb2xpY3klMjBDQSgx\n" +"KS5jcnQwgcsGCCsGAQUFBzAChoG+bGRhcDovLy9DTj1JbnRlbCUyMEludHJhbmV0\n" +"JTIwQmFzaWMlMjBQb2xpY3klMjBDQSxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIw\n" +"U2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1jb3JwLERD\n" +"PWludGVsLERDPWNvbT9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9Y2Vy\n" +"dGlmaWNhdGlvbkF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAQEAe3SmN0lsGF0h\n" +"zq+NANnUD4YJS31UqreVm4kJv07+9CTBtlB0AVqJ2RcjRosdQmrbhx7R0WwcXSdR\n" +"QnRGhaoDVRNehKiz3Grp6ehJr9LInhCp6WtOeKRlOSb2xgRDJCtzCi07TuAb9h2I\n" +"urpmndeA4NEbPYL1GYEBpKYawUcFCq5yTv0YgZXy53DdBDv9ygRWYGEk7/gPgvCu\n" +"2O1GNs9n25goy+3/aMkHnUyl3MOtiooXJR7eKOEgTPHNe42LQ9KuUz5SoZQN8vSL\n" +"r49IRDC4dgMkGvsC5h0+ftixQ66ni6QJe6SNcpSZrpW5vBE9J+vtDI0gTyq2SYPo\n" +"0fiS3V8p4g==\n" +"-----END CERTIFICATE-----\n", +NULL}; + +/* this certificate has the same CN as one of the CAs above */ +static const char same_dn_cert_str[] = +"-----BEGIN CERTIFICATE-----\n" +"MIIHSjCCBjKgAwIBAgIKYRHt9wABAAAAFTANBgkqhkiG9w0BAQUFADBSMQswCQYD\n" +"VQQGEwJVUzEaMBgGA1UEChMRSW50ZWwgQ29ycG9yYXRpb24xJzAlBgNVBAMTHklu\n" +"dGVsIEludHJhbmV0IEJvc2FjIFBvbGljeSBDQTAeFw0xMzAyMDQyMTUyMThaFw0x\n" +"ODA1MjQxOTU5MzlaMFYxCzAJBgNVBAYTAlVTMRowGAYDVQQKExFJbnRlbCBDb3Jw\n" +"b3JhdGlvbjErMCkGA1UEAxMiSW50ZWwgSW50cmFuZXQgQmFzaWMgSXNzdWluZyBD\n" +"QSAyQjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALn3ogjraWSmK5Wb\n" +"/4e9mENA1F36FBVemaG7L93ZhRRXq4UV0PQM5/4TOe9KAaOlX+a2cuULeeUtN9Rk\n" +"V/nHAVzSWlqc/NTMJfuI/1AD7ICNejQFYLxDMXGjR7eAHtiMz0iTMp9u6YTw4WXh\n" +"WffqTPiqUZ6DEWsMic9dM9yw/JqzycKClLcTD1OCvtw7Fx4tNTu6/ngrYJcTo29e\n" +"BBh/DupgtgnYPYuExEkHmucb4VIDdjfRkPo/BdNqrUSYfYqnUDj5mH+hPzIgppsZ\n" +"Rw0S5PUZGuC1f+Zok+4vZPR+hGG3Pdm2LTUEWSnurlhyfBoM+0yxeHsmL9aHU7zt\n" +"EIzVmKUCAwEAAaOCBBwwggQYMBIGCSsGAQQBgjcVAQQFAgMCAAIwIwYJKwYBBAGC\n" +"NxUCBBYEFMqHyYZOx6LYwRwZ+5vjOyIl9hENMB0GA1UdDgQWBBQ4Y3b6tgU6qVlP\n" +"SoeNoIO3fpE6CzAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC\n" +"AYYwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBRp6zCRHAOAgE4RFYhG\n" +"pOJBmtNpHzCCAaIGA1UdHwSCAZkwggGVMIIBkaCCAY2gggGJhlFodHRwOi8vd3d3\n" +"LmludGVsLmNvbS9yZXBvc2l0b3J5L1hYWC9JbnRlbCUyMEludHJhbmV0JTIwQmFz\n" +"aWMlMjBQb2xpY3klMjBDQSgxKS5jcmyGWmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuaW50\n" +"ZWwuY29tL3JlcG9zaXRvcnkvQ1JML0ludGVsJTIwSW50cmFuZXQlMjBCYXNpYyUy\n" +"MFBvbGljeSUyMENBKDEpLmNybIaB12xkYXA6Ly8vQ049SW50ZWwlMjBJbnRyYW5l\n" +"dCUyMEJhc2ljJTIwUG9saWN5JTIwQ0EoMSksQ049bWNzaWJwY2EsQ049Q0RQLENO\n" +"PVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3Vy\n" +"YXRpb24sREM9Y29ycCxEQz1pbnRlbCxEQz1jb20/Y2VydGlmaWNhdGVSZXZvY2F0\n" +"aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MIIB\n" +"uQYIKwYBBQUHAQEEggGrMIIBpzBmBggrBgEFBQcwAoZaaHR0cDovL3d3dy5pbnRl\n" +"bC5jb20vcmVwb3NpdG9yeS9jZXJ0aWZpY2F0ZXMvSW50ZWwlMjBJbnRyYW5ldCUy\n" +"MEJhc2ljJTIwUG9saWN5JTIwQ0EoMSkuY3J0MG8GCCsGAQUFBzAChmNodHRwOi8v\n" +"Y2VydGlmaWNhdGVzLmludGVsLmNvbS9yZXBvc2l0b3J5L2NlcnRpZmljYXRlcy9J\n" +"bnRlbCUyMEludHJhbmV0JTIwQmFzaWMlMjBQb2xpY3klMjBDQSgxKS5jcnQwgcsG\n" +"CCsGAQUFBzAChoG+bGRhcDovLy9DTj1JbnRlbCUyMEludHJhbmV0JTIwQmFzaWMl\n" +"MjBQb2xpY3klMjBDQSxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIwU2VydmljZXMs\n" +"Q049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1jb3JwLERDPWludGVsLERD\n" +"PWNvbT9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9Y2VydGlmaWNhdGlv\n" +"bkF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAQEAsj8cHt2jSAmnIGulE9jXooAc\n" +"qH2xehlI+ko/al+nDnBzbjDYYjVS52XitYg8JGo6j72ijiGlGb/03FcQJRBZmUH6\n" +"znktx2rGTm4IdjL8quhvHthlzXXCozL8GMeeOuZ5rzHlhapKx764a5RuZtyx89uS\n" +"9cECon6oLGesXjFJ8Xrq6ecHZrQwJUpmvZalwvloKACAWqBh8yV12WDnUNZhtp8N\n" +"8rqeJZoy/lXGnTxsSSodO/5Y/CxYJM4W6u4WgvXNJSjO/0qWvb64S+pVLjBzwI+Y\n" +"X6oLqmBovRp1lGPOLjkXZi3EKDR8DmzhtpJq2677RtYowewnFedQ+exH9cXoJw==\n" +"-----END CERTIFICATE-----\n"; + +/* this certificate has the same subject and issuer DNs and serial as one of the CAs above */ +static const char same_issuer_cert_str[] = +"-----BEGIN CERTIFICATE-----\n" +"MIIHSjCCBjKgAwIBAgIKYRHt9wABAAAAFTANBgkqhkiG9w0BAQUFADBSMQswCQYD\n" +"VQQGEwJVUzEaMBgGA1UEChMRSW50ZWwgQ29ycG9yYXRpb24xJzAlBgNVBAMTHklu\n" +"dGVsIEludHJhbmV0IEJhc2ljIFBvbGljeSBDQTAeFw0xMzAyMDQyMTUyMThaFw0x\n" +"ODA1MjQxOTU5MzlaMFYxCzAJBgNVBAYTAlVTMRowGAYDVQQKExFJbnRlbCBDb3Jw\n" +"b3JhdGlvbjErMCkGA1UEAxMiSW50ZWwgSW50cmFuZXQgQmFzaWMgSXNzdWluZyBD\n" +"QSAyQjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALn3ogjraWSmK5Wb\n" +"/4e9mENA1F36FBVemaG7L93ZhRRXq4UV0PQM5/4TOe9KAaOlX+a2cuULeeUtN9Rk\n" +"V/nHAVzSWlqc/NTMJfuI/1AD7ICNejQFYLxDMXGjR7eAHtiMz0iTMp9u6YTw4WXh\n" +"WffqTPiqUZ6DEWsMic9dM9yw/JqzycKClLcTD1OCvtw7Fx4tNTu6/ngrYJcTo29e\n" +"BBh/DupgtgnYPYuExEkHmucb4VIDdjfRkPo/BdNqrUSYfYqnUDj5mH+hPzIgppsZ\n" +"Rw0S5PUZGuC1f+Zok+4vZPR+hGG3Pdm2LTUEWSnurlhyfBoM+0yxeHsmL9aHU7zt\n" +"EIzVmKUCAwEAAaOCBBwwggQYMBIGCSsGAQQBgjcVAQQFAgMCAAIwIwYJKwYBBAGC\n" +"NxUCBBYEFMqHyYZOx6LYwRwZ+5vjOyIl9hENMB0GA1UdDgQWBBQ4Y3b6tgU6qVlP\n" +"SoeNoIO3fpE6CzAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC\n" +"AYYwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBRp6zCRHAOAgE4RFYhG\n" +"pOJBmtNpHzCCAaIGA1UdHwSCAZkwggGVMIIBkaCCAY2gggGJhlFodHRwOi8vd3d3\n" +"LmludGVsLmNvbS9yZXBvc2l0b3J5L1hYWC9JbnRlbCUyMEludHJhbmV0JTIwQmFz\n" +"aWMlMjBQb2xpY3klMjBDQSgxKS5jcmyGWmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuaW50\n" +"ZWwuY29tL3JlcG9zaXRvcnkvQ1JML0ludGVsJTIwSW50cmFuZXQlMjBCYXNpYyUy\n" +"MFBvbGljeSUyMENBKDEpLmNybIaB12xkYXA6Ly8vQ049SW50ZWwlMjBJbnRyYW5l\n" +"dCUyMEJhc2ljJTIwUG9saWN5JTIwQ0EoMSksQ049bWNzaWJwY2EsQ049Q0RQLENO\n" +"PVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3Vy\n" +"YXRpb24sREM9Y29ycCxEQz1pbnRlbCxEQz1jb20/Y2VydGlmaWNhdGVSZXZvY2F0\n" +"aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MIIB\n" +"uQYIKwYBBQUHAQEEggGrMIIBpzBmBggrBgEFBQcwAoZaaHR0cDovL3d3dy5pbnRl\n" +"bC5jb20vcmVwb3NpdG9yeS9jZXJ0aWZpY2F0ZXMvSW50ZWwlMjBJbnRyYW5ldCUy\n" +"MEJhc2ljJTIwUG9saWN5JTIwQ0EoMSkuY3J0MG8GCCsGAQUFBzAChmNodHRwOi8v\n" +"Y2VydGlmaWNhdGVzLmludGVsLmNvbS9yZXBvc2l0b3J5L2NlcnRpZmljYXRlcy9J\n" +"bnRlbCUyMEludHJhbmV0JTIwQmFzaWMlMjBQb2xpY3klMjBDQSgxKS5jcnQwgcsG\n" +"CCsGAQUFBzAChoG+bGRhcDovLy9DTj1JbnRlbCUyMEludHJhbmV0JTIwQmFzaWMl\n" +"MjBQb2xpY3klMjBDQSxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIwU2VydmljZXMs\n" +"Q049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1jb3JwLERDPWludGVsLERD\n" +"PWNvbT9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9Y2VydGlmaWNhdGlv\n" +"bkF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAQEAsj8cHt2jSAmnIGulE9jXooAc\n" +"qH2xehlI+ko/al+nDnBzbjDYYjVS52XitYg8JGo6j72ijiGlGb/03FcQJRBZmUH6\n" +"znktx2rGTm4IdjL8quhvHthlzXXCozL8GMeeOuZ5rzHlhapKx764a5RuZtyx89uS\n" +"9cECon6oLGesXjFJ8Xrq6ecHZrQwJUpmvZalwvloKACAWqBh8yV12WDnUNZhtp8N\n" +"8rqeJZoy/lXGnTxsSSodO/5Y/CxYJM4W6u4WgvXNJSjO/0qWvb64S+pVLjBzwI+Y\n" +"X6oLqmBovRp1lGPOLjkXZi3EKDR8DmzhtpJq2677RtYowewnFedQ+exH9cXoJw==\n" +"-----END CERTIFICATE-----\n"; + +/* this certificate is issued by one of the above */ +static const char intermediate_str[] = +"-----BEGIN CERTIFICATE-----\n" +"MIIH4DCCBsigAwIBAgIKFpIKYgACAAJ8lTANBgkqhkiG9w0BAQUFADBWMQswCQYD\n" +"VQQGEwJVUzEaMBgGA1UEChMRSW50ZWwgQ29ycG9yYXRpb24xKzApBgNVBAMTIklu\n" +"dGVsIEludHJhbmV0IEJhc2ljIElzc3VpbmcgQ0EgMkIwHhcNMTQwMTA4MTc0MTM5\n" +"WhcNMTcwMTA3MTc0MTM5WjB1MQswCQYDVQQGEwJJRTELMAkGA1UEBxMCSVIxGjAY\n" +"BgNVBAoTEUludGVsIENvcnBvcmF0aW9uMQswCQYDVQQLEwJJVDEWMBQGA1UEAxMN\n" +"dnBuLmludGVsLmNvbTEYMBYGA1UEAxMPc2NzaXIuaW50ZWwuY29tMIIBIjANBgkq\n" +"hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi3WoORH5ITJ2lpcgCHex1HBUnmN/bb6s\n" +"sS1Arm50NEHMlqGfbsdCxq2iodMvrGWvdRAPaf/7Ii1UwUhEzxyKYAXC3KRAgioh\n" +"C0pvGmAFq1ciDYRhANPlW92lIgkt83WwGtOcES2u36VmUxBfdQe6rO3ldoZHVofY\n" +"uIG/ubBVLz0NhWMaRYSUzTv/4PKJ4paIS7COUROYsyKwc5wNjTcR2PB7RRW+YHgM\n" +"FkvqPpLjLAGpHdN+wuPNLlUcyzkZVhhXxvQJ9gc5hw/LLQvbmeiGIZCvOVy3ZSfi\n" +"cGw2jkbqKcFttVV52Wild3ZigALZtkKuFnGw5DEIfk4EAZhG8eHfFQIDAQABo4IE\n" +"jzCCBIswCwYDVR0PBAQDAgWgMB0GA1UdDgQWBBR4EAIG7OggvIFAhrB8m0eyhCKV\n" +"GzAfBgNVHSMEGDAWgBQ4Y3b6tgU6qVlPSoeNoIO3fpE6CzCCAbkGA1UdHwSCAbAw\n" +"ggGsMIIBqKCCAaSgggGghoHibGRhcDovLy9DTj1JbnRlbCUyMEludHJhbmV0JTIw\n" +"QmFzaWMlMjBJc3N1aW5nJTIwQ0ElMjAyQigyKSxDTj1BWlNNQ1NJQkVDQTAyLENO\n" +"PUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1D\n" +"b25maWd1cmF0aW9uLERDPWNvcnAsREM9aW50ZWwsREM9Y29tP2NlcnRpZmljYXRl\n" +"UmV2b2NhdGlvbkxpc3Q/YmFzZT9vYmplY3RDbGFzcz1jUkxEaXN0cmlidXRpb25Q\n" +"b2ludIZXaHR0cDovL3d3dy5pbnRlbC5jb20vcmVwb3NpdG9yeS9DUkwvSW50ZWwl\n" +"MjBJbnRyYW5ldCUyMEJhc2ljJTIwSXNzdWluZyUyMENBJTIwMkIoMikuY3JshmBo\n" +"dHRwOi8vY2VydGlmaWNhdGVzLmludGVsLmNvbS9yZXBvc2l0b3J5L0NSTC9JbnRl\n" +"bCUyMEludHJhbmV0JTIwQmFzaWMlMjBJc3N1aW5nJTIwQ0ElMjAyQigyKS5jcmww\n" +"ggHLBggrBgEFBQcBAQSCAb0wggG5MIHRBggrBgEFBQcwAoaBxGxkYXA6Ly8vQ049\n" +"SW50ZWwlMjBJbnRyYW5ldCUyMEJhc2ljJTIwSXNzdWluZyUyMENBJTIwMkIsQ049\n" +"QUlBLENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNv\n" +"bmZpZ3VyYXRpb24sREM9Y29ycCxEQz1pbnRlbCxEQz1jb20/Y0FDZXJ0aWZpY2F0\n" +"ZT9iYXNlP29iamVjdENsYXNzPWNlcnRpZmljYXRpb25BdXRob3JpdHkwbAYIKwYB\n" +"BQUHMAKGYGh0dHA6Ly93d3cuaW50ZWwuY29tL3JlcG9zaXRvcnkvY2VydGlmaWNh\n" +"dGVzL0ludGVsJTIwSW50cmFuZXQlMjBCYXNpYyUyMElzc3VpbmclMjBDQSUyMDJC\n" +"KDIpLmNydDB1BggrBgEFBQcwAoZpaHR0cDovL2NlcnRpZmljYXRlcy5pbnRlbC5j\n" +"b20vcmVwb3NpdG9yeS9jZXJ0aWZpY2F0ZXMvSW50ZWwlMjBJbnRyYW5ldCUyMEJh\n" +"c2ljJTIwSXNzdWluZyUyMENBJTIwMkIoMikuY3J0MD0GCSsGAQQBgjcVBwQwMC4G\n" +"JisGAQQBgjcVCIbDjHWEmeVRg/2BKIWOn1OCkcAJZ4eC0UGC37J5AgFkAgERMB0G\n" +"A1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAnBgkrBgEEAYI3FQoEGjAYMAoG\n" +"CCsGAQUFBwMCMAoGCCsGAQUFBwMBMCkGA1UdEQQiMCCCD3Njc2lyLmludGVsLmNv\n" +"bYINdnBuLmludGVsLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEALjO591IHOTt28HZ9\n" +"+Vm2TJp8EJSgWW3luKFAAPUOxix5FgK7mqNQk1052qV8NCQKqChO64f6kl3R29Pp\n" +"yv0ALYaxdYZXkxPuts05gwu9caeH9fK6vGTRk5pWygVIsobS2MypCYFs9VftFw5d\n" +"EPUAOsigQmkBC+k+icYzZDjm4HBGd0mTHwniNsKkkjxSnF4UGH9OYp4+hs9/pWly\n" +"19X4gVWwuxKB59TOe/tVxHBt57zZA3zYyXG+VPzVmklmYLPxVFcmeUDOjWU3x3Wp\n" +"0D5YUmvQlsd4+73IYw0BrvB42bQEFDUU/v0u6mwluk1m0LEdm+jlM/YCbrAgA3O8\n" +"eV1xMQ==\n" +"-----END CERTIFICATE-----\n"; + + + +/* GnuTLS internally calls time() to find out the current time when + verifying certificates. To avoid a time bomb, we hard code the + current time. This should work fine on systems where the library + call to time is resolved at run-time. */ +static time_t mytime(time_t * t) +{ + time_t then = 1412850586; + + if (t) + *t = then; + + return then; +} + +#define PIN "1234" + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +void doit(void) +{ + char buf[128]; + int exit_val = 0; + int ret; + unsigned j; + const char *lib, *bin; + gnutls_x509_crt_t issuer = NULL; + gnutls_x509_trust_list_t tl; + gnutls_x509_crt_t certs[MAX_CHAIN]; + gnutls_x509_crt_t intermediate, same_dn, same_issuer; + gnutls_datum_t tmp; + + if (gnutls_fips140_mode_enabled()) + exit(77); + + /* The overloading of time() seems to work in linux (ELF?) + * systems only. Disable it on windows. + */ +#ifdef _WIN32 + exit(77); +#endif + bin = softhsm_bin(); + + lib = softhsm_lib(); + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + gnutls_global_set_time_function(mytime); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin "PIN" --pin "PIN, bin); + system(buf); + + ret = gnutls_pkcs11_add_provider(lib, "trusted"); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + for (j = 0; ca_list[j]; j++) { + if (debug > 2) + printf("\tAdding certificate %d...", + (int) j); + + ret = gnutls_x509_crt_init(&certs[j]); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_init[%d,%d]: %s\n", + (int) 3, (int) j, + gnutls_strerror(ret)); + exit(1); + } + + tmp.data = (unsigned char *) ca_list[j]; + tmp.size = strlen(ca_list[j]); + + ret = + gnutls_x509_crt_import(certs[j], &tmp, + GNUTLS_X509_FMT_PEM); + if (debug > 2) + printf("done\n"); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_import[%d]: %s\n", + (int) j, + gnutls_strerror(ret)); + exit(1); + } + + gnutls_x509_crt_print(certs[j], + GNUTLS_CRT_PRINT_ONELINE, + &tmp); + if (debug) + printf("\tCertificate %d: %.*s\n", (int) j, + tmp.size, tmp.data); + gnutls_free(tmp.data); + } + + if (debug > 2) + printf("\tAdding intermediate certificate..."); + + ret = gnutls_x509_crt_init(&intermediate); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + tmp.data = (unsigned char *) intermediate_str; + tmp.size = strlen(intermediate_str); + + ret = + gnutls_x509_crt_import(intermediate, &tmp, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + if (debug > 2) + printf("done\n"); + + gnutls_x509_crt_print(intermediate, GNUTLS_CRT_PRINT_ONELINE, &tmp); + if (debug) + printf("\tIntermediate Certificate: %.*s\n", tmp.size, + tmp.data); + gnutls_free(tmp.data); + + assert(gnutls_x509_crt_init(&same_dn)>=0); + assert(gnutls_x509_crt_init(&same_issuer)>=0); + + tmp.data = (unsigned char *) same_issuer_cert_str; + tmp.size = strlen(same_issuer_cert_str); + + ret = + gnutls_x509_crt_import(same_dn, &tmp, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + tmp.data = (unsigned char *) same_dn_cert_str; + tmp.size = strlen(same_dn_cert_str); + + ret = + gnutls_x509_crt_import(same_issuer, &tmp, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + if (debug) + printf("\tVerifying..."); + + /* initialize softhsm token */ + ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test"); + if (ret < 0) { + fail("gnutls_pkcs11_token_init\n"); + exit(1); + } + + /* write CA certificate to softhsm */ + for (j = 0; ca_list[j]; j++) { + char name[64]; + snprintf(name, sizeof(name), "test-ca%d", j); + ret = gnutls_pkcs11_copy_x509_crt(SOFTHSM_URL, certs[j], name, GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED|GNUTLS_PKCS11_OBJ_FLAG_MARK_CA|GNUTLS_PKCS11_OBJ_FLAG_LOGIN_SO); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_crt: %s\n", gnutls_strerror(ret)); + } + } + + + /* try to extract an issuer when using an object URL + */ + gnutls_x509_trust_list_init(&tl, 0); + + ret = gnutls_x509_trust_list_add_trust_file(tl, OBJ_URL, NULL, 0, 0, 0); + if (ret != 1) { + fail("gnutls_x509_trust_list_add_trust_file (with expl. object 0): %d\n", ret); + exit(1); + } + + /* extract the issuer of the certificate */ + ret = gnutls_x509_trust_list_get_issuer(tl, intermediate, &issuer, GNUTLS_TL_GET_COPY); + if (ret < 0) { + fail("gnutls_x509_trust_list_get_issuer (with expl. object) should have succeeded\n"); + exit(1); + } + gnutls_x509_crt_deinit(issuer); + + gnutls_x509_trust_list_deinit(tl, 1); + + + + /* Try to extract issuers using PKCS #11 token URL + */ + gnutls_x509_trust_list_init(&tl, 0); + + ret = gnutls_x509_trust_list_add_trust_file(tl, SOFTHSM_URL, NULL, 0, 0, 0); + if (ret < 0) { + fail("gnutls_x509_trust_list_add_trust_file\n"); + exit(1); + } + + /* extract the issuer of the certificate */ + ret = gnutls_x509_trust_list_get_issuer(tl, intermediate, &issuer, GNUTLS_TL_GET_COPY); + if (ret < 0) { + fail("gnutls_x509_trust_list_get_issuer should have succeeded\n"); + exit(1); + } + gnutls_x509_crt_deinit(issuer); + + ret = gnutls_pkcs11_crt_is_known(SOFTHSM_URL, certs[2], GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED); + if (ret == 0) { + fail("error in gnutls_pkcs11_crt_is_known - 0\n"); + exit(1); + } + + ret = gnutls_pkcs11_crt_is_known(SOFTHSM_URL, certs[0], GNUTLS_PKCS11_OBJ_FLAG_COMPARE|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED); + if (ret == 0) { + fail("error in gnutls_pkcs11_crt_is_known - 0\n"); + exit(1); + } + + ret = gnutls_pkcs11_crt_is_known(SOFTHSM_URL, certs[1], GNUTLS_PKCS11_OBJ_FLAG_COMPARE|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED); + if (ret == 0) { + fail("error in gnutls_pkcs11_crt_is_known - 0\n"); + exit(1); + } + +#if 0 + /* test searching invalid certs. the distrusted flag disables any validity check except DN and serial number + * matching so it should work - unfortunately works only under p11-kit */ + + ret = gnutls_pkcs11_crt_is_known(SOFTHSM_URL, same_dn, GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED); + if (ret == 0) { + fail("error in gnutls_pkcs11_crt_is_known - did not get a known cert\n"); + exit(1); + } + + ret = gnutls_pkcs11_crt_is_known(SOFTHSM_URL, same_issuer, GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED); + if (ret == 0) { + fail("error in gnutls_pkcs11_crt_is_known - did not get a known cert\n"); + exit(1); + } +#endif + + /* we should find a certificate with the same DN */ + ret = gnutls_pkcs11_crt_is_known(SOFTHSM_URL, same_dn, 0); + if (ret != 0) { + fail("error in gnutls_pkcs11_crt_is_known - found a cert that doesn't match\n"); + exit(1); + } + + /* we should find a certificate with the same issuer DN + serial number */ + ret = gnutls_pkcs11_crt_is_known(SOFTHSM_URL, same_issuer, 0); + if (ret != 0) { + fail("error in gnutls_pkcs11_crt_is_known - found a cert that doesn't match\n"); + exit(1); + } + + /* these are invalid certificates but their key matches existing keys, the following should work */ + ret = gnutls_pkcs11_crt_is_known(SOFTHSM_URL, same_dn, GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED); + if (ret == 0) { + fail("error in gnutls_pkcs11_crt_is_known - did not find a cert that does match key\n"); + exit(1); + } + + ret = gnutls_pkcs11_crt_is_known(SOFTHSM_URL, same_issuer, GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED); + if (ret == 0) { + fail("error in gnutls_pkcs11_crt_is_known - did not find a cert that does match key\n"); + exit(1); + } + + + /* The following check whether the RETRIEVE_TRUSTED implies compare of the certificate */ + ret = gnutls_pkcs11_crt_is_known(SOFTHSM_URL, same_dn, GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED); + if (ret != 0) { + fail("error in gnutls_pkcs11_crt_is_known - found a cert that doesn't match\n"); + exit(1); + } + + ret = gnutls_pkcs11_crt_is_known(SOFTHSM_URL, same_issuer, GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED); + if (ret != 0) { + fail("error in gnutls_pkcs11_crt_is_known - found a cert that doesn't match\n"); + exit(1); + } + + ret = gnutls_pkcs11_crt_is_known(SOFTHSM_URL, same_dn, GNUTLS_PKCS11_OBJ_FLAG_COMPARE|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED); + if (ret != 0) { + fail("error in gnutls_pkcs11_crt_is_known - found a cert that doesn't match\n"); + exit(1); + } + + ret = gnutls_pkcs11_crt_is_known(SOFTHSM_URL, same_issuer, GNUTLS_PKCS11_OBJ_FLAG_COMPARE|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED); + if (ret != 0) { + fail("error in gnutls_pkcs11_crt_is_known - found a cert that doesn't match\n"); + exit(1); + } + + gnutls_x509_trust_list_deinit(tl, 1); + + /* deinit */ + if (debug) + printf("\tCleanup..."); + + gnutls_x509_crt_deinit(intermediate); + gnutls_x509_crt_deinit(same_dn); + gnutls_x509_crt_deinit(same_issuer); + for (j = 0; ca_list[j]; j++) { + gnutls_x509_crt_deinit(certs[j]); + } + if (debug) + printf("done\n\n\n"); + + gnutls_global_deinit(); + + if (debug) + printf("Exit status...%d\n", exit_val); + remove(CONFIG); + + exit(exit_val); +} diff --git a/tests/pkcs11/pkcs11-mechanisms.c b/tests/pkcs11/pkcs11-mechanisms.c new file mode 100644 index 0000000..c38f6ac --- /dev/null +++ b/tests/pkcs11/pkcs11-mechanisms.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2016-2017 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> + +#include "utils.h" + +/* Tests whether a gnutls_privkey_t will continue to work after + * a fork(), when gnutls_pkcs11_reinit() is manually called. */ + +#if defined(HAVE___REGISTER_ATFORK) + +#ifdef _WIN32 +# define P11LIB "libpkcs11mock1.dll" +#else +# include <dlfcn.h> +# define P11LIB "libpkcs11mock1.so" +#endif + + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +void doit(void) +{ + int ret; + const char *lib; + unsigned long mech; + unsigned i; + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + lib = getenv("P11MOCKLIB1"); + if (lib == NULL) + lib = P11LIB; + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + for (i=0;;i++) { + ret = gnutls_pkcs11_token_get_mechanism("pkcs11:", i, &mech); + if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) + break; + success("mech: %lu\n", mech); + ret = gnutls_pkcs11_token_check_mechanism("pkcs11:", mech, NULL, 0, 0); + if (ret == 0) { + fail("mechanism %ld was reported are supported, but is not found!\n", mech); + } + } + if (debug) + printf("done\n\n\n"); + + ret = gnutls_pkcs11_token_check_mechanism("pkcs11:", -1, NULL, 0, 0); + if (ret != 0) + fail("found invalid mechanism1\n"); + + ret = gnutls_pkcs11_token_check_mechanism("pkcs11:", -3, NULL, 0, 0); + if (ret != 0) + fail("found invalid mechanism2\n"); + + gnutls_pkcs11_deinit(); + gnutls_global_deinit(); +} +#else +void doit(void) +{ + exit(77); +} +#endif diff --git a/tests/pkcs11/pkcs11-mock-ext.h b/tests/pkcs11/pkcs11-mock-ext.h new file mode 100644 index 0000000..277e4a7 --- /dev/null +++ b/tests/pkcs11/pkcs11-mock-ext.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef PKCS11_MOCK_EXT_H +# define PKCS11_MOCK_EXT_H + +/* This flag instructs the module to return CKR_OK on sensitive + * objects */ +#define MOCK_FLAG_BROKEN_GET_ATTRIBUTES 1 +#define MOCK_FLAG_ALWAYS_AUTH (1<<1) +/* simulate the safenet HSMs always auth behavior */ +#define MOCK_FLAG_SAFENET_ALWAYS_AUTH (1<<2) + +#endif diff --git a/tests/pkcs11/pkcs11-mock.c b/tests/pkcs11/pkcs11-mock.c new file mode 100644 index 0000000..0645187 --- /dev/null +++ b/tests/pkcs11/pkcs11-mock.c @@ -0,0 +1,2819 @@ +/* + * Copyright 2011-2016 The Pkcs11Interop Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Written originally for the Pkcs11Interop project by: + * Jaroslav IMRICH <jimrich@jimrich.sk> + */ + +#include "pkcs11-mock.h" +#include "pkcs11-mock-ext.h" +#include <string.h> +#include <stdlib.h> + +unsigned int pkcs11_mock_flags = 0; + +/* This is a very basic mock PKCS #11 module that will return a given fixed + * certificate, and public key for all searches. It will also provide a + * CKO_X_CERTIFICATE_EXTENSION so that it can be used as a p11-kit trust + * module. */ + +const char mock_certificate[] = + "\x30\x82\x03\x97\x30\x82\x02\x4f\xa0\x03\x02\x01\x02\x02\x04\x4d" + "\xa7\x54\x21\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b" + "\x05\x00\x30\x32\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x42" + "\x45\x31\x0f\x30\x0d\x06\x03\x55\x04\x0a\x13\x06\x47\x6e\x75\x54" + "\x4c\x53\x31\x12\x30\x10\x06\x03\x55\x04\x03\x13\x09\x6c\x6f\x63" + "\x61\x6c\x68\x6f\x73\x74\x30\x1e\x17\x0d\x31\x31\x30\x34\x31\x34" + "\x32\x30\x30\x38\x30\x32\x5a\x17\x0d\x33\x38\x30\x38\x32\x39\x32" + "\x30\x30\x38\x30\x34\x5a\x30\x32\x31\x0b\x30\x09\x06\x03\x55\x04" + "\x06\x13\x02\x42\x45\x31\x0f\x30\x0d\x06\x03\x55\x04\x0a\x13\x06" + "\x47\x6e\x75\x54\x4c\x53\x31\x12\x30\x10\x06\x03\x55\x04\x03\x13" + "\x09\x6c\x6f\x63\x61\x6c\x68\x6f\x73\x74\x30\x82\x01\x52\x30\x0d" + "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x82\x01" + "\x3f\x00\x30\x82\x01\x3a\x02\x82\x01\x31\x00\xdd\xcf\x97\xd2\xa5" + "\x1d\x95\xdd\x86\x18\xd8\xc4\xb9\xad\xa6\x0c\xb4\x9d\xb6\xdc\xfa" + "\xdc\x21\xe1\x3a\x62\x34\x07\xe8\x33\xb2\xe8\x97\xee\x2c\x41\xd2" + "\x12\xf1\x5f\xed\xe4\x76\xff\x65\x26\x1e\x0c\xc7\x41\x15\x69\x5f" + "\x0d\xf9\xad\x89\x14\x8d\xea\xd7\x16\x52\x9a\x47\xc1\xbb\x00\x02" + "\xe4\x88\x45\x73\x78\xa4\xae\xdb\x38\xc3\xc6\x07\xd2\x64\x0e\x87" + "\xed\x74\x8c\x6b\xc4\xc0\x02\x50\x7c\x4e\xa6\xd1\x58\xe9\xe5\x13" + "\x09\xa9\xdb\x5a\xea\xeb\x0f\x06\x80\x5c\x09\xef\x94\xc8\xe9\xfb" + "\x37\x2e\x75\xe1\xac\x93\xad\x9b\x37\x13\x4b\x66\x3a\x76\x33\xd8" + "\xc4\xd7\x4c\xfb\x61\xc8\x92\x21\x07\xfc\xdf\xa9\x88\x54\xe4\xa3" + "\xa9\x47\xd2\x6c\xb8\xe3\x39\x89\x11\x88\x38\x2d\xa2\xdc\x3e\x5e" + "\x4a\xa9\xa4\x8e\xd5\x1f\xb2\xd0\xdd\x41\x3c\xda\x10\x68\x9e\x47" + "\x1b\x65\x02\xa2\xc5\x28\x73\x02\x83\x03\x09\xfd\xf5\x29\x7e\x97" + "\xdc\x2a\x4e\x4b\xaa\x79\x46\x46\x70\x86\x1b\x9b\xb8\xf6\x8a\xbe" + "\x29\x87\x7d\x5f\xda\xa5\x97\x6b\xef\xc8\x43\x09\x43\xe2\x1f\x8a" + "\x16\x7e\x1d\x50\x5d\xf5\xda\x02\xee\xf2\xc3\x2a\x48\xe6\x6b\x30" + "\xea\x02\xd7\xef\xac\x8b\x0c\xb8\xc1\x85\xd8\xbf\x7c\x85\xa8\x1e" + "\x83\xbe\x5c\x26\x2e\x79\x7b\x47\xf5\x4a\x3f\x66\x62\x92\xfd\x41" + "\x20\xb6\x2c\x00\xf0\x52\xca\x26\x06\x2d\x7c\xcf\x7a\x50\x7d\x0f" + "\xcb\xdd\x97\x20\xc8\x6f\xe4\xe0\x50\xf4\xe3\x02\x03\x01\x00\x01" + "\xa3\x55\x30\x53\x30\x0c\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x02" + "\x30\x00\x30\x13\x06\x03\x55\x1d\x25\x04\x0c\x30\x0a\x06\x08\x2b" + "\x06\x01\x05\x05\x07\x03\x01\x30\x0f\x06\x03\x55\x1d\x0f\x01\x01" + "\xff\x04\x05\x03\x03\x07\xa0\x00\x30\x1d\x06\x03\x55\x1d\x0e\x04" + "\x16\x04\x14\x92\x53\xd6\x71\xb9\xf8\x68\xaa\xb3\x53\xf6\x8d\xf5" + "\x39\x45\x66\x9c\xa7\xe5\x31\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7" + "\x0d\x01\x01\x0b\x05\x00\x03\x82\x01\x31\x00\x98\xbf\x48\x89\xc1" + "\xe6\xe6\x15\x13\xcc\xfc\xba\xed\xa0\x89\xe5\x86\x45\x30\x73\x68" + "\xb2\x79\x1f\x88\x02\x80\xfb\x2d\xc9\xb8\x21\x55\x8d\xc5\xb7\x56" + "\x1b\xcf\xc3\x76\xee\xd0\xf0\xd9\x22\x3a\x63\x92\xc5\x04\x86\x70" + "\x1e\x42\x33\x2a\x3b\xc4\x14\x08\xc5\x42\x92\x73\x7c\x3e\x39\xc0" + "\xee\x34\xc7\x33\x16\x5f\x93\xae\xcf\x1f\x9a\x30\x09\x51\xfe\x2d" + "\x94\x9c\x28\xad\x2a\x7e\xe4\x14\x81\x45\x6b\x0d\xd7\x11\x21\xfc" + "\xdb\x27\x17\x74\xb4\xcc\x94\x1a\x6e\x9e\x7b\x58\xa9\xe0\x06\x8d" + "\xda\x5f\x60\xe1\xb8\x6f\x28\x68\xb6\x58\xbe\xc5\xac\x36\x47\x37" + "\xf6\xa8\x38\x74\x23\x81\xf3\x22\xbe\x61\xff\x08\x08\x87\xeb\xc2" + "\x8f\x29\x25\x75\x5d\x4c\xeb\xd5\x09\x28\xab\x7b\x99\xf9\x69\x08" + "\xa2\xc6\x02\xd2\x2e\xcd\xfa\xf1\x19\xce\x3f\x44\x6a\xa1\x4b\xa8" + "\x56\xd5\x11\xae\x44\xe3\x68\x05\x50\x57\x8d\x72\x0f\xc7\x21\xdb" + "\x8f\xa3\x50\x78\x5d\x5a\x39\xcb\x90\x3d\x52\x43\x33\xbf\xea\x89" + "\x07\x1a\x92\xcc\x85\x27\xa8\x3d\x34\xb8\x5b\x52\xee\xef\x20\xb9" + "\xb6\xff\xea\xc5\x90\xd3\x47\xc5\x51\x90\xe2\xe6\x3e\x52\xb9\x1e" + "\x79\x18\xbe\xfd\xe2\x24\xbe\x47\x32\x5a\xb0\x03\x6b\xaa\xdb\xc3" + "\xdb\xf6\x60\x44\x08\xb6\x2c\x19\x47\xa2\xf0\x43\x7f\xf0\x07\x97" + "\x57\xab\xec\xa0\xb8\x6a\x49\xce\x08\xe6\xc3\x4d\xf2\xa4\xe9\xb8" + "\x43\xe7\xf0\x84\xd7\x1a\x72\x14\x5d\x82\x1a"; + +/* ca == true */ +const char mock_cert_ext1[] = "\x30\x0f\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x05\x30\x03\x01\x01\xff"; +/* GNUTLS_KEY_ENCIPHER_ONLY | GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_KEY_CERT_SIGN */ +const char mock_cert_ext2[] = "\x30\x0f\x06\x03\x55\x1d\x0f\x01\x01\xff\x04\x05\x03\x03\x07\x25\x00"; + +const char mock_pubkey[] = + "\x30\x82\x01\x52\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01" + "\x01\x05\x00\x03\x82\x01\x3f\x00\x30\x82\x01\x3a\x02\x82\x01\x31" + "\x00\xdd\xcf\x97\xd2\xa5\x1d\x95\xdd\x86\x18\xd8\xc4\xb9\xad\xa6" + "\x0c\xb4\x9d\xb6\xdc\xfa\xdc\x21\xe1\x3a\x62\x34\x07\xe8\x33\xb2" + "\xe8\x97\xee\x2c\x41\xd2\x12\xf1\x5f\xed\xe4\x76\xff\x65\x26\x1e" + "\x0c\xc7\x41\x15\x69\x5f\x0d\xf9\xad\x89\x14\x8d\xea\xd7\x16\x52" + "\x9a\x47\xc1\xbb\x00\x02\xe4\x88\x45\x73\x78\xa4\xae\xdb\x38\xc3" + "\xc6\x07\xd2\x64\x0e\x87\xed\x74\x8c\x6b\xc4\xc0\x02\x50\x7c\x4e" + "\xa6\xd1\x58\xe9\xe5\x13\x09\xa9\xdb\x5a\xea\xeb\x0f\x06\x80\x5c" + "\x09\xef\x94\xc8\xe9\xfb\x37\x2e\x75\xe1\xac\x93\xad\x9b\x37\x13" + "\x4b\x66\x3a\x76\x33\xd8\xc4\xd7\x4c\xfb\x61\xc8\x92\x21\x07\xfc" + "\xdf\xa9\x88\x54\xe4\xa3\xa9\x47\xd2\x6c\xb8\xe3\x39\x89\x11\x88" + "\x38\x2d\xa2\xdc\x3e\x5e\x4a\xa9\xa4\x8e\xd5\x1f\xb2\xd0\xdd\x41" + "\x3c\xda\x10\x68\x9e\x47\x1b\x65\x02\xa2\xc5\x28\x73\x02\x83\x03" + "\x09\xfd\xf5\x29\x7e\x97\xdc\x2a\x4e\x4b\xaa\x79\x46\x46\x70\x86" + "\x1b\x9b\xb8\xf6\x8a\xbe\x29\x87\x7d\x5f\xda\xa5\x97\x6b\xef\xc8" + "\x43\x09\x43\xe2\x1f\x8a\x16\x7e\x1d\x50\x5d\xf5\xda\x02\xee\xf2" + "\xc3\x2a\x48\xe6\x6b\x30\xea\x02\xd7\xef\xac\x8b\x0c\xb8\xc1\x85" + "\xd8\xbf\x7c\x85\xa8\x1e\x83\xbe\x5c\x26\x2e\x79\x7b\x47\xf5\x4a" + "\x3f\x66\x62\x92\xfd\x41\x20\xb6\x2c\x00\xf0\x52\xca\x26\x06\x2d" + "\x7c\xcf\x7a\x50\x7d\x0f\xcb\xdd\x97\x20\xc8\x6f\xe4\xe0\x50\xf4" + "\xe3\x02\x03\x01\x00\x01"; +const char mock_public_exponent[] = "\x01\x00\x01"; +const char mock_modulus[] = + "\xDD\xCF\x97\xD2\xA5\x1D\x95\xDD\x86\x18\xD8\xC4\xB9\xAD\xA6\x0C" + "\xB4\x9D\xB6\xDC\xFA\xDC\x21\xE1\x3A\x62\x34\x07\xE8\x33\xB2\xE8" + "\x97\xEE\x2C\x41\xD2\x12\xF1\x5F\xED\xE4\x76\xFF\x65\x26\x1E\x0C" + "\xC7\x41\x15\x69\x5F\x0D\xF9\xAD\x89\x14\x8D\xEA\xD7\x16\x52\x9A" + "\x47\xC1\xBB\x00\x02\xE4\x88\x45\x73\x78\xA4\xAE\xDB\x38\xC3\xC6" + "\x07\xD2\x64\x0E\x87\xED\x74\x8C\x6B\xC4\xC0\x02\x50\x7C\x4E\xA6" + "\xD1\x58\xE9\xE5\x13\x09\xA9\xDB\x5A\xEA\xEB\x0F\x06\x80\x5C\x09" + "\xEF\x94\xC8\xE9\xFB\x37\x2E\x75\xE1\xAC\x93\xAD\x9B\x37\x13\x4B" + "\x66\x3A\x76\x33\xD8\xC4\xD7\x4C\xFB\x61\xC8\x92\x21\x07\xFC\xDF" + "\xA9\x88\x54\xE4\xA3\xA9\x47\xD2\x6C\xB8\xE3\x39\x89\x11\x88\x38" + "\x2D\xA2\xDC\x3E\x5E\x4A\xA9\xA4\x8E\xD5\x1F\xB2\xD0\xDD\x41\x3C" + "\xDA\x10\x68\x9E\x47\x1B\x65\x02\xA2\xC5\x28\x73\x02\x83\x03\x09" + "\xFD\xF5\x29\x7E\x97\xDC\x2A\x4E\x4B\xAA\x79\x46\x46\x70\x86\x1B" + "\x9B\xB8\xF6\x8A\xBE\x29\x87\x7D\x5F\xDA\xA5\x97\x6B\xEF\xC8\x43" + "\x09\x43\xE2\x1F\x8A\x16\x7E\x1D\x50\x5D\xF5\xDA\x02\xEE\xF2\xC3" + "\x2A\x48\xE6\x6B\x30\xEA\x02\xD7\xEF\xAC\x8B\x0C\xB8\xC1\x85\xD8" + "\xBF\x7C\x85\xA8\x1E\x83\xBE\x5C\x26\x2E\x79\x7B\x47\xF5\x4A\x3F" + "\x66\x62\x92\xFD\x41\x20\xB6\x2C\x00\xF0\x52\xCA\x26\x06\x2D\x7C" + "\xCF\x7A\x50\x7D\x0F\xCB\xDD\x97\x20\xC8\x6F\xE4\xE0\x50\xF4\xE3"; +const char mock_subject[] = + "DN: C=US, O=Test Government, OU=Test Department, OU=Test Agency/serialNumber="; + +CK_BBOOL pkcs11_mock_initialized = CK_FALSE; +CK_BBOOL pkcs11_mock_session_opened = CK_FALSE; +CK_BBOOL pkcs11_mock_session_reauth = CK_FALSE; + +static session_ptr_st *mock_session = NULL; + +CK_FUNCTION_LIST pkcs11_mock_functions = +{ + {2, 20}, + &C_Initialize, + &C_Finalize, + &C_GetInfo, + &C_GetFunctionList, + &C_GetSlotList, + &C_GetSlotInfo, + &C_GetTokenInfo, + &C_GetMechanismList, + &C_GetMechanismInfo, + &C_InitToken, + &C_InitPIN, + &C_SetPIN, + &C_OpenSession, + &C_CloseSession, + &C_CloseAllSessions, + &C_GetSessionInfo, + &C_GetOperationState, + &C_SetOperationState, + &C_Login, + &C_Logout, + &C_CreateObject, + &C_CopyObject, + &C_DestroyObject, + &C_GetObjectSize, + &C_GetAttributeValue, + &C_SetAttributeValue, + &C_FindObjectsInit, + &C_FindObjects, + &C_FindObjectsFinal, + &C_EncryptInit, + &C_Encrypt, + &C_EncryptUpdate, + &C_EncryptFinal, + &C_DecryptInit, + &C_Decrypt, + &C_DecryptUpdate, + &C_DecryptFinal, + &C_DigestInit, + &C_Digest, + &C_DigestUpdate, + &C_DigestKey, + &C_DigestFinal, + &C_SignInit, + &C_Sign, + &C_SignUpdate, + &C_SignFinal, + &C_SignRecoverInit, + &C_SignRecover, + &C_VerifyInit, + &C_Verify, + &C_VerifyUpdate, + &C_VerifyFinal, + &C_VerifyRecoverInit, + &C_VerifyRecover, + &C_DigestEncryptUpdate, + &C_DecryptDigestUpdate, + &C_SignEncryptUpdate, + &C_DecryptVerifyUpdate, + &C_GenerateKey, + &C_GenerateKeyPair, + &C_WrapKey, + &C_UnwrapKey, + &C_DeriveKey, + &C_SeedRandom, + &C_GenerateRandom, + &C_GetFunctionStatus, + &C_CancelFunction, + &C_WaitForSlotEvent +}; + +#if defined(HAVE___REGISTER_ATFORK) +extern int __register_atfork(void (*)(void), void(*)(void), void (*)(void), void *); +extern void *__dso_handle; +static unsigned registered_fork_handler = 0; + +static void fork_handler(void) +{ + pkcs11_mock_initialized = CK_FALSE; + pkcs11_mock_session_opened = CK_FALSE; + if (mock_session) { + mock_session->state = CKS_RO_PUBLIC_SESSION; + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + free(mock_session->find_label); + } + free(mock_session); + mock_session = NULL; +} +#endif + + +CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(CK_VOID_PTR pInitArgs) +{ + if (CK_TRUE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_ALREADY_INITIALIZED; + + IGNORE(pInitArgs); +#if defined(HAVE___REGISTER_ATFORK) + if (registered_fork_handler == 0) { + __register_atfork(NULL, NULL, fork_handler, __dso_handle); + registered_fork_handler = 1; + } +#endif + pkcs11_mock_initialized = CK_TRUE; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_Finalize)(CK_VOID_PTR pReserved) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + IGNORE(pReserved); + + pkcs11_mock_initialized = CK_FALSE; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_GetInfo)(CK_INFO_PTR pInfo) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (NULL == pInfo) + return CKR_ARGUMENTS_BAD; + + pInfo->cryptokiVersion.major = 0x02; + pInfo->cryptokiVersion.minor = 0x14; + memset(pInfo->manufacturerID, ' ', sizeof(pInfo->manufacturerID)); + memcpy(pInfo->manufacturerID, PKCS11_MOCK_CK_INFO_MANUFACTURER_ID, strlen(PKCS11_MOCK_CK_INFO_MANUFACTURER_ID)); + pInfo->flags = 0; + memset(pInfo->libraryDescription, ' ', sizeof(pInfo->libraryDescription)); + memcpy(pInfo->libraryDescription, PKCS11_MOCK_CK_INFO_LIBRARY_DESCRIPTION, strlen(PKCS11_MOCK_CK_INFO_LIBRARY_DESCRIPTION)); + pInfo->libraryVersion.major = 0x01; + pInfo->libraryVersion.minor = 0x00; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) +{ + if (NULL == ppFunctionList) + return CKR_ARGUMENTS_BAD; + + *ppFunctionList = &pkcs11_mock_functions; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_GetSlotList)(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + IGNORE(tokenPresent); + + if (NULL == pulCount) + return CKR_ARGUMENTS_BAD; + + if (NULL == pSlotList) + { + *pulCount = 1; + } + else + { + if (0 == *pulCount) + return CKR_BUFFER_TOO_SMALL; + + pSlotList[0] = PKCS11_MOCK_CK_SLOT_ID; + *pulCount = 1; + } + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_GetSlotInfo)(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_SLOT_ID != slotID) + return CKR_SLOT_ID_INVALID; + + if (NULL == pInfo) + return CKR_ARGUMENTS_BAD; + + memset(pInfo->slotDescription, ' ', sizeof(pInfo->slotDescription)); + memcpy(pInfo->slotDescription, PKCS11_MOCK_CK_SLOT_INFO_SLOT_DESCRIPTION, strlen(PKCS11_MOCK_CK_SLOT_INFO_SLOT_DESCRIPTION)); + memset(pInfo->manufacturerID, ' ', sizeof(pInfo->manufacturerID)); + memcpy(pInfo->manufacturerID, PKCS11_MOCK_CK_SLOT_INFO_MANUFACTURER_ID, strlen(PKCS11_MOCK_CK_SLOT_INFO_MANUFACTURER_ID)); + pInfo->flags = CKF_TOKEN_PRESENT; + pInfo->hardwareVersion.major = 0x01; + pInfo->hardwareVersion.minor = 0x00; + pInfo->firmwareVersion.major = 0x01; + pInfo->firmwareVersion.minor = 0x00; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_GetTokenInfo)(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_SLOT_ID != slotID) + return CKR_SLOT_ID_INVALID; + + if (NULL == pInfo) + return CKR_ARGUMENTS_BAD; + + memset(pInfo->label, ' ', sizeof(pInfo->label)); + memcpy(pInfo->label, PKCS11_MOCK_CK_TOKEN_INFO_LABEL, strlen(PKCS11_MOCK_CK_TOKEN_INFO_LABEL)); + memset(pInfo->manufacturerID, ' ', sizeof(pInfo->manufacturerID)); + memcpy(pInfo->manufacturerID, PKCS11_MOCK_CK_TOKEN_INFO_MANUFACTURER_ID, strlen(PKCS11_MOCK_CK_TOKEN_INFO_MANUFACTURER_ID)); + memset(pInfo->model, ' ', sizeof(pInfo->model)); + memcpy(pInfo->model, PKCS11_MOCK_CK_TOKEN_INFO_MODEL, strlen(PKCS11_MOCK_CK_TOKEN_INFO_MODEL)); + memset(pInfo->serialNumber, ' ', sizeof(pInfo->serialNumber)); + memcpy(pInfo->serialNumber, PKCS11_MOCK_CK_TOKEN_INFO_SERIAL_NUMBER, strlen(PKCS11_MOCK_CK_TOKEN_INFO_SERIAL_NUMBER)); + pInfo->flags = CKF_RNG | CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | CKF_TOKEN_INITIALIZED; + + if (pkcs11_mock_flags & MOCK_FLAG_SAFENET_ALWAYS_AUTH) + pInfo->flags &= ~CKF_LOGIN_REQUIRED; + + pInfo->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE; + pInfo->ulSessionCount = (CK_TRUE == pkcs11_mock_session_opened) ? 1 : 0; + pInfo->ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE; + if ((CK_TRUE == pkcs11_mock_session_opened) && ((CKS_RO_PUBLIC_SESSION != mock_session->state) && (CKS_RO_USER_FUNCTIONS != mock_session->state))) + pInfo->ulRwSessionCount = 1; + else + pInfo->ulRwSessionCount = 0; + pInfo->ulMaxPinLen = PKCS11_MOCK_CK_TOKEN_INFO_MAX_PIN_LEN; + pInfo->ulMinPinLen = PKCS11_MOCK_CK_TOKEN_INFO_MIN_PIN_LEN; + pInfo->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION; + pInfo->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION; + pInfo->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION; + pInfo->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION; + pInfo->hardwareVersion.major = 0x01; + pInfo->hardwareVersion.minor = 0x00; + pInfo->firmwareVersion.major = 0x01; + pInfo->firmwareVersion.minor = 0x00; + memset(pInfo->utcTime, ' ', sizeof(pInfo->utcTime)); + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_GetMechanismList)(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_SLOT_ID != slotID) + return CKR_SLOT_ID_INVALID; + + if (NULL == pulCount) + return CKR_ARGUMENTS_BAD; + + if (NULL == pMechanismList) + { + *pulCount = 9; + } + else + { + if (9 > *pulCount) + return CKR_BUFFER_TOO_SMALL; + + pMechanismList[0] = CKM_RSA_PKCS_KEY_PAIR_GEN; + pMechanismList[1] = CKM_RSA_PKCS; + pMechanismList[2] = CKM_SHA1_RSA_PKCS; + pMechanismList[3] = CKM_RSA_PKCS_OAEP; + pMechanismList[4] = CKM_DES3_CBC; + pMechanismList[5] = CKM_DES3_KEY_GEN; + pMechanismList[6] = CKM_SHA_1; + pMechanismList[7] = CKM_XOR_BASE_AND_DATA; + pMechanismList[8] = CKM_AES_CBC; + + *pulCount = 9; + } + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_GetMechanismInfo)(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_SLOT_ID != slotID) + return CKR_SLOT_ID_INVALID; + + if (NULL == pInfo) + return CKR_ARGUMENTS_BAD; + + switch (type) + { + case CKM_RSA_PKCS_KEY_PAIR_GEN: + pInfo->ulMinKeySize = 1024; + pInfo->ulMaxKeySize = 1024; + pInfo->flags = CKF_GENERATE_KEY_PAIR; + break; + + case CKM_RSA_PKCS: + pInfo->ulMinKeySize = 1024; + pInfo->ulMaxKeySize = 1024; + pInfo->flags = CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_SIGN_RECOVER | CKF_VERIFY | CKF_VERIFY_RECOVER | CKF_WRAP | CKF_UNWRAP; + break; + + case CKM_SHA1_RSA_PKCS: + pInfo->ulMinKeySize = 1024; + pInfo->ulMaxKeySize = 1024; + pInfo->flags = CKF_SIGN | CKF_VERIFY; + break; + + case CKM_RSA_PKCS_OAEP: + pInfo->ulMinKeySize = 1024; + pInfo->ulMaxKeySize = 1024; + pInfo->flags = CKF_ENCRYPT | CKF_DECRYPT; + break; + + case CKM_DES3_CBC: + pInfo->ulMinKeySize = 192; + pInfo->ulMaxKeySize = 192; + pInfo->flags = CKF_ENCRYPT | CKF_DECRYPT; + break; + + case CKM_DES3_KEY_GEN: + pInfo->ulMinKeySize = 192; + pInfo->ulMaxKeySize = 192; + pInfo->flags = CKF_GENERATE; + break; + + case CKM_SHA_1: + pInfo->ulMinKeySize = 0; + pInfo->ulMaxKeySize = 0; + pInfo->flags = CKF_DIGEST; + break; + + case CKM_XOR_BASE_AND_DATA: + pInfo->ulMinKeySize = 128; + pInfo->ulMaxKeySize = 256; + pInfo->flags = CKF_DERIVE; + break; + + case CKM_AES_CBC: + pInfo->ulMinKeySize = 128; + pInfo->ulMaxKeySize = 256; + pInfo->flags = CKF_ENCRYPT | CKF_DECRYPT; + break; + + default: + return CKR_MECHANISM_INVALID; + } + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_InitToken)(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_SLOT_ID != slotID) + return CKR_SLOT_ID_INVALID; + + if (NULL == pPin) + return CKR_ARGUMENTS_BAD; + + if ((ulPinLen < PKCS11_MOCK_CK_TOKEN_INFO_MIN_PIN_LEN) || (ulPinLen > PKCS11_MOCK_CK_TOKEN_INFO_MAX_PIN_LEN)) + return CKR_PIN_LEN_RANGE; + + if (NULL == pLabel) + return CKR_ARGUMENTS_BAD; + + if (CK_TRUE == pkcs11_mock_session_opened) + return CKR_SESSION_EXISTS; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_InitPIN)(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (CKS_RW_SO_FUNCTIONS != mock_session->state) + return CKR_USER_NOT_LOGGED_IN; + + if (NULL == pPin) + return CKR_ARGUMENTS_BAD; + + if ((ulPinLen < PKCS11_MOCK_CK_TOKEN_INFO_MIN_PIN_LEN) || (ulPinLen > PKCS11_MOCK_CK_TOKEN_INFO_MAX_PIN_LEN)) + return CKR_PIN_LEN_RANGE; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_SetPIN)(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewLen) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if ((CKS_RO_PUBLIC_SESSION == mock_session->state) || (CKS_RO_USER_FUNCTIONS == mock_session->state)) + return CKR_SESSION_READ_ONLY; + + if (NULL == pOldPin) + return CKR_ARGUMENTS_BAD; + + if ((ulOldLen < PKCS11_MOCK_CK_TOKEN_INFO_MIN_PIN_LEN) || (ulOldLen > PKCS11_MOCK_CK_TOKEN_INFO_MAX_PIN_LEN)) + return CKR_PIN_LEN_RANGE; + + if (NULL == pNewPin) + return CKR_ARGUMENTS_BAD; + + if ((ulNewLen < PKCS11_MOCK_CK_TOKEN_INFO_MIN_PIN_LEN) || (ulNewLen > PKCS11_MOCK_CK_TOKEN_INFO_MAX_PIN_LEN)) + return CKR_PIN_LEN_RANGE; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_OpenSession)(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + if (CK_TRUE == pkcs11_mock_session_opened) + return CKR_SESSION_COUNT; + + if (PKCS11_MOCK_CK_SLOT_ID != slotID) + return CKR_SLOT_ID_INVALID; + + if (!(flags & CKF_SERIAL_SESSION)) + return CKR_SESSION_PARALLEL_NOT_SUPPORTED; + + IGNORE(pApplication); + + IGNORE(Notify); + + if (NULL == phSession) + return CKR_ARGUMENTS_BAD; + + pkcs11_mock_session_opened = CK_TRUE; + + mock_session = calloc(1, sizeof(session_ptr_st)); + if (mock_session == NULL) + return CKR_HOST_MEMORY; + + mock_session->state = (flags & CKF_RW_SESSION) ? CKS_RW_PUBLIC_SESSION : CKS_RO_PUBLIC_SESSION; + + mock_session->find_op.find_result = CKR_OBJECT_HANDLE_INVALID; + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + mock_session->state = CKS_RO_PUBLIC_SESSION; + + *phSession = PKCS11_MOCK_CK_SESSION_ID; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_CloseSession)(CK_SESSION_HANDLE hSession) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + pkcs11_mock_session_opened = CK_FALSE; + mock_session->state = CKS_RO_PUBLIC_SESSION; + + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + free(mock_session->find_label); + free(mock_session); + mock_session = NULL; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_CloseAllSessions)(CK_SLOT_ID slotID) +{ + return C_CloseSession(PKCS11_MOCK_CK_SESSION_ID); +} + + +CK_DEFINE_FUNCTION(CK_RV, C_GetSessionInfo)(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pInfo) + return CKR_ARGUMENTS_BAD; + + pInfo->slotID = PKCS11_MOCK_CK_SLOT_ID; + pInfo->state = mock_session->state; + pInfo->flags = CKF_SERIAL_SESSION; + if ((mock_session->state != CKS_RO_PUBLIC_SESSION) && (mock_session->state != CKS_RO_USER_FUNCTIONS)) + pInfo->flags = pInfo->flags | CKF_RW_SESSION; + pInfo->ulDeviceError = 0; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_GetOperationState)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pulOperationStateLen) + return CKR_ARGUMENTS_BAD; + + if (NULL == pOperationState) + { + *pulOperationStateLen = 256; + } + else + { + if (256 > *pulOperationStateLen) + return CKR_BUFFER_TOO_SMALL; + + memset(pOperationState, 1, 256); + *pulOperationStateLen = 256; + } + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_SetOperationState)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pOperationState) + return CKR_ARGUMENTS_BAD; + + if (256 != ulOperationStateLen) + return CKR_ARGUMENTS_BAD; + + IGNORE(hEncryptionKey); + + IGNORE(hAuthenticationKey); + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_Login)(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) +{ + CK_RV rv = CKR_OK; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if ((pkcs11_mock_flags & MOCK_FLAG_SAFENET_ALWAYS_AUTH) && userType == CKU_CONTEXT_SPECIFIC) { + return CKR_USER_TYPE_INVALID; + } + + if ((pkcs11_mock_flags & MOCK_FLAG_ALWAYS_AUTH) || (pkcs11_mock_flags & MOCK_FLAG_SAFENET_ALWAYS_AUTH)) { + if ((CKU_CONTEXT_SPECIFIC != userType) && (CKU_SO != userType) && (CKU_USER != userType)) + return CKR_USER_TYPE_INVALID; + } else if ((CKU_SO != userType) && (CKU_USER != userType)) { + return CKR_USER_TYPE_INVALID; + } + + if (NULL == pPin) + return CKR_ARGUMENTS_BAD; + + if ((ulPinLen < PKCS11_MOCK_CK_TOKEN_INFO_MIN_PIN_LEN) || (ulPinLen > PKCS11_MOCK_CK_TOKEN_INFO_MAX_PIN_LEN)) + return CKR_PIN_LEN_RANGE; + + switch (mock_session->state) + { + case CKS_RO_PUBLIC_SESSION: + + if (CKU_SO == userType) + rv = CKR_SESSION_READ_ONLY_EXISTS; + else + mock_session->state = CKS_RO_USER_FUNCTIONS; + + break; + + case CKS_RO_USER_FUNCTIONS: + case CKS_RW_USER_FUNCTIONS: + + rv = (CKU_SO == userType) ? CKR_USER_ANOTHER_ALREADY_LOGGED_IN : CKR_USER_ALREADY_LOGGED_IN; + + break; + + case CKS_RW_PUBLIC_SESSION: + + mock_session->state = (CKU_SO == userType) ? CKS_RW_SO_FUNCTIONS : CKS_RW_USER_FUNCTIONS; + + break; + + case CKS_RW_SO_FUNCTIONS: + + rv = (CKU_SO == userType) ? CKR_USER_ALREADY_LOGGED_IN : CKR_USER_ANOTHER_ALREADY_LOGGED_IN; + + break; + } + + if ((pkcs11_mock_flags & MOCK_FLAG_ALWAYS_AUTH || pkcs11_mock_flags & MOCK_FLAG_SAFENET_ALWAYS_AUTH) && rv == CKR_USER_ALREADY_LOGGED_IN) { + rv = 0; + } + + pkcs11_mock_session_reauth = 1; + return rv; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_Logout)(CK_SESSION_HANDLE hSession) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if ((mock_session->state == CKS_RO_PUBLIC_SESSION) || (mock_session->state == CKS_RW_PUBLIC_SESSION)) + return CKR_USER_NOT_LOGGED_IN; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pTemplate) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulCount) + return CKR_ARGUMENTS_BAD; + + if (NULL == phObject) + return CKR_ARGUMENTS_BAD; + + for (i = 0; i < ulCount; i++) + { + if (NULL == pTemplate[i].pValue) + return CKR_ATTRIBUTE_VALUE_INVALID; + + if (0 >= pTemplate[i].ulValueLen) + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + *phObject = PKCS11_MOCK_CK_OBJECT_HANDLE_DATA; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_CopyObject)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_DATA != hObject) + return CKR_OBJECT_HANDLE_INVALID; + + if (NULL == phNewObject) + return CKR_ARGUMENTS_BAD; + + if ((NULL != pTemplate) && (0 >= ulCount)) + { + for (i = 0; i < ulCount; i++) + { + if (NULL == pTemplate[i].pValue) + return CKR_ATTRIBUTE_VALUE_INVALID; + + if (0 >= pTemplate[i].ulValueLen) + return CKR_ATTRIBUTE_VALUE_INVALID; + } + } + + *phNewObject = PKCS11_MOCK_CK_OBJECT_HANDLE_DATA; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_DestroyObject)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if ((PKCS11_MOCK_CK_OBJECT_HANDLE_DATA != hObject) && + (PKCS11_MOCK_CK_OBJECT_HANDLE_SECRET_KEY != hObject) && + (PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY != hObject) && + (PKCS11_MOCK_CK_OBJECT_HANDLE_PRIVATE_KEY != hObject)) + return CKR_OBJECT_HANDLE_INVALID; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_GetObjectSize)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if ((PKCS11_MOCK_CK_OBJECT_HANDLE_DATA != hObject) && + (PKCS11_MOCK_CK_OBJECT_HANDLE_SECRET_KEY != hObject) && + (PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY != hObject) && + (PKCS11_MOCK_CK_OBJECT_HANDLE_PRIVATE_KEY != hObject)) + return CKR_OBJECT_HANDLE_INVALID; + + if (NULL == pulSize) + return CKR_ARGUMENTS_BAD; + + *pulSize = PKCS11_MOCK_CK_OBJECT_SIZE; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_GetAttributeValue)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if ((PKCS11_MOCK_CK_OBJECT_HANDLE_DATA != hObject) && + (PKCS11_MOCK_CK_OBJECT_HANDLE_SECRET_KEY != hObject) && + (PKCS11_MOCK_CK_OBJECT_HANDLE_CERTIFICATE_EXTENSION != hObject) && + (PKCS11_MOCK_CK_OBJECT_HANDLE_CERTIFICATE != hObject) && + (PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY != hObject) && + (PKCS11_MOCK_CK_OBJECT_HANDLE_PRIVATE_KEY != hObject)) + return CKR_OBJECT_HANDLE_INVALID; + + if (NULL == pTemplate) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulCount) + return CKR_ARGUMENTS_BAD; + + for (i = 0; i < ulCount; i++) + { + if (CKA_PUBLIC_KEY_INFO == pTemplate[i].type && + (PKCS11_MOCK_CK_OBJECT_HANDLE_CERTIFICATE == hObject || PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY == hObject)) + { + if (pTemplate[i].ulValueLen < sizeof(mock_pubkey)-1) { + pTemplate[i].ulValueLen = sizeof(mock_pubkey)-1; + if (pTemplate[i].pValue == NULL) + return CKR_OK; + else + return CKR_BUFFER_TOO_SMALL; + } + pTemplate[i].ulValueLen = (CK_ULONG) sizeof(mock_pubkey)-1; + memcpy(pTemplate[i].pValue, mock_pubkey, pTemplate[i].ulValueLen); + } + else if (CKA_CLASS == pTemplate[i].type) + { + if (NULL != pTemplate[i].pValue) + { + if (pTemplate[i].ulValueLen < sizeof(hObject)) + return CKR_BUFFER_TOO_SMALL; + else + memcpy(pTemplate[i].pValue, &hObject, sizeof(hObject)); + } + + pTemplate[i].ulValueLen = sizeof(hObject); + } + else if (CKA_PUBLIC_EXPONENT == pTemplate[i].type && + (PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY == hObject || PKCS11_MOCK_CK_OBJECT_HANDLE_PRIVATE_KEY == hObject)) + { + if (NULL != pTemplate[i].pValue) + { + if (pTemplate[i].ulValueLen < sizeof(mock_public_exponent)-1) + return CKR_BUFFER_TOO_SMALL; + else + memcpy(pTemplate[i].pValue, mock_public_exponent, sizeof(mock_public_exponent)-1); + } + + pTemplate[i].ulValueLen = sizeof(mock_public_exponent)-1; + } + else if (CKA_MODULUS == pTemplate[i].type && + (PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY == hObject || PKCS11_MOCK_CK_OBJECT_HANDLE_PRIVATE_KEY == hObject)) + { + if (NULL != pTemplate[i].pValue) + { + if (pTemplate[i].ulValueLen < sizeof(mock_modulus)-1) + return CKR_BUFFER_TOO_SMALL; + else + memcpy(pTemplate[i].pValue, mock_modulus, sizeof(mock_modulus)-1); + } + + pTemplate[i].ulValueLen = sizeof(mock_modulus)-1; + } + else if (CKA_SUBJECT == pTemplate[i].type && PKCS11_MOCK_CK_OBJECT_HANDLE_CERTIFICATE == hObject) + { + if (NULL != pTemplate[i].pValue) + { + if (pTemplate[i].ulValueLen < strlen(mock_subject)) + return CKR_BUFFER_TOO_SMALL; + else + memcpy(pTemplate[i].pValue, mock_subject, strlen(mock_subject)); + } + + pTemplate[i].ulValueLen = strlen(mock_subject); + } + else if (CKA_LABEL == pTemplate[i].type) + { + if (NULL != pTemplate[i].pValue) + { + if (pTemplate[i].ulValueLen < strlen(PKCS11_MOCK_CK_OBJECT_CKA_LABEL)) + return CKR_BUFFER_TOO_SMALL; + else + memcpy(pTemplate[i].pValue, PKCS11_MOCK_CK_OBJECT_CKA_LABEL, strlen(PKCS11_MOCK_CK_OBJECT_CKA_LABEL)); + } + + pTemplate[i].ulValueLen = strlen(PKCS11_MOCK_CK_OBJECT_CKA_LABEL); + } + else if (CKA_KEY_TYPE == pTemplate[i].type) + { + CK_KEY_TYPE t; + if (pTemplate[i].ulValueLen != sizeof(CK_KEY_TYPE)) + return CKR_ARGUMENTS_BAD; + + t = CKK_RSA; + memcpy(pTemplate[i].pValue, &t, sizeof(CK_KEY_TYPE)); + } + else if (CKA_ALWAYS_AUTHENTICATE == pTemplate[i].type) + { + CK_BBOOL t; + if (pkcs11_mock_flags & MOCK_FLAG_SAFENET_ALWAYS_AUTH) + return CKR_ATTRIBUTE_TYPE_INVALID; + + if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) + return CKR_ARGUMENTS_BAD; + + if (!(pkcs11_mock_flags & MOCK_FLAG_ALWAYS_AUTH)) { + t = CK_FALSE; + } else { + t = CK_TRUE; + } + memcpy(pTemplate[i].pValue, &t, sizeof(CK_BBOOL)); + } + else if (CKA_ID == pTemplate[i].type) + { + if (NULL != pTemplate[i].pValue) + { + if (pTemplate[i].ulValueLen < strlen(PKCS11_MOCK_CK_OBJECT_CKA_LABEL)) + return CKR_BUFFER_TOO_SMALL; + else + memcpy(pTemplate[i].pValue, PKCS11_MOCK_CK_OBJECT_CKA_LABEL, strlen(PKCS11_MOCK_CK_OBJECT_CKA_LABEL)); + } + + pTemplate[i].ulValueLen = strlen(PKCS11_MOCK_CK_OBJECT_CKA_LABEL); + } + else if (CKA_CERTIFICATE_CATEGORY == pTemplate[i].type) + { + CK_ULONG t = 2; /* authority */ + if (pTemplate[i].ulValueLen < sizeof(CK_ULONG)) + return CKR_BUFFER_TOO_SMALL; + memcpy(pTemplate[i].pValue, &t, sizeof(CK_ULONG)); + } + else if (CKA_VALUE == pTemplate[i].type) + { + if (PKCS11_MOCK_CK_OBJECT_HANDLE_CERTIFICATE_EXTENSION == hObject) + { + const void *obj; + unsigned obj_len; + + if (mock_session->find_op.remaining_data == 1) { + obj = mock_cert_ext1; + obj_len = sizeof(mock_cert_ext1)-1; + } else { + obj = mock_cert_ext2; + obj_len = sizeof(mock_cert_ext2)-1; + } + + if (pTemplate[i].ulValueLen < obj_len) { + pTemplate[i].ulValueLen = obj_len; + if (pTemplate[i].pValue == NULL) + return CKR_OK; + else + return CKR_BUFFER_TOO_SMALL; + } + pTemplate[i].ulValueLen = (CK_ULONG) obj_len; + memcpy(pTemplate[i].pValue, obj, pTemplate[i].ulValueLen); + } + else if (PKCS11_MOCK_CK_OBJECT_HANDLE_CERTIFICATE == hObject) + { + if (pTemplate[i].ulValueLen < sizeof(mock_certificate)-1) { + pTemplate[i].ulValueLen = sizeof(mock_certificate)-1; + if (pTemplate[i].pValue == NULL) + return CKR_OK; + else + return CKR_BUFFER_TOO_SMALL; + } + pTemplate[i].ulValueLen = (CK_ULONG) sizeof(mock_certificate)-1; + memcpy(pTemplate[i].pValue, mock_certificate, pTemplate[i].ulValueLen); + } + else if (PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY == hObject) + { + if (pTemplate[i].ulValueLen < sizeof(mock_pubkey)-1) { + pTemplate[i].ulValueLen = sizeof(mock_pubkey)-1; + if (pTemplate[i].pValue == NULL) + return CKR_OK; + else + return CKR_BUFFER_TOO_SMALL; + } + pTemplate[i].ulValueLen = (CK_ULONG) sizeof(mock_pubkey)-1; + memcpy(pTemplate[i].pValue, mock_pubkey, pTemplate[i].ulValueLen); + } + else if (PKCS11_MOCK_CK_OBJECT_HANDLE_PRIVATE_KEY == hObject) + { + pTemplate[i].ulValueLen = (CK_ULONG) -1; + if (!(pkcs11_mock_flags & MOCK_FLAG_BROKEN_GET_ATTRIBUTES)) { + return CKR_ATTRIBUTE_SENSITIVE; + } + } + else + { + if (NULL != pTemplate[i].pValue) + { + if (pTemplate[i].ulValueLen < strlen(PKCS11_MOCK_CK_OBJECT_CKA_VALUE)) + return CKR_BUFFER_TOO_SMALL; + else + memcpy(pTemplate[i].pValue, PKCS11_MOCK_CK_OBJECT_CKA_VALUE, strlen(PKCS11_MOCK_CK_OBJECT_CKA_VALUE)); + } + + pTemplate[i].ulValueLen = strlen(PKCS11_MOCK_CK_OBJECT_CKA_VALUE); + } + } + else + { + return CKR_ATTRIBUTE_TYPE_INVALID; + } + } + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_SetAttributeValue)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if ((PKCS11_MOCK_CK_OBJECT_HANDLE_DATA != hObject) && + (PKCS11_MOCK_CK_OBJECT_HANDLE_SECRET_KEY != hObject) && + (PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY != hObject) && + (PKCS11_MOCK_CK_OBJECT_HANDLE_PRIVATE_KEY != hObject)) + return CKR_OBJECT_HANDLE_INVALID; + + if (NULL == pTemplate) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulCount) + return CKR_ARGUMENTS_BAD; + + for (i = 0; i < ulCount; i++) + { + if ((CKA_LABEL == pTemplate[i].type) || (CKA_VALUE == pTemplate[i].type)) + { + if (NULL == pTemplate[i].pValue) + return CKR_ATTRIBUTE_VALUE_INVALID; + + if (0 >= pTemplate[i].ulValueLen) + return CKR_ATTRIBUTE_VALUE_INVALID; + } + else + { + return CKR_ATTRIBUTE_TYPE_INVALID; + } + } + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit)(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) +{ + CK_ULONG i = 0; + CK_ULONG_PTR cka_class_value = NULL; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_OPERATION_NONE != mock_session->find_op.active_operation) + return CKR_OPERATION_ACTIVE; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pTemplate) + return CKR_ARGUMENTS_BAD; + + IGNORE(ulCount); + + mock_session->find_op.find_result = CK_INVALID_HANDLE; + + for (i = 0; i < ulCount; i++) + { + if (NULL == pTemplate[i].pValue) + return CKR_ATTRIBUTE_VALUE_INVALID; + + if (0 >= pTemplate[i].ulValueLen) + return CKR_ATTRIBUTE_VALUE_INVALID; + + if (CKA_LABEL == pTemplate[i].type) + { + free(mock_session->find_label); + mock_session->find_label = strndup(pTemplate[i].pValue, pTemplate[i].ulValueLen); + } + else if (CKA_CLASS == pTemplate[i].type) + { + if (sizeof(CK_ULONG) != pTemplate[i].ulValueLen) + return CKR_ATTRIBUTE_VALUE_INVALID; + + cka_class_value = (CK_ULONG_PTR) pTemplate[i].pValue; + + switch (*cka_class_value) + { + case CKO_DATA: + mock_session->find_op.find_result = PKCS11_MOCK_CK_OBJECT_HANDLE_DATA; + mock_session->find_op.remaining_data = 2; + break; + case CKO_SECRET_KEY: + mock_session->find_op.find_result = PKCS11_MOCK_CK_OBJECT_HANDLE_SECRET_KEY; + mock_session->find_op.remaining_data = 1; + break; + case CKO_CERTIFICATE: + mock_session->find_op.find_result = PKCS11_MOCK_CK_OBJECT_HANDLE_CERTIFICATE; + mock_session->find_op.remaining_data = 1; + break; + case CKO_PUBLIC_KEY: + mock_session->find_op.find_result = PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY; + mock_session->find_op.remaining_data = 1; + break; + case CKO_PRIVATE_KEY: + mock_session->find_op.find_result = PKCS11_MOCK_CK_OBJECT_HANDLE_PRIVATE_KEY; + mock_session->find_op.remaining_data = 1; + break; + case CKO_X_CERTIFICATE_EXTENSION: + mock_session->find_op.find_result = PKCS11_MOCK_CK_OBJECT_HANDLE_CERTIFICATE_EXTENSION; + mock_session->find_op.remaining_data = 2; + break; + } + } + } + + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_FIND; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_FindObjects)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) +{ + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_OPERATION_FIND != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if ((NULL == phObject) && (0 < ulMaxObjectCount)) + return CKR_ARGUMENTS_BAD; + + if (NULL == pulObjectCount) + return CKR_ARGUMENTS_BAD; + + if (mock_session->find_op.remaining_data <= 0) { + *pulObjectCount = 0; + return CKR_OK; + } + + switch (mock_session->find_op.find_result) + { + case PKCS11_MOCK_CK_OBJECT_HANDLE_DATA: + + if (ulMaxObjectCount >= 2) + { + phObject[0] = mock_session->find_op.find_result; + phObject[1] = mock_session->find_op.find_result; + } + + *pulObjectCount = 2; + mock_session->find_op.remaining_data -= 2; + + break; + + case CK_INVALID_HANDLE: + + *pulObjectCount = 0; + + break; + + default: + + if (ulMaxObjectCount >= 1) + { + phObject[0] = mock_session->find_op.find_result; + } + + *pulObjectCount = 1; + mock_session->find_op.remaining_data --; + + break; + } + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsFinal)(CK_SESSION_HANDLE hSession) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_OPERATION_FIND != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_EncryptInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((PKCS11_MOCK_CK_OPERATION_NONE != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_DIGEST != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_SIGN != mock_session->find_op.active_operation)) + return CKR_OPERATION_ACTIVE; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pMechanism) + return CKR_ARGUMENTS_BAD; + + switch (pMechanism->mechanism) + { + case CKM_RSA_PKCS: + + if ((NULL != pMechanism->pParameter) || (0 != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY != hKey) + return CKR_KEY_TYPE_INCONSISTENT; + + break; + +#if 0 + case CKM_RSA_PKCS_OAEP: + + if ((NULL == pMechanism->pParameter) || (sizeof(CK_RSA_PKCS_OAEP_PARAMS) != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY != hKey) + return CKR_KEY_TYPE_INCONSISTENT; + + break; +#endif + case CKM_DES3_CBC: + + if ((NULL == pMechanism->pParameter) || (8 != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_SECRET_KEY != hKey) + return CKR_KEY_TYPE_INCONSISTENT; + + break; + + case CKM_AES_CBC: + + if ((NULL == pMechanism->pParameter) || (16 != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_SECRET_KEY != hKey) + return CKR_KEY_TYPE_INCONSISTENT; + + break; + + default: + + return CKR_MECHANISM_INVALID; + } + + switch (mock_session->find_op.active_operation) + { + case PKCS11_MOCK_CK_OPERATION_NONE: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_ENCRYPT; + break; + case PKCS11_MOCK_CK_OPERATION_DIGEST: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_DIGEST_ENCRYPT; + break; + case PKCS11_MOCK_CK_OPERATION_SIGN: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_SIGN_ENCRYPT; + break; + default: + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_Encrypt)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_OPERATION_ENCRYPT != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pData) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulDataLen) + return CKR_ARGUMENTS_BAD; + + if (NULL == pulEncryptedDataLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pEncryptedData) + { + if (ulDataLen > *pulEncryptedDataLen) + { + return CKR_BUFFER_TOO_SMALL; + } + else + { + for (i = 0; i < ulDataLen; i++) + pEncryptedData[i] = pData[i] ^ 0xAB; + + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + } + } + + *pulEncryptedDataLen = ulDataLen; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_EncryptUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_OPERATION_ENCRYPT != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pPart) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulPartLen) + return CKR_ARGUMENTS_BAD; + + if (NULL == pulEncryptedPartLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pEncryptedPart) + { + if (ulPartLen > *pulEncryptedPartLen) + { + return CKR_BUFFER_TOO_SMALL; + } + else + { + for (i = 0; i < ulPartLen; i++) + pEncryptedPart[i] = pPart[i] ^ 0xAB; + } + } + + *pulEncryptedPartLen = ulPartLen; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_EncryptFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((PKCS11_MOCK_CK_OPERATION_ENCRYPT != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_DIGEST_ENCRYPT != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_SIGN_ENCRYPT != mock_session->find_op.active_operation)) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pulLastEncryptedPartLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pLastEncryptedPart) + { + switch (mock_session->find_op.active_operation) + { + case PKCS11_MOCK_CK_OPERATION_ENCRYPT: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + break; + case PKCS11_MOCK_CK_OPERATION_DIGEST_ENCRYPT: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_DIGEST; + break; + case PKCS11_MOCK_CK_OPERATION_SIGN_ENCRYPT: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_SIGN; + break; + default: + return CKR_FUNCTION_FAILED; + } + } + + *pulLastEncryptedPartLen = 0; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_DecryptInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if ((PKCS11_MOCK_CK_OPERATION_NONE != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_DIGEST != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_VERIFY != mock_session->find_op.active_operation)) + return CKR_OPERATION_ACTIVE; + + if (pkcs11_mock_flags & MOCK_FLAG_ALWAYS_AUTH || pkcs11_mock_flags & MOCK_FLAG_SAFENET_ALWAYS_AUTH) { + mock_session->state = CKS_RO_PUBLIC_SESSION; + pkcs11_mock_session_reauth = 0; + } + + if (NULL == pMechanism) + return CKR_ARGUMENTS_BAD; + + switch (pMechanism->mechanism) + { + case CKM_RSA_PKCS: + + if ((NULL != pMechanism->pParameter) || (0 != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_PRIVATE_KEY != hKey) + return CKR_KEY_TYPE_INCONSISTENT; + + break; +#if 0 + case CKM_RSA_PKCS_OAEP: + + if ((NULL == pMechanism->pParameter) || (sizeof(CK_RSA_PKCS_OAEP_PARAMS) != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_PRIVATE_KEY != hKey) + return CKR_KEY_TYPE_INCONSISTENT; + + break; +#endif + case CKM_DES3_CBC: + + if ((NULL == pMechanism->pParameter) || (8 != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_SECRET_KEY != hKey) + return CKR_KEY_TYPE_INCONSISTENT; + + break; + + case CKM_AES_CBC: + + if ((NULL == pMechanism->pParameter) || (16 != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_SECRET_KEY != hKey) + return CKR_KEY_TYPE_INCONSISTENT; + + break; + + default: + + return CKR_MECHANISM_INVALID; + } + + switch (mock_session->find_op.active_operation) + { + case PKCS11_MOCK_CK_OPERATION_NONE: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_DECRYPT; + break; + case PKCS11_MOCK_CK_OPERATION_DIGEST: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_DECRYPT_DIGEST; + break; + case PKCS11_MOCK_CK_OPERATION_VERIFY: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_DECRYPT_VERIFY; + break; + default: + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_Decrypt)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (PKCS11_MOCK_CK_OPERATION_DECRYPT != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if (pkcs11_mock_flags & MOCK_FLAG_ALWAYS_AUTH || pkcs11_mock_flags & MOCK_FLAG_SAFENET_ALWAYS_AUTH) { + if (!pkcs11_mock_session_reauth) { + return CKR_USER_NOT_LOGGED_IN; + } + if ((pkcs11_mock_flags & MOCK_FLAG_ALWAYS_AUTH) && pData != NULL) { + pkcs11_mock_session_reauth = 0; + } + } + + if (NULL == pEncryptedData) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulEncryptedDataLen) + return CKR_ARGUMENTS_BAD; + + if (NULL == pulDataLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pData) + { + if (ulEncryptedDataLen > *pulDataLen) + { + return CKR_BUFFER_TOO_SMALL; + } + else + { + for (i = 0; i < ulEncryptedDataLen; i++) + pData[i] = pEncryptedData[i] ^ 0xAB; + + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + } + } + + *pulDataLen = ulEncryptedDataLen; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_DecryptUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (PKCS11_MOCK_CK_OPERATION_DECRYPT != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if (NULL == pEncryptedPart) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulEncryptedPartLen) + return CKR_ARGUMENTS_BAD; + + if (NULL == pulPartLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pPart) + { + if (ulEncryptedPartLen > *pulPartLen) + { + return CKR_BUFFER_TOO_SMALL; + } + else + { + for (i = 0; i < ulEncryptedPartLen; i++) + pPart[i] = pEncryptedPart[i] ^ 0xAB; + } + } + + *pulPartLen = ulEncryptedPartLen; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_DecryptFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if ((PKCS11_MOCK_CK_OPERATION_DECRYPT != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_DECRYPT_DIGEST != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_DECRYPT_VERIFY != mock_session->find_op.active_operation)) + return CKR_OPERATION_NOT_INITIALIZED; + + if (NULL == pulLastPartLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pLastPart) + { + switch (mock_session->find_op.active_operation) + { + case PKCS11_MOCK_CK_OPERATION_DECRYPT: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + break; + case PKCS11_MOCK_CK_OPERATION_DECRYPT_DIGEST: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_DIGEST; + break; + case PKCS11_MOCK_CK_OPERATION_DECRYPT_VERIFY: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_VERIFY; + break; + default: + return CKR_FUNCTION_FAILED; + } + } + + *pulLastPartLen = 0; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_DigestInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((PKCS11_MOCK_CK_OPERATION_NONE != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_ENCRYPT != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_DECRYPT != mock_session->find_op.active_operation)) + return CKR_OPERATION_ACTIVE; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pMechanism) + return CKR_ARGUMENTS_BAD; + + if (CKM_SHA_1 != pMechanism->mechanism) + return CKR_MECHANISM_INVALID; + + if ((NULL != pMechanism->pParameter) || (0 != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + switch (mock_session->find_op.active_operation) + { + case PKCS11_MOCK_CK_OPERATION_NONE: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_DIGEST; + break; + case PKCS11_MOCK_CK_OPERATION_ENCRYPT: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_DIGEST_ENCRYPT; + break; + case PKCS11_MOCK_CK_OPERATION_DECRYPT: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_DECRYPT_DIGEST; + break; + default: + return CKR_FUNCTION_FAILED; + } + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_Digest)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) +{ + CK_BYTE hash[20] = { 0x7B, 0x50, 0x2C, 0x3A, 0x1F, 0x48, 0xC8, 0x60, 0x9A, 0xE2, 0x12, 0xCD, 0xFB, 0x63, 0x9D, 0xEE, 0x39, 0x67, 0x3F, 0x5E }; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_OPERATION_DIGEST != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pData) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulDataLen) + return CKR_ARGUMENTS_BAD; + + if (NULL == pulDigestLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pDigest) + { + if (sizeof(hash) > *pulDigestLen) + { + return CKR_BUFFER_TOO_SMALL; + } + else + { + memcpy(pDigest, hash, sizeof(hash)); + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + } + } + + *pulDigestLen = sizeof(hash); + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_DigestUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_OPERATION_DIGEST != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pPart) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulPartLen) + return CKR_ARGUMENTS_BAD; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_DigestKey)(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_OPERATION_DIGEST != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_SECRET_KEY != hKey) + return CKR_OBJECT_HANDLE_INVALID; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_DigestFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) +{ + CK_BYTE hash[20] = { 0x7B, 0x50, 0x2C, 0x3A, 0x1F, 0x48, 0xC8, 0x60, 0x9A, 0xE2, 0x12, 0xCD, 0xFB, 0x63, 0x9D, 0xEE, 0x39, 0x67, 0x3F, 0x5E }; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((PKCS11_MOCK_CK_OPERATION_DIGEST != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_DIGEST_ENCRYPT != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_DECRYPT_DIGEST != mock_session->find_op.active_operation)) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pulDigestLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pDigest) + { + if (sizeof(hash) > *pulDigestLen) + { + return CKR_BUFFER_TOO_SMALL; + } + else + { + memcpy(pDigest, hash, sizeof(hash)); + + switch (mock_session->find_op.active_operation) + { + case PKCS11_MOCK_CK_OPERATION_DIGEST: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + break; + case PKCS11_MOCK_CK_OPERATION_DIGEST_ENCRYPT: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_ENCRYPT; + break; + case PKCS11_MOCK_CK_OPERATION_DECRYPT_DIGEST: + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_DECRYPT; + break; + default: + return CKR_FUNCTION_FAILED; + } + } + } + + *pulDigestLen = sizeof(hash); + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_SignInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if ((PKCS11_MOCK_CK_OPERATION_NONE != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_ENCRYPT != mock_session->find_op.active_operation)) + return CKR_OPERATION_ACTIVE; + + if (pkcs11_mock_flags & MOCK_FLAG_ALWAYS_AUTH || pkcs11_mock_flags & MOCK_FLAG_SAFENET_ALWAYS_AUTH) { + mock_session->state = CKS_RO_PUBLIC_SESSION; + pkcs11_mock_session_reauth = 0; + } + + if (NULL == pMechanism) + return CKR_ARGUMENTS_BAD; + + if ((CKM_RSA_PKCS == pMechanism->mechanism) || (CKM_SHA1_RSA_PKCS == pMechanism->mechanism)) + { + if ((NULL != pMechanism->pParameter) || (0 != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_PRIVATE_KEY != hKey) + return CKR_KEY_TYPE_INCONSISTENT; + } + else + { + return CKR_MECHANISM_INVALID; + } + + if (PKCS11_MOCK_CK_OPERATION_NONE == mock_session->find_op.active_operation) + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_SIGN; + else + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_SIGN_ENCRYPT; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_Sign)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) +{ + CK_BYTE signature[10] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_OPERATION_SIGN != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (pkcs11_mock_flags & MOCK_FLAG_ALWAYS_AUTH || pkcs11_mock_flags & MOCK_FLAG_SAFENET_ALWAYS_AUTH) { + if (!pkcs11_mock_session_reauth) { + return CKR_USER_NOT_LOGGED_IN; + } + + if ((pkcs11_mock_flags & MOCK_FLAG_ALWAYS_AUTH) && pSignature != NULL) { + pkcs11_mock_session_reauth = 0; + } + } + + if (NULL == pData) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulDataLen) + return CKR_ARGUMENTS_BAD; + + if (NULL == pulSignatureLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pSignature) + { + if (sizeof(signature) > *pulSignatureLen) + { + return CKR_BUFFER_TOO_SMALL; + } + else + { + memcpy(pSignature, signature, sizeof(signature)); + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + } + } + + *pulSignatureLen = sizeof(signature); + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_SignUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_OPERATION_SIGN != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pPart) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulPartLen) + return CKR_ARGUMENTS_BAD; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_SignFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) +{ + CK_BYTE signature[10] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((PKCS11_MOCK_CK_OPERATION_SIGN != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_SIGN_ENCRYPT != mock_session->find_op.active_operation)) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pulSignatureLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pSignature) + { + if (sizeof(signature) > *pulSignatureLen) + { + return CKR_BUFFER_TOO_SMALL; + } + else + { + memcpy(pSignature, signature, sizeof(signature)); + + if (PKCS11_MOCK_CK_OPERATION_SIGN == mock_session->find_op.active_operation) + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + else + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_ENCRYPT; + } + } + + *pulSignatureLen = sizeof(signature); + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_SignRecoverInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (PKCS11_MOCK_CK_OPERATION_NONE != mock_session->find_op.active_operation) + return CKR_OPERATION_ACTIVE; + + if (NULL == pMechanism) + return CKR_ARGUMENTS_BAD; + + if (CKM_RSA_PKCS == pMechanism->mechanism) + { + if ((NULL != pMechanism->pParameter) || (0 != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_PRIVATE_KEY != hKey) + return CKR_KEY_TYPE_INCONSISTENT; + } + else + { + return CKR_MECHANISM_INVALID; + } + + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_SIGN_RECOVER; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_SignRecover)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_OPERATION_SIGN_RECOVER != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pData) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulDataLen) + return CKR_ARGUMENTS_BAD; + + if (NULL == pulSignatureLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pSignature) + { + if (ulDataLen > *pulSignatureLen) + { + return CKR_BUFFER_TOO_SMALL; + } + else + { + for (i = 0; i < ulDataLen; i++) + pSignature[i] = pData[i] ^ 0xAB; + + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + } + } + + *pulSignatureLen = ulDataLen; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_VerifyInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if ((PKCS11_MOCK_CK_OPERATION_NONE != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_DECRYPT != mock_session->find_op.active_operation)) + return CKR_OPERATION_ACTIVE; + + if (NULL == pMechanism) + return CKR_ARGUMENTS_BAD; + + if ((CKM_RSA_PKCS == pMechanism->mechanism) || (CKM_SHA1_RSA_PKCS == pMechanism->mechanism)) + { + if ((NULL != pMechanism->pParameter) || (0 != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY != hKey) + return CKR_KEY_TYPE_INCONSISTENT; + } + else + { + return CKR_MECHANISM_INVALID; + } + + if (PKCS11_MOCK_CK_OPERATION_NONE == mock_session->find_op.active_operation) + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_VERIFY; + else + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_DECRYPT_VERIFY; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_Verify)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) +{ + CK_BYTE signature[10] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_OPERATION_VERIFY != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pData) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulDataLen) + return CKR_ARGUMENTS_BAD; + + if (NULL == pSignature) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulSignatureLen) + return CKR_ARGUMENTS_BAD; + + if (sizeof(signature) != ulSignatureLen) + return CKR_SIGNATURE_LEN_RANGE; + + if (0 != memcmp(pSignature, signature, sizeof(signature))) + return CKR_SIGNATURE_INVALID; + + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_VerifyUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_OPERATION_VERIFY != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pPart) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulPartLen) + return CKR_ARGUMENTS_BAD; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_VerifyFinal)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) +{ + CK_BYTE signature[10] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((PKCS11_MOCK_CK_OPERATION_VERIFY != mock_session->find_op.active_operation) && + (PKCS11_MOCK_CK_OPERATION_DECRYPT_VERIFY != mock_session->find_op.active_operation)) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pSignature) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulSignatureLen) + return CKR_ARGUMENTS_BAD; + + if (sizeof(signature) != ulSignatureLen) + return CKR_SIGNATURE_LEN_RANGE; + + if (0 != memcmp(pSignature, signature, sizeof(signature))) + return CKR_SIGNATURE_INVALID; + + if (PKCS11_MOCK_CK_OPERATION_VERIFY == mock_session->find_op.active_operation) + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + else + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_DECRYPT; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_VerifyRecoverInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (PKCS11_MOCK_CK_OPERATION_NONE != mock_session->find_op.active_operation) + return CKR_OPERATION_ACTIVE; + + if (NULL == pMechanism) + return CKR_ARGUMENTS_BAD; + + if (CKM_RSA_PKCS == pMechanism->mechanism) + { + if ((NULL != pMechanism->pParameter) || (0 != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY != hKey) + return CKR_KEY_TYPE_INCONSISTENT; + } + else + { + return CKR_MECHANISM_INVALID; + } + + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_VERIFY_RECOVER; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_VerifyRecover)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_OPERATION_VERIFY_RECOVER != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pSignature) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulSignatureLen) + return CKR_ARGUMENTS_BAD; + + if (NULL == pulDataLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pData) + { + if (ulSignatureLen > *pulDataLen) + { + return CKR_BUFFER_TOO_SMALL; + } + else + { + for (i = 0; i < ulSignatureLen; i++) + pData[i] = pSignature[i] ^ 0xAB; + + mock_session->find_op.active_operation = PKCS11_MOCK_CK_OPERATION_NONE; + } + } + + *pulDataLen = ulSignatureLen; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_DigestEncryptUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if (PKCS11_MOCK_CK_OPERATION_DIGEST_ENCRYPT != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pPart) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulPartLen) + return CKR_ARGUMENTS_BAD; + + if (NULL == pulEncryptedPartLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pEncryptedPart) + { + if (ulPartLen > *pulEncryptedPartLen) + { + return CKR_BUFFER_TOO_SMALL; + } + else + { + for (i = 0; i < ulPartLen; i++) + pEncryptedPart[i] = pPart[i] ^ 0xAB; + } + } + + *pulEncryptedPartLen = ulPartLen; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_DecryptDigestUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (PKCS11_MOCK_CK_OPERATION_DECRYPT_DIGEST != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if (NULL == pEncryptedPart) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulEncryptedPartLen) + return CKR_ARGUMENTS_BAD; + + if (NULL == pulPartLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pPart) + { + if (ulEncryptedPartLen > *pulPartLen) + { + return CKR_BUFFER_TOO_SMALL; + } + else + { + for (i = 0; i < ulEncryptedPartLen; i++) + pPart[i] = pEncryptedPart[i] ^ 0xAB; + } + } + + *pulPartLen = ulEncryptedPartLen; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_SignEncryptUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (PKCS11_MOCK_CK_OPERATION_SIGN_ENCRYPT != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if (NULL == pPart) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulPartLen) + return CKR_ARGUMENTS_BAD; + + if (NULL == pulEncryptedPartLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pEncryptedPart) + { + if (ulPartLen > *pulEncryptedPartLen) + { + return CKR_BUFFER_TOO_SMALL; + } + else + { + for (i = 0; i < ulPartLen; i++) + pEncryptedPart[i] = pPart[i] ^ 0xAB; + } + } + + *pulEncryptedPartLen = ulPartLen; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_DecryptVerifyUpdate)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (PKCS11_MOCK_CK_OPERATION_DECRYPT_VERIFY != mock_session->find_op.active_operation) + return CKR_OPERATION_NOT_INITIALIZED; + + if (NULL == pEncryptedPart) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulEncryptedPartLen) + return CKR_ARGUMENTS_BAD; + + if (NULL == pulPartLen) + return CKR_ARGUMENTS_BAD; + + if (NULL != pPart) + { + if (ulEncryptedPartLen > *pulPartLen) + { + return CKR_BUFFER_TOO_SMALL; + } + else + { + for (i = 0; i < ulEncryptedPartLen; i++) + pPart[i] = pEncryptedPart[i] ^ 0xAB; + } + } + + *pulPartLen = ulEncryptedPartLen; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_GenerateKey)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pMechanism) + return CKR_ARGUMENTS_BAD; + + if (CKM_DES3_KEY_GEN != pMechanism->mechanism) + return CKR_MECHANISM_INVALID; + + if ((NULL != pMechanism->pParameter) || (0 != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (NULL == pTemplate) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulCount) + return CKR_ARGUMENTS_BAD; + + if (NULL == phKey) + return CKR_ARGUMENTS_BAD; + + for (i = 0; i < ulCount; i++) + { + if (NULL == pTemplate[i].pValue) + return CKR_ATTRIBUTE_VALUE_INVALID; + + if (0 >= pTemplate[i].ulValueLen) + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + *phKey = PKCS11_MOCK_CK_OBJECT_HANDLE_SECRET_KEY; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_GenerateKeyPair)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pMechanism) + return CKR_ARGUMENTS_BAD; + + if (CKM_RSA_PKCS_KEY_PAIR_GEN != pMechanism->mechanism) + return CKR_MECHANISM_INVALID; + + if ((NULL != pMechanism->pParameter) || (0 != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (NULL == pPublicKeyTemplate) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulPublicKeyAttributeCount) + return CKR_ARGUMENTS_BAD; + + if (NULL == pPrivateKeyTemplate) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulPrivateKeyAttributeCount) + return CKR_ARGUMENTS_BAD; + + if (NULL == phPublicKey) + return CKR_ARGUMENTS_BAD; + + if (NULL == phPrivateKey) + return CKR_ARGUMENTS_BAD; + + for (i = 0; i < ulPublicKeyAttributeCount; i++) + { + if (NULL == pPublicKeyTemplate[i].pValue) + return CKR_ATTRIBUTE_VALUE_INVALID; + + if (0 >= pPublicKeyTemplate[i].ulValueLen) + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + for (i = 0; i < ulPrivateKeyAttributeCount; i++) + { + if (NULL == pPrivateKeyTemplate[i].pValue) + return CKR_ATTRIBUTE_VALUE_INVALID; + + if (0 >= pPrivateKeyTemplate[i].ulValueLen) + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + *phPublicKey = PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY; + *phPrivateKey = PKCS11_MOCK_CK_OBJECT_HANDLE_PRIVATE_KEY; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_WrapKey)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen) +{ + CK_BYTE wrappedKey[10] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pMechanism) + return CKR_ARGUMENTS_BAD; + + if (CKM_RSA_PKCS != pMechanism->mechanism) + return CKR_MECHANISM_INVALID; + + if ((NULL != pMechanism->pParameter) || (0 != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY != hWrappingKey) + return CKR_KEY_HANDLE_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_SECRET_KEY != hKey) + return CKR_KEY_HANDLE_INVALID; + + if (NULL != pWrappedKey) + { + if (sizeof(wrappedKey) > *pulWrappedKeyLen) + return CKR_BUFFER_TOO_SMALL; + else + memcpy(pWrappedKey, wrappedKey, sizeof(wrappedKey)); + } + + *pulWrappedKeyLen = sizeof(wrappedKey); + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_UnwrapKey)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) +{ + CK_ULONG i = 0; + + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pMechanism) + return CKR_ARGUMENTS_BAD; + + if (CKM_RSA_PKCS != pMechanism->mechanism) + return CKR_MECHANISM_INVALID; + + if ((NULL != pMechanism->pParameter) || (0 != pMechanism->ulParameterLen)) + return CKR_MECHANISM_PARAM_INVALID; + + if (PKCS11_MOCK_CK_OBJECT_HANDLE_PRIVATE_KEY != hUnwrappingKey) + return CKR_KEY_HANDLE_INVALID; + + if (NULL == pWrappedKey) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulWrappedKeyLen) + return CKR_ARGUMENTS_BAD; + + if (NULL == pTemplate) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulAttributeCount) + return CKR_ARGUMENTS_BAD; + + if (NULL == phKey) + return CKR_ARGUMENTS_BAD; + + for (i = 0; i < ulAttributeCount; i++) + { + if (NULL == pTemplate[i].pValue) + return CKR_ATTRIBUTE_VALUE_INVALID; + + if (0 >= pTemplate[i].ulValueLen) + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + *phKey = PKCS11_MOCK_CK_OBJECT_HANDLE_SECRET_KEY; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_DeriveKey)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) +{ + return CKR_GENERAL_ERROR; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_SeedRandom)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == pSeed) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulSeedLen) + return CKR_ARGUMENTS_BAD; + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_GenerateRandom)(CK_SESSION_HANDLE hSession, CK_BYTE_PTR RandomData, CK_ULONG ulRandomLen) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + if (NULL == RandomData) + return CKR_ARGUMENTS_BAD; + + if (0 >= ulRandomLen) + return CKR_ARGUMENTS_BAD; + + memset(RandomData, 1, ulRandomLen); + + return CKR_OK; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_GetFunctionStatus)(CK_SESSION_HANDLE hSession) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + return CKR_FUNCTION_NOT_PARALLEL; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_CancelFunction)(CK_SESSION_HANDLE hSession) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession)) + return CKR_SESSION_HANDLE_INVALID; + + return CKR_FUNCTION_NOT_PARALLEL; +} + + +CK_DEFINE_FUNCTION(CK_RV, C_WaitForSlotEvent)(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved) +{ + if (CK_FALSE == pkcs11_mock_initialized) + return CKR_CRYPTOKI_NOT_INITIALIZED; + + if ((0 != flags) && (CKF_DONT_BLOCK != flags)) + return CKR_ARGUMENTS_BAD; + + if (NULL == pSlot) + return CKR_ARGUMENTS_BAD; + + if (NULL != pReserved) + return CKR_ARGUMENTS_BAD; + + return CKR_NO_EVENT; +} + diff --git a/tests/pkcs11/pkcs11-mock.h b/tests/pkcs11/pkcs11-mock.h new file mode 100644 index 0000000..6764c02 --- /dev/null +++ b/tests/pkcs11/pkcs11-mock.h @@ -0,0 +1,99 @@ +/* + * Copyright 2011-2016 The Pkcs11Interop Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Written originally for the Pkcs11Interop project by: + * Jaroslav IMRICH <jimrich@jimrich.sk> + */ + +#define _POSIX_C_SOURCE 200809 +#include <config.h> +#include <stdio.h> +#include <string.h> + +// PKCS#11 related stuff +#define CK_PTR * +#define CK_DEFINE_FUNCTION(returnType, name) returnType name +#define CK_DECLARE_FUNCTION(returnType, name) returnType name +#define CK_DECLARE_FUNCTION_POINTER(returnType, name) returnType (* name) +#define CK_CALLBACK_FUNCTION(returnType, name) returnType (* name) + +#include <p11-kit/pkcs11.h> +#include <p11-kit/pkcs11x.h> + +#ifndef NULL_PTR +#define NULL_PTR 0 +#endif + +#define IGNORE(P) (void)(P) + +#define PKCS11_MOCK_CK_INFO_MANUFACTURER_ID "Pkcs11Interop Project" +#define PKCS11_MOCK_CK_INFO_LIBRARY_DESCRIPTION "Mock module" + +#define PKCS11_MOCK_CK_SLOT_ID 1 +#define PKCS11_MOCK_CK_SLOT_INFO_SLOT_DESCRIPTION "Mock slot" +#define PKCS11_MOCK_CK_SLOT_INFO_MANUFACTURER_ID "Pkcs11Interop Project" + +#define PKCS11_MOCK_CK_TOKEN_INFO_LABEL "Pkcs11Interop" +#define PKCS11_MOCK_CK_TOKEN_INFO_MANUFACTURER_ID "Pkcs11Interop Project" +#define PKCS11_MOCK_CK_TOKEN_INFO_MODEL "Mock token" +#define PKCS11_MOCK_CK_TOKEN_INFO_SERIAL_NUMBER "0123456789A" +#define PKCS11_MOCK_CK_TOKEN_INFO_MAX_PIN_LEN 256 +#define PKCS11_MOCK_CK_TOKEN_INFO_MIN_PIN_LEN 4 + +#define PKCS11_MOCK_CK_SESSION_ID 1 + +#define PKCS11_MOCK_CK_OBJECT_CKA_LABEL "Pkcs11Interop" +#define PKCS11_MOCK_CK_OBJECT_CKA_VALUE "Hello world!" +#define PKCS11_MOCK_CK_OBJECT_SIZE 256 +#define PKCS11_MOCK_CK_OBJECT_HANDLE_DATA 1 +#define PKCS11_MOCK_CK_OBJECT_HANDLE_SECRET_KEY 2 +#define PKCS11_MOCK_CK_OBJECT_HANDLE_PUBLIC_KEY 3 +#define PKCS11_MOCK_CK_OBJECT_HANDLE_PRIVATE_KEY 4 +#define PKCS11_MOCK_CK_OBJECT_HANDLE_CERTIFICATE_EXTENSION 5 +#define PKCS11_MOCK_CK_OBJECT_HANDLE_CERTIFICATE 6 + +typedef enum +{ + PKCS11_MOCK_CK_OPERATION_NONE, + PKCS11_MOCK_CK_OPERATION_FIND, + PKCS11_MOCK_CK_OPERATION_ENCRYPT, + PKCS11_MOCK_CK_OPERATION_DECRYPT, + PKCS11_MOCK_CK_OPERATION_DIGEST, + PKCS11_MOCK_CK_OPERATION_SIGN, + PKCS11_MOCK_CK_OPERATION_SIGN_RECOVER, + PKCS11_MOCK_CK_OPERATION_VERIFY, + PKCS11_MOCK_CK_OPERATION_VERIFY_RECOVER, + PKCS11_MOCK_CK_OPERATION_DIGEST_ENCRYPT, + PKCS11_MOCK_CK_OPERATION_DECRYPT_DIGEST, + PKCS11_MOCK_CK_OPERATION_SIGN_ENCRYPT, + PKCS11_MOCK_CK_OPERATION_DECRYPT_VERIFY +} +PKCS11_MOCK_CK_OPERATION; + +struct find_ptr_st { + int remaining_data; + PKCS11_MOCK_CK_OPERATION active_operation; + CK_OBJECT_HANDLE find_result; +}; + +typedef struct session_ptr_st { + char *find_label; + CK_ULONG state; + + struct find_ptr_st find_op; +} session_ptr_st; + diff --git a/tests/pkcs11/pkcs11-mock2.c b/tests/pkcs11/pkcs11-mock2.c new file mode 100644 index 0000000..44bf517 --- /dev/null +++ b/tests/pkcs11/pkcs11-mock2.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2019 Red Hat, Inc. + * + * Author: Daiki Ueno + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <dlfcn.h> +#include <p11-kit/pkcs11.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <assert.h> + +#include "softhsm.h" + +/* This provides a mock PKCS #11 module that delegates all the + * operations to SoftHSM except that it filters out CKM_RSA_PKCS_PSS + * mechanism. + */ + +static void *dl; +static CK_C_GetMechanismInfo base_C_GetMechanismInfo; +static CK_FUNCTION_LIST override_funcs; + +#ifdef __sun +# pragma fini(mock_deinit) +# pragma init(mock_init) +# define _CONSTRUCTOR +# define _DESTRUCTOR +#else +# define _CONSTRUCTOR __attribute__((constructor)) +# define _DESTRUCTOR __attribute__((destructor)) +#endif + +static CK_RV +override_C_GetMechanismInfo(CK_SLOT_ID slot_id, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO *info) +{ + if (type == CKM_RSA_PKCS_PSS) + return CKR_MECHANISM_INVALID; + + return base_C_GetMechanismInfo(slot_id, type, info); +} + +CK_RV +C_GetFunctionList(CK_FUNCTION_LIST **function_list) +{ + CK_C_GetFunctionList func; + CK_FUNCTION_LIST *funcs; + + assert(dl); + + func = dlsym(dl, "C_GetFunctionList"); + if (func == NULL) { + return CKR_GENERAL_ERROR; + } + + func(&funcs); + base_C_GetMechanismInfo = funcs->C_GetMechanismInfo; + + memcpy(&override_funcs, funcs, sizeof(CK_FUNCTION_LIST)); + override_funcs.C_GetMechanismInfo = override_C_GetMechanismInfo; + *function_list = &override_funcs; + + return CKR_OK; +} + +static _CONSTRUCTOR void +mock_init(void) +{ + const char *lib; + + /* suppress compiler warning */ + (void) set_softhsm_conf; + + lib = softhsm_lib(); + + dl = dlopen(lib, RTLD_NOW); + if (dl == NULL) + exit(77); +} + +static _DESTRUCTOR void +mock_deinit(void) +{ + dlclose(dl); +} diff --git a/tests/pkcs11/pkcs11-obj-import.c b/tests/pkcs11/pkcs11-obj-import.c new file mode 100644 index 0000000..17c75a7 --- /dev/null +++ b/tests/pkcs11/pkcs11-obj-import.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> + +#define CONFIG_NAME "softhsm-obj-import" +#define CONFIG CONFIG_NAME".config" + +#include "../utils.h" +#include "softhsm.h" + +/* Tests whether gnutls_pubkey_import_privkey works well for + * RSA keys under PKCS #11 */ + + +#include "../cert-common.h" + +#define PIN "1234" + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +void doit(void) +{ + static char buf[1024]; + int ret; + const char *lib, *bin; + gnutls_x509_crt_t crt; + gnutls_pkcs11_obj_t obj; + char *url; + gnutls_datum_t tmp, tmp2; + size_t buf_size; + + if (gnutls_fips140_mode_enabled()) + exit(77); + + bin = softhsm_bin(); + + lib = softhsm_lib(); + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin "PIN" --pin "PIN, bin); + system(buf); + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_crt_init(&crt); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_x509_crt_import(crt, &server_cert, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + if (debug) { + gnutls_x509_crt_print(crt, + GNUTLS_CRT_PRINT_ONELINE, + &tmp); + + printf("\tCertificate: %.*s\n", + tmp.size, tmp.data); + gnutls_free(tmp.data); + } + + /* initialize softhsm token */ + ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test"); + if (ret < 0) { + fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_token_set_pin(SOFTHSM_URL, NULL, PIN, GNUTLS_PIN_USER); + if (ret < 0) { + fail("gnutls_pkcs11_token_set_pin: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_copy_x509_crt(SOFTHSM_URL, crt, "cert", + GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE|GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_crt: %s\n", gnutls_strerror(ret)); + exit(1); + } + + gnutls_pkcs11_set_pin_function(NULL, NULL); + + assert(gnutls_pkcs11_obj_init(&obj) >= 0); + + ret = gnutls_pkcs11_obj_import_url(obj, SOFTHSM_URL";object=cert", 0); + if (ret < 0) { + fprintf(stderr, "error in %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + + assert(gnutls_pkcs11_obj_export_url(obj, GNUTLS_PKCS11_URL_GENERIC, &url) >= 0); + assert(url != NULL); + + gnutls_free(url); + + assert(gnutls_pkcs11_obj_export3(obj, GNUTLS_X509_FMT_DER, &tmp) >= 0); + assert(gnutls_x509_crt_export2(crt, GNUTLS_X509_FMT_DER, &tmp2) >= 0); + + assert(tmp2.size == tmp.size); + assert(memcmp(tmp.data, tmp2.data, tmp.size) == 0); + gnutls_free(tmp2.data); + + /* check gnutls_pkcs11_obj_export */ + buf_size = 4; + assert(gnutls_pkcs11_obj_export(obj, buf, &buf_size) == GNUTLS_E_SHORT_MEMORY_BUFFER); + + buf_size = sizeof(buf); + assert(gnutls_pkcs11_obj_export(obj, buf, &buf_size)>=0); + assert(buf_size == tmp.size); + assert(memcmp(buf, tmp.data, tmp.size) == 0); + + gnutls_free(tmp.data); + + /* The ID is constant and copied from the certificate */ + buf_size = sizeof(buf); + assert(gnutls_pkcs11_obj_get_info(obj, GNUTLS_PKCS11_OBJ_ID_HEX, buf, &buf_size) >= 0); + assert(buf_size == 60); + assert(memcmp(buf, "95:d1:ad:a4:52:e4:c5:61:12:a6:91:13:8d:80:dd:2d:81:22:3e:d4", 60) == 0); + + /* label */ + buf_size = sizeof(buf); + assert(gnutls_pkcs11_obj_get_info(obj, GNUTLS_PKCS11_OBJ_LABEL, buf, &buf_size) >= 0); + assert(buf_size == 4); + assert(memcmp(buf, "cert", 4) == 0); + + /* token-label */ + buf_size = sizeof(buf); + assert(gnutls_pkcs11_obj_get_info(obj, GNUTLS_PKCS11_OBJ_TOKEN_LABEL, buf, &buf_size) >= 0); + assert(buf_size == 4); + assert(memcmp(buf, "test", 4) == 0); + + /* token-serial */ + buf_size = sizeof(buf); + assert(gnutls_pkcs11_obj_get_info(obj, GNUTLS_PKCS11_OBJ_TOKEN_SERIAL, buf, &buf_size) >= 0); + assert(buf_size != 0); + assert(strlen(buf) != 0); + + /* token-model */ + buf_size = sizeof(buf); + assert(gnutls_pkcs11_obj_get_info(obj, GNUTLS_PKCS11_OBJ_TOKEN_MODEL, buf, &buf_size) >= 0); + assert(buf_size != 0); + assert(strlen(buf) != 0); + + /* token-manufacturer */ + buf_size = sizeof(buf); + assert(gnutls_pkcs11_obj_get_info(obj, GNUTLS_PKCS11_OBJ_TOKEN_MANUFACTURER, buf, &buf_size) >= 0); + assert(buf_size != 0); + assert(strlen(buf) != 0); + + /* token-ID */ + buf_size = sizeof(buf); + assert(gnutls_pkcs11_obj_get_info(obj, GNUTLS_PKCS11_OBJ_ID, buf, &buf_size) >= 0); + assert(buf_size != 0); + + /* library description */ + buf_size = sizeof(buf); + assert(gnutls_pkcs11_obj_get_info(obj, GNUTLS_PKCS11_OBJ_LIBRARY_DESCRIPTION, buf, &buf_size) >= 0); + assert(buf_size != 0); + assert(strlen(buf) != 0); + + /* library manufacturer */ + buf_size = sizeof(buf); + assert(gnutls_pkcs11_obj_get_info(obj, GNUTLS_PKCS11_OBJ_LIBRARY_MANUFACTURER, buf, &buf_size) >= 0); + assert(buf_size != 0); + assert(strlen(buf) != 0); + + /* library version */ + buf_size = sizeof(buf); + assert(gnutls_pkcs11_obj_get_info(obj, GNUTLS_PKCS11_OBJ_LIBRARY_VERSION, buf, &buf_size) >= 0); + assert(buf_size != 0); + assert(strlen(buf) != 0); + + gnutls_pkcs11_obj_deinit(obj); + gnutls_x509_crt_deinit(crt); + + gnutls_global_deinit(); + + remove(CONFIG); +} + diff --git a/tests/pkcs11/pkcs11-obj-raw.c b/tests/pkcs11/pkcs11-obj-raw.c new file mode 100644 index 0000000..a955272 --- /dev/null +++ b/tests/pkcs11/pkcs11-obj-raw.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2016-2018 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <gnutls/gnutls.h> +#include <gnutls/pkcs11.h> +#ifndef CRYPTOKI_GNU +# define CRYPTOKI_GNU +#endif +#include <p11-kit/pkcs11.h> + +#include "utils.h" + +/* Tests whether a gnutls_pkcs11_obj_get_ptr returns valid handles. */ + +#if defined(HAVE___REGISTER_ATFORK) + +#ifdef _WIN32 +# define P11LIB "libpkcs11mock1.dll" +#else +# include <dlfcn.h> +# define P11LIB "libpkcs11mock1.so" +#endif + + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +#define PIN "1234" + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +void doit(void) +{ + int ret; + const char *lib; + unsigned long slot_id; + unsigned char sig[256]; + unsigned long len; + struct ck_function_list *mod; + struct ck_info info; + struct ck_token_info tinfo; + ck_session_handle_t session; + ck_object_handle_t ohandle; + gnutls_pkcs11_obj_t obj; + struct ck_mechanism mech; + ck_rv_t rv; + gnutls_datum_t data; + + data.data = (void*)"\x38\x17\x0c\x08\xcb\x45\x8f\xd4\x87\x9c\x34\xb6\xf6\x08\x29\x4c\x50\x31\x2b\xbb"; + data.size = 20; + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + lib = getenv("P11MOCKLIB1"); + if (lib == NULL) + lib = P11LIB; + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + assert(gnutls_pkcs11_obj_init(&obj)>=0); + + gnutls_pkcs11_obj_set_pin_function(obj, pin_func, NULL); + + /* unknown object */ + ret = gnutls_pkcs11_obj_import_url(obj, "pkcs11:token=unknown;object=invalid;type=private", GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + assert(ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + + ret = gnutls_pkcs11_obj_import_url(obj, "pkcs11:object=test;type=private", GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + assert(ret >= 0); + + ret = gnutls_pkcs11_obj_get_ptr(obj, (void**)&mod, (void*)&session, + (void*)&ohandle, + &slot_id, GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_pkcs11_obj_deinit(obj); + + rv = mod->C_GetInfo(&info); + if (rv != CKR_OK) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + assert(info.cryptoki_version.major == 0x02); + assert(info.cryptoki_version.minor == 0x14); + assert(info.flags == 0); + assert(info.library_version.major == 0x01); + assert(info.library_version.minor == 0x00); + + rv = mod->C_GetTokenInfo(slot_id, &tinfo); + if (rv != CKR_OK) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + assert(tinfo.hardware_version.major == 0x01); + assert(tinfo.firmware_version.major == 0x01); + + mech.mechanism = CKM_RSA_PKCS; + mech.parameter = NULL; + mech.parameter_len = 0; + + rv = mod->C_SignInit(session, &mech, ohandle); + if (rv != CKR_OK) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + len = sizeof(sig); + rv = mod->C_Sign(session, data.data, data.size, sig, &len); + if (rv != CKR_OK) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + mod->C_CloseSession(session); + + gnutls_pkcs11_deinit(); + gnutls_global_deinit(); +} +#else +void doit(void) +{ + exit(77); +} +#endif diff --git a/tests/pkcs11/pkcs11-pin-func.c b/tests/pkcs11/pkcs11-pin-func.c new file mode 100644 index 0000000..b6d707e --- /dev/null +++ b/tests/pkcs11/pkcs11-pin-func.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2017 Nikos Mavrogiannopoulos + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <assert.h> +#include <gnutls/gnutls.h> +#include <gnutls/pkcs11.h> + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, "xxx"); + return 0; + } + return -1; +} + +int main(int argc, char **argv) +{ + void *u; + gnutls_pin_callback_t cb; + + gnutls_pkcs11_set_pin_function(pin_func, (void*)-1); + + cb = gnutls_pkcs11_get_pin_function(&u); + + assert(u==(void*)-1); + assert(cb == pin_func); + + return 0; +} diff --git a/tests/pkcs11/pkcs11-privkey-always-auth.c b/tests/pkcs11/pkcs11-privkey-always-auth.c new file mode 100644 index 0000000..441f637 --- /dev/null +++ b/tests/pkcs11/pkcs11-privkey-always-auth.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> +#include <gnutls/pkcs11.h> + +#ifdef _WIN32 + +void doit(void) +{ + exit(77); +} + +#else + +# include "utils.h" +# include "pkcs11-mock-ext.h" + +/* Tests whether a gnutls_privkey_t will work properly with a key marked + * as always authenticate */ + +static unsigned pin_called = 0; +static const char *_pin = "1234"; + +# include <dlfcn.h> +# define P11LIB "libpkcs11mock1.so" + + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (_pin == NULL) + return -1; + + strcpy(pin, _pin); + pin_called++; + return 0; +} + +void doit(void) +{ + int ret; + const char *lib; + gnutls_privkey_t key; + gnutls_pkcs11_obj_t obj; + gnutls_datum_t sig = {NULL, 0}, data; + unsigned flags = 0; + + lib = getenv("P11MOCKLIB1"); + if (lib == NULL) + lib = P11LIB; + + { + void *dl; + unsigned int *pflags; + + dl = dlopen(lib, RTLD_NOW); + if (dl == NULL) { + fail("could not dlopen %s\n", lib); + exit(1); + } + + pflags = dlsym(dl, "pkcs11_mock_flags"); + if (pflags == NULL) { + fail("could find pkcs11_mock_flags\n"); + exit(1); + } + + *pflags = MOCK_FLAG_ALWAYS_AUTH; + } + + data.data = (void*)"\x38\x17\x0c\x08\xcb\x45\x8f\xd4\x87\x9c\x34\xb6\xf6\x08\x29\x4c\x50\x31\x2b\xbb"; + data.size = 20; + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_obj_init(&obj); + assert(ret>=0); + + gnutls_pkcs11_obj_set_pin_function(obj, pin_func, NULL); + + ret = gnutls_pkcs11_obj_import_url(obj, "pkcs11:object=test;type=private", GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + assert(ret>=0); + + ret = gnutls_pkcs11_obj_get_flags(obj, &flags); + assert(ret>=0); + + if (!(flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_ALWAYS_AUTH)) { + fail("key object doesn't have the always authenticate flag\n"); + } + gnutls_pkcs11_obj_deinit(obj); + + + ret = gnutls_privkey_init(&key); + assert(ret>=0); + + gnutls_privkey_set_pin_function(key, pin_func, NULL); + + ret = gnutls_privkey_import_url(key, "pkcs11:object=test", GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + pin_called = 0; + + ret = gnutls_privkey_sign_hash(key, GNUTLS_DIG_SHA1, 0, &data, &sig); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + if (pin_called == 0) { + fail("PIN function wasn't called!\n"); + } + pin_called = 0; + + gnutls_free(sig.data); + + /* call again - should re-authenticate */ + ret = gnutls_privkey_sign_hash(key, GNUTLS_DIG_SHA1, 0, &data, &sig); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + if (pin_called == 0) { + fail("PIN function wasn't called twice!\n"); + } + pin_called = 0; + + gnutls_free(sig.data); + + if (debug) + printf("done\n\n\n"); + + gnutls_privkey_deinit(key); + gnutls_pkcs11_deinit(); + gnutls_global_deinit(); +} +#endif diff --git a/tests/pkcs11/pkcs11-privkey-export.c b/tests/pkcs11/pkcs11-privkey-export.c new file mode 100644 index 0000000..ce22ea7 --- /dev/null +++ b/tests/pkcs11/pkcs11-privkey-export.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> + +#include "utils.h" + +/* This checks whether the public parts of RSA private and public keys + * can be properly extracted from a PKCS#11 module. */ + +#define PIN "1234" +#ifdef _WIN32 +# define P11LIB "libpkcs11mock1.dll" +#else +# include <dlfcn.h> +# define P11LIB "libpkcs11mock1.so" +#endif + + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +void doit(void) +{ + int ret; + const char *lib; + gnutls_privkey_t key; + gnutls_pubkey_t pub; + gnutls_datum_t m1, e1; + gnutls_datum_t m2, e2; + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + lib = getenv("P11MOCKLIB1"); + if (lib == NULL) + lib = P11LIB; + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_privkey_init(&key); + assert(ret>=0); + ret = gnutls_pubkey_init(&pub); + assert(ret>=0); + + gnutls_privkey_set_pin_function(key, pin_func, NULL); + + ret = gnutls_privkey_import_url(key, "pkcs11:object=test", GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pubkey_import_privkey(pub, key, 0, 0); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pubkey_export_rsa_raw(pub, &m1, &e1); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_pubkey_deinit(pub); + gnutls_privkey_deinit(key); + + /* try again using gnutls_pubkey_import_url */ + ret = gnutls_pubkey_init(&pub); + assert(ret>=0); + + ret = gnutls_pubkey_import_url(pub, "pkcs11:object=test;type=public", 0); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pubkey_export_rsa_raw(pub, &m2, &e2); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + assert(m1.size == m2.size); + assert(e1.size == e2.size); + assert(memcmp(e1.data, e2.data, e2.size)==0); + assert(memcmp(m1.data, m2.data, m2.size)==0); + + gnutls_pubkey_deinit(pub); + gnutls_free(m1.data); + gnutls_free(e1.data); + gnutls_free(m2.data); + gnutls_free(e2.data); + gnutls_pkcs11_deinit(); + gnutls_global_deinit(); +} diff --git a/tests/pkcs11/pkcs11-privkey-fork-reinit.c b/tests/pkcs11/pkcs11-privkey-fork-reinit.c new file mode 100644 index 0000000..a725842 --- /dev/null +++ b/tests/pkcs11/pkcs11-privkey-fork-reinit.c @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2016-2017 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> + +#include "utils.h" + +/* Tests whether a gnutls_privkey_t will continue to work after + * a fork(), when gnutls_pkcs11_reinit() is manually called. */ + +#if defined(HAVE___REGISTER_ATFORK) + +#define PIN "1234" +#ifdef _WIN32 +# define P11LIB "libpkcs11mock1.dll" +#else +# include <dlfcn.h> +# define P11LIB "libpkcs11mock1.so" +#endif + + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +void doit(void) +{ + int ret; + const char *lib; + gnutls_privkey_t key; + gnutls_datum_t sig = {NULL, 0}, data; + pid_t pid; + + data.data = (void*)"\x38\x17\x0c\x08\xcb\x45\x8f\xd4\x87\x9c\x34\xb6\xf6\x08\x29\x4c\x50\x31\x2b\xbb"; + data.size = 20; + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + lib = getenv("P11MOCKLIB1"); + if (lib == NULL) + lib = P11LIB; + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_privkey_init(&key); + assert(ret>=0); + + gnutls_privkey_set_pin_function(key, pin_func, NULL); + + ret = gnutls_privkey_import_url(key, "pkcs11:object=test", GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_privkey_sign_hash(key, GNUTLS_DIG_SHA1, 0, &data, &sig); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_free(sig.data); + + pid = fork(); + if (pid != 0) { + int status; + assert(waitpid(pid, &status, 0) >= 0); + + if (WEXITSTATUS(status) != 0) { + fail("child return status was unexpected: %d\n", WEXITSTATUS(status)); + exit(1); + } + } else { /* child */ + + ret = gnutls_pkcs11_reinit(); + assert(ret == 0); + + ret = gnutls_privkey_sign_hash(key, GNUTLS_DIG_SHA1, 0, &data, &sig); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_free(sig.data); + gnutls_privkey_deinit(key); + gnutls_pkcs11_deinit(); + gnutls_global_deinit(); + exit(0); + } + + if (debug) + printf("done\n\n\n"); + + gnutls_privkey_deinit(key); + gnutls_pkcs11_deinit(); + gnutls_global_deinit(); +} +#else +void doit(void) +{ + exit(77); +} +#endif diff --git a/tests/pkcs11/pkcs11-privkey-fork.c b/tests/pkcs11/pkcs11-privkey-fork.c new file mode 100644 index 0000000..b99755c --- /dev/null +++ b/tests/pkcs11/pkcs11-privkey-fork.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> + +#include "utils.h" + +/* Tests whether a gnutls_privkey_t will continue to work after + * a fork(). */ + +#if defined(HAVE___REGISTER_ATFORK) + +#define PIN "1234" +#ifdef _WIN32 +# define P11LIB "libpkcs11mock1.dll" +#else +# include <dlfcn.h> +# define P11LIB "libpkcs11mock1.so" +#endif + + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +void doit(void) +{ + int ret; + const char *lib; + gnutls_privkey_t key; + gnutls_datum_t sig = {NULL, 0}, data; + pid_t pid; + + data.data = (void*)"\x38\x17\x0c\x08\xcb\x45\x8f\xd4\x87\x9c\x34\xb6\xf6\x08\x29\x4c\x50\x31\x2b\xbb"; + data.size = 20; + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + lib = getenv("P11MOCKLIB1"); + if (lib == NULL) + lib = P11LIB; + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_privkey_init(&key); + assert(ret>=0); + + gnutls_privkey_set_pin_function(key, pin_func, NULL); + + ret = gnutls_privkey_import_url(key, "pkcs11:object=test", GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_privkey_sign_hash(key, GNUTLS_DIG_SHA1, 0, &data, &sig); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_free(sig.data); + + pid = fork(); + if (pid != 0) { + int status; + assert(waitpid(pid, &status, 0) >= 0); + + if (WEXITSTATUS(status) != 0) { + fail("child return status was unexpected: %d\n", WEXITSTATUS(status)); + exit(1); + } + } else { /* child */ + ret = gnutls_privkey_sign_hash(key, GNUTLS_DIG_SHA1, 0, &data, &sig); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_free(sig.data); + gnutls_privkey_deinit(key); + gnutls_pkcs11_deinit(); + gnutls_global_deinit(); + exit(0); + } + + if (debug) + printf("done\n\n\n"); + + gnutls_privkey_deinit(key); + gnutls_pkcs11_deinit(); + gnutls_global_deinit(); +} +#else +void doit(void) +{ + exit(77); +} +#endif diff --git a/tests/pkcs11/pkcs11-privkey-generate.c b/tests/pkcs11/pkcs11-privkey-generate.c new file mode 100644 index 0000000..102cf4b --- /dev/null +++ b/tests/pkcs11/pkcs11-privkey-generate.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2018 Nikos Mavrogiannopoulos + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> +#include <gnutls/pkcs11.h> + +#ifdef _WIN32 + +void doit(void) +{ + exit(77); +} + +#else + +#include "../utils.h" +#include "softhsm.h" +#include <assert.h> + +#define CONFIG_NAME "softhsm-generate" +#define CONFIG CONFIG_NAME".config" +#define PIN "1234" +/* Tests whether a gnutls_privkey_generate3 will work generate a key + * which is marked as sensitive. + */ + +static unsigned pin_called = 0; +static const char *_pin = PIN; + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (_pin == NULL) + return -1; + + strcpy(pin, _pin); + pin_called++; + return 0; +} + +void doit(void) +{ + char buf[128]; + int ret; + const char *lib, *bin; + gnutls_datum_t out; + unsigned flags; + gnutls_pkcs11_obj_t obj; + + if (gnutls_fips140_mode_enabled()) + exit(77); + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + bin = softhsm_bin(); + + lib = softhsm_lib(); + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin "PIN" --pin "PIN, bin); + system(buf); + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + + /* generate sensitive */ + ret = gnutls_pkcs11_privkey_generate3("pkcs11:token=test", GNUTLS_PK_RSA, 2048, + "testkey", NULL, GNUTLS_X509_FMT_DER, + &out, 0, GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + assert(gnutls_pkcs11_obj_init(&obj) >= 0); + assert(out.size > 0); + + gnutls_pkcs11_obj_set_pin_function(obj, pin_func, NULL); + assert(gnutls_pkcs11_obj_import_url(obj, "pkcs11:token=test;object=testkey;type=private", GNUTLS_PKCS11_OBJ_FLAG_LOGIN) >= 0); + + assert(gnutls_pkcs11_obj_get_flags(obj, &flags) >= 0); + + assert(!(flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_SENSITIVE)); + assert(flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE); + + gnutls_free(out.data); + gnutls_pkcs11_obj_deinit(obj); + + /* generate non-sensitive */ + ret = gnutls_pkcs11_privkey_generate3("pkcs11:token=test", GNUTLS_PK_RSA, 2048, + "testkey2", NULL, GNUTLS_X509_FMT_DER, + &out, 0, GNUTLS_PKCS11_OBJ_FLAG_LOGIN|GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_SENSITIVE); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + assert(gnutls_pkcs11_obj_init(&obj) >= 0); + assert(out.size > 0); + + gnutls_pkcs11_obj_set_pin_function(obj, pin_func, NULL); + assert(gnutls_pkcs11_obj_import_url(obj, "pkcs11:token=test;object=testkey2;type=private", GNUTLS_PKCS11_OBJ_FLAG_LOGIN) >= 0); + + assert(gnutls_pkcs11_obj_get_flags(obj, &flags) >= 0); + + assert(!(flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE)); + assert(flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_SENSITIVE); + + gnutls_free(out.data); + gnutls_pkcs11_obj_deinit(obj); + + gnutls_pkcs11_deinit(); + gnutls_global_deinit(); + remove(CONFIG); +} +#endif diff --git a/tests/pkcs11/pkcs11-privkey-pthread.c b/tests/pkcs11/pkcs11-privkey-pthread.c new file mode 100644 index 0000000..8b23759 --- /dev/null +++ b/tests/pkcs11/pkcs11-privkey-pthread.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <gnutls/gnutls.h> +#include <gnutls/abstract.h> +#include <gnutls/crypto.h> +#include <signal.h> +#include <unistd.h> +#include <assert.h> +#ifndef _WIN32 +# include <netinet/in.h> +# include <sys/types.h> +# include <sys/socket.h> +# include <sys/wait.h> +# include <pthread.h> +#endif +#include "utils.h" + +#if !defined(HAVE___REGISTER_ATFORK) + +void doit(void) +{ + exit(77); +} + +#else + +#ifdef _WIN32 +# define P11LIB "libpkcs11mock1.dll" +#else +# include <dlfcn.h> +# define P11LIB "libpkcs11mock1.so" +#endif + +/* Tests whether we can use gnutls_privkey_sign() under multiple threads + * with the same key when PKCS#11 is in use. + */ + +#include "../cert-common.h" + +#define PIN "1234" + +static const gnutls_datum_t testdata = {(void*)"test test", 9}; + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +typedef struct thread_data_st { + gnutls_privkey_t pkey; + pthread_t id; +} thread_data_st; + +static void *start_thread(void *arg) +{ + thread_data_st *data = arg; + int ret; + gnutls_datum_t sig; + + ret = gnutls_privkey_sign_data(data->pkey, GNUTLS_DIG_SHA256, 0, &testdata, &sig); + if (ret < 0) + pthread_exit((void*)-2); + + gnutls_free(sig.data); + + pthread_exit(0); +} + +#define MAX_THREADS 48 + +static +void do_thread_stuff(gnutls_privkey_t pkey) +{ + int ret; + thread_data_st *data; + unsigned i; + void *retval; + + data = calloc(1, sizeof(thread_data_st)*MAX_THREADS); + if (data == NULL) + abort(); + + for (i=0;i<MAX_THREADS;i++) { + data[i].pkey = pkey; + ret = pthread_create(&data[i].id, NULL, start_thread, &data[i]); + if (ret != 0) { + fail("Error creating thread\n"); + } + } + + for (i=0;i<MAX_THREADS;i++) { + ret = pthread_join(data[i].id, &retval); + if (ret != 0 || retval != NULL) { + fail("Error in %d: %p\n", (int)data[i].id, retval); + } + } + free(data); + +} + +void doit(void) +{ + int ret, status; + const char *lib; + gnutls_privkey_t pkey; + pid_t pid; + + signal(SIGPIPE, SIG_IGN); + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + lib = getenv("P11MOCKLIB1"); + if (lib == NULL) + lib = P11LIB; + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + assert(gnutls_privkey_init(&pkey) == 0); + + ret = gnutls_privkey_import_url(pkey, "pkcs11:object=test", GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fprintf(stderr, "error in %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + + /* fork to force PKCS#11 reinitialization */ + pid = fork(); + if (pid == -1) { + exit(1); + } else if (pid) { + waitpid(pid, &status, 0); + check_wait_status(status); + goto cleanup; + } + + do_thread_stuff(pkey); + + cleanup: + gnutls_privkey_deinit(pkey); +} + +#endif diff --git a/tests/pkcs11/pkcs11-privkey-safenet-always-auth.c b/tests/pkcs11/pkcs11-privkey-safenet-always-auth.c new file mode 100644 index 0000000..a4ab5b5 --- /dev/null +++ b/tests/pkcs11/pkcs11-privkey-safenet-always-auth.c @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2017 Nikos Mavrogiannopoulos + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> +#include <gnutls/pkcs11.h> + +#ifdef _WIN32 + +void doit(void) +{ + exit(77); +} + +#else + +# include "utils.h" +# include "pkcs11-mock-ext.h" + +/* Tests whether a gnutls_privkey_t will work properly with a key marked + * as always authenticate, but on the safenet HSMs where CKA_ALWAYS_AUTHENTICATE + * is not supported */ + +static unsigned pin_called = 0; +static const char *_pin = "1234"; + +# include <dlfcn.h> +# define P11LIB "libpkcs11mock1.so" + + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (_pin == NULL) + return -1; + + strcpy(pin, _pin); + pin_called++; + return 0; +} + +void doit(void) +{ + int ret; + const char *lib; + gnutls_privkey_t key; + gnutls_datum_t sig = {NULL, 0}, data; + + lib = getenv("P11MOCKLIB1"); + if (lib == NULL) + lib = P11LIB; + + { + void *dl; + unsigned int *pflags; + + dl = dlopen(lib, RTLD_NOW); + if (dl == NULL) { + fail("could not dlopen %s\n", lib); + exit(1); + } + + pflags = dlsym(dl, "pkcs11_mock_flags"); + if (pflags == NULL) { + fail("could find pkcs11_mock_flags\n"); + exit(1); + } + + *pflags = MOCK_FLAG_SAFENET_ALWAYS_AUTH; + } + + data.data = (void*)"\x38\x17\x0c\x08\xcb\x45\x8f\xd4\x87\x9c\x34\xb6\xf6\x08\x29\x4c\x50\x31\x2b\xbb"; + data.size = 20; + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_privkey_init(&key); + assert(ret>=0); + + gnutls_privkey_set_pin_function(key, pin_func, NULL); + + ret = gnutls_privkey_import_url(key, "pkcs11:object=test", GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + pin_called = 0; + + ret = gnutls_privkey_sign_hash(key, GNUTLS_DIG_SHA1, 0, &data, &sig); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + if (pin_called == 0) { + fail("PIN function wasn't called!\n"); + } + pin_called = 0; + + gnutls_free(sig.data); + + /* call again - should re-authenticate */ + ret = gnutls_privkey_sign_hash(key, GNUTLS_DIG_SHA1, 0, &data, &sig); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + if (pin_called == 0) { + fail("PIN function wasn't called twice!\n"); + } + pin_called = 0; + + gnutls_free(sig.data); + + if (debug) + printf("done\n\n\n"); + + gnutls_privkey_deinit(key); + gnutls_pkcs11_deinit(); + gnutls_global_deinit(); +} +#endif diff --git a/tests/pkcs11/pkcs11-privkey.c b/tests/pkcs11/pkcs11-privkey.c new file mode 100644 index 0000000..a4217d4 --- /dev/null +++ b/tests/pkcs11/pkcs11-privkey.c @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2014 Nikos Mavrogiannopoulos + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/x509-ext.h> + +#include "../utils.h" +#include "softhsm.h" + +/* Tests whether gnutls_certificate_set_x509_key_file2() will utilize + * the provided password as PIN when PKCS #11 keys are imported */ + +#define CONFIG_NAME "softhsm-privkey" +#define CONFIG CONFIG_NAME".config" + +static unsigned char server_cert_pem[] = +"-----BEGIN CERTIFICATE-----\n" +"MIICdDCCAd2gAwIBAgIBAzANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQDEwJDQTEL\n" +"MAkGA1UEBhMCQ1owIhgPMjAxMzExMTAwODI1MjdaGA8yMDIwMTIxMzA4MjUyN1ow\n" +"HjEPMA0GA1UEAxMGQ2xpZW50MQswCQYDVQQGEwJDWjCBnzANBgkqhkiG9w0BAQEF\n" +"AAOBjQAwgYkCgYEAvQRIzvKyhr3tqmB4Pe+91DWSFayaNtcrDIT597bhxugVYW8o\n" +"jB206kx5aknAMA3PQGYcGqkLrt+nsJcmOIXDZsC6P4zeOSsF1PPhDAoX3bkUr2lF\n" +"MEt374eKdg1yvyhRxt4DOR6aD4gkC7fVtaYdgV6yXpJGMHV05LBIgQ7QtykCAwEA\n" +"AaOBwTCBvjAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMBgGA1Ud\n" +"EQQRMA+BDW5vbmVAbm9uZS5vcmcwDwYDVR0PAQH/BAUDAweAADAdBgNVHQ4EFgQU\n" +"Dbinh11GaaJcTyOpmxPYuttsiGowHwYDVR0jBBgwFoAUEg7aURJAVq70HG3MobA9\n" +"KGF+MwEwLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDovL3d3dy5nZXRjcmwuY3JsL2dl\n" +"dGNybC8wDQYJKoZIhvcNAQELBQADgYEAN/Henso+5zzuFQWTpJXlUsWtRQAFhRY3\n" +"WVt3xtnyPs4pF/LKBp3Ov0GLGBkz5YlyJGFNESSyUviMsH7g7rJM8i7Bph6BQTE9\n" +"XdqbZPc0opfms4EHjmlXj5HQ0f0yoxHnLk43CR+vmbn0JPuurnEKAwjznAJR8GxI\n" +"R2MRyMxdGqs=\n" +"-----END CERTIFICATE-----\n"; + +const gnutls_datum_t server_cert = { server_cert_pem, + sizeof(server_cert_pem) +}; + +static unsigned char server_key_pem[] = +"-----BEGIN RSA PRIVATE KEY-----\n" +"MIICXQIBAAKBgQC9BEjO8rKGve2qYHg9773UNZIVrJo21ysMhPn3tuHG6BVhbyiM\n" +"HbTqTHlqScAwDc9AZhwaqQuu36ewlyY4hcNmwLo/jN45KwXU8+EMChfduRSvaUUw\n" +"S3fvh4p2DXK/KFHG3gM5HpoPiCQLt9W1ph2BXrJekkYwdXTksEiBDtC3KQIDAQAB\n" +"AoGBAKXrseIAB5jh9lPeNQ7heXhjwiXGiuTjAkYOIMNDRXPuXH5YLna4yQv3L4mO\n" +"zecg6DI2sCrzA29xoukP9ZweR4RUK2cS4/QggH9UgWP0QUpvj4nogyRkh7UrWyVV\n" +"xbboHcmgqWgNLR8GrEZqlpOWFiT+f+QAx783/khvP5QLNp6BAkEA3YvvqfPpepdv\n" +"UC/Uk/8LbVK0LGTSu2ynyl1fMbos9lkJNFdfPM31K6DHeqziIGSoWCSjAsN/e8V7\n" +"MU7egWtI+QJBANppSlO+PTYHWKeOWE7NkM1yVHxAiav9Oott0JywAH8RarfyTuCB\n" +"iyMJP8Rv920GsciDY4dyx0MBJF0tiH+5G7ECQQDQbU5UPbxyMPXwIo+DjHZbq2sG\n" +"OPRoj5hrsdxVFCoouSsHqwtWUQ1Otjv1FaDHiOs3wX/6oaHV97wmb2S1rRFBAkAq\n" +"prELFXVinaCkZ9m62c3TMOZqtTetTHAoVjOMxZnzNnV+omTg1qtTFjVLqQnKUqpZ\n" +"G79N7g4XeZueTov/VSihAkAwGeDXvQ8NlrBlZACCKp1sUqaJptuJ438Qwztbl3Pq\n" +"E6/8TD5yXtrLt9S2LNAFw1i7LVksUB8IbQNTuuwV7LYI\n" +"-----END RSA PRIVATE KEY-----\n"; + +const gnutls_datum_t server_key = { server_key_pem, + sizeof(server_key_pem) +}; + + +/* GnuTLS internally calls time() to find out the current time when + verifying certificates. To avoid a time bomb, we hard code the + current time. This should work fine on systems where the library + call to time is resolved at run-time. */ +static time_t mytime(time_t * t) +{ + time_t then = 1412850586; + + if (t) + *t = then; + + return then; +} + +#define PIN "1234" + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +void doit(void) +{ + char buf[128]; + int exit_val = 0; + int ret; + const char *lib, *bin; + gnutls_x509_crt_t crt; + gnutls_x509_privkey_t key; + gnutls_certificate_credentials_t cred; + gnutls_datum_t tmp; + + if (gnutls_fips140_mode_enabled()) + exit(77); + + /* The overloading of time() seems to work in linux (ELF?) + * systems only. Disable it on windows. + */ +#ifdef _WIN32 + exit(77); +#endif + bin = softhsm_bin(); + + lib = softhsm_lib(); + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + gnutls_global_set_time_function(mytime); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin "PIN" --pin "PIN, bin); + system(buf); + + ret = gnutls_pkcs11_add_provider(lib, "trusted"); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_crt_init(&crt); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_x509_crt_import(crt, &server_cert, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + if (debug) { + gnutls_x509_crt_print(crt, + GNUTLS_CRT_PRINT_ONELINE, + &tmp); + + printf("\tCertificate: %.*s\n", + tmp.size, tmp.data); + gnutls_free(tmp.data); + } + + ret = gnutls_x509_privkey_init(&key); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_privkey_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_x509_privkey_import(key, &server_key, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_privkey_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + /* initialize softhsm token */ + ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test"); + if (ret < 0) { + fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_token_set_pin(SOFTHSM_URL, NULL, PIN, GNUTLS_PIN_USER); + if (ret < 0) { + fail("gnutls_pkcs11_token_set_pin: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_copy_x509_crt(SOFTHSM_URL, crt, "cert", + GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE|GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_crt: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_copy_x509_privkey(SOFTHSM_URL, key, "cert", GNUTLS_KEY_DIGITAL_SIGNATURE|GNUTLS_KEY_KEY_ENCIPHERMENT, + GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE|GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE|GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_privkey: %s\n", gnutls_strerror(ret)); + exit(1); + } + + gnutls_x509_crt_deinit(crt); + gnutls_x509_privkey_deinit(key); + gnutls_pkcs11_set_pin_function(NULL, NULL); + + /* Test whether gnutls_certificate_set_x509_key_file2() would import the keys + * when the PIN is provided as parameter */ + + ret = gnutls_certificate_allocate_credentials(&cred); + if (ret < 0) { + fail("gnutls_certificate_allocate_credentials: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_certificate_set_x509_key_file2(cred, SOFTHSM_URL";object=cert;object-type=cert", SOFTHSM_URL";object=cert;object-type=private", 0, PIN, 0); + if (ret < 0) { + fail("gnutls_certificate_set_x509_key_file2: %s\n", gnutls_strerror(ret)); + exit(1); + } + + gnutls_certificate_free_credentials(cred); + + gnutls_global_deinit(); + + if (debug) + printf("Exit status...%d\n", exit_val); + remove(CONFIG); + + exit(exit_val); +} diff --git a/tests/pkcs11/pkcs11-pubkey-import-ecdsa.c b/tests/pkcs11/pkcs11-pubkey-import-ecdsa.c new file mode 100644 index 0000000..6ee42e8 --- /dev/null +++ b/tests/pkcs11/pkcs11-pubkey-import-ecdsa.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 Nikos Mavrogiannopoulos + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "softhsm.h" + +#define CONFIG_NAME "softhsm-pubkey-import-ecdsa" +#define CONFIG CONFIG_NAME".config" + +#include "pkcs11-pubkey-import.c" + +void doit(void) +{ +#ifdef SOFTHSM_V1 + exit(77); +#else + success("Testing ECDSA key\n"); + return try(0); +#endif +} diff --git a/tests/pkcs11/pkcs11-pubkey-import-rsa.c b/tests/pkcs11/pkcs11-pubkey-import-rsa.c new file mode 100644 index 0000000..f0d64ab --- /dev/null +++ b/tests/pkcs11/pkcs11-pubkey-import-rsa.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015 Nikos Mavrogiannopoulos + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define CONFIG_NAME "softhsm-pubkey-import-rsa" +#define CONFIG CONFIG_NAME".config" + +#include "pkcs11-pubkey-import.c" + +void doit(void) +{ + success("Testing RSA key\n"); + return try(1); +} diff --git a/tests/pkcs11/pkcs11-pubkey-import.c b/tests/pkcs11/pkcs11-pubkey-import.c new file mode 100644 index 0000000..57d0d59 --- /dev/null +++ b/tests/pkcs11/pkcs11-pubkey-import.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2015 Nikos Mavrogiannopoulos + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> + +#include "../utils.h" +#include "softhsm.h" + +/* Tests whether gnutls_pubkey_import_privkey works well for + * RSA keys under PKCS #11 */ + + +#include "../cert-common.h" + +#define PIN "1234" + +static const gnutls_datum_t testdata = {(void*)"test test", 9}; + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +static void try(int rsa) +{ + char buf[128]; + int ret, pk; + const char *lib, *bin; + gnutls_x509_crt_t crt; + gnutls_x509_privkey_t key; + gnutls_datum_t tmp, sig; + gnutls_privkey_t pkey; + gnutls_pubkey_t pubkey; + gnutls_pubkey_t pubkey2; + + if (gnutls_fips140_mode_enabled()) + exit(77); + + bin = softhsm_bin(); + + lib = softhsm_lib(); + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin "PIN" --pin "PIN, bin); + system(buf); + + ret = gnutls_pkcs11_add_provider(lib, "trusted"); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_crt_init(&crt); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_x509_crt_import(crt, rsa?&server_cert:&server_ecc_cert, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + if (debug) { + gnutls_x509_crt_print(crt, + GNUTLS_CRT_PRINT_ONELINE, + &tmp); + + printf("\tCertificate: %.*s\n", + tmp.size, tmp.data); + gnutls_free(tmp.data); + } + + ret = gnutls_x509_privkey_init(&key); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_privkey_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_x509_privkey_import(key, rsa?&server_key:&server_ecc_key, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_privkey_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + /* initialize softhsm token */ + ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test"); + if (ret < 0) { + fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_token_set_pin(SOFTHSM_URL, NULL, PIN, GNUTLS_PIN_USER); + if (ret < 0) { + fail("gnutls_pkcs11_token_set_pin: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_copy_x509_crt(SOFTHSM_URL, crt, "cert", + GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE|GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_crt: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_copy_x509_privkey(SOFTHSM_URL, key, "cert", GNUTLS_KEY_DIGITAL_SIGNATURE|GNUTLS_KEY_KEY_ENCIPHERMENT, + GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE|GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE|GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_privkey: %s\n", gnutls_strerror(ret)); + exit(1); + } + + gnutls_x509_crt_deinit(crt); + gnutls_x509_privkey_deinit(key); + gnutls_pkcs11_set_pin_function(NULL, NULL); + + assert(gnutls_privkey_init(&pkey) == 0); + + ret = gnutls_privkey_import_pkcs11_url(pkey, SOFTHSM_URL";object=cert;object-type=private;pin-value="PIN); + if (ret < 0) { + fprintf(stderr, "error in %d: %s\n", __LINE__, gnutls_strerror(ret)); + exit(1); + } + + assert(gnutls_pubkey_init(&pubkey) == 0); + assert(gnutls_pubkey_import_privkey(pubkey, pkey, 0, 0) == 0); + + pk = gnutls_pubkey_get_pk_algorithm(pubkey, NULL); + + /* check whether privkey and pubkey are operational + * by signing and verifying */ + assert(gnutls_privkey_sign_data(pkey, GNUTLS_DIG_SHA256, 0, &testdata, &sig) == 0); + + /* verify against the raw pubkey */ + assert(gnutls_pubkey_init(&pubkey2) == 0); + assert(gnutls_pubkey_import_x509_raw(pubkey2, rsa?&server_cert:&server_ecc_cert, GNUTLS_X509_FMT_PEM, 0) == 0); + assert(gnutls_pubkey_verify_data2(pubkey2, gnutls_pk_to_sign(pk, GNUTLS_DIG_SHA256), 0, &testdata, &sig) == 0); + + /* verify against the pubkey in PKCS #11 */ + assert(gnutls_pubkey_verify_data2(pubkey, gnutls_pk_to_sign(pk, GNUTLS_DIG_SHA256), 0, &testdata, &sig) == 0); + + gnutls_free(sig.data); + + gnutls_pubkey_deinit(pubkey2); + gnutls_pubkey_deinit(pubkey); + gnutls_privkey_deinit(pkey); + + gnutls_global_deinit(); + + remove(CONFIG); +} + diff --git a/tests/pkcs11/pkcs11-rsa-pss-privkey-test.c b/tests/pkcs11/pkcs11-rsa-pss-privkey-test.c new file mode 100644 index 0000000..2d1d093 --- /dev/null +++ b/tests/pkcs11/pkcs11-rsa-pss-privkey-test.c @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> + +#include "../utils.h" +#include "softhsm.h" + +#define CONFIG_NAME "softhsm-privkey-rsa-pss-test" +#define CONFIG CONFIG_NAME".config" + +/* Tests whether signing with PKCS#11 and RSA-PSS would + * generate valid signatures */ + +#include "../cert-common.h" + +#define PIN "1234" + +static const gnutls_datum_t testdata = { (void *)"test test", 9 }; + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +static +int pin_func(void *userdata, int attempt, const char *url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +#define myfail(fmt, ...) \ + fail("%s (iter %d): "fmt, gnutls_sign_get_name(sigalgo), i, ##__VA_ARGS__) + +static unsigned verify_rsa_pss_presence(void) +{ + unsigned i; + unsigned long mechanism; + int ret; + + i = 0; + do { + ret = gnutls_pkcs11_token_get_mechanism("pkcs11:", i++, &mechanism); + if (ret >= 0 && mechanism == 0xd /* CKM_RSA_PKCS_PSS*/) + return 1; + } while(ret>=0); + + return 0; +} + +void doit(void) +{ + char buf[128]; + int ret; + const char *lib, *bin; + gnutls_x509_crt_t crt; + gnutls_x509_privkey_t key; + gnutls_datum_t tmp, sig; + gnutls_privkey_t pkey; + gnutls_pubkey_t pubkey; + gnutls_pubkey_t pubkey2; + unsigned i, sigalgo; + + if (gnutls_fips140_mode_enabled()) + exit(77); + + bin = softhsm_bin(); + + lib = softhsm_lib(); + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), + "%s --init-token --slot 0 --label test --so-pin " PIN " --pin " + PIN, bin); + system(buf); + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret < 0) { + fprintf(stderr, "gnutls_x509_crt_init: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + if (verify_rsa_pss_presence() == 0) { + fprintf(stderr, "Skipping test as no RSA-PSS mech is supported\n"); + exit(77); + } + + ret = gnutls_x509_crt_init(&crt); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_x509_crt_import(crt, &cli_ca3_rsa_pss_cert, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_import: %s\n", gnutls_strerror(ret)); + exit(1); + } + + if (debug) { + gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &tmp); + + printf("\tCertificate: %.*s\n", tmp.size, tmp.data); + gnutls_free(tmp.data); + } + + ret = gnutls_x509_privkey_init(&key); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_privkey_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_x509_privkey_import(key, &cli_ca3_rsa_pss_key, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_privkey_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + /* initialize softhsm token */ + ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test"); + if (ret < 0) { + fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_pkcs11_token_set_pin(SOFTHSM_URL, NULL, PIN, + GNUTLS_PIN_USER); + if (ret < 0) { + fail("gnutls_pkcs11_token_set_pin: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_copy_x509_crt(SOFTHSM_URL, crt, "cert", + GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE | + GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_crt: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_pkcs11_copy_x509_privkey(SOFTHSM_URL, key, "cert", + GNUTLS_KEY_DIGITAL_SIGNATURE | + GNUTLS_KEY_KEY_ENCIPHERMENT, + GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE + | + GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE + | GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_privkey: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + gnutls_x509_crt_deinit(crt); + gnutls_x509_privkey_deinit(key); + gnutls_pkcs11_set_pin_function(NULL, NULL); + + assert(gnutls_privkey_init(&pkey) == 0); + + ret = + gnutls_privkey_import_pkcs11_url(pkey, + SOFTHSM_URL + ";object=cert;object-type=private;pin-value=" + PIN); + if (ret < 0) { + fprintf(stderr, "error in %d: %s\n", __LINE__, + gnutls_strerror(ret)); + exit(1); + } + + assert(gnutls_pubkey_init(&pubkey) == 0); + assert(gnutls_pubkey_import_privkey(pubkey, pkey, 0, 0) == 0); + + assert(gnutls_pubkey_init(&pubkey2) == 0); + assert(gnutls_pubkey_import_x509_raw + (pubkey2, &cli_ca3_rsa_pss_cert, GNUTLS_X509_FMT_PEM, 0) == 0); + + /* this is the algorithm supported by the certificate */ + sigalgo = GNUTLS_SIGN_RSA_PSS_SHA256; + + for (i = 0; i < 20; i++) { + /* check whether privkey and pubkey are operational + * by signing and verifying */ + ret = + gnutls_privkey_sign_data2(pkey, sigalgo, 0, + &testdata, &sig); + if (ret < 0) + myfail("Error signing data %s\n", gnutls_strerror(ret)); + + /* verify against the pubkey in PKCS #11 */ + ret = + gnutls_pubkey_verify_data2(pubkey, sigalgo, 0, + &testdata, &sig); + if (ret < 0) + myfail("Error verifying data1: %s\n", + gnutls_strerror(ret)); + + /* verify against the raw pubkey */ + ret = + gnutls_pubkey_verify_data2(pubkey2, sigalgo, 0, + &testdata, &sig); + if (ret < 0) + myfail("Error verifying data2: %s\n", + gnutls_strerror(ret)); + + gnutls_free(sig.data); + } + + gnutls_pubkey_deinit(pubkey2); + gnutls_pubkey_deinit(pubkey); + gnutls_privkey_deinit(pkey); + + gnutls_global_deinit(); + + remove(CONFIG); +} diff --git a/tests/pkcs11/pkcs11-token-raw.c b/tests/pkcs11/pkcs11-token-raw.c new file mode 100644 index 0000000..04ff12d --- /dev/null +++ b/tests/pkcs11/pkcs11-token-raw.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2016-2018 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <gnutls/gnutls.h> +#include <gnutls/pkcs11.h> +#ifndef CRYPTOKI_GNU +# define CRYPTOKI_GNU +#endif +#include <p11-kit/pkcs11.h> + +#include "utils.h" + +/* Tests whether a gnutls_pkcs11_token_get_ptr returns valid handles. */ + +#if defined(HAVE___REGISTER_ATFORK) + +#ifdef _WIN32 +# define P11LIB "libpkcs11mock1.dll" +#else +# include <dlfcn.h> +# define P11LIB "libpkcs11mock1.so" +#endif + + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "|<%d>| %s", level, str); +} + +#define TOKEN_NAME "whatever" +void doit(void) +{ + int ret; + const char *lib; + unsigned long slot_id; + struct ck_function_list *mod; + struct ck_info info; + struct ck_token_info tinfo; + ck_rv_t rv; + + ret = global_init(); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + lib = getenv("P11MOCKLIB1"); + if (lib == NULL) + lib = P11LIB; + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + { + static const char url[] = "pkcs11:token="TOKEN_NAME; + + /* Testing a too small buffer */ + size_t size = 1; + char *buf = gnutls_malloc(size); + assert(buf != NULL); + ret = gnutls_pkcs11_token_get_info(url, + GNUTLS_PKCS11_TOKEN_LABEL, + buf, &size); + assert(ret == GNUTLS_E_SHORT_MEMORY_BUFFER); + assert(size == strlen(TOKEN_NAME)+1); + + /* Testing a too small buffer by one */ + size -= 1; + buf = gnutls_realloc(buf, size); + assert(buf != NULL); + ret = gnutls_pkcs11_token_get_info(url, + GNUTLS_PKCS11_TOKEN_LABEL, + buf, &size); + assert(ret == GNUTLS_E_SHORT_MEMORY_BUFFER); + assert(size == strlen(TOKEN_NAME)+1); + + /* Testing an exactly fitting buffer */ + buf = gnutls_realloc(buf, size); + assert(buf != NULL); + ret = gnutls_pkcs11_token_get_info(url, + GNUTLS_PKCS11_TOKEN_LABEL, + buf, &size); + assert(ret == 0); + assert(strcmp(buf, TOKEN_NAME) == 0); + assert(size == strlen(TOKEN_NAME)); + + gnutls_free(buf); + } + + ret = gnutls_pkcs11_token_get_ptr("pkcs11:token=invalid", (void**)&mod, &slot_id, 0); + assert(ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); + + ret = gnutls_pkcs11_token_get_ptr("pkcs11:", (void**)&mod, &slot_id, 0); + if (ret < 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + rv = mod->C_GetInfo(&info); + if (rv != CKR_OK) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + assert(info.cryptoki_version.major == 0x02); + assert(info.cryptoki_version.minor == 0x14); + assert(info.flags == 0); + assert(info.library_version.major == 0x01); + assert(info.library_version.minor == 0x00); + + rv = mod->C_GetTokenInfo(slot_id, &tinfo); + if (rv != CKR_OK) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + assert(tinfo.session_count == 0); + assert(tinfo.hardware_version.major == 0x01); + assert(tinfo.firmware_version.major == 0x01); + + if (debug) + printf("done\n\n\n"); + + gnutls_pkcs11_deinit(); + gnutls_global_deinit(); +} +#else +void doit(void) +{ + exit(77); +} +#endif diff --git a/tests/pkcs11/softhsm.h b/tests/pkcs11/softhsm.h new file mode 100644 index 0000000..725d29e --- /dev/null +++ b/tests/pkcs11/softhsm.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2014 Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef SOFTHSM_H +# define SOFTHSM_H + +#include <sys/stat.h> + +#define SOFTHSM_V2 + +#ifdef SOFTHSM_V1 +# define SOFTHSM_URL "pkcs11:model=SoftHSM;manufacturer=SoftHSM;serial=1;token=test" +# define LIB1 "/usr/lib64/pkcs11/libsofthsm.so" +# define LIB2 "/usr/lib/pkcs11/libsofthsm.so" +# define LIB3 "/usr/lib/softhsm/libsofthsm.so" +# define LIB4 "/usr/local/lib/softhsm/libsofthsm.so" +# define SOFTHSM_BIN1 "/usr/bin/softhsm" +# define SOFTHSM_BIN2 "/usr/local/bin/softhsm" +# define SOFTHSM_ENV "SOFTHSM_CONF" +#else +# define SOFTHSM_URL "pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;token=test" +# define LIB1 "/usr/lib64/pkcs11/libsofthsm2.so" +# define LIB2 "/usr/lib/pkcs11/libsofthsm2.so" +# define LIB3 "/usr/lib/softhsm/libsofthsm2.so" +# define LIB4 "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so" +# define SOFTHSM_BIN1 "/usr/bin/softhsm2-util" +# define SOFTHSM_BIN2 "/usr/local/bin/softhsm2-util" +# define SOFTHSM_ENV "SOFTHSM2_CONF" +#endif + + +inline static const char *softhsm_lib(void) +{ + const char *lib; + + if (sizeof(long) == 8 && access(LIB1, R_OK) == 0) { + lib = LIB1; + } else if (access(LIB2, R_OK) == 0) { + lib = LIB2; + } else if (access(LIB3, R_OK) == 0) { + lib = LIB3; + } else if (sizeof(long) == 8 && access(LIB4, R_OK) == 0) { + lib = LIB4; + } else { + fprintf(stderr, "cannot find softhsm module\n"); + exit(77); + } + + return lib; +} + +inline static const char *softhsm_bin(void) +{ + const char *bin; + + if (access(SOFTHSM_BIN1, X_OK) == 0) { + bin = SOFTHSM_BIN1; + } else if (access(SOFTHSM_BIN2, X_OK) == 0) { + bin = SOFTHSM_BIN2; + } else { + fprintf(stderr, "cannot find softhsm bin\n"); + exit(77); + } + + return bin; +} + +static +void set_softhsm_conf(const char *config) +{ + char buf[128]; + char db_dir[128]; + FILE *fp; + + snprintf(db_dir, sizeof(db_dir), "%s.db", config); + + unsetenv(SOFTHSM_ENV); + remove(config); + fp = fopen(config, "w"); + if (fp == NULL) { + fprintf(stderr, "error writing %s\n", config); + exit(1); + } + +#ifdef SOFTHSM_V1 + remove(db_dir); + snprintf(buf, sizeof(buf), "0:./%s\n", db_dir); + fputs(buf, fp); +#else + fputs("directories.tokendir = ", fp); + fputs(db_dir, fp); + fputs("\n", fp); + fputs("objectstore.backend = file\n", fp); + + if (strlen(db_dir) < 6) { + fprintf(stderr, "too short name for db: %s\n", db_dir); + exit(1); + } + snprintf(buf, sizeof(buf), "rm -rf %s\n", db_dir); + system(buf); + mkdir(db_dir, 0755); +#endif + fclose(fp); + + setenv(SOFTHSM_ENV, config, 0); +} + +#endif diff --git a/tests/pkcs11/tls-neg-pkcs11-key.c b/tests/pkcs11/tls-neg-pkcs11-key.c new file mode 100644 index 0000000..25f08ac --- /dev/null +++ b/tests/pkcs11/tls-neg-pkcs11-key.c @@ -0,0 +1,488 @@ +/* + * Copyright (C) 2017 Nikos Mavrogiannopoulos + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +/* This tests TLS negotiation using the gnutls_privkey_import_ext2() APIs */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#ifndef _WIN32 +# include <netinet/in.h> +# include <sys/socket.h> +# include <arpa/inet.h> +#endif +#include <unistd.h> +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include <gnutls/abstract.h> +#include <assert.h> +#include "cert-common.h" +#include "eagain-common.h" +#include "utils.h" +#include "softhsm.h" + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "<%d> %s", level, str); +} + +#define CONFIG_NAME "softhsm-neg" +#define CONFIG CONFIG_NAME".config" +#define PIN "1234" + +#define testfail(fmt, ...) \ + fail("%s: "fmt, name, ##__VA_ARGS__) + +static unsigned verify_eddsa_presence(void) +{ + unsigned i; + unsigned long mechanism; + int ret; + + i = 0; + do { + ret = gnutls_pkcs11_token_get_mechanism("pkcs11:", i++, &mechanism); + if (ret >= 0 && mechanism == 0x1057 /* CKM_EDDSA */) + return 1; + } while(ret>=0); + + return 0; +} + +static gnutls_privkey_t load_virt_privkey(const char *name, const gnutls_datum_t *txtkey, + int exp_key_err, unsigned needs_decryption) +{ + unsigned flags; + gnutls_privkey_t privkey; + gnutls_x509_privkey_t tmp; + int ret; + + ret = gnutls_x509_privkey_init(&tmp); + if (ret < 0) + testfail("gnutls_privkey_init\n"); + + ret = gnutls_x509_privkey_import(tmp, txtkey, GNUTLS_X509_FMT_PEM); + if (ret < 0) + testfail("gnutls_privkey_import: %s\n", gnutls_strerror(ret)); + + if (needs_decryption) + flags = GNUTLS_KEY_KEY_ENCIPHERMENT; + else + flags = GNUTLS_KEY_DIGITAL_SIGNATURE; + + ret = gnutls_pkcs11_copy_x509_privkey(SOFTHSM_URL, tmp, "key", flags, + GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE|GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE|GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + gnutls_x509_privkey_deinit(tmp); + + if (ret < 0) { + if (ret == exp_key_err) { + return NULL; + } + fail("gnutls_pkcs11_copy_x509_privkey: %s\n", gnutls_strerror(ret)); + } + + ret = gnutls_privkey_init(&privkey); + if (ret < 0) + testfail("gnutls_privkey_init\n"); + + ret = + gnutls_privkey_import_url(privkey, SOFTHSM_URL";object=key", 0); + if (ret < 0) { + if (ret == exp_key_err) { + gnutls_privkey_deinit(privkey); + return NULL; + } + testfail("gnutls_privkey_import: %s\n", gnutls_strerror(ret)); + } + + if (exp_key_err) { + testfail("did not fail in key import, although expected\n"); + } + + return privkey; +} + +static +void try_with_key(const char *name, const char *client_prio, + gnutls_kx_algorithm_t client_kx, + gnutls_sign_algorithm_t server_sign_algo, + gnutls_sign_algorithm_t client_sign_algo, + const gnutls_datum_t *serv_cert, + gnutls_privkey_t key, + int exp_serv_err) +{ + int ret; + gnutls_pcert_st pcert_list[4]; + unsigned pcert_list_size; + /* Server stuff. */ + gnutls_certificate_credentials_t s_xcred; + gnutls_session_t server; + int sret = GNUTLS_E_AGAIN; + /* Client stuff. */ + gnutls_certificate_credentials_t c_xcred; + gnutls_session_t client; + int cret = GNUTLS_E_AGAIN, version; + const char *err; + + /* General init. */ + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(6); + + reset_buffers(); + /* Init server */ + gnutls_certificate_allocate_credentials(&s_xcred); + + pcert_list_size = sizeof(pcert_list)/sizeof(pcert_list[0]); + ret = gnutls_pcert_list_import_x509_raw(pcert_list, &pcert_list_size, + serv_cert, GNUTLS_X509_FMT_PEM, 0); + if (ret < 0) { + testfail("error in gnutls_pcert_list_import_x509_raw: %s\n", gnutls_strerror(ret)); + } + + ret = gnutls_certificate_set_key(s_xcred, NULL, 0, pcert_list, + pcert_list_size, key); + if (ret < 0) { + testfail("Could not set key/cert: %s\n", gnutls_strerror(ret)); + } + + gnutls_init(&server, GNUTLS_SERVER); + gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE, + s_xcred); + + assert(gnutls_priority_set_direct(server, + "NORMAL:+VERS-SSL3.0:+ANON-ECDH:+ANON-DH:+ECDHE-RSA:+DHE-RSA:+RSA:+ECDHE-ECDSA:+CURVE-X25519:+SIGN-EDDSA-ED25519", + NULL) >= 0); + gnutls_transport_set_push_function(server, server_push); + gnutls_transport_set_pull_function(server, server_pull); + gnutls_transport_set_ptr(server, server); + + /* Init client */ + + ret = gnutls_certificate_allocate_credentials(&c_xcred); + if (ret < 0) + exit(1); + + ret = gnutls_init(&client, GNUTLS_CLIENT); + if (ret < 0) + exit(1); + + ret = gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE, + c_xcred); + if (ret < 0) + exit(1); + + gnutls_transport_set_push_function(client, client_push); + gnutls_transport_set_pull_function(client, client_pull); + gnutls_transport_set_ptr(client, client); + + ret = gnutls_priority_set_direct(client, client_prio, &err); + if (ret < 0) { + if (ret == GNUTLS_E_INVALID_REQUEST) + fprintf(stderr, "Error in %s\n", err); + exit(1); + } + if (exp_serv_err) { + HANDSHAKE_EXPECT(client, server, GNUTLS_E_AGAIN, exp_serv_err); + goto cleanup; + } else { + HANDSHAKE(client, server); + } + + if (gnutls_kx_get(client) != client_kx) { + testfail("%s: got unexpected key exchange algorithm: %s (expected %s)\n", name, gnutls_kx_get_name(gnutls_kx_get(client)), + gnutls_kx_get_name(client_kx)); + exit(1); + } + + /* test signature algorithm match */ + version = gnutls_protocol_get_version(client); + if (version >= GNUTLS_TLS1_2) { + ret = gnutls_sign_algorithm_get(server); + if (ret != (int)server_sign_algo && server_sign_algo != 0) { + testfail("%s: got unexpected server signature algorithm: %d/%s\n", name, ret, gnutls_sign_get_name(ret)); + exit(1); + } + + ret = gnutls_sign_algorithm_get_client(server); + if (ret != (int)client_sign_algo && client_sign_algo != 0) { + testfail("%s: got unexpected client signature algorithm: %d/%s\n", name, ret, gnutls_sign_get_name(ret)); + exit(1); + } + + ret = gnutls_sign_algorithm_get(client); + if (ret != (int)server_sign_algo && server_sign_algo != 0) { + testfail("%s: cl: got unexpected server signature algorithm: %d/%s\n", name, ret, gnutls_sign_get_name(ret)); + exit(1); + } + + ret = gnutls_sign_algorithm_get_client(client); + if (ret != (int)client_sign_algo && client_sign_algo != 0) { + testfail("%s: cl: got unexpected client signature algorithm: %d/%s\n", name, ret, gnutls_sign_get_name(ret)); + exit(1); + } + } + + gnutls_bye(client, GNUTLS_SHUT_RDWR); + gnutls_bye(server, GNUTLS_SHUT_RDWR); + + cleanup: + gnutls_deinit(client); + gnutls_deinit(server); + + gnutls_certificate_free_credentials(s_xcred); + gnutls_certificate_free_credentials(c_xcred); +} + +typedef struct test_st { + const char *name; + gnutls_pk_algorithm_t pk; + const char *prio; + const gnutls_datum_t *cert; + const gnutls_datum_t *key; + gnutls_kx_algorithm_t exp_kx; + int exp_key_err; + int exp_serv_err; + int needs_eddsa; + int needs_decryption; + int nofips; + unsigned requires_pkcs11_pss; +} test_st; + +static const test_st tests[] = { + {.name = "tls1.2: rsa-decryption key", + .pk = GNUTLS_PK_RSA, + .prio = "NORMAL:-KX-ALL:+RSA:-VERS-TLS-ALL:+VERS-TLS1.2", + .cert = &server_ca3_localhost_rsa_decrypt_cert, + .key = &server_ca3_key, + .exp_kx = GNUTLS_KX_RSA, + .needs_decryption = 1 + }, + {.name = "tls1.2: rsa-decryption key, signatures prioritized", + .pk = GNUTLS_PK_RSA, + .prio = "NORMAL:-KX-ALL:+ECDHE-RSA:+RSA:-VERS-TLS-ALL:+VERS-TLS1.2:-SIGN-ALL:+SIGN-RSA-PSS-RSAE-SHA256", + .cert = &server_ca3_localhost_cert, + .key = &server_ca3_key, + .exp_kx = GNUTLS_KX_RSA, + .needs_decryption = 1 + }, + {.name = "tls1.2: ecc key", + .pk = GNUTLS_PK_ECDSA, + .prio = "NORMAL:-KX-ALL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.2", + .cert = &server_ca3_localhost_ecc_cert, + .key = &server_ca3_ecc_key, + .exp_kx = GNUTLS_KX_ECDHE_ECDSA + }, + {.name = "tls1.2: rsa-sign key", + .pk = GNUTLS_PK_RSA, + .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.2", + .cert = &server_ca3_localhost_cert, + .key = &server_ca3_key, + .exp_kx = GNUTLS_KX_ECDHE_RSA + }, + {.name = "tls1.2: rsa-sign key with rsa-pss sigs prioritized", + .pk = GNUTLS_PK_RSA, + .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256:+SIGN-RSA-PSS-SHA384:+SIGN-RSA-PSS-SHA512:+SIGN-RSA-SHA256:+SIGN-RSA-SHA384:+SIGN-RSA-SHA512:-VERS-TLS-ALL:+VERS-TLS1.2", + .cert = &server_ca3_localhost_cert, + .key = &server_ca3_key, + .exp_kx = GNUTLS_KX_ECDHE_RSA + }, + {.name = "tls1.2: rsa-pss-sign key", + .pk = GNUTLS_PK_RSA_PSS, + .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.2", + .cert = &server_ca3_rsa_pss2_cert, + .key = &server_ca3_rsa_pss2_key, + .exp_kx = GNUTLS_KX_ECDHE_RSA, + .requires_pkcs11_pss = 1, + }, + {.name = "tls1.2: rsa-pss cert, rsa-sign key", + .pk = GNUTLS_PK_RSA, + .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.2", + .cert = &server_ca3_rsa_pss_cert, + .key = &server_ca3_rsa_pss_key, + .exp_kx = GNUTLS_KX_ECDHE_RSA, + .requires_pkcs11_pss = 1, + }, + {.name = "tls1.2: rsa-pss cert, rsa-sign key no PSS signatures", + .pk = GNUTLS_PK_RSA, + .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.2:-SIGN-RSA-PSS-SHA256:-SIGN-RSA-PSS-SHA384:-SIGN-RSA-PSS-SHA512:-SIGN-RSA-PSS-RSAE-SHA256:-SIGN-RSA-PSS-RSAE-SHA384:-SIGN-RSA-PSS-RSAE-SHA512", + .cert = &server_ca3_rsa_pss_cert, + .key = &server_ca3_rsa_pss_key, + .exp_kx = GNUTLS_KX_ECDHE_RSA, + .exp_serv_err = GNUTLS_E_NO_CIPHER_SUITES + }, + {.name = "tls1.2: ed25519 cert, ed25519 key", + .pk = GNUTLS_PK_EDDSA_ED25519, + .needs_eddsa = 1, + .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA", + .cert = &server_ca3_eddsa_cert, + .key = &server_ca3_eddsa_key, + .exp_kx = GNUTLS_KX_ECDHE_RSA, + .nofips = 1 + }, + {.name = "tls1.3: ecc key", + .pk = GNUTLS_PK_ECDSA, + .prio = "NORMAL:-KX-ALL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.3", + .cert = &server_ca3_localhost_ecc_cert, + .key = &server_ca3_ecc_key, + .exp_kx = GNUTLS_KX_ECDHE_RSA + }, + {.name = "tls1.3: rsa-sign key", + .pk = GNUTLS_PK_RSA, + .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.3", + .cert = &server_ca3_localhost_cert, + .key = &server_ca3_key, + .exp_kx = GNUTLS_KX_ECDHE_RSA + }, + {.name = "tls1.3: rsa-sign key with rsa-pss sigs prioritized", + .pk = GNUTLS_PK_RSA, + .prio = "NORMAL:-SIGN-ALL:+SIGN-RSA-PSS-SHA256:+SIGN-RSA-PSS-SHA384:+SIGN-RSA-PSS-SHA512:+SIGN-RSA-PSS-RSAE-SHA256:+SIGN-RSA-PSS-RSAE-SHA384:+SIGN-RSA-PSS-RSAE-SHA512:-VERS-TLS-ALL:+VERS-TLS1.3", + .cert = &server_ca3_localhost_cert, + .key = &server_ca3_key, + .exp_kx = GNUTLS_KX_ECDHE_RSA + }, + {.name = "tls1.3: rsa-pss-sign key", + .pk = GNUTLS_PK_RSA_PSS, + .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.3", + .cert = &server_ca3_rsa_pss2_cert, + .key = &server_ca3_rsa_pss2_key, + .exp_kx = GNUTLS_KX_ECDHE_RSA, + .requires_pkcs11_pss = 1, + }, + {.name = "tls1.3: rsa-pss cert, rsa-sign key", + .pk = GNUTLS_PK_RSA, + .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.3", + .cert = &server_ca3_rsa_pss_cert, + .key = &server_ca3_rsa_pss_key, + .exp_kx = GNUTLS_KX_ECDHE_RSA, + .requires_pkcs11_pss = 1, + }, + {.name = "tls1.3: rsa-pss cert, rsa-sign key no PSS signatures", + .pk = GNUTLS_PK_RSA, + .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.3:-SIGN-RSA-PSS-SHA256:-SIGN-RSA-PSS-SHA384:-SIGN-RSA-PSS-SHA512:-SIGN-RSA-PSS-RSAE-SHA256:-SIGN-RSA-PSS-RSAE-SHA384:-SIGN-RSA-PSS-RSAE-SHA512", + .cert = &server_ca3_rsa_pss_cert, + .key = &server_ca3_rsa_pss_key, + .exp_kx = GNUTLS_KX_ECDHE_RSA, + .exp_serv_err = GNUTLS_E_NO_CIPHER_SUITES + }, + {.name = "tls1.3: ed25519 cert, ed25519 key", + .needs_eddsa = 1, + .pk = GNUTLS_PK_EDDSA_ED25519, + .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA", + .cert = &server_ca3_eddsa_cert, + .key = &server_ca3_eddsa_key, + .exp_kx = GNUTLS_KX_ECDHE_RSA, + .nofips = 1 + } +}; + +static +int pin_func(void* userdata, int attempt, const char* url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +#ifndef CKM_RSA_PKCS_PSS +# define CKM_RSA_PKCS_PSS (0xdUL) +#endif + +void doit(void) +{ + gnutls_privkey_t privkey; + const char *bin, *lib; + char buf[512]; + unsigned int i, have_eddsa; + int ret; + + if (gnutls_fips140_mode_enabled()) + exit(77); + +#ifdef _WIN32 + exit(77); +#endif + bin = softhsm_bin(); + + lib = softhsm_lib(); + + global_init(); + + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(6); + + + /* initialize token */ + gnutls_pkcs11_set_pin_function(pin_func, NULL); + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin "PIN" --pin "PIN, bin); + system(buf); + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret < 0) { + fail("gnutls_pkcs11_add_provider: %s\n", + gnutls_strerror(ret)); + } + + have_eddsa = verify_eddsa_presence(); + + for (i=0;i<sizeof(tests)/sizeof(tests[0]);i++) { + if (tests[i].nofips && gnutls_fips140_mode_enabled()) + continue; + + if (tests[i].needs_eddsa && !have_eddsa) + continue; + + success("checking: %s\n", tests[i].name); + + if (tests[i].requires_pkcs11_pss) { + ret = gnutls_pkcs11_token_check_mechanism("pkcs11:", CKM_RSA_PKCS_PSS, NULL, 0, 0); + if (ret == 0) { + fprintf(stderr, "softhsm2 doesn't support CKM_RSA_PKCS_PSS; skipping test\n"); + continue; + } + } + + privkey = load_virt_privkey(tests[i].name, tests[i].key, tests[i].exp_key_err, tests[i].needs_decryption); + if (privkey == NULL && tests[i].exp_key_err < 0) + continue; + assert(privkey != 0); + + try_with_key(tests[i].name, tests[i].prio, + tests[i].exp_kx, 0, 0, + tests[i].cert, privkey, + tests[i].exp_serv_err); + + gnutls_pkcs11_delete_url(SOFTHSM_URL";object=key", GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + remove(CONFIG); + } + + gnutls_global_deinit(); +} diff --git a/tests/pkcs11/tls-neg-pkcs11-no-key.c b/tests/pkcs11/tls-neg-pkcs11-no-key.c new file mode 100644 index 0000000..124378d --- /dev/null +++ b/tests/pkcs11/tls-neg-pkcs11-no-key.c @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2017-2019 Red Hat, Inc. + * + * Author: Daiki Ueno + * + * This file is part of GnuTLS. + * + * GnuTLS 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. + * + * GnuTLS 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 Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> + +#if defined(_WIN32) + +int main() +{ + exit(77); +} + +#else + +#include <string.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <gnutls/gnutls.h> +#include <gnutls/dtls.h> +#include <signal.h> +#include <assert.h> + +#include "cert-common.h" +#include "tls13/ext-parse.h" +#include "pkcs11/softhsm.h" +#include "utils.h" + +/* This program tests that TLS 1.3 is disabled as expected. + */ + +static void server_log_func(int level, const char *str) +{ + fprintf(stderr, "server|<%d>| %s", level, str); +} + +static void client_log_func(int level, const char *str) +{ + fprintf(stderr, "client|<%d>| %s", level, str); +} + +#define P11LIB "libpkcs11mock2.so" + +#define PIN "1234" + +#define CONFIG_NAME "softhsm-neg-no-key" +#define CONFIG CONFIG_NAME".config" + +static +int pin_func(void *userdata, int attempt, const char *url, const char *label, + unsigned flags, char *pin, size_t pin_max) +{ + if (attempt == 0) { + strcpy(pin, PIN); + return 0; + } + return -1; +} + +static void client(int fd) +{ + int ret; + gnutls_session_t session; + gnutls_certificate_credentials_t x509_cred; + + global_init(); + + if (debug) { + gnutls_global_set_log_function(client_log_func); + gnutls_global_set_log_level(7); + } + + ret = gnutls_certificate_allocate_credentials(&x509_cred); + if (ret < 0) + exit(1); + + ret = gnutls_certificate_set_x509_trust_mem(x509_cred, &ca_cert, GNUTLS_X509_FMT_PEM); + if (ret < 0) + exit(1); + + /* Initialize TLS session + */ + assert(gnutls_init(&session, GNUTLS_CLIENT)>=0); + + gnutls_handshake_set_timeout(session, get_timeout()); + + ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); + if (ret < 0) + fail("cannot set credentials\n"); + + ret = gnutls_priority_set_direct(session, "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2", NULL); + if (ret < 0) + fail("cannot set priorities\n"); + + + gnutls_transport_set_int(session, fd); + + /* Perform the TLS handshake + */ + do { + ret = gnutls_handshake(session); + } + while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + + if (ret != 0) + fail("handshake failed: %s\n", gnutls_strerror(ret)); + + if (debug) + success("client handshake completed\n"); + + if (gnutls_protocol_get_version(session) == GNUTLS_TLS1_2) { + if (debug) + success("session is downgraded to TLS 1.2\n"); + } else + fail("session is NOT downgraded to TLS 1.2\n"); + + do { + ret = gnutls_bye(session, GNUTLS_SHUT_WR); + } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); + + close(fd); + + gnutls_deinit(session); + + gnutls_global_deinit(); +} + +static void server(int fd) +{ + int ret; + const char *lib; + gnutls_x509_crt_t crt; + gnutls_x509_privkey_t key; + gnutls_datum_t tmp; + gnutls_session_t session; + gnutls_certificate_credentials_t x509_cred; + + /* this must be called once in the program + */ + global_init(); + + if (debug) { + gnutls_global_set_log_function(server_log_func); + gnutls_global_set_log_level(4711); + } + + /* point to SoftHSM token that libpkcs11mock2.so internally uses */ + setenv(SOFTHSM_ENV, CONFIG, 1); + + gnutls_pkcs11_set_pin_function(pin_func, NULL); + + lib = getenv("P11MOCKLIB2"); + if (lib == NULL) + lib = P11LIB; + + ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_add_provider(lib, NULL); + if (ret != 0) { + fail("%d: %s\n", ret, gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_crt_init(&crt); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_crt_import(crt, &server_ca3_cert, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_crt_import: %s\n", gnutls_strerror(ret)); + exit(1); + } + + if (debug) { + gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &tmp); + + printf("\tCertificate: %.*s\n", tmp.size, tmp.data); + gnutls_free(tmp.data); + } + + ret = gnutls_x509_privkey_init(&key); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_privkey_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_privkey_import(key, &server_ca3_key, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, + "gnutls_x509_privkey_import: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + /* initialize softhsm token */ + ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test"); + if (ret < 0) { + fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_pkcs11_token_set_pin(SOFTHSM_URL, NULL, PIN, + GNUTLS_PIN_USER); + if (ret < 0) { + fail("gnutls_pkcs11_token_set_pin: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_pkcs11_copy_x509_crt(SOFTHSM_URL, crt, "cert", + GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE | + GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_crt: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_pkcs11_copy_x509_privkey(SOFTHSM_URL, key, "cert", + GNUTLS_KEY_DIGITAL_SIGNATURE | + GNUTLS_KEY_KEY_ENCIPHERMENT, + GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE + | + GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE + | GNUTLS_PKCS11_OBJ_FLAG_LOGIN); + if (ret < 0) { + fail("gnutls_pkcs11_copy_x509_privkey: %s\n", + gnutls_strerror(ret)); + exit(1); + } + + gnutls_x509_crt_deinit(crt); + gnutls_x509_privkey_deinit(key); + + assert(gnutls_certificate_allocate_credentials(&x509_cred)>=0); + + gnutls_init(&session, GNUTLS_SERVER); + + gnutls_handshake_set_timeout(session, get_timeout()); + + assert(gnutls_certificate_set_x509_key_file(x509_cred, + SOFTHSM_URL + ";object=cert;object-type=cert", + SOFTHSM_URL + ";object=cert;object-type=private;pin-value=" + PIN, + GNUTLS_X509_FMT_DER)>=0); + + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); + + /* avoid calling all the priority functions, since the defaults + * are adequate. + */ + gnutls_priority_set_direct(session, "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2", NULL); + + gnutls_transport_set_int(session, fd); + + do { + ret = gnutls_handshake(session); + } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + + if (ret != 0) + fail("handshake failed: %s\n", gnutls_strerror(ret)); + + if (debug) + success("server handshake completed\n"); + + if (gnutls_protocol_get_version(session) == GNUTLS_TLS1_2) { + if (debug) + success("session is downgraded to TLS 1.2\n"); + } else + fail("session is NOT downgraded to TLS 1.2\n"); + + do { + ret = gnutls_bye(session, GNUTLS_SHUT_RDWR); + } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); + + close(fd); + gnutls_deinit(session); + + gnutls_certificate_free_credentials(x509_cred); + + gnutls_global_deinit(); + + if (debug) + success("server: client/server hello were verified\n"); +} + +void doit(void) +{ + const char *bin; + char buf[128]; + int fd[2]; + int ret; + pid_t child; + int status = 0; + + if (gnutls_fips140_mode_enabled()) + exit(77); + + /* check if softhsm module is loadable */ + (void) softhsm_lib(); + + /* initialize SoftHSM token that libpkcs11mock2.so internally uses */ + bin = softhsm_bin(); + + set_softhsm_conf(CONFIG); + snprintf(buf, sizeof(buf), + "%s --init-token --slot 0 --label test --so-pin " PIN " --pin " + PIN, bin); + system(buf); + + signal(SIGCHLD, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd); + if (ret < 0) { + perror("socketpair"); + exit(1); + } + + child = fork(); + if (child < 0) { + perror("fork"); + fail("fork"); + exit(1); + } + + if (child) { + /* parent */ + close(fd[1]); + server(fd[0]); + kill(child, SIGTERM); + wait(&status); + check_wait_status(status); + } else { + close(fd[0]); + client(fd[1]); + exit(0); + } + +} +#endif /* _WIN32 */ |