1 /* $OpenBSD: ssh-add.c,v 1.166 2022/06/18 02:17:16 dtucker Exp $ */
3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6 * Adds an identity to the authentication server, or removes an identity.
8 * As far as I am concerned, the code I have written for this software
9 * can be used freely for any purpose. Any derived versions of this
10 * software must be clearly marked as such, and if the derived work is
11 * incompatible with the protocol description in the RFC file, it must be
12 * called by a name other than "ssh" or "Secure Shell".
14 * SSH2 implementation,
15 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 #include <sys/types.h>
44 # include <openssl/evp.h>
45 # include "openbsd-compat/openssl-compat.h"
65 #include "pathnames.h"
74 extern char *__progname
;
76 /* Default files to add */
77 static char *default_files
[] = {
79 _PATH_SSH_CLIENT_ID_RSA
,
80 #ifdef OPENSSL_HAS_ECC
81 _PATH_SSH_CLIENT_ID_ECDSA
,
82 _PATH_SSH_CLIENT_ID_ECDSA_SK
,
84 #endif /* WITH_OPENSSL */
85 _PATH_SSH_CLIENT_ID_ED25519
,
86 _PATH_SSH_CLIENT_ID_ED25519_SK
,
87 _PATH_SSH_CLIENT_ID_XMSS
,
88 _PATH_SSH_CLIENT_ID_DSA
,
92 static int fingerprint_hash
= SSH_FP_HASH_DEFAULT
;
94 /* Default lifetime (0 == forever) */
95 static int lifetime
= 0;
97 /* User has to confirm key use */
98 static int confirm
= 0;
100 /* Maximum number of signatures (XMSS) */
101 static u_int maxsign
= 0;
102 static u_int minleft
= 0;
104 /* we keep a cache of one passphrase */
105 static char *pass
= NULL
;
110 freezero(pass
, strlen(pass
));
116 delete_one(int agent_fd
, const struct sshkey
*key
, const char *comment
,
117 const char *path
, int qflag
)
121 if ((r
= ssh_remove_identity(agent_fd
, key
)) != 0) {
122 fprintf(stderr
, "Could not remove identity \"%s\": %s\n",
127 fprintf(stderr
, "Identity removed: %s %s (%s)\n", path
,
128 sshkey_type(key
), comment
? comment
: "no comment");
134 delete_stdin(int agent_fd
, int qflag
)
136 char *line
= NULL
, *cp
;
138 struct sshkey
*key
= NULL
;
139 int lnum
= 0, r
, ret
= -1;
141 while (getline(&line
, &linesize
, stdin
) != -1) {
145 line
[strcspn(line
, "\n")] = '\0';
146 cp
= line
+ strspn(line
, " \t");
147 if (*cp
== '#' || *cp
== '\0')
149 if ((key
= sshkey_new(KEY_UNSPEC
)) == NULL
)
150 fatal_f("sshkey_new");
151 if ((r
= sshkey_read(key
, &cp
)) != 0) {
152 error_r(r
, "(stdin):%d: invalid key", lnum
);
155 if (delete_one(agent_fd
, key
, cp
, "(stdin)", qflag
) == 0)
164 delete_file(int agent_fd
, const char *filename
, int key_only
, int qflag
)
166 struct sshkey
*public, *cert
= NULL
;
167 char *certpath
= NULL
, *comment
= NULL
;
170 if (strcmp(filename
, "-") == 0)
171 return delete_stdin(agent_fd
, qflag
);
173 if ((r
= sshkey_load_public(filename
, &public, &comment
)) != 0) {
174 printf("Bad key file %s: %s\n", filename
, ssh_err(r
));
177 if (delete_one(agent_fd
, public, comment
, filename
, qflag
) == 0)
183 /* Now try to delete the corresponding certificate too */
186 xasprintf(&certpath
, "%s-cert.pub", filename
);
187 if ((r
= sshkey_load_public(certpath
, &cert
, &comment
)) != 0) {
188 if (r
!= SSH_ERR_SYSTEM_ERROR
|| errno
!= ENOENT
)
189 error_r(r
, "Failed to load certificate \"%s\"", certpath
);
193 if (!sshkey_equal_public(cert
, public))
194 fatal("Certificate %s does not match private key %s",
197 if (delete_one(agent_fd
, cert
, comment
, certpath
, qflag
) == 0)
209 /* Send a request to remove all identities. */
211 delete_all(int agent_fd
, int qflag
)
216 * Since the agent might be forwarded, old or non-OpenSSH, when asked
217 * to remove all keys, attempt to remove both protocol v.1 and v.2
220 if (ssh_remove_all_identities(agent_fd
, 2) == 0)
222 /* ignore error-code for ssh1 */
223 ssh_remove_all_identities(agent_fd
, 1);
226 fprintf(stderr
, "Failed to remove all identities.\n");
228 fprintf(stderr
, "All identities removed.\n");
234 add_file(int agent_fd
, const char *filename
, int key_only
, int qflag
,
235 const char *skprovider
, struct dest_constraint
**dest_constraints
,
236 size_t ndest_constraints
)
238 struct sshkey
*private, *cert
;
239 char *comment
= NULL
;
240 char msg
[1024], *certpath
= NULL
;
244 struct sshbuf
*keyblob
;
245 struct ssh_identitylist
*idlist
;
247 if (strcmp(filename
, "-") == 0) {
249 filename
= "(stdin)";
250 } else if ((fd
= open(filename
, O_RDONLY
)) == -1) {
256 * Since we'll try to load a keyfile multiple times, permission errors
257 * will occur multiple times, so check perms first and bail if wrong.
259 if (fd
!= STDIN_FILENO
) {
260 if (sshkey_perm_ok(fd
, filename
) != 0) {
265 if ((r
= sshbuf_load_fd(fd
, &keyblob
)) != 0) {
266 fprintf(stderr
, "Error loading key \"%s\": %s\n",
267 filename
, ssh_err(r
));
268 sshbuf_free(keyblob
);
274 /* At first, try empty passphrase */
275 if ((r
= sshkey_parse_private_fileblob(keyblob
, "", &private,
276 &comment
)) != 0 && r
!= SSH_ERR_KEY_WRONG_PASSPHRASE
) {
277 fprintf(stderr
, "Error loading key \"%s\": %s\n",
278 filename
, ssh_err(r
));
282 if (private == NULL
&& pass
!= NULL
) {
283 if ((r
= sshkey_parse_private_fileblob(keyblob
, pass
, &private,
284 &comment
)) != 0 && r
!= SSH_ERR_KEY_WRONG_PASSPHRASE
) {
285 fprintf(stderr
, "Error loading key \"%s\": %s\n",
286 filename
, ssh_err(r
));
290 if (private == NULL
) {
291 /* clear passphrase since it did not work */
293 snprintf(msg
, sizeof msg
, "Enter passphrase for %s%s: ",
294 filename
, confirm
? " (will confirm each use)" : "");
296 pass
= read_passphrase(msg
, RP_ALLOW_STDIN
);
297 if (strcmp(pass
, "") == 0)
299 if ((r
= sshkey_parse_private_fileblob(keyblob
, pass
,
300 &private, &comment
)) == 0)
302 else if (r
!= SSH_ERR_KEY_WRONG_PASSPHRASE
) {
304 "Error loading key \"%s\": %s\n",
305 filename
, ssh_err(r
));
308 sshbuf_free(keyblob
);
312 snprintf(msg
, sizeof msg
,
313 "Bad passphrase, try again for %s%s: ", filename
,
314 confirm
? " (will confirm each use)" : "");
317 if (comment
== NULL
|| *comment
== '\0')
318 comment
= xstrdup(filename
);
319 sshbuf_free(keyblob
);
322 if ((r
= sshkey_set_filename(private, filename
)) != 0) {
323 fprintf(stderr
, "Could not add filename to private key: %s (%s)\n",
327 if (maxsign
&& minleft
&&
328 (r
= ssh_fetch_identitylist(agent_fd
, &idlist
)) == 0) {
329 for (i
= 0; i
< idlist
->nkeys
; i
++) {
330 if (!sshkey_equal_public(idlist
->keys
[i
], private))
332 left
= sshkey_signatures_left(idlist
->keys
[i
]);
333 if (left
< minleft
) {
335 "Only %d signatures left.\n", left
);
338 fprintf(stderr
, "Skipping update: ");
339 if (left
== minleft
) {
341 "required signatures left (%d).\n", left
);
344 "more signatures left (%d) than"
345 " required (%d).\n", left
, minleft
);
347 ssh_free_identitylist(idlist
);
350 ssh_free_identitylist(idlist
);
353 if (sshkey_is_sk(private)) {
354 if (skprovider
== NULL
) {
355 fprintf(stderr
, "Cannot load FIDO key %s "
356 "without provider\n", filename
);
360 /* Don't send provider constraint for other keys */
364 if ((r
= ssh_add_identity_constrained(agent_fd
, private, comment
,
365 lifetime
, confirm
, maxsign
, skprovider
,
366 dest_constraints
, ndest_constraints
)) == 0) {
369 fprintf(stderr
, "Identity added: %s (%s)\n",
373 "Lifetime set to %d seconds\n", lifetime
);
376 fprintf(stderr
, "The user must confirm "
377 "each use of the key\n");
381 fprintf(stderr
, "Could not add identity \"%s\": %s\n",
382 filename
, ssh_err(r
));
385 /* Skip trying to load the cert if requested */
389 /* Now try to add the certificate flavour too */
390 xasprintf(&certpath
, "%s-cert.pub", filename
);
391 if ((r
= sshkey_load_public(certpath
, &cert
, NULL
)) != 0) {
392 if (r
!= SSH_ERR_SYSTEM_ERROR
|| errno
!= ENOENT
)
393 error_r(r
, "Failed to load certificate \"%s\"", certpath
);
397 if (!sshkey_equal_public(cert
, private)) {
398 error("Certificate %s does not match private key %s",
404 /* Graft with private bits */
405 if ((r
= sshkey_to_certified(private)) != 0) {
406 error_fr(r
, "sshkey_to_certified");
410 if ((r
= sshkey_cert_copy(cert
, private)) != 0) {
411 error_fr(r
, "sshkey_cert_copy");
417 if ((r
= ssh_add_identity_constrained(agent_fd
, private, comment
,
418 lifetime
, confirm
, maxsign
, skprovider
,
419 dest_constraints
, ndest_constraints
)) != 0) {
420 error_r(r
, "Certificate %s (%s) add failed", certpath
,
421 private->cert
->key_id
);
426 fprintf(stderr
, "Certificate added: %s (%s)\n", certpath
,
427 private->cert
->key_id
);
429 fprintf(stderr
, "Lifetime set to %d seconds\n",
433 fprintf(stderr
, "The user must confirm each use "
441 sshkey_free(private);
447 update_card(int agent_fd
, int add
, const char *id
, int qflag
,
448 struct dest_constraint
**dest_constraints
, size_t ndest_constraints
)
454 if ((pin
= read_passphrase("Enter passphrase for PKCS#11: ",
455 RP_ALLOW_STDIN
)) == NULL
)
459 if ((r
= ssh_update_card(agent_fd
, add
, id
, pin
== NULL
? "" : pin
,
460 lifetime
, confirm
, dest_constraints
, ndest_constraints
)) == 0) {
463 fprintf(stderr
, "Card %s: %s\n",
464 add
? "added" : "removed", id
);
467 fprintf(stderr
, "Could not %s card \"%s\": %s\n",
468 add
? "add" : "remove", id
, ssh_err(r
));
476 test_key(int agent_fd
, const char *filename
)
478 struct sshkey
*key
= NULL
;
484 if ((r
= sshkey_load_public(filename
, &key
, NULL
)) != 0) {
485 error_r(r
, "Couldn't read public key %s", filename
);
488 arc4random_buf(data
, sizeof(data
));
489 if ((r
= ssh_agent_sign(agent_fd
, key
, &sig
, &slen
, data
, sizeof(data
),
491 error_r(r
, "Agent signature failed for %s", filename
);
494 if ((r
= sshkey_verify(key
, sig
, slen
, data
, sizeof(data
),
495 NULL
, 0, NULL
)) != 0) {
496 error_r(r
, "Signature verification failed for %s", filename
);
508 list_identities(int agent_fd
, int do_fp
)
512 struct ssh_identitylist
*idlist
;
516 if ((r
= ssh_fetch_identitylist(agent_fd
, &idlist
)) != 0) {
517 if (r
!= SSH_ERR_AGENT_NO_IDENTITIES
)
518 fprintf(stderr
, "error fetching identities: %s\n",
521 printf("The agent has no identities.\n");
524 for (i
= 0; i
< idlist
->nkeys
; i
++) {
526 fp
= sshkey_fingerprint(idlist
->keys
[i
],
527 fingerprint_hash
, SSH_FP_DEFAULT
);
528 printf("%u %s %s (%s)\n", sshkey_size(idlist
->keys
[i
]),
529 fp
== NULL
? "(null)" : fp
, idlist
->comments
[i
],
530 sshkey_type(idlist
->keys
[i
]));
533 if ((r
= sshkey_write(idlist
->keys
[i
], stdout
)) != 0) {
534 fprintf(stderr
, "sshkey_write: %s\n",
538 fprintf(stdout
, " %s", idlist
->comments
[i
]);
539 left
= sshkey_signatures_left(idlist
->keys
[i
]);
542 " [signatures left %d]", left
);
543 fprintf(stdout
, "\n");
546 ssh_free_identitylist(idlist
);
551 lock_agent(int agent_fd
, int lock
)
553 char prompt
[100], *p1
, *p2
;
554 int r
, passok
= 1, ret
= -1;
556 strlcpy(prompt
, "Enter lock password: ", sizeof(prompt
));
557 p1
= read_passphrase(prompt
, RP_ALLOW_STDIN
);
559 strlcpy(prompt
, "Again: ", sizeof prompt
);
560 p2
= read_passphrase(prompt
, RP_ALLOW_STDIN
);
561 if (strcmp(p1
, p2
) != 0) {
562 fprintf(stderr
, "Passwords do not match.\n");
565 freezero(p2
, strlen(p2
));
568 if ((r
= ssh_lock_agent(agent_fd
, lock
, p1
)) == 0) {
569 fprintf(stderr
, "Agent %slocked.\n", lock
? "" : "un");
572 fprintf(stderr
, "Failed to %slock agent: %s\n",
573 lock
? "" : "un", ssh_err(r
));
576 freezero(p1
, strlen(p1
));
581 load_resident_keys(int agent_fd
, const char *skprovider
, int qflag
,
582 struct dest_constraint
**dest_constraints
, size_t ndest_constraints
)
584 struct sshsk_resident_key
**srks
;
590 pass
= read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN
);
591 if ((r
= sshsk_load_resident(skprovider
, NULL
, pass
, 0,
592 &srks
, &nsrks
)) != 0) {
593 error_r(r
, "Unable to load resident keys");
596 for (i
= 0; i
< nsrks
; i
++) {
598 if ((fp
= sshkey_fingerprint(key
,
599 fingerprint_hash
, SSH_FP_DEFAULT
)) == NULL
)
600 fatal_f("sshkey_fingerprint failed");
601 if ((r
= ssh_add_identity_constrained(agent_fd
, key
, "",
602 lifetime
, confirm
, maxsign
, skprovider
,
603 dest_constraints
, ndest_constraints
)) != 0) {
604 error("Unable to add key %s %s",
605 sshkey_type(key
), fp
);
613 fprintf(stderr
, "Resident identity added: %s %s\n",
614 sshkey_type(key
), fp
);
617 "Lifetime set to %d seconds\n", lifetime
);
620 fprintf(stderr
, "The user must confirm "
621 "each use of the key\n");
626 sshsk_free_resident_keys(srks
, nsrks
);
628 return SSH_ERR_KEY_NOT_FOUND
;
629 return ok
== 1 ? 0 : ok
;
633 do_file(int agent_fd
, int deleting
, int key_only
, char *file
, int qflag
,
634 const char *skprovider
, struct dest_constraint
**dest_constraints
,
635 size_t ndest_constraints
)
638 if (delete_file(agent_fd
, file
, key_only
, qflag
) == -1)
641 if (add_file(agent_fd
, file
, key_only
, qflag
, skprovider
,
642 dest_constraints
, ndest_constraints
) == -1)
648 /* Append string 's' to a NULL-terminated array of strings */
650 stringlist_append(char ***listp
, const char *s
)
655 *listp
= xcalloc(2, sizeof(**listp
));
657 for (i
= 0; (*listp
)[i
] != NULL
; i
++)
659 *listp
= xrecallocarray(*listp
, i
+ 1, i
+ 2, sizeof(**listp
));
661 (*listp
)[i
] = xstrdup(s
);
665 parse_dest_constraint_hop(const char *s
, struct dest_constraint_hop
*dch
,
666 char **hostkey_files
)
668 char *user
= NULL
, *host
, *os
, *path
;
670 struct hostkeys
*hostkeys
;
671 const struct hostkey_entry
*hke
;
674 memset(dch
, '\0', sizeof(*dch
));
676 if ((host
= strchr(os
, '@')) == NULL
)
683 /* Trivial case: username@ (all hosts) */
686 fatal("Invalid key destination constraint \"%s\": "
687 "does not specify user or host", s
);
689 dch
->user
= xstrdup(user
);
690 /* other fields left blank */
694 if (hostkey_files
== NULL
)
695 fatal_f("no hostkey files");
696 /* Otherwise we need to look up the keys for this hostname */
697 hostkeys
= init_hostkeys();
698 for (i
= 0; hostkey_files
[i
]; i
++) {
699 path
= tilde_expand_filename(hostkey_files
[i
], getuid());
700 debug2_f("looking up host keys for \"%s\" in %s", host
, path
);
701 load_hostkeys(hostkeys
, host
, path
, 0);
704 dch
->user
= user
== NULL
? NULL
: xstrdup(user
);
705 dch
->hostname
= xstrdup(host
);
706 for (i
= 0; i
< hostkeys
->num_entries
; i
++) {
707 hke
= hostkeys
->entries
+ i
;
708 want_ca
= hke
->marker
== MRK_CA
;
709 if (hke
->marker
!= MRK_NONE
&& !want_ca
)
711 debug3_f("%s%s%s: adding %s %skey from %s:%lu as key %u",
712 user
== NULL
? "": user
, user
== NULL
? "" : "@",
713 host
, sshkey_type(hke
->key
), want_ca
? "CA " : "",
714 hke
->file
, hke
->line
, dch
->nkeys
);
715 dch
->keys
= xrecallocarray(dch
->keys
, dch
->nkeys
,
716 dch
->nkeys
+ 1, sizeof(*dch
->keys
));
717 dch
->key_is_ca
= xrecallocarray(dch
->key_is_ca
, dch
->nkeys
,
718 dch
->nkeys
+ 1, sizeof(*dch
->key_is_ca
));
719 if ((r
= sshkey_from_private(hke
->key
,
720 &(dch
->keys
[dch
->nkeys
]))) != 0)
721 fatal_fr(r
, "sshkey_from_private");
722 dch
->key_is_ca
[dch
->nkeys
] = want_ca
;
726 fatal("No host keys found for destination \"%s\"", host
);
727 free_hostkeys(hostkeys
);
733 parse_dest_constraint(const char *s
, struct dest_constraint
***dcp
,
734 size_t *ndcp
, char **hostkey_files
)
736 struct dest_constraint
*dc
;
739 dc
= xcalloc(1, sizeof(*dc
));
741 if ((cp
= strchr(os
, '>')) == NULL
) {
742 /* initial hop; no 'from' hop specified */
743 parse_dest_constraint_hop(os
, &dc
->to
, hostkey_files
);
745 /* two hops specified */
747 parse_dest_constraint_hop(os
, &dc
->from
, hostkey_files
);
748 parse_dest_constraint_hop(cp
, &dc
->to
, hostkey_files
);
749 if (dc
->from
.user
!= NULL
) {
750 fatal("Invalid key constraint %s: cannot specify "
751 "user on 'from' host", os
);
754 /* XXX eliminate or error on duplicates */
755 debug2_f("constraint %zu: %s%s%s (%u keys) > %s%s%s (%u keys)", *ndcp
,
756 dc
->from
.user
? dc
->from
.user
: "", dc
->from
.user
? "@" : "",
757 dc
->from
.hostname
? dc
->from
.hostname
: "(ORIGIN)", dc
->from
.nkeys
,
758 dc
->to
.user
? dc
->to
.user
: "", dc
->to
.user
? "@" : "",
759 dc
->to
.hostname
? dc
->to
.hostname
: "(ANY)", dc
->to
.nkeys
);
760 *dcp
= xrecallocarray(*dcp
, *ndcp
, *ndcp
+ 1, sizeof(**dcp
));
761 (*dcp
)[(*ndcp
)++] = dc
;
770 "usage: ssh-add [-cDdKkLlqvXx] [-E fingerprint_hash] [-H hostkey_file]\n"
771 " [-h destination_constraint] [-S provider] [-t life]\n"
773 " [-M maxsign] [-m minleft]\n"
776 " ssh-add -s pkcs11\n"
777 " ssh-add -e pkcs11\n"
778 " ssh-add -T pubkey ...\n"
783 main(int argc
, char **argv
)
788 char *pkcs11provider
= NULL
, *skprovider
= NULL
;
789 char **dest_constraint_strings
= NULL
, **hostkey_files
= NULL
;
790 int r
, i
, ch
, deleting
= 0, ret
= 0, key_only
= 0, do_download
= 0;
791 int xflag
= 0, lflag
= 0, Dflag
= 0, qflag
= 0, Tflag
= 0;
792 SyslogFacility log_facility
= SYSLOG_FACILITY_AUTH
;
793 LogLevel log_level
= SYSLOG_LEVEL_INFO
;
794 struct dest_constraint
**dest_constraints
= NULL
;
795 size_t ndest_constraints
= 0;
797 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
800 __progname
= ssh_get_progname(argv
[0]);
803 log_init(__progname
, log_level
, log_facility
, 1);
805 setvbuf(stdout
, NULL
, _IOLBF
, 0);
807 /* First, get a connection to the authentication agent. */
808 switch (r
= ssh_get_authentication_socket(&agent_fd
)) {
811 case SSH_ERR_AGENT_NOT_PRESENT
:
812 fprintf(stderr
, "Could not open a connection to your "
813 "authentication agent.\n");
816 fprintf(stderr
, "Error connecting to agent: %s\n", ssh_err(r
));
820 skprovider
= getenv("SSH_SK_PROVIDER");
822 while ((ch
= getopt(argc
, argv
, "vkKlLcdDTxXE:e:h:H:M:m:qs:S:t:")) != -1) {
825 if (log_level
== SYSLOG_LEVEL_INFO
)
826 log_level
= SYSLOG_LEVEL_DEBUG1
;
827 else if (log_level
< SYSLOG_LEVEL_DEBUG3
)
831 fingerprint_hash
= ssh_digest_alg_by_name(optarg
);
832 if (fingerprint_hash
== -1)
833 fatal("Invalid hash algorithm \"%s\"", optarg
);
836 stringlist_append(&hostkey_files
, optarg
);
839 stringlist_append(&dest_constraint_strings
, optarg
);
850 fatal("-%c flag already specified", lflag
);
856 fatal("-%c flag already specified", xflag
);
863 minleft
= (int)strtonum(optarg
, 1, UINT_MAX
, NULL
);
871 maxsign
= (int)strtonum(optarg
, 1, UINT_MAX
, NULL
);
885 pkcs11provider
= optarg
;
892 pkcs11provider
= optarg
;
895 if ((lifetime
= convtime(optarg
)) == -1 ||
896 lifetime
< 0 || (u_long
)lifetime
> UINT32_MAX
) {
897 fprintf(stderr
, "Invalid lifetime\n");
914 log_init(__progname
, log_level
, log_facility
, 1);
916 if ((xflag
!= 0) + (lflag
!= 0) + (Dflag
!= 0) > 1)
917 fatal("Invalid combination of actions");
919 if (lock_agent(agent_fd
, xflag
== 'x' ? 1 : 0) == -1)
923 if (list_identities(agent_fd
, lflag
== 'l' ? 1 : 0) == -1)
927 if (delete_all(agent_fd
, qflag
) == -1)
932 #ifdef ENABLE_SK_INTERNAL
933 if (skprovider
== NULL
)
934 skprovider
= "internal";
937 if (hostkey_files
== NULL
) {
938 /* use defaults from readconf.c */
939 stringlist_append(&hostkey_files
, _PATH_SSH_USER_HOSTFILE
);
940 stringlist_append(&hostkey_files
, _PATH_SSH_USER_HOSTFILE2
);
941 stringlist_append(&hostkey_files
, _PATH_SSH_SYSTEM_HOSTFILE
);
942 stringlist_append(&hostkey_files
, _PATH_SSH_SYSTEM_HOSTFILE2
);
944 if (dest_constraint_strings
!= NULL
) {
945 for (i
= 0; dest_constraint_strings
[i
] != NULL
; i
++) {
946 parse_dest_constraint(dest_constraint_strings
[i
],
947 &dest_constraints
, &ndest_constraints
, hostkey_files
);
955 fatal("no keys to test");
956 for (r
= i
= 0; i
< argc
; i
++)
957 r
|= test_key(agent_fd
, argv
[i
]);
958 ret
= r
== 0 ? 0 : 1;
961 if (pkcs11provider
!= NULL
) {
962 if (update_card(agent_fd
, !deleting
, pkcs11provider
,
963 qflag
, dest_constraints
, ndest_constraints
) == -1)
968 if (skprovider
== NULL
)
969 fatal("Cannot download keys without provider");
970 if (load_resident_keys(agent_fd
, skprovider
, qflag
,
971 dest_constraints
, ndest_constraints
) != 0)
981 if ((pw
= getpwuid(getuid())) == NULL
) {
982 fprintf(stderr
, "No user found with uid %u\n",
988 for (i
= 0; default_files
[i
]; i
++) {
989 snprintf(buf
, sizeof(buf
), "%s/%s", pw
->pw_dir
,
991 if (stat(buf
, &st
) == -1)
993 if (do_file(agent_fd
, deleting
, key_only
, buf
,
995 dest_constraints
, ndest_constraints
) == -1)
1003 for (i
= 0; i
< argc
; i
++) {
1004 if (do_file(agent_fd
, deleting
, key_only
,
1005 argv
[i
], qflag
, skprovider
,
1006 dest_constraints
, ndest_constraints
) == -1)
1012 ssh_close_authentication_socket(agent_fd
);