1 /*
2  * Copyright (C) 2017 Red Hat, Inc.
3  *
4  * Author: Nikos Mavrogiannopoulos
5  *
6  * This file is part of GnuTLS.
7  *
8  * GnuTLS is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * GnuTLS is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with GnuTLS; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <assert.h>
31 #include <unistd.h>
32 
33 #include <gnutls/gnutls.h>
34 #include <gnutls/x509.h>
35 #include <gnutls/abstract.h>
36 
37 #include "../utils.h"
38 #include "softhsm.h"
39 
40 /* Tests whether a protected object is imported with PIN obtained using
41  * pin-value or pin-source. */
42 
43 #define CONFIG_NAME "softhsm-import-with-pin"
44 #define CONFIG CONFIG_NAME".config"
45 
46 #include "../cert-common.h"
47 
48 #define PIN "1234"
49 
50 static const gnutls_datum_t testdata = {(void*)"test test", 9};
51 
tls_log_func(int level,const char * str)52 static void tls_log_func(int level, const char *str)
53 {
54 	fprintf(stderr, "|<%d>| %s", level, str);
55 }
56 
57 static
pin_func(void * userdata,int attempt,const char * url,const char * label,unsigned flags,char * pin,size_t pin_max)58 int pin_func(void* userdata, int attempt, const char* url, const char *label,
59 		unsigned flags, char *pin, size_t pin_max)
60 {
61 	if (attempt == 0) {
62 		strcpy(pin, PIN);
63 		return 0;
64 	}
65 	return -1;
66 }
67 
write_pin(const char * file,const char * pin)68 static void write_pin(const char *file, const char *pin)
69 {
70 	FILE *fp = fopen(file, "w");
71 	assert(fp != NULL);
72 	fputs(pin, fp);
73 	fclose(fp);
74 }
75 
doit(void)76 void doit(void)
77 {
78 	char buf[512];
79 	int ret;
80 	const char *lib, *bin;
81 	gnutls_x509_privkey_t key;
82 	gnutls_datum_t sig;
83 	gnutls_privkey_t pkey;
84 	char file[TMPNAME_SIZE];
85 
86 	bin = softhsm_bin();
87 
88 	lib = softhsm_lib();
89 
90 	ret = global_init();
91 	if (ret != 0) {
92 		fail("%d: %s\n", ret, gnutls_strerror(ret));
93 		exit(1);
94 	}
95 
96 	gnutls_pkcs11_set_pin_function(pin_func, NULL);
97 	gnutls_global_set_log_function(tls_log_func);
98 	if (debug)
99 		gnutls_global_set_log_level(4711);
100 
101 	set_softhsm_conf(CONFIG);
102 	snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin "PIN" --pin "PIN, bin);
103 	system(buf);
104 
105 	ret = gnutls_pkcs11_add_provider(lib, "trusted");
106 	if (ret < 0) {
107 		fprintf(stderr, "add_provider: %s\n",
108 			gnutls_strerror(ret));
109 		exit(1);
110 	}
111 
112 	ret = gnutls_x509_privkey_init(&key);
113 	if (ret < 0) {
114 		fprintf(stderr,
115 			"gnutls_x509_privkey_init: %s\n",
116 			gnutls_strerror(ret));
117 		exit(1);
118 	}
119 
120 	ret =
121 	    gnutls_x509_privkey_import(key, &server_key,
122 				   GNUTLS_X509_FMT_PEM);
123 	if (ret < 0) {
124 		fprintf(stderr,
125 			"gnutls_x509_privkey_import: %s\n",
126 			gnutls_strerror(ret));
127 			exit(1);
128 	}
129 
130 	/* initialize softhsm token */
131 	ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test");
132 	if (ret < 0) {
133 		fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret));
134 		exit(1);
135 	}
136 
137 	ret = gnutls_pkcs11_token_set_pin(SOFTHSM_URL, NULL, PIN, GNUTLS_PIN_USER);
138 	if (ret < 0) {
139 		fail("gnutls_pkcs11_token_set_pin: %s\n", gnutls_strerror(ret));
140 		exit(1);
141 	}
142 
143 	ret = gnutls_pkcs11_copy_x509_privkey(SOFTHSM_URL, key, "cert", GNUTLS_KEY_DIGITAL_SIGNATURE|GNUTLS_KEY_KEY_ENCIPHERMENT,
144 					      GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE|GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE|GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
145 	if (ret < 0) {
146 		fail("gnutls_pkcs11_copy_x509_privkey: %s\n", gnutls_strerror(ret));
147 		exit(1);
148 	}
149 
150 	gnutls_x509_privkey_deinit(key);
151 	gnutls_pkcs11_set_pin_function(NULL, NULL);
152 
153 	assert(gnutls_privkey_init(&pkey) == 0);
154 
155 	/* Test 1
156 	 * Try importing with wrong pin-value */
157 	ret = gnutls_privkey_import_pkcs11_url(pkey, SOFTHSM_URL";object=cert;object-type=private;pin-value=XXXX");
158 	if (ret != GNUTLS_E_PKCS11_PIN_ERROR) {
159 		fprintf(stderr, "unexpected error in %d: %s\n", __LINE__, gnutls_strerror(ret));
160 		exit(1);
161 	}
162 	gnutls_privkey_deinit(pkey);
163 	assert(gnutls_privkey_init(&pkey) == 0);
164 
165 	/* Test 2
166 	 * Try importing with pin-value */
167 	ret = gnutls_privkey_import_pkcs11_url(pkey, SOFTHSM_URL";object=cert;object-type=private;pin-value="PIN);
168 	if (ret < 0) {
169 		fprintf(stderr, "error in %d: %s\n", __LINE__, gnutls_strerror(ret));
170 		exit(1);
171 	}
172 
173 	/* check whether privkey is operational by signing */
174 	assert(gnutls_privkey_sign_data(pkey, GNUTLS_DIG_SHA256, 0, &testdata, &sig) == 0);
175 	gnutls_free(sig.data);
176 	gnutls_privkey_deinit(pkey);
177 
178 	/* Test 3
179 	 * Try importing with wrong pin-source */
180 	track_temp_files();
181 	get_tmpname(file);
182 
183 	write_pin(file, "XXXX");
184 
185 	assert(gnutls_privkey_init(&pkey) == 0);
186 	snprintf(buf, sizeof(buf), "%s;object=cert;object-type=private;pin-source=%s", SOFTHSM_URL, file);
187 	ret = gnutls_privkey_import_pkcs11_url(pkey, buf);
188 	if (ret != GNUTLS_E_PKCS11_PIN_ERROR) {
189 		fprintf(stderr, "error in %d: %s\n", __LINE__, gnutls_strerror(ret));
190 		exit(1);
191 	}
192 
193 	gnutls_privkey_deinit(pkey);
194 
195 	/* Test 4
196 	 * Try importing with pin-source */
197 	write_pin(file, PIN);
198 
199 	assert(gnutls_privkey_init(&pkey) == 0);
200 	snprintf(buf, sizeof(buf), "%s;object=cert;object-type=private;pin-source=%s", SOFTHSM_URL, file);
201 	ret = gnutls_privkey_import_pkcs11_url(pkey, buf);
202 	if (ret < 0) {
203 		fprintf(stderr, "error in %d: %s\n", __LINE__, gnutls_strerror(ret));
204 		exit(1);
205 	}
206 
207 	/* check whether privkey is operational by signing */
208 	assert(gnutls_privkey_sign_data(pkey, GNUTLS_DIG_SHA256, 0, &testdata, &sig) == 0);
209 	gnutls_free(sig.data);
210 	gnutls_privkey_deinit(pkey);
211 
212 	gnutls_global_deinit();
213 	delete_temp_files();
214 
215 	remove(CONFIG);
216 }
217 
218