diff options
Diffstat (limited to 'meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-02.patch')
-rw-r--r-- | meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-02.patch | 581 |
1 files changed, 581 insertions, 0 deletions
diff --git a/meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-02.patch b/meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-02.patch new file mode 100644 index 0000000000..25ba921869 --- /dev/null +++ b/meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-02.patch | |||
@@ -0,0 +1,581 @@ | |||
1 | From 92cebfbcc221c9ef3f6bbb78da3d7699c0ae56be Mon Sep 17 00:00:00 2001 | ||
2 | From: "djm@openbsd.org" <djm@openbsd.org> | ||
3 | Date: Wed, 19 Jul 2023 14:03:45 +0000 | ||
4 | Subject: [PATCH 02/12] upstream: Separate ssh-pkcs11-helpers for each p11 | ||
5 | module | ||
6 | |||
7 | Make ssh-pkcs11-client start an independent helper for each provider, | ||
8 | providing better isolation between modules and reliability if a single | ||
9 | module misbehaves. | ||
10 | |||
11 | This also implements reference counting of PKCS#11-hosted keys, | ||
12 | allowing ssh-pkcs11-helper subprocesses to be automatically reaped | ||
13 | when no remaining keys reference them. This fixes some bugs we have | ||
14 | that make PKCS11 keys unusable after they have been deleted, e.g. | ||
15 | https://bugzilla.mindrot.org/show_bug.cgi?id=3125 | ||
16 | |||
17 | ok markus@ | ||
18 | |||
19 | OpenBSD-Commit-ID: 0ce188b14fe271ab0568f4500070d96c5657244e | ||
20 | |||
21 | Upstream-Status: Backport [https://github.com/openssh/openssh-portable/commit/099cdf59ce1e72f55d421c8445bf6321b3004755] | ||
22 | CVE: CVE-2023-38408 | ||
23 | Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> | ||
24 | --- | ||
25 | ssh-pkcs11-client.c | 372 +++++++++++++++++++++++++++++++++----------- | ||
26 | 1 file changed, 282 insertions(+), 90 deletions(-) | ||
27 | |||
28 | diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c | ||
29 | index 41114c7..4f3c6ed 100644 | ||
30 | --- a/ssh-pkcs11-client.c | ||
31 | +++ b/ssh-pkcs11-client.c | ||
32 | @@ -1,4 +1,4 @@ | ||
33 | -/* $OpenBSD: ssh-pkcs11-client.c,v 1.16 2020/01/25 00:03:36 djm Exp $ */ | ||
34 | +/* $OpenBSD: ssh-pkcs11-client.c,v 1.18 2023/07/19 14:03:45 djm Exp $ */ | ||
35 | /* | ||
36 | * Copyright (c) 2010 Markus Friedl. All rights reserved. | ||
37 | * Copyright (c) 2014 Pedro Martelletto. All rights reserved. | ||
38 | @@ -30,12 +30,11 @@ | ||
39 | #include <string.h> | ||
40 | #include <unistd.h> | ||
41 | #include <errno.h> | ||
42 | +#include <limits.h> | ||
43 | |||
44 | #include <openssl/ecdsa.h> | ||
45 | #include <openssl/rsa.h> | ||
46 | |||
47 | -#include "openbsd-compat/openssl-compat.h" | ||
48 | - | ||
49 | #include "pathnames.h" | ||
50 | #include "xmalloc.h" | ||
51 | #include "sshbuf.h" | ||
52 | @@ -47,18 +46,140 @@ | ||
53 | #include "ssh-pkcs11.h" | ||
54 | #include "ssherr.h" | ||
55 | |||
56 | +#include "openbsd-compat/openssl-compat.h" | ||
57 | + | ||
58 | /* borrows code from sftp-server and ssh-agent */ | ||
59 | |||
60 | -static int fd = -1; | ||
61 | -static pid_t pid = -1; | ||
62 | +/* | ||
63 | + * Maintain a list of ssh-pkcs11-helper subprocesses. These may be looked up | ||
64 | + * by provider path or their unique EC/RSA METHOD pointers. | ||
65 | + */ | ||
66 | +struct helper { | ||
67 | + char *path; | ||
68 | + pid_t pid; | ||
69 | + int fd; | ||
70 | + RSA_METHOD *rsa_meth; | ||
71 | + EC_KEY_METHOD *ec_meth; | ||
72 | + int (*rsa_finish)(RSA *rsa); | ||
73 | + void (*ec_finish)(EC_KEY *key); | ||
74 | + size_t nrsa, nec; /* number of active keys of each type */ | ||
75 | +}; | ||
76 | +static struct helper **helpers; | ||
77 | +static size_t nhelpers; | ||
78 | + | ||
79 | +static struct helper * | ||
80 | +helper_by_provider(const char *path) | ||
81 | +{ | ||
82 | + size_t i; | ||
83 | + | ||
84 | + for (i = 0; i < nhelpers; i++) { | ||
85 | + if (helpers[i] == NULL || helpers[i]->path == NULL || | ||
86 | + helpers[i]->fd == -1) | ||
87 | + continue; | ||
88 | + if (strcmp(helpers[i]->path, path) == 0) | ||
89 | + return helpers[i]; | ||
90 | + } | ||
91 | + return NULL; | ||
92 | +} | ||
93 | + | ||
94 | +static struct helper * | ||
95 | +helper_by_rsa(const RSA *rsa) | ||
96 | +{ | ||
97 | + size_t i; | ||
98 | + const RSA_METHOD *meth; | ||
99 | + | ||
100 | + if ((meth = RSA_get_method(rsa)) == NULL) | ||
101 | + return NULL; | ||
102 | + for (i = 0; i < nhelpers; i++) { | ||
103 | + if (helpers[i] != NULL && helpers[i]->rsa_meth == meth) | ||
104 | + return helpers[i]; | ||
105 | + } | ||
106 | + return NULL; | ||
107 | + | ||
108 | +} | ||
109 | + | ||
110 | +static struct helper * | ||
111 | +helper_by_ec(const EC_KEY *ec) | ||
112 | +{ | ||
113 | + size_t i; | ||
114 | + const EC_KEY_METHOD *meth; | ||
115 | + | ||
116 | + if ((meth = EC_KEY_get_method(ec)) == NULL) | ||
117 | + return NULL; | ||
118 | + for (i = 0; i < nhelpers; i++) { | ||
119 | + if (helpers[i] != NULL && helpers[i]->ec_meth == meth) | ||
120 | + return helpers[i]; | ||
121 | + } | ||
122 | + return NULL; | ||
123 | + | ||
124 | +} | ||
125 | + | ||
126 | +static void | ||
127 | +helper_free(struct helper *helper) | ||
128 | +{ | ||
129 | + size_t i; | ||
130 | + int found = 0; | ||
131 | + | ||
132 | + if (helper == NULL) | ||
133 | + return; | ||
134 | + if (helper->path == NULL || helper->ec_meth == NULL || | ||
135 | + helper->rsa_meth == NULL) | ||
136 | + fatal("%s: inconsistent helper", __func__); | ||
137 | + debug3("%s: free helper for provider %s", __func__ , helper->path); | ||
138 | + for (i = 0; i < nhelpers; i++) { | ||
139 | + if (helpers[i] == helper) { | ||
140 | + if (found) | ||
141 | + fatal("%s: helper recorded more than once", __func__); | ||
142 | + found = 1; | ||
143 | + } | ||
144 | + else if (found) | ||
145 | + helpers[i - 1] = helpers[i]; | ||
146 | + } | ||
147 | + if (found) { | ||
148 | + helpers = xrecallocarray(helpers, nhelpers, | ||
149 | + nhelpers - 1, sizeof(*helpers)); | ||
150 | + nhelpers--; | ||
151 | + } | ||
152 | + free(helper->path); | ||
153 | + EC_KEY_METHOD_free(helper->ec_meth); | ||
154 | + RSA_meth_free(helper->rsa_meth); | ||
155 | + free(helper); | ||
156 | +} | ||
157 | + | ||
158 | +static void | ||
159 | +helper_terminate(struct helper *helper) | ||
160 | +{ | ||
161 | + if (helper == NULL) { | ||
162 | + return; | ||
163 | + } else if (helper->fd == -1) { | ||
164 | + debug3("%s: already terminated", __func__); | ||
165 | + } else { | ||
166 | + debug3("terminating helper for %s; " | ||
167 | + "remaining %zu RSA %zu ECDSA", __func__, | ||
168 | + helper->path, helper->nrsa, helper->nec); | ||
169 | + close(helper->fd); | ||
170 | + /* XXX waitpid() */ | ||
171 | + helper->fd = -1; | ||
172 | + helper->pid = -1; | ||
173 | + } | ||
174 | + /* | ||
175 | + * Don't delete the helper entry until there are no remaining keys | ||
176 | + * that reference it. Otherwise, any signing operation would call | ||
177 | + * a free'd METHOD pointer and that would be bad. | ||
178 | + */ | ||
179 | + if (helper->nrsa == 0 && helper->nec == 0) | ||
180 | + helper_free(helper); | ||
181 | +} | ||
182 | |||
183 | static void | ||
184 | -send_msg(struct sshbuf *m) | ||
185 | +send_msg(int fd, struct sshbuf *m) | ||
186 | { | ||
187 | u_char buf[4]; | ||
188 | size_t mlen = sshbuf_len(m); | ||
189 | int r; | ||
190 | |||
191 | + if (fd == -1) | ||
192 | + return; | ||
193 | POKE_U32(buf, mlen); | ||
194 | if (atomicio(vwrite, fd, buf, 4) != 4 || | ||
195 | atomicio(vwrite, fd, sshbuf_mutable_ptr(m), | ||
196 | @@ -69,12 +190,15 @@ send_msg(struct sshbuf *m) | ||
197 | } | ||
198 | |||
199 | static int | ||
200 | -recv_msg(struct sshbuf *m) | ||
201 | +recv_msg(int fd, struct sshbuf *m) | ||
202 | { | ||
203 | u_int l, len; | ||
204 | u_char c, buf[1024]; | ||
205 | int r; | ||
206 | |||
207 | + sshbuf_reset(m); | ||
208 | + if (fd == -1) | ||
209 | + return 0; /* XXX */ | ||
210 | if ((len = atomicio(read, fd, buf, 4)) != 4) { | ||
211 | error("read from helper failed: %u", len); | ||
212 | return (0); /* XXX */ | ||
213 | @@ -83,7 +207,6 @@ recv_msg(struct sshbuf *m) | ||
214 | if (len > 256 * 1024) | ||
215 | fatal("response too long: %u", len); | ||
216 | /* read len bytes into m */ | ||
217 | - sshbuf_reset(m); | ||
218 | while (len > 0) { | ||
219 | l = len; | ||
220 | if (l > sizeof(buf)) | ||
221 | @@ -104,14 +227,17 @@ recv_msg(struct sshbuf *m) | ||
222 | int | ||
223 | pkcs11_init(int interactive) | ||
224 | { | ||
225 | - return (0); | ||
226 | + return 0; | ||
227 | } | ||
228 | |||
229 | void | ||
230 | pkcs11_terminate(void) | ||
231 | { | ||
232 | - if (fd >= 0) | ||
233 | - close(fd); | ||
234 | + size_t i; | ||
235 | + | ||
236 | + debug3("%s: terminating %zu helpers", __func__, nhelpers); | ||
237 | + for (i = 0; i < nhelpers; i++) | ||
238 | + helper_terminate(helpers[i]); | ||
239 | } | ||
240 | |||
241 | static int | ||
242 | @@ -122,7 +248,11 @@ rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding) | ||
243 | u_char *blob = NULL, *signature = NULL; | ||
244 | size_t blen, slen = 0; | ||
245 | int r, ret = -1; | ||
246 | + struct helper *helper; | ||
247 | |||
248 | + if ((helper = helper_by_rsa(rsa)) == NULL || helper->fd == -1) | ||
249 | + fatal("%s: no helper for PKCS11 key", __func__); | ||
250 | + debug3("%s: signing with PKCS11 provider %s", __func__, helper->path); | ||
251 | if (padding != RSA_PKCS1_PADDING) | ||
252 | goto fail; | ||
253 | key = sshkey_new(KEY_UNSPEC); | ||
254 | @@ -144,10 +274,10 @@ rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding) | ||
255 | (r = sshbuf_put_string(msg, from, flen)) != 0 || | ||
256 | (r = sshbuf_put_u32(msg, 0)) != 0) | ||
257 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
258 | - send_msg(msg); | ||
259 | + send_msg(helper->fd, msg); | ||
260 | sshbuf_reset(msg); | ||
261 | |||
262 | - if (recv_msg(msg) == SSH2_AGENT_SIGN_RESPONSE) { | ||
263 | + if (recv_msg(helper->fd, msg) == SSH2_AGENT_SIGN_RESPONSE) { | ||
264 | if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0) | ||
265 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
266 | if (slen <= (size_t)RSA_size(rsa)) { | ||
267 | @@ -163,7 +293,26 @@ rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding) | ||
268 | return (ret); | ||
269 | } | ||
270 | |||
271 | -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) | ||
272 | +static int | ||
273 | +rsa_finish(RSA *rsa) | ||
274 | +{ | ||
275 | + struct helper *helper; | ||
276 | + | ||
277 | + if ((helper = helper_by_rsa(rsa)) == NULL) | ||
278 | + fatal("%s: no helper for PKCS11 key", __func__); | ||
279 | + debug3("%s: free PKCS11 RSA key for provider %s", __func__, helper->path); | ||
280 | + if (helper->rsa_finish != NULL) | ||
281 | + helper->rsa_finish(rsa); | ||
282 | + if (helper->nrsa == 0) | ||
283 | + fatal("%s: RSA refcount error", __func__); | ||
284 | + helper->nrsa--; | ||
285 | + debug3("%s: provider %s remaining keys: %zu RSA %zu ECDSA", __func__, | ||
286 | + helper->path, helper->nrsa, helper->nec); | ||
287 | + if (helper->nrsa == 0 && helper->nec == 0) | ||
288 | + helper_terminate(helper); | ||
289 | + return 1; | ||
290 | +} | ||
291 | + | ||
292 | static ECDSA_SIG * | ||
293 | ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv, | ||
294 | const BIGNUM *rp, EC_KEY *ec) | ||
295 | @@ -175,7 +324,11 @@ ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv, | ||
296 | u_char *blob = NULL, *signature = NULL; | ||
297 | size_t blen, slen = 0; | ||
298 | int r, nid; | ||
299 | + struct helper *helper; | ||
300 | |||
301 | + if ((helper = helper_by_ec(ec)) == NULL || helper->fd == -1) | ||
302 | + fatal("%s: no helper for PKCS11 key", __func__); | ||
303 | + debug3("%s: signing with PKCS11 provider %s", __func__, helper->path); | ||
304 | nid = sshkey_ecdsa_key_to_nid(ec); | ||
305 | if (nid < 0) { | ||
306 | error("%s: couldn't get curve nid", __func__); | ||
307 | @@ -203,10 +356,10 @@ ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv, | ||
308 | (r = sshbuf_put_string(msg, dgst, dgst_len)) != 0 || | ||
309 | (r = sshbuf_put_u32(msg, 0)) != 0) | ||
310 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
311 | - send_msg(msg); | ||
312 | + send_msg(helper->fd, msg); | ||
313 | sshbuf_reset(msg); | ||
314 | |||
315 | - if (recv_msg(msg) == SSH2_AGENT_SIGN_RESPONSE) { | ||
316 | + if (recv_msg(helper->fd, msg) == SSH2_AGENT_SIGN_RESPONSE) { | ||
317 | if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0) | ||
318 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
319 | cp = signature; | ||
320 | @@ -220,75 +373,110 @@ ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv, | ||
321 | sshbuf_free(msg); | ||
322 | return (ret); | ||
323 | } | ||
324 | -#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ | ||
325 | |||
326 | -static RSA_METHOD *helper_rsa; | ||
327 | -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) | ||
328 | -static EC_KEY_METHOD *helper_ecdsa; | ||
329 | -#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ | ||
330 | +static void | ||
331 | +ecdsa_do_finish(EC_KEY *ec) | ||
332 | +{ | ||
333 | + struct helper *helper; | ||
334 | + | ||
335 | + if ((helper = helper_by_ec(ec)) == NULL) | ||
336 | + fatal("%s: no helper for PKCS11 key", __func__); | ||
337 | + debug3("%s: free PKCS11 ECDSA key for provider %s", __func__, helper->path); | ||
338 | + if (helper->ec_finish != NULL) | ||
339 | + helper->ec_finish(ec); | ||
340 | + if (helper->nec == 0) | ||
341 | + fatal("%s: ECDSA refcount error", __func__); | ||
342 | + helper->nec--; | ||
343 | + debug3("%s: provider %s remaining keys: %zu RSA %zu ECDSA", __func__, | ||
344 | + helper->path, helper->nrsa, helper->nec); | ||
345 | + if (helper->nrsa == 0 && helper->nec == 0) | ||
346 | + helper_terminate(helper); | ||
347 | +} | ||
348 | |||
349 | /* redirect private key crypto operations to the ssh-pkcs11-helper */ | ||
350 | static void | ||
351 | -wrap_key(struct sshkey *k) | ||
352 | +wrap_key(struct helper *helper, struct sshkey *k) | ||
353 | { | ||
354 | - if (k->type == KEY_RSA) | ||
355 | - RSA_set_method(k->rsa, helper_rsa); | ||
356 | -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) | ||
357 | - else if (k->type == KEY_ECDSA) | ||
358 | - EC_KEY_set_method(k->ecdsa, helper_ecdsa); | ||
359 | -#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ | ||
360 | - else | ||
361 | + debug3("%s: wrap %s for provider %s", __func__, sshkey_type(k), helper->path); | ||
362 | + if (k->type == KEY_RSA) { | ||
363 | + RSA_set_method(k->rsa, helper->rsa_meth); | ||
364 | + if (helper->nrsa++ >= INT_MAX) | ||
365 | + fatal("%s: RSA refcount error", __func__); | ||
366 | + } else if (k->type == KEY_ECDSA) { | ||
367 | + EC_KEY_set_method(k->ecdsa, helper->ec_meth); | ||
368 | + if (helper->nec++ >= INT_MAX) | ||
369 | + fatal("%s: EC refcount error", __func__); | ||
370 | + } else | ||
371 | fatal("%s: unknown key type", __func__); | ||
372 | + k->flags |= SSHKEY_FLAG_EXT; | ||
373 | + debug3("%s: provider %s remaining keys: %zu RSA %zu ECDSA", __func__, | ||
374 | + helper->path, helper->nrsa, helper->nec); | ||
375 | } | ||
376 | |||
377 | static int | ||
378 | -pkcs11_start_helper_methods(void) | ||
379 | +pkcs11_start_helper_methods(struct helper *helper) | ||
380 | { | ||
381 | - if (helper_rsa != NULL) | ||
382 | - return (0); | ||
383 | - | ||
384 | -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) | ||
385 | - int (*orig_sign)(int, const unsigned char *, int, unsigned char *, | ||
386 | + int (*ec_init)(EC_KEY *key); | ||
387 | + int (*ec_copy)(EC_KEY *dest, const EC_KEY *src); | ||
388 | + int (*ec_set_group)(EC_KEY *key, const EC_GROUP *grp); | ||
389 | + int (*ec_set_private)(EC_KEY *key, const BIGNUM *priv_key); | ||
390 | + int (*ec_set_public)(EC_KEY *key, const EC_POINT *pub_key); | ||
391 | + int (*ec_sign)(int, const unsigned char *, int, unsigned char *, | ||
392 | unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL; | ||
393 | - if (helper_ecdsa != NULL) | ||
394 | - return (0); | ||
395 | - helper_ecdsa = EC_KEY_METHOD_new(EC_KEY_OpenSSL()); | ||
396 | - if (helper_ecdsa == NULL) | ||
397 | - return (-1); | ||
398 | - EC_KEY_METHOD_get_sign(helper_ecdsa, &orig_sign, NULL, NULL); | ||
399 | - EC_KEY_METHOD_set_sign(helper_ecdsa, orig_sign, NULL, ecdsa_do_sign); | ||
400 | -#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ | ||
401 | - | ||
402 | - if ((helper_rsa = RSA_meth_dup(RSA_get_default_method())) == NULL) | ||
403 | + RSA_METHOD *rsa_meth; | ||
404 | + EC_KEY_METHOD *ec_meth; | ||
405 | + | ||
406 | + if ((ec_meth = EC_KEY_METHOD_new(EC_KEY_OpenSSL())) == NULL) | ||
407 | + return -1; | ||
408 | + EC_KEY_METHOD_get_sign(ec_meth, &ec_sign, NULL, NULL); | ||
409 | + EC_KEY_METHOD_set_sign(ec_meth, ec_sign, NULL, ecdsa_do_sign); | ||
410 | + EC_KEY_METHOD_get_init(ec_meth, &ec_init, &helper->ec_finish, | ||
411 | + &ec_copy, &ec_set_group, &ec_set_private, &ec_set_public); | ||
412 | + EC_KEY_METHOD_set_init(ec_meth, ec_init, ecdsa_do_finish, | ||
413 | + ec_copy, ec_set_group, ec_set_private, ec_set_public); | ||
414 | + | ||
415 | + if ((rsa_meth = RSA_meth_dup(RSA_get_default_method())) == NULL) | ||
416 | fatal("%s: RSA_meth_dup failed", __func__); | ||
417 | - if (!RSA_meth_set1_name(helper_rsa, "ssh-pkcs11-helper") || | ||
418 | - !RSA_meth_set_priv_enc(helper_rsa, rsa_encrypt)) | ||
419 | + helper->rsa_finish = RSA_meth_get_finish(rsa_meth); | ||
420 | + if (!RSA_meth_set1_name(rsa_meth, "ssh-pkcs11-helper") || | ||
421 | + !RSA_meth_set_priv_enc(rsa_meth, rsa_encrypt) || | ||
422 | + !RSA_meth_set_finish(rsa_meth, rsa_finish)) | ||
423 | fatal("%s: failed to prepare method", __func__); | ||
424 | |||
425 | - return (0); | ||
426 | + helper->ec_meth = ec_meth; | ||
427 | + helper->rsa_meth = rsa_meth; | ||
428 | + return 0; | ||
429 | } | ||
430 | |||
431 | -static int | ||
432 | -pkcs11_start_helper(void) | ||
433 | +static struct helper * | ||
434 | +pkcs11_start_helper(const char *path) | ||
435 | { | ||
436 | int pair[2]; | ||
437 | - char *helper, *verbosity = NULL; | ||
438 | - | ||
439 | - if (log_level_get() >= SYSLOG_LEVEL_DEBUG1) | ||
440 | - verbosity = "-vvv"; | ||
441 | - | ||
442 | - if (pkcs11_start_helper_methods() == -1) { | ||
443 | - error("pkcs11_start_helper_methods failed"); | ||
444 | - return (-1); | ||
445 | - } | ||
446 | + char *prog, *verbosity = NULL; | ||
447 | + struct helper *helper; | ||
448 | + pid_t pid; | ||
449 | |||
450 | + if (nhelpers >= INT_MAX) | ||
451 | + fatal("%s: too many helpers", __func__); | ||
452 | + debug3("%s: start helper for %s", __func__, path); | ||
453 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { | ||
454 | error("socketpair: %s", strerror(errno)); | ||
455 | - return (-1); | ||
456 | + return NULL; | ||
457 | + } | ||
458 | + helper = xcalloc(1, sizeof(*helper)); | ||
459 | + if (pkcs11_start_helper_methods(helper) == -1) { | ||
460 | + error("pkcs11_start_helper_methods failed"); | ||
461 | + goto fail; | ||
462 | } | ||
463 | if ((pid = fork()) == -1) { | ||
464 | error("fork: %s", strerror(errno)); | ||
465 | - return (-1); | ||
466 | + fail: | ||
467 | + close(pair[0]); | ||
468 | + close(pair[1]); | ||
469 | + RSA_meth_free(helper->rsa_meth); | ||
470 | + EC_KEY_METHOD_free(helper->ec_meth); | ||
471 | + free(helper); | ||
472 | + return NULL; | ||
473 | } else if (pid == 0) { | ||
474 | if ((dup2(pair[1], STDIN_FILENO) == -1) || | ||
475 | (dup2(pair[1], STDOUT_FILENO) == -1)) { | ||
476 | @@ -297,18 +485,27 @@ pkcs11_start_helper(void) | ||
477 | } | ||
478 | close(pair[0]); | ||
479 | close(pair[1]); | ||
480 | - helper = getenv("SSH_PKCS11_HELPER"); | ||
481 | - if (helper == NULL || strlen(helper) == 0) | ||
482 | - helper = _PATH_SSH_PKCS11_HELPER; | ||
483 | + prog = getenv("SSH_PKCS11_HELPER"); | ||
484 | + if (prog == NULL || strlen(prog) == 0) | ||
485 | + prog = _PATH_SSH_PKCS11_HELPER; | ||
486 | + if (log_level_get() >= SYSLOG_LEVEL_DEBUG1) | ||
487 | + verbosity = "-vvv"; | ||
488 | debug("%s: starting %s %s", __func__, helper, | ||
489 | verbosity == NULL ? "" : verbosity); | ||
490 | - execlp(helper, helper, verbosity, (char *)NULL); | ||
491 | - fprintf(stderr, "exec: %s: %s\n", helper, strerror(errno)); | ||
492 | + execlp(prog, prog, verbosity, (char *)NULL); | ||
493 | + fprintf(stderr, "exec: %s: %s\n", prog, strerror(errno)); | ||
494 | _exit(1); | ||
495 | } | ||
496 | close(pair[1]); | ||
497 | - fd = pair[0]; | ||
498 | - return (0); | ||
499 | + helper->fd = pair[0]; | ||
500 | + helper->path = xstrdup(path); | ||
501 | + helper->pid = pid; | ||
502 | + debug3("%s: helper %zu for \"%s\" on fd %d pid %ld", __func__, nhelpers, | ||
503 | + helper->path, helper->fd, (long)helper->pid); | ||
504 | + helpers = xrecallocarray(helpers, nhelpers, | ||
505 | + nhelpers + 1, sizeof(*helpers)); | ||
506 | + helpers[nhelpers++] = helper; | ||
507 | + return helper; | ||
508 | } | ||
509 | |||
510 | int | ||
511 | @@ -322,9 +519,11 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, | ||
512 | size_t blen; | ||
513 | u_int nkeys, i; | ||
514 | struct sshbuf *msg; | ||
515 | + struct helper *helper; | ||
516 | |||
517 | - if (fd < 0 && pkcs11_start_helper() < 0) | ||
518 | - return (-1); | ||
519 | + if ((helper = helper_by_provider(name)) == NULL && | ||
520 | + (helper = pkcs11_start_helper(name)) == NULL) | ||
521 | + return -1; | ||
522 | |||
523 | if ((msg = sshbuf_new()) == NULL) | ||
524 | fatal("%s: sshbuf_new failed", __func__); | ||
525 | @@ -332,10 +531,10 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, | ||
526 | (r = sshbuf_put_cstring(msg, name)) != 0 || | ||
527 | (r = sshbuf_put_cstring(msg, pin)) != 0) | ||
528 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
529 | - send_msg(msg); | ||
530 | + send_msg(helper->fd, msg); | ||
531 | sshbuf_reset(msg); | ||
532 | |||
533 | - type = recv_msg(msg); | ||
534 | + type = recv_msg(helper->fd, msg); | ||
535 | if (type == SSH2_AGENT_IDENTITIES_ANSWER) { | ||
536 | if ((r = sshbuf_get_u32(msg, &nkeys)) != 0) | ||
537 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
538 | @@ -350,7 +549,7 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, | ||
539 | __func__, ssh_err(r)); | ||
540 | if ((r = sshkey_from_blob(blob, blen, &k)) != 0) | ||
541 | fatal("%s: bad key: %s", __func__, ssh_err(r)); | ||
542 | - wrap_key(k); | ||
543 | + wrap_key(helper, k); | ||
544 | (*keysp)[i] = k; | ||
545 | if (labelsp) | ||
546 | (*labelsp)[i] = label; | ||
547 | @@ -371,22 +570,15 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, | ||
548 | int | ||
549 | pkcs11_del_provider(char *name) | ||
550 | { | ||
551 | - int r, ret = -1; | ||
552 | - struct sshbuf *msg; | ||
553 | - | ||
554 | - if ((msg = sshbuf_new()) == NULL) | ||
555 | - fatal("%s: sshbuf_new failed", __func__); | ||
556 | - if ((r = sshbuf_put_u8(msg, SSH_AGENTC_REMOVE_SMARTCARD_KEY)) != 0 || | ||
557 | - (r = sshbuf_put_cstring(msg, name)) != 0 || | ||
558 | - (r = sshbuf_put_cstring(msg, "")) != 0) | ||
559 | - fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
560 | - send_msg(msg); | ||
561 | - sshbuf_reset(msg); | ||
562 | - | ||
563 | - if (recv_msg(msg) == SSH_AGENT_SUCCESS) | ||
564 | - ret = 0; | ||
565 | - sshbuf_free(msg); | ||
566 | - return (ret); | ||
567 | + struct helper *helper; | ||
568 | + | ||
569 | + /* | ||
570 | + * ssh-agent deletes keys before calling this, so the helper entry | ||
571 | + * should be gone before we get here. | ||
572 | + */ | ||
573 | + debug3("%s: delete %s", __func__, name); | ||
574 | + if ((helper = helper_by_provider(name)) != NULL) | ||
575 | + helper_terminate(helper); | ||
576 | + return 0; | ||
577 | } | ||
578 | - | ||
579 | #endif /* ENABLE_PKCS11 */ | ||
580 | -- | ||
581 | 2.41.0 | ||