diff options
author | markus@openbsd.org <markus@openbsd.org> | 2018-02-23 15:58:37 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2018-02-26 11:40:41 +1100 |
commit | 1b11ea7c58cd5c59838b5fa574cd456d6047b2d4 (patch) | |
tree | 7e96cb41b5234b9d327f7c8f41392f09aed0994e /ssh-add.c | |
parent | 7d330a1ac02076de98cfc8fda05353d57b603755 (diff) |
upstream: Add experimental support for PQC XMSS keys (Extended
Hash-Based Signatures) The code is not compiled in by default (see WITH_XMSS
in Makefile.inc) Joint work with stefan-lukas_gazdag at genua.eu See
https://tools.ietf.org/html/draft-irtf-cfrg-xmss-hash-based-signatures-12 ok
djm@
OpenBSD-Commit-ID: ef3eccb96762a5d6f135d7daeef608df7776a7ac
Diffstat (limited to 'ssh-add.c')
-rw-r--r-- | ssh-add.c | 74 |
1 files changed, 69 insertions, 5 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-add.c,v 1.134 2017/08/29 09:42:29 dlg Exp $ */ | 1 | /* $OpenBSD: ssh-add.c,v 1.135 2018/02/23 15:58:37 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -78,6 +78,7 @@ static char *default_files[] = { | |||
78 | #endif | 78 | #endif |
79 | #endif /* WITH_OPENSSL */ | 79 | #endif /* WITH_OPENSSL */ |
80 | _PATH_SSH_CLIENT_ID_ED25519, | 80 | _PATH_SSH_CLIENT_ID_ED25519, |
81 | _PATH_SSH_CLIENT_ID_XMSS, | ||
81 | NULL | 82 | NULL |
82 | }; | 83 | }; |
83 | 84 | ||
@@ -89,6 +90,10 @@ static int lifetime = 0; | |||
89 | /* User has to confirm key use */ | 90 | /* User has to confirm key use */ |
90 | static int confirm = 0; | 91 | static int confirm = 0; |
91 | 92 | ||
93 | /* Maximum number of signatures (XMSS) */ | ||
94 | static u_int maxsign = 0; | ||
95 | static u_int minleft = 0; | ||
96 | |||
92 | /* we keep a cache of one passphrase */ | 97 | /* we keep a cache of one passphrase */ |
93 | static char *pass = NULL; | 98 | static char *pass = NULL; |
94 | static void | 99 | static void |
@@ -190,7 +195,10 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag) | |||
190 | char *comment = NULL; | 195 | char *comment = NULL; |
191 | char msg[1024], *certpath = NULL; | 196 | char msg[1024], *certpath = NULL; |
192 | int r, fd, ret = -1; | 197 | int r, fd, ret = -1; |
198 | size_t i; | ||
199 | u_int32_t left; | ||
193 | struct sshbuf *keyblob; | 200 | struct sshbuf *keyblob; |
201 | struct ssh_identitylist *idlist; | ||
194 | 202 | ||
195 | if (strcmp(filename, "-") == 0) { | 203 | if (strcmp(filename, "-") == 0) { |
196 | fd = STDIN_FILENO; | 204 | fd = STDIN_FILENO; |
@@ -268,8 +276,40 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag) | |||
268 | comment = xstrdup(filename); | 276 | comment = xstrdup(filename); |
269 | sshbuf_free(keyblob); | 277 | sshbuf_free(keyblob); |
270 | 278 | ||
279 | /* For XMSS */ | ||
280 | if ((r = sshkey_set_filename(private, filename)) != 0) { | ||
281 | fprintf(stderr, "Could not add filename to private key: %s (%s)\n", | ||
282 | filename, comment); | ||
283 | goto out; | ||
284 | } | ||
285 | if (maxsign && minleft && | ||
286 | (r = ssh_fetch_identitylist(agent_fd, &idlist)) == 0) { | ||
287 | for (i = 0; i < idlist->nkeys; i++) { | ||
288 | if (!sshkey_equal_public(idlist->keys[i], private)) | ||
289 | continue; | ||
290 | left = sshkey_signatures_left(idlist->keys[i]); | ||
291 | if (left < minleft) { | ||
292 | fprintf(stderr, | ||
293 | "Only %d signatures left.\n", left); | ||
294 | break; | ||
295 | } | ||
296 | fprintf(stderr, "Skipping update: "); | ||
297 | if (left == minleft) { | ||
298 | fprintf(stderr, | ||
299 | "required signatures left (%d).\n", left); | ||
300 | } else { | ||
301 | fprintf(stderr, | ||
302 | "more signatures left (%d) than" | ||
303 | " required (%d).\n", left, minleft); | ||
304 | } | ||
305 | ssh_free_identitylist(idlist); | ||
306 | goto out; | ||
307 | } | ||
308 | ssh_free_identitylist(idlist); | ||
309 | } | ||
310 | |||
271 | if ((r = ssh_add_identity_constrained(agent_fd, private, comment, | 311 | if ((r = ssh_add_identity_constrained(agent_fd, private, comment, |
272 | lifetime, confirm)) == 0) { | 312 | lifetime, confirm, maxsign)) == 0) { |
273 | fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); | 313 | fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); |
274 | ret = 0; | 314 | ret = 0; |
275 | if (lifetime != 0) | 315 | if (lifetime != 0) |
@@ -317,7 +357,7 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag) | |||
317 | sshkey_free(cert); | 357 | sshkey_free(cert); |
318 | 358 | ||
319 | if ((r = ssh_add_identity_constrained(agent_fd, private, comment, | 359 | if ((r = ssh_add_identity_constrained(agent_fd, private, comment, |
320 | lifetime, confirm)) != 0) { | 360 | lifetime, confirm, maxsign)) != 0) { |
321 | error("Certificate %s (%s) add failed: %s", certpath, | 361 | error("Certificate %s (%s) add failed: %s", certpath, |
322 | private->cert->key_id, ssh_err(r)); | 362 | private->cert->key_id, ssh_err(r)); |
323 | goto out; | 363 | goto out; |
@@ -368,6 +408,7 @@ list_identities(int agent_fd, int do_fp) | |||
368 | char *fp; | 408 | char *fp; |
369 | int r; | 409 | int r; |
370 | struct ssh_identitylist *idlist; | 410 | struct ssh_identitylist *idlist; |
411 | u_int32_t left; | ||
371 | size_t i; | 412 | size_t i; |
372 | 413 | ||
373 | if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) { | 414 | if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) { |
@@ -392,7 +433,12 @@ list_identities(int agent_fd, int do_fp) | |||
392 | ssh_err(r)); | 433 | ssh_err(r)); |
393 | continue; | 434 | continue; |
394 | } | 435 | } |
395 | fprintf(stdout, " %s\n", idlist->comments[i]); | 436 | fprintf(stdout, " %s", idlist->comments[i]); |
437 | left = sshkey_signatures_left(idlist->keys[i]); | ||
438 | if (left > 0) | ||
439 | fprintf(stdout, | ||
440 | " [signatures left %d]", left); | ||
441 | fprintf(stdout, "\n"); | ||
396 | } | 442 | } |
397 | } | 443 | } |
398 | ssh_free_identitylist(idlist); | 444 | ssh_free_identitylist(idlist); |
@@ -454,6 +500,8 @@ usage(void) | |||
454 | fprintf(stderr, " -L List public key parameters of all identities.\n"); | 500 | fprintf(stderr, " -L List public key parameters of all identities.\n"); |
455 | fprintf(stderr, " -k Load only keys and not certificates.\n"); | 501 | fprintf(stderr, " -k Load only keys and not certificates.\n"); |
456 | fprintf(stderr, " -c Require confirmation to sign using identities\n"); | 502 | fprintf(stderr, " -c Require confirmation to sign using identities\n"); |
503 | fprintf(stderr, " -m minleft Maxsign is only changed if less than minleft are left (for XMSS)\n"); | ||
504 | fprintf(stderr, " -M maxsign Maximum number of signatures allowed (for XMSS)\n"); | ||
457 | fprintf(stderr, " -t life Set lifetime (in seconds) when adding identities.\n"); | 505 | fprintf(stderr, " -t life Set lifetime (in seconds) when adding identities.\n"); |
458 | fprintf(stderr, " -d Delete identity.\n"); | 506 | fprintf(stderr, " -d Delete identity.\n"); |
459 | fprintf(stderr, " -D Delete all identities.\n"); | 507 | fprintf(stderr, " -D Delete all identities.\n"); |
@@ -500,7 +548,7 @@ main(int argc, char **argv) | |||
500 | exit(2); | 548 | exit(2); |
501 | } | 549 | } |
502 | 550 | ||
503 | while ((ch = getopt(argc, argv, "klLcdDxXE:e:qs:t:")) != -1) { | 551 | while ((ch = getopt(argc, argv, "klLcdDxXE:e:M:m:qs:t:")) != -1) { |
504 | switch (ch) { | 552 | switch (ch) { |
505 | case 'E': | 553 | case 'E': |
506 | fingerprint_hash = ssh_digest_alg_by_name(optarg); | 554 | fingerprint_hash = ssh_digest_alg_by_name(optarg); |
@@ -525,6 +573,22 @@ main(int argc, char **argv) | |||
525 | case 'c': | 573 | case 'c': |
526 | confirm = 1; | 574 | confirm = 1; |
527 | break; | 575 | break; |
576 | case 'm': | ||
577 | minleft = (int)strtonum(optarg, 1, UINT_MAX, NULL); | ||
578 | if (minleft == 0) { | ||
579 | usage(); | ||
580 | ret = 1; | ||
581 | goto done; | ||
582 | } | ||
583 | break; | ||
584 | case 'M': | ||
585 | maxsign = (int)strtonum(optarg, 1, UINT_MAX, NULL); | ||
586 | if (maxsign == 0) { | ||
587 | usage(); | ||
588 | ret = 1; | ||
589 | goto done; | ||
590 | } | ||
591 | break; | ||
528 | case 'd': | 592 | case 'd': |
529 | deleting = 1; | 593 | deleting = 1; |
530 | break; | 594 | break; |