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 Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <unistd.h>
31 
32 #include <gnutls/gnutls.h>
33 #include <gnutls/x509.h>
34 #include <gnutls/abstract.h>
35 
36 #include "../utils.h"
37 #include "softhsm.h"
38 
39 #define CONFIG_NAME "softhsm-privkey-rsa-pss-test"
40 #define CONFIG CONFIG_NAME".config"
41 
42 /* Tests whether signing with PKCS#11 and RSA-PSS would
43  * generate valid signatures */
44 
45 #include "../cert-common.h"
46 
47 #define PIN "1234"
48 
49 static const gnutls_datum_t testdata = { (void *)"test test", 9 };
50 
tls_log_func(int level,const char * str)51 static void tls_log_func(int level, const char *str)
52 {
53 	fprintf(stderr, "|<%d>| %s", level, str);
54 }
55 
56 static
pin_func(void * userdata,int attempt,const char * url,const char * label,unsigned flags,char * pin,size_t pin_max)57 int pin_func(void *userdata, int attempt, const char *url, const char *label,
58 	     unsigned flags, char *pin, size_t pin_max)
59 {
60 	if (attempt == 0) {
61 		strcpy(pin, PIN);
62 		return 0;
63 	}
64 	return -1;
65 }
66 
67 #define myfail(fmt, ...) \
68 	fail("%s (iter %d): "fmt, gnutls_sign_get_name(sigalgo), i, ##__VA_ARGS__)
69 
verify_rsa_pss_presence(void)70 static unsigned verify_rsa_pss_presence(void)
71 {
72 	unsigned i;
73 	unsigned long mechanism;
74 	int ret;
75 
76 	i = 0;
77 	do {
78 		ret = gnutls_pkcs11_token_get_mechanism("pkcs11:", i++, &mechanism);
79 		if (ret >= 0 && mechanism == 0xd /* CKM_RSA_PKCS_PSS*/)
80 			return 1;
81 	} while(ret>=0);
82 
83 	return 0;
84 }
85 
doit(void)86 void doit(void)
87 {
88 	char buf[128];
89 	int ret;
90 	const char *lib, *bin;
91 	gnutls_x509_crt_t crt;
92 	gnutls_x509_privkey_t key;
93 	gnutls_datum_t tmp, sig;
94 	gnutls_privkey_t pkey;
95 	gnutls_pubkey_t pubkey;
96 	gnutls_pubkey_t pubkey2;
97 	unsigned i, sigalgo;
98 
99 	bin = softhsm_bin();
100 
101 	lib = softhsm_lib();
102 
103 	ret = global_init();
104 	if (ret != 0) {
105 		fail("%d: %s\n", ret, gnutls_strerror(ret));
106 		exit(1);
107 	}
108 
109 	gnutls_pkcs11_set_pin_function(pin_func, NULL);
110 	gnutls_global_set_log_function(tls_log_func);
111 	if (debug)
112 		gnutls_global_set_log_level(4711);
113 
114 	set_softhsm_conf(CONFIG);
115 	snprintf(buf, sizeof(buf),
116 		 "%s --init-token --slot 0 --label test --so-pin " PIN " --pin "
117 		 PIN, bin);
118 	system(buf);
119 
120 	ret = gnutls_pkcs11_add_provider(lib, NULL);
121 	if (ret < 0) {
122 		fprintf(stderr, "gnutls_x509_crt_init: %s\n",
123 			gnutls_strerror(ret));
124 		exit(1);
125 	}
126 
127 	if (verify_rsa_pss_presence() == 0) {
128 		fprintf(stderr, "Skipping test as no RSA-PSS mech is supported\n");
129 		exit(77);
130 	}
131 
132 	ret = gnutls_x509_crt_init(&crt);
133 	if (ret < 0) {
134 		fprintf(stderr,
135 			"gnutls_x509_crt_init: %s\n", gnutls_strerror(ret));
136 		exit(1);
137 	}
138 
139 	ret =
140 	    gnutls_x509_crt_import(crt, &cli_ca3_rsa_pss_cert,
141 				   GNUTLS_X509_FMT_PEM);
142 	if (ret < 0) {
143 		fprintf(stderr,
144 			"gnutls_x509_crt_import: %s\n", gnutls_strerror(ret));
145 		exit(1);
146 	}
147 
148 	if (debug) {
149 		gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &tmp);
150 
151 		printf("\tCertificate: %.*s\n", tmp.size, tmp.data);
152 		gnutls_free(tmp.data);
153 	}
154 
155 	ret = gnutls_x509_privkey_init(&key);
156 	if (ret < 0) {
157 		fprintf(stderr,
158 			"gnutls_x509_privkey_init: %s\n", gnutls_strerror(ret));
159 		exit(1);
160 	}
161 
162 	ret =
163 	    gnutls_x509_privkey_import(key, &cli_ca3_rsa_pss_key,
164 				       GNUTLS_X509_FMT_PEM);
165 	if (ret < 0) {
166 		fprintf(stderr,
167 			"gnutls_x509_privkey_import: %s\n",
168 			gnutls_strerror(ret));
169 		exit(1);
170 	}
171 
172 	/* initialize softhsm token */
173 	ret = gnutls_pkcs11_token_init(SOFTHSM_URL, PIN, "test");
174 	if (ret < 0) {
175 		fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret));
176 		exit(1);
177 	}
178 
179 	ret =
180 	    gnutls_pkcs11_token_set_pin(SOFTHSM_URL, NULL, PIN,
181 					GNUTLS_PIN_USER);
182 	if (ret < 0) {
183 		fail("gnutls_pkcs11_token_set_pin: %s\n", gnutls_strerror(ret));
184 		exit(1);
185 	}
186 
187 	ret = gnutls_pkcs11_copy_x509_crt(SOFTHSM_URL, crt, "cert",
188 					  GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE |
189 					  GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
190 	if (ret < 0) {
191 		fail("gnutls_pkcs11_copy_x509_crt: %s\n", gnutls_strerror(ret));
192 		exit(1);
193 	}
194 
195 	ret =
196 	    gnutls_pkcs11_copy_x509_privkey(SOFTHSM_URL, key, "cert",
197 					    GNUTLS_KEY_DIGITAL_SIGNATURE |
198 					    GNUTLS_KEY_KEY_ENCIPHERMENT,
199 					    GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE
200 					    |
201 					    GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE
202 					    | GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
203 	if (ret < 0) {
204 		fail("gnutls_pkcs11_copy_x509_privkey: %s\n",
205 		     gnutls_strerror(ret));
206 		exit(1);
207 	}
208 
209 	gnutls_x509_crt_deinit(crt);
210 	gnutls_x509_privkey_deinit(key);
211 	gnutls_pkcs11_set_pin_function(NULL, NULL);
212 
213 	assert(gnutls_privkey_init(&pkey) == 0);
214 
215 	ret =
216 	    gnutls_privkey_import_pkcs11_url(pkey,
217 					     SOFTHSM_URL
218 					     ";object=cert;object-type=private;pin-value="
219 					     PIN);
220 	if (ret < 0) {
221 		fprintf(stderr, "error in %d: %s\n", __LINE__,
222 			gnutls_strerror(ret));
223 		exit(1);
224 	}
225 
226 	assert(gnutls_pubkey_init(&pubkey) == 0);
227 	assert(gnutls_pubkey_import_privkey(pubkey, pkey, 0, 0) == 0);
228 
229 	assert(gnutls_pubkey_init(&pubkey2) == 0);
230 	assert(gnutls_pubkey_import_x509_raw
231 	       (pubkey2, &cli_ca3_rsa_pss_cert, GNUTLS_X509_FMT_PEM, 0) == 0);
232 
233 	/* this is the algorithm supported by the certificate */
234 	sigalgo = GNUTLS_SIGN_RSA_PSS_SHA256;
235 
236 	for (i = 0; i < 20; i++) {
237 		/* check whether privkey and pubkey are operational
238 		 * by signing and verifying */
239 		ret =
240 		    gnutls_privkey_sign_data2(pkey, sigalgo, 0,
241 					      &testdata, &sig);
242 		if (ret < 0)
243 			myfail("Error signing data %s\n", gnutls_strerror(ret));
244 
245 		/* verify against the pubkey in PKCS #11 */
246 		ret =
247 		    gnutls_pubkey_verify_data2(pubkey, sigalgo, 0,
248 					       &testdata, &sig);
249 		if (ret < 0)
250 			myfail("Error verifying data1: %s\n",
251 			       gnutls_strerror(ret));
252 
253 		/* verify against the raw pubkey */
254 		ret =
255 		    gnutls_pubkey_verify_data2(pubkey2, sigalgo, 0,
256 					       &testdata, &sig);
257 		if (ret < 0)
258 			myfail("Error verifying data2: %s\n",
259 			       gnutls_strerror(ret));
260 
261 		gnutls_free(sig.data);
262 	}
263 
264 	gnutls_pubkey_deinit(pubkey2);
265 	gnutls_pubkey_deinit(pubkey);
266 	gnutls_privkey_deinit(pkey);
267 
268 	gnutls_global_deinit();
269 
270 	remove(CONFIG);
271 }
272