xref: /netbsd-src/crypto/external/bsd/openssh/dist/ssh-pkcs11-client.c (revision 8ecbf5f02b752fcb7debe1a8fab1dc82602bc760)
1 /*	$NetBSD: ssh-pkcs11-client.c,v 1.16 2020/02/27 00:24:40 christos Exp $	*/
2 /* $OpenBSD: ssh-pkcs11-client.c,v 1.16 2020/01/25 00:03:36 djm Exp $ */
3 /*
4  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
5  * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 #include "includes.h"
20 __RCSID("$NetBSD: ssh-pkcs11-client.c,v 1.16 2020/02/27 00:24:40 christos Exp $");
21 
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <sys/socket.h>
25 
26 #include <stdarg.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <errno.h>
30 
31 #include <openssl/ecdsa.h>
32 #include <openssl/rsa.h>
33 
34 #include "pathnames.h"
35 #include "xmalloc.h"
36 #include "sshbuf.h"
37 #include "log.h"
38 #include "misc.h"
39 #include "sshkey.h"
40 #include "authfd.h"
41 #include "atomicio.h"
42 #include "ssh-pkcs11.h"
43 #include "ssherr.h"
44 
45 /* borrows code from sftp-server and ssh-agent */
46 
47 static int fd = -1;
48 static pid_t pid = -1;
49 
50 static void
51 send_msg(struct sshbuf *m)
52 {
53 	u_char buf[4];
54 	size_t mlen = sshbuf_len(m);
55 	int r;
56 
57 	POKE_U32(buf, mlen);
58 	if (atomicio(vwrite, fd, buf, 4) != 4 ||
59 	    atomicio(vwrite, fd, sshbuf_mutable_ptr(m),
60 	    sshbuf_len(m)) != sshbuf_len(m))
61 		error("write to helper failed");
62 	if ((r = sshbuf_consume(m, mlen)) != 0)
63 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
64 }
65 
66 static int
67 recv_msg(struct sshbuf *m)
68 {
69 	u_int l, len;
70 	u_char c, buf[1024];
71 	int r;
72 
73 	if ((len = atomicio(read, fd, buf, 4)) != 4) {
74 		error("read from helper failed: %u", len);
75 		return (0); /* XXX */
76 	}
77 	len = PEEK_U32(buf);
78 	if (len > 256 * 1024)
79 		fatal("response too long: %u", len);
80 	/* read len bytes into m */
81 	sshbuf_reset(m);
82 	while (len > 0) {
83 		l = len;
84 		if (l > sizeof(buf))
85 			l = sizeof(buf);
86 		if (atomicio(read, fd, buf, l) != l) {
87 			error("response from helper failed.");
88 			return (0); /* XXX */
89 		}
90 		if ((r = sshbuf_put(m, buf, l)) != 0)
91 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
92 		len -= l;
93 	}
94 	if ((r = sshbuf_get_u8(m, &c)) != 0)
95 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
96 	return c;
97 }
98 
99 int
100 pkcs11_init(int interactive)
101 {
102 	return (0);
103 }
104 
105 void
106 pkcs11_terminate(void)
107 {
108 	if (fd >= 0)
109 		close(fd);
110 }
111 
112 static int
113 rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
114 {
115 	struct sshkey *key = NULL;
116 	struct sshbuf *msg = NULL;
117 	u_char *blob = NULL, *signature = NULL;
118 	size_t blen, slen = 0;
119 	int r, ret = -1;
120 
121 	if (padding != RSA_PKCS1_PADDING)
122 		goto fail;
123 	key = sshkey_new(KEY_UNSPEC);
124 	if (key == NULL) {
125 		error("%s: sshkey_new failed", __func__);
126 		goto fail;
127 	}
128 	key->type = KEY_RSA;
129 	RSA_up_ref(rsa);
130 	key->rsa = rsa;
131 	if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
132 		error("%s: sshkey_to_blob: %s", __func__, ssh_err(r));
133 		goto fail;
134 	}
135 	if ((msg = sshbuf_new()) == NULL)
136 		fatal("%s: sshbuf_new failed", __func__);
137 	if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
138 	    (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
139 	    (r = sshbuf_put_string(msg, from, flen)) != 0 ||
140 	    (r = sshbuf_put_u32(msg, 0)) != 0)
141 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
142 	send_msg(msg);
143 	sshbuf_reset(msg);
144 
145 	if (recv_msg(msg) == SSH2_AGENT_SIGN_RESPONSE) {
146 		if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
147 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
148 		if (slen <= (size_t)RSA_size(rsa)) {
149 			memcpy(to, signature, slen);
150 			ret = slen;
151 		}
152 		free(signature);
153 	}
154  fail:
155 	free(blob);
156 	sshkey_free(key);
157 	sshbuf_free(msg);
158 	return (ret);
159 }
160 
161 static ECDSA_SIG *
162 ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
163     const BIGNUM *rp, EC_KEY *ec)
164 {
165 	struct sshkey *key = NULL;
166 	struct sshbuf *msg = NULL;
167 	ECDSA_SIG *ret = NULL;
168 	const u_char *cp;
169 	u_char *blob = NULL, *signature = NULL;
170 	size_t blen, slen = 0;
171 	int r, nid;
172 
173 	nid = sshkey_ecdsa_key_to_nid(ec);
174 	if (nid < 0) {
175 		error("%s: couldn't get curve nid", __func__);
176 		goto fail;
177 	}
178 
179 	key = sshkey_new(KEY_UNSPEC);
180 	if (key == NULL) {
181 		error("%s: sshkey_new failed", __func__);
182 		goto fail;
183 	}
184 	key->ecdsa = ec;
185 	key->ecdsa_nid = nid;
186 	key->type = KEY_ECDSA;
187 	EC_KEY_up_ref(ec);
188 
189 	if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
190 		error("%s: sshkey_to_blob: %s", __func__, ssh_err(r));
191 		goto fail;
192 	}
193 	if ((msg = sshbuf_new()) == NULL)
194 		fatal("%s: sshbuf_new failed", __func__);
195 	if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
196 	    (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
197 	    (r = sshbuf_put_string(msg, dgst, dgst_len)) != 0 ||
198 	    (r = sshbuf_put_u32(msg, 0)) != 0)
199 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
200 	send_msg(msg);
201 	sshbuf_reset(msg);
202 
203 	if (recv_msg(msg) == SSH2_AGENT_SIGN_RESPONSE) {
204 		if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
205 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
206 		cp = signature;
207 		ret = d2i_ECDSA_SIG(NULL, &cp, slen);
208 		free(signature);
209 	}
210 
211  fail:
212 	free(blob);
213 	sshkey_free(key);
214 	sshbuf_free(msg);
215 	return (ret);
216 }
217 
218 static RSA_METHOD	*helper_rsa;
219 static EC_KEY_METHOD	*helper_ecdsa;
220 
221 /* redirect private key crypto operations to the ssh-pkcs11-helper */
222 static void
223 wrap_key(struct sshkey *k)
224 {
225 	if (k->type == KEY_RSA)
226 		RSA_set_method(k->rsa, helper_rsa);
227 	else if (k->type == KEY_ECDSA)
228 		EC_KEY_set_method(k->ecdsa, helper_ecdsa);
229 	else
230 		fatal("%s: unknown key type", __func__);
231 }
232 
233 static int
234 pkcs11_start_helper_methods(void)
235 {
236 	if (helper_ecdsa != NULL)
237 		return (0);
238 
239 	int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
240 	    unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
241 	if (helper_ecdsa != NULL)
242 		return (0);
243 	helper_ecdsa = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
244 	if (helper_ecdsa == NULL)
245 		return (-1);
246 	EC_KEY_METHOD_get_sign(helper_ecdsa, &orig_sign, NULL, NULL);
247 	EC_KEY_METHOD_set_sign(helper_ecdsa, orig_sign, NULL, ecdsa_do_sign);
248 
249 	if ((helper_rsa = RSA_meth_dup(RSA_get_default_method())) == NULL)
250 		fatal("%s: RSA_meth_dup failed", __func__);
251 	if (!RSA_meth_set1_name(helper_rsa, "ssh-pkcs11-helper") ||
252 	    !RSA_meth_set_priv_enc(helper_rsa, rsa_encrypt))
253 		fatal("%s: failed to prepare method", __func__);
254 
255 	return (0);
256 }
257 
258 static int
259 pkcs11_start_helper(void)
260 {
261 	int pair[2];
262 	const char *helper, *verbosity = NULL;
263 
264 	if (log_level_get() >= SYSLOG_LEVEL_DEBUG1)
265 		verbosity = "-vvv";
266 
267 	if (pkcs11_start_helper_methods() == -1) {
268 		error("pkcs11_start_helper_methods failed");
269 		return (-1);
270 	}
271 
272 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
273 		error("socketpair: %s", strerror(errno));
274 		return (-1);
275 	}
276 	if ((pid = fork()) == -1) {
277 		error("fork: %s", strerror(errno));
278 		return (-1);
279 	} else if (pid == 0) {
280 		if ((dup2(pair[1], STDIN_FILENO) == -1) ||
281 		    (dup2(pair[1], STDOUT_FILENO) == -1)) {
282 			fprintf(stderr, "dup2: %s\n", strerror(errno));
283 			_exit(1);
284 		}
285 		close(pair[0]);
286 		close(pair[1]);
287 		helper = getenv("SSH_PKCS11_HELPER");
288 		if (helper == NULL || strlen(helper) == 0)
289 			helper = _PATH_SSH_PKCS11_HELPER;
290 		debug("%s: starting %s %s", __func__, helper,
291 		    verbosity == NULL ? "" : verbosity);
292 		execlp(helper, helper, verbosity, (char *)NULL);
293 		fprintf(stderr, "exec: %s: %s\n", helper, strerror(errno));
294 		_exit(1);
295 	}
296 	close(pair[1]);
297 	fd = pair[0];
298 	return (0);
299 }
300 
301 int
302 pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp,
303     char ***labelsp)
304 {
305 	struct sshkey *k;
306 	int r, type;
307 	u_char *blob;
308 	char *label;
309 	size_t blen;
310 	u_int nkeys, i;
311 	struct sshbuf *msg;
312 
313 	if (fd < 0 && pkcs11_start_helper() < 0)
314 		return (-1);
315 
316 	if ((msg = sshbuf_new()) == NULL)
317 		fatal("%s: sshbuf_new failed", __func__);
318 	if ((r = sshbuf_put_u8(msg, SSH_AGENTC_ADD_SMARTCARD_KEY)) != 0 ||
319 	    (r = sshbuf_put_cstring(msg, name)) != 0 ||
320 	    (r = sshbuf_put_cstring(msg, pin)) != 0)
321 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
322 	send_msg(msg);
323 	sshbuf_reset(msg);
324 
325 	type = recv_msg(msg);
326 	if (type == SSH2_AGENT_IDENTITIES_ANSWER) {
327 		if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
328 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
329 		*keysp = xcalloc(nkeys, sizeof(struct sshkey *));
330 		if (labelsp)
331 			*labelsp = xcalloc(nkeys, sizeof(char *));
332 		for (i = 0; i < nkeys; i++) {
333 			/* XXX clean up properly instead of fatal() */
334 			if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 ||
335 			    (r = sshbuf_get_cstring(msg, &label, NULL)) != 0)
336 				fatal("%s: buffer error: %s",
337 				    __func__, ssh_err(r));
338 			if ((r = sshkey_from_blob(blob, blen, &k)) != 0)
339 				fatal("%s: bad key: %s", __func__, ssh_err(r));
340 			wrap_key(k);
341 			(*keysp)[i] = k;
342 			if (labelsp)
343 				(*labelsp)[i] = label;
344 			else
345 				free(label);
346 			free(blob);
347 		}
348 	} else if (type == SSH2_AGENT_FAILURE) {
349 		if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
350 			nkeys = -1;
351 	} else {
352 		nkeys = -1;
353 	}
354 	sshbuf_free(msg);
355 	return (nkeys);
356 }
357 
358 int
359 pkcs11_del_provider(char *name)
360 {
361 	int r, ret = -1;
362 	struct sshbuf *msg;
363 
364 	if ((msg = sshbuf_new()) == NULL)
365 		fatal("%s: sshbuf_new failed", __func__);
366 	if ((r = sshbuf_put_u8(msg, SSH_AGENTC_REMOVE_SMARTCARD_KEY)) != 0 ||
367 	    (r = sshbuf_put_cstring(msg, name)) != 0 ||
368 	    (r = sshbuf_put_cstring(msg, "")) != 0)
369 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
370 	send_msg(msg);
371 	sshbuf_reset(msg);
372 
373 	if (recv_msg(msg) == SSH_AGENT_SUCCESS)
374 		ret = 0;
375 	sshbuf_free(msg);
376 	return (ret);
377 }
378