summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2020-08-27 01:06:18 +0000
committerDamien Miller <djm@mindrot.org>2020-08-27 11:28:36 +1000
commit9b8ad93824c682ce841f53f3b5762cef4e7cc4dc (patch)
treed4523956d4623b19bf5904d1b92afeb2307f69d3
parent1196d7f49d4fbc90f37e550de3056561613b0960 (diff)
upstream: support for user-verified FIDO keys
FIDO2 supports a notion of "user verification" where the user is required to demonstrate their identity to the token before particular operations (e.g. signing). Typically this is done by authenticating themselves using a PIN that has been set on the token. This adds support for generating and using user verified keys where the verification happens via PIN (other options might be added in the future, but none are in common use now). Practically, this adds another key generation option "verify-required" that yields a key that requires a PIN before each authentication. feedback markus@ and Pedro Martelletto; ok markus@ OpenBSD-Commit-ID: 57fd461e4366f87c47502c5614ec08573e6d6a15
-rw-r--r--krl.c7
-rw-r--r--monitor.c4
-rw-r--r--monitor_wrap.c4
-rw-r--r--monitor_wrap.h5
-rw-r--r--sk-usbhid.c38
-rw-r--r--ssh-agent.c5
-rw-r--r--ssh-keygen.122
-rw-r--r--ssh-keygen.c55
-rw-r--r--ssh-keysign.c4
-rw-r--r--ssh_api.c10
-rw-r--r--sshconnect2.c37
-rw-r--r--sshd.c8
-rw-r--r--sshkey.c20
-rw-r--r--sshkey.h11
-rw-r--r--sshsig.c16
-rw-r--r--sshsig.h8
16 files changed, 164 insertions, 90 deletions
diff --git a/krl.c b/krl.c
index c431f7047..3a69b636a 100644
--- a/krl.c
+++ b/krl.c
@@ -14,7 +14,7 @@
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */ 15 */
16 16
17/* $OpenBSD: krl.c,v 1.50 2020/04/03 05:48:57 djm Exp $ */ 17/* $OpenBSD: krl.c,v 1.51 2020/08/27 01:06:18 djm Exp $ */
18 18
19#include "includes.h" 19#include "includes.h"
20 20
@@ -812,9 +812,10 @@ ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf,
812 if ((r = sshbuf_put_u8(buf, KRL_SECTION_SIGNATURE)) != 0 || 812 if ((r = sshbuf_put_u8(buf, KRL_SECTION_SIGNATURE)) != 0 ||
813 (r = sshkey_puts(sign_keys[i], buf)) != 0) 813 (r = sshkey_puts(sign_keys[i], buf)) != 0)
814 goto out; 814 goto out;
815 815 /* XXX support sk-* keys */
816 if ((r = sshkey_sign(sign_keys[i], &sblob, &slen, 816 if ((r = sshkey_sign(sign_keys[i], &sblob, &slen,
817 sshbuf_ptr(buf), sshbuf_len(buf), NULL, NULL, 0)) != 0) 817 sshbuf_ptr(buf), sshbuf_len(buf), NULL, NULL,
818 NULL, 0)) != 0)
818 goto out; 819 goto out;
819 KRL_DBG(("%s: signature sig len %zu", __func__, slen)); 820 KRL_DBG(("%s: signature sig len %zu", __func__, slen));
820 if ((r = sshbuf_put_string(buf, sblob, slen)) != 0) 821 if ((r = sshbuf_put_string(buf, sblob, slen)) != 0)
diff --git a/monitor.c b/monitor.c
index 0107a7eba..7c3e6aafe 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: monitor.c,v 1.212 2020/07/07 02:47:21 deraadt Exp $ */ 1/* $OpenBSD: monitor.c,v 1.213 2020/08/27 01:06:18 djm Exp $ */
2/* 2/*
3 * Copyright 2002 Niels Provos <provos@citi.umich.edu> 3 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
4 * Copyright 2002 Markus Friedl <markus@openbsd.org> 4 * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -679,7 +679,7 @@ mm_answer_sign(struct ssh *ssh, int sock, struct sshbuf *m)
679 679
680 if ((key = get_hostkey_by_index(keyid)) != NULL) { 680 if ((key = get_hostkey_by_index(keyid)) != NULL) {
681 if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, alg, 681 if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, alg,
682 options.sk_provider, compat)) != 0) 682 options.sk_provider, NULL, compat)) != 0)
683 fatal("%s: sshkey_sign failed: %s", 683 fatal("%s: sshkey_sign failed: %s",
684 __func__, ssh_err(r)); 684 __func__, ssh_err(r));
685 } else if ((key = get_hostkey_public_by_index(keyid, ssh)) != NULL && 685 } else if ((key = get_hostkey_public_by_index(keyid, ssh)) != NULL &&
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 001a8fa1c..5e38d83eb 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: monitor_wrap.c,v 1.117 2019/12/15 18:57:30 djm Exp $ */ 1/* $OpenBSD: monitor_wrap.c,v 1.118 2020/08/27 01:06:18 djm Exp $ */
2/* 2/*
3 * Copyright 2002 Niels Provos <provos@citi.umich.edu> 3 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
4 * Copyright 2002 Markus Friedl <markus@openbsd.org> 4 * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -216,7 +216,7 @@ mm_choose_dh(int min, int nbits, int max)
216int 216int
217mm_sshkey_sign(struct ssh *ssh, struct sshkey *key, u_char **sigp, size_t *lenp, 217mm_sshkey_sign(struct ssh *ssh, struct sshkey *key, u_char **sigp, size_t *lenp,
218 const u_char *data, size_t datalen, const char *hostkey_alg, 218 const u_char *data, size_t datalen, const char *hostkey_alg,
219 const char *sk_provider, u_int compat) 219 const char *sk_provider, const char *sk_pin, u_int compat)
220{ 220{
221 struct kex *kex = *pmonitor->m_pkex; 221 struct kex *kex = *pmonitor->m_pkex;
222 struct sshbuf *m; 222 struct sshbuf *m;
diff --git a/monitor_wrap.h b/monitor_wrap.h
index 23ab096aa..0db38c206 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: monitor_wrap.h,v 1.44 2019/11/25 00:51:37 djm Exp $ */ 1/* $OpenBSD: monitor_wrap.h,v 1.45 2020/08/27 01:06:18 djm Exp $ */
2 2
3/* 3/*
4 * Copyright 2002 Niels Provos <provos@citi.umich.edu> 4 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -46,7 +46,8 @@ int mm_is_monitor(void);
46DH *mm_choose_dh(int, int, int); 46DH *mm_choose_dh(int, int, int);
47#endif 47#endif
48int mm_sshkey_sign(struct ssh *, struct sshkey *, u_char **, size_t *, 48int mm_sshkey_sign(struct ssh *, struct sshkey *, u_char **, size_t *,
49 const u_char *, size_t, const char *, const char *, u_int compat); 49 const u_char *, size_t, const char *, const char *,
50 const char *, u_int compat);
50void mm_inform_authserv(char *, char *); 51void mm_inform_authserv(char *, char *);
51struct passwd *mm_getpwnamallow(struct ssh *, const char *); 52struct passwd *mm_getpwnamallow(struct ssh *, const char *);
52char *mm_auth2_read_banner(void); 53char *mm_auth2_read_banner(void);
diff --git a/sk-usbhid.c b/sk-usbhid.c
index 2a573caa2..1dd834883 100644
--- a/sk-usbhid.c
+++ b/sk-usbhid.c
@@ -163,7 +163,8 @@ pick_first_device(void)
163/* Check if the specified key handle exists on a given device. */ 163/* Check if the specified key handle exists on a given device. */
164static int 164static int
165try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len, 165try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len,
166 const char *application, const uint8_t *key_handle, size_t key_handle_len) 166 const char *application, const uint8_t *key_handle, size_t key_handle_len,
167 uint8_t flags, const char *pin)
167{ 168{
168 fido_assert_t *assert = NULL; 169 fido_assert_t *assert = NULL;
169 int r = FIDO_ERR_INTERNAL; 170 int r = FIDO_ERR_INTERNAL;
@@ -191,7 +192,7 @@ try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len,
191 skdebug(__func__, "fido_assert_up: %s", fido_strerr(r)); 192 skdebug(__func__, "fido_assert_up: %s", fido_strerr(r));
192 goto out; 193 goto out;
193 } 194 }
194 r = fido_dev_get_assert(dev, assert, NULL); 195 r = fido_dev_get_assert(dev, assert, pin);
195 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); 196 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
196 if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) { 197 if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) {
197 /* U2F tokens may return this */ 198 /* U2F tokens may return this */
@@ -206,7 +207,8 @@ try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len,
206/* Iterate over configured devices looking for a specific key handle */ 207/* Iterate over configured devices looking for a specific key handle */
207static fido_dev_t * 208static fido_dev_t *
208find_device(const char *path, const uint8_t *message, size_t message_len, 209find_device(const char *path, const uint8_t *message, size_t message_len,
209 const char *application, const uint8_t *key_handle, size_t key_handle_len) 210 const char *application, const uint8_t *key_handle, size_t key_handle_len,
211 uint8_t flags, const char *pin)
210{ 212{
211 fido_dev_info_t *devlist = NULL; 213 fido_dev_info_t *devlist = NULL;
212 fido_dev_t *dev = NULL; 214 fido_dev_t *dev = NULL;
@@ -260,7 +262,7 @@ find_device(const char *path, const uint8_t *message, size_t message_len,
260 continue; 262 continue;
261 } 263 }
262 if (try_device(dev, message, message_len, application, 264 if (try_device(dev, message, message_len, application,
263 key_handle, key_handle_len) == 0) { 265 key_handle, key_handle_len, flags, pin) == 0) {
264 skdebug(__func__, "found key"); 266 skdebug(__func__, "found key");
265 break; 267 break;
266 } 268 }
@@ -570,19 +572,23 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
570 skdebug(__func__, "fido_dev_open: %s", fido_strerr(r)); 572 skdebug(__func__, "fido_dev_open: %s", fido_strerr(r));
571 goto out; 573 goto out;
572 } 574 }
573 if ((flags & SSH_SK_RESIDENT_KEY) != 0) { 575 if ((flags & (SSH_SK_RESIDENT_KEY|SSH_SK_USER_VERIFICATION_REQD)) != 0) {
574 if (check_sk_extensions(dev, "credProtect", &credprot) < 0) { 576 if (check_sk_extensions(dev, "credProtect", &credprot) < 0) {
575 skdebug(__func__, "check_sk_extensions failed"); 577 skdebug(__func__, "check_sk_extensions failed");
576 goto out; 578 goto out;
577 } 579 }
578 if (credprot == 0) { 580 if (credprot == 0) {
579 skdebug(__func__, "refusing to create unprotected " 581 skdebug(__func__, "refusing to create unprotected "
580 "resident key"); 582 "resident/verify-required key");
581 ret = SSH_SK_ERR_UNSUPPORTED; 583 ret = SSH_SK_ERR_UNSUPPORTED;
582 goto out; 584 goto out;
583 } 585 }
584 if ((r = fido_cred_set_prot(cred, 586 if ((flags & SSH_SK_USER_VERIFICATION_REQD))
585 FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID)) != FIDO_OK) { 587 credprot = FIDO_CRED_PROT_UV_REQUIRED;
588 else
589 credprot = FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID;
590
591 if ((r = fido_cred_set_prot(cred, credprot)) != FIDO_OK) {
586 skdebug(__func__, "fido_cred_set_prot: %s", 592 skdebug(__func__, "fido_cred_set_prot: %s",
587 fido_strerr(r)); 593 fido_strerr(r));
588 ret = fidoerr_to_skerr(r); 594 ret = fidoerr_to_skerr(r);
@@ -826,7 +832,7 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
826 goto out; 832 goto out;
827 } 833 }
828 if ((dev = find_device(device, message, sizeof(message), 834 if ((dev = find_device(device, message, sizeof(message),
829 application, key_handle, key_handle_len)) == NULL) { 835 application, key_handle, key_handle_len, flags, pin)) == NULL) {
830 skdebug(__func__, "couldn't find device for key handle"); 836 skdebug(__func__, "couldn't find device for key handle");
831 goto out; 837 goto out;
832 } 838 }
@@ -855,8 +861,15 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
855 skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r)); 861 skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r));
856 goto out; 862 goto out;
857 } 863 }
858 if ((r = fido_dev_get_assert(dev, assert, NULL)) != FIDO_OK) { 864 if (pin == NULL && (flags & SSH_SK_USER_VERIFICATION_REQD) &&
865 (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) {
866 skdebug(__func__, "fido_assert_set_uv: %s", fido_strerr(r));
867 ret = FIDO_ERR_PIN_REQUIRED;
868 goto out;
869 }
870 if ((r = fido_dev_get_assert(dev, assert, pin)) != FIDO_OK) {
859 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r)); 871 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
872 ret = fidoerr_to_skerr(r);
860 goto out; 873 goto out;
861 } 874 }
862 if ((response = calloc(1, sizeof(*response))) == NULL) { 875 if ((response = calloc(1, sizeof(*response))) == NULL) {
@@ -978,8 +991,9 @@ read_rks(const char *devpath, const char *pin,
978 continue; 991 continue;
979 } 992 }
980 skdebug(__func__, "Device %s RP \"%s\" slot %zu: " 993 skdebug(__func__, "Device %s RP \"%s\" slot %zu: "
981 "type %d", devpath, fido_credman_rp_id(rp, i), j, 994 "type %d flags 0x%02x prot 0x%02x", devpath,
982 fido_cred_type(cred)); 995 fido_credman_rp_id(rp, i), j, fido_cred_type(cred),
996 fido_cred_flags(cred), fido_cred_prot(cred));
983 997
984 /* build response entry */ 998 /* build response entry */
985 if ((srk = calloc(1, sizeof(*srk))) == NULL || 999 if ((srk = calloc(1, sizeof(*srk))) == NULL ||
diff --git a/ssh-agent.c b/ssh-agent.c
index 5f7ac8b91..d24a63089 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-agent.c,v 1.262 2020/07/05 23:59:45 djm Exp $ */ 1/* $OpenBSD: ssh-agent.c,v 1.263 2020/08/27 01:06:18 djm 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
@@ -407,9 +407,10 @@ process_sign_request2(SocketEntry *e)
407 sshkey_type(id->key), fp); 407 sshkey_type(id->key), fp);
408 } 408 }
409 } 409 }
410 /* XXX support PIN required FIDO keys */
410 if ((r = sshkey_sign(id->key, &signature, &slen, 411 if ((r = sshkey_sign(id->key, &signature, &slen,
411 data, dlen, agent_decode_alg(key, flags), 412 data, dlen, agent_decode_alg(key, flags),
412 id->sk_provider, compat)) != 0) { 413 id->sk_provider, NULL, compat)) != 0) {
413 error("%s: sshkey_sign: %s", __func__, ssh_err(r)); 414 error("%s: sshkey_sign: %s", __func__, ssh_err(r));
414 goto send; 415 goto send;
415 } 416 }
diff --git a/ssh-keygen.1 b/ssh-keygen.1
index 9198a511f..7e0558fe1 100644
--- a/ssh-keygen.1
+++ b/ssh-keygen.1
@@ -1,4 +1,4 @@
1.\" $OpenBSD: ssh-keygen.1,v 1.205 2020/07/15 07:50:46 solene Exp $ 1.\" $OpenBSD: ssh-keygen.1,v 1.206 2020/08/27 01:06:18 djm 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
@@ -35,7 +35,7 @@
35.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37.\" 37.\"
38.Dd $Mdocdate: July 15 2020 $ 38.Dd $Mdocdate: August 27 2020 $
39.Dt SSH-KEYGEN 1 39.Dt SSH-KEYGEN 1
40.Os 40.Os
41.Sh NAME 41.Sh NAME
@@ -511,6 +511,12 @@ A username to be associated with a resident key,
511overriding the empty default username. 511overriding the empty default username.
512Specifying a username may be useful when generating multiple resident keys 512Specifying a username may be useful when generating multiple resident keys
513for the same application name. 513for the same application name.
514.It Cm verify-required
515Indicate that this private key should require user verification for
516each signature.
517Not all FIDO tokens support support this option.
518Currently PIN authentication is the only supported verification method,
519but other methods may be supported in the future.
514.It Cm write-attestation Ns = Ns Ar path 520.It Cm write-attestation Ns = Ns Ar path
515May be used at key generation time to record the attestation certificate 521May be used at key generation time to record the attestation certificate
516returned from FIDO tokens during key generation. 522returned from FIDO tokens during key generation.
@@ -961,7 +967,7 @@ by
961Allows X11 forwarding. 967Allows X11 forwarding.
962.Pp 968.Pp
963.It Ic no-touch-required 969.It Ic no-touch-required
964Do not require signatures made using this key require demonstration 970Do not require signatures made using this key include demonstration
965of user presence (e.g. by having the user touch the authenticator). 971of user presence (e.g. by having the user touch the authenticator).
966This option only makes sense for the FIDO authenticator algorithms 972This option only makes sense for the FIDO authenticator algorithms
967.Cm ecdsa-sk 973.Cm ecdsa-sk
@@ -974,6 +980,16 @@ The
974.Ar address_list 980.Ar address_list
975is a comma-separated list of one or more address/netmask pairs in CIDR 981is a comma-separated list of one or more address/netmask pairs in CIDR
976format. 982format.
983.Pp
984.It Ic verify-required
985Require signatures made using this key indicate that the user was first
986verified.
987This option only makes sense for the FIDO authenticator algorithms
988.Cm ecdsa-sk
989and
990.Cm ed25519-sk .
991Currently PIN authentication is the only supported verification method,
992but other methods may be supported in the future.
977.El 993.El
978.Pp 994.Pp
979At present, no standard options are valid for host keys. 995At present, no standard options are valid for host keys.
diff --git a/ssh-keygen.c b/ssh-keygen.c
index cc092368e..89ef9a143 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keygen.c,v 1.415 2020/08/03 02:53:51 djm Exp $ */ 1/* $OpenBSD: ssh-keygen.c,v 1.416 2020/08/27 01:06:18 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -589,7 +589,7 @@ do_convert_private_ssh2(struct sshbuf *b)
589 589
590 /* try the key */ 590 /* try the key */
591 if (sshkey_sign(key, &sig, &slen, data, sizeof(data), 591 if (sshkey_sign(key, &sig, &slen, data, sizeof(data),
592 NULL, NULL, 0) != 0 || 592 NULL, NULL, NULL, 0) != 0 ||
593 sshkey_verify(key, sig, slen, data, sizeof(data), 593 sshkey_verify(key, sig, slen, data, sizeof(data),
594 NULL, 0, NULL) != 0) { 594 NULL, 0, NULL) != 0) {
595 sshkey_free(key); 595 sshkey_free(key);
@@ -1727,7 +1727,8 @@ load_pkcs11_key(char *path)
1727static int 1727static int
1728agent_signer(struct sshkey *key, u_char **sigp, size_t *lenp, 1728agent_signer(struct sshkey *key, u_char **sigp, size_t *lenp,
1729 const u_char *data, size_t datalen, 1729 const u_char *data, size_t datalen,
1730 const char *alg, const char *provider, u_int compat, void *ctx) 1730 const char *alg, const char *provider, const char *pin,
1731 u_int compat, void *ctx)
1731{ 1732{
1732 int *agent_fdp = (int *)ctx; 1733 int *agent_fdp = (int *)ctx;
1733 1734
@@ -1744,7 +1745,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1744 u_int n; 1745 u_int n;
1745 struct sshkey *ca, *public; 1746 struct sshkey *ca, *public;
1746 char valid[64], *otmp, *tmp, *cp, *out, *comment; 1747 char valid[64], *otmp, *tmp, *cp, *out, *comment;
1747 char *ca_fp = NULL, **plist = NULL; 1748 char *ca_fp = NULL, **plist = NULL, *pin = NULL;
1748 struct ssh_identitylist *agent_ids; 1749 struct ssh_identitylist *agent_ids;
1749 size_t j; 1750 size_t j;
1750 struct notifier_ctx *notifier = NULL; 1751 struct notifier_ctx *notifier = NULL;
@@ -1785,6 +1786,12 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1785 } else { 1786 } else {
1786 /* CA key is assumed to be a private key on the filesystem */ 1787 /* CA key is assumed to be a private key on the filesystem */
1787 ca = load_identity(tmp, NULL); 1788 ca = load_identity(tmp, NULL);
1789 if (sshkey_is_sk(ca) &&
1790 (ca->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) {
1791 if ((pin = read_passphrase("Enter PIN for CA key: ",
1792 RP_ALLOW_STDIN)) == NULL)
1793 fatal("%s: couldn't read PIN", __func__);
1794 }
1788 } 1795 }
1789 free(tmp); 1796 free(tmp);
1790 1797
@@ -1844,7 +1851,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1844 1851
1845 if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) { 1852 if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) {
1846 if ((r = sshkey_certify_custom(public, ca, 1853 if ((r = sshkey_certify_custom(public, ca,
1847 key_type_name, sk_provider, agent_signer, 1854 key_type_name, sk_provider, NULL, agent_signer,
1848 &agent_fd)) != 0) 1855 &agent_fd)) != 0)
1849 fatal("Couldn't certify key %s via agent: %s", 1856 fatal("Couldn't certify key %s via agent: %s",
1850 tmp, ssh_err(r)); 1857 tmp, ssh_err(r));
@@ -1856,7 +1863,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1856 sshkey_type(ca), ca_fp); 1863 sshkey_type(ca), ca_fp);
1857 } 1864 }
1858 r = sshkey_certify(public, ca, key_type_name, 1865 r = sshkey_certify(public, ca, key_type_name,
1859 sk_provider); 1866 sk_provider, pin);
1860 notify_complete(notifier); 1867 notify_complete(notifier);
1861 if (r != 0) 1868 if (r != 0)
1862 fatal("Couldn't certify key %s: %s", 1869 fatal("Couldn't certify key %s: %s",
@@ -1890,6 +1897,8 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1890 if (cert_serial_autoinc) 1897 if (cert_serial_autoinc)
1891 cert_serial++; 1898 cert_serial++;
1892 } 1899 }
1900 if (pin != NULL)
1901 freezero(pin, strlen(pin));
1893 free(ca_fp); 1902 free(ca_fp);
1894#ifdef ENABLE_PKCS11 1903#ifdef ENABLE_PKCS11
1895 pkcs11_terminate(); 1904 pkcs11_terminate();
@@ -2526,6 +2535,7 @@ sign_one(struct sshkey *signkey, const char *filename, int fd,
2526 struct sshbuf *sigbuf = NULL, *abuf = NULL; 2535 struct sshbuf *sigbuf = NULL, *abuf = NULL;
2527 int r = SSH_ERR_INTERNAL_ERROR, wfd = -1, oerrno; 2536 int r = SSH_ERR_INTERNAL_ERROR, wfd = -1, oerrno;
2528 char *wfile = NULL, *asig = NULL, *fp = NULL; 2537 char *wfile = NULL, *asig = NULL, *fp = NULL;
2538 char *pin = NULL, *prompt = NULL;
2529 2539
2530 if (!quiet) { 2540 if (!quiet) {
2531 if (fd == STDIN_FILENO) 2541 if (fd == STDIN_FILENO)
@@ -2533,17 +2543,25 @@ sign_one(struct sshkey *signkey, const char *filename, int fd,
2533 else 2543 else
2534 fprintf(stderr, "Signing file %s\n", filename); 2544 fprintf(stderr, "Signing file %s\n", filename);
2535 } 2545 }
2536 if (signer == NULL && sshkey_is_sk(signkey) && 2546 if (signer == NULL && sshkey_is_sk(signkey)) {
2537 (signkey->sk_flags & SSH_SK_USER_PRESENCE_REQD)) { 2547 if ((signkey->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) {
2538 if ((fp = sshkey_fingerprint(signkey, fingerprint_hash, 2548 xasprintf(&prompt, "Enter PIN for %s key: ",
2539 SSH_FP_DEFAULT)) == NULL) 2549 sshkey_type(signkey));
2540 fatal("%s: sshkey_fingerprint failed", __func__); 2550 if ((pin = read_passphrase(prompt,
2541 fprintf(stderr, "Confirm user presence for key %s %s\n", 2551 RP_ALLOW_STDIN)) == NULL)
2542 sshkey_type(signkey), fp); 2552 fatal("%s: couldn't read PIN", __func__);
2543 free(fp); 2553 }
2554 if ((signkey->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
2555 if ((fp = sshkey_fingerprint(signkey, fingerprint_hash,
2556 SSH_FP_DEFAULT)) == NULL)
2557 fatal("%s: fingerprint failed", __func__);
2558 fprintf(stderr, "Confirm user presence for key %s %s\n",
2559 sshkey_type(signkey), fp);
2560 free(fp);
2561 }
2544 } 2562 }
2545 if ((r = sshsig_sign_fd(signkey, NULL, sk_provider, fd, sig_namespace, 2563 if ((r = sshsig_sign_fd(signkey, NULL, sk_provider, pin,
2546 &sigbuf, signer, signer_ctx)) != 0) { 2564 fd, sig_namespace, &sigbuf, signer, signer_ctx)) != 0) {
2547 error("Signing %s failed: %s", filename, ssh_err(r)); 2565 error("Signing %s failed: %s", filename, ssh_err(r));
2548 goto out; 2566 goto out;
2549 } 2567 }
@@ -2591,7 +2609,10 @@ sign_one(struct sshkey *signkey, const char *filename, int fd,
2591 r = 0; 2609 r = 0;
2592 out: 2610 out:
2593 free(wfile); 2611 free(wfile);
2612 free(prompt);
2594 free(asig); 2613 free(asig);
2614 if (pin != NULL)
2615 freezero(pin, strlen(pin));
2595 sshbuf_free(abuf); 2616 sshbuf_free(abuf);
2596 sshbuf_free(sigbuf); 2617 sshbuf_free(sigbuf);
2597 if (wfd != -1) 2618 if (wfd != -1)
@@ -3554,6 +3575,8 @@ main(int argc, char **argv)
3554 for (i = 0; i < nopts; i++) { 3575 for (i = 0; i < nopts; i++) {
3555 if (strcasecmp(opts[i], "no-touch-required") == 0) { 3576 if (strcasecmp(opts[i], "no-touch-required") == 0) {
3556 sk_flags &= ~SSH_SK_USER_PRESENCE_REQD; 3577 sk_flags &= ~SSH_SK_USER_PRESENCE_REQD;
3578 } else if (strcasecmp(opts[i], "verify-required") == 0) {
3579 sk_flags |= SSH_SK_USER_VERIFICATION_REQD;
3557 } else if (strcasecmp(opts[i], "resident") == 0) { 3580 } else if (strcasecmp(opts[i], "resident") == 0) {
3558 sk_flags |= SSH_SK_RESIDENT_KEY; 3581 sk_flags |= SSH_SK_RESIDENT_KEY;
3559 } else if (strncasecmp(opts[i], "device=", 7) == 0) { 3582 } else if (strncasecmp(opts[i], "device=", 7) == 0) {
diff --git a/ssh-keysign.c b/ssh-keysign.c
index 3e3ea3e14..7991e0f01 100644
--- a/ssh-keysign.c
+++ b/ssh-keysign.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keysign.c,v 1.63 2019/11/18 16:10:05 naddy Exp $ */ 1/* $OpenBSD: ssh-keysign.c,v 1.64 2020/08/27 01:06:18 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2002 Markus Friedl. All rights reserved. 3 * Copyright (c) 2002 Markus Friedl. All rights reserved.
4 * 4 *
@@ -278,7 +278,7 @@ main(int argc, char **argv)
278 } 278 }
279 279
280 if ((r = sshkey_sign(keys[i], &signature, &slen, data, dlen, 280 if ((r = sshkey_sign(keys[i], &signature, &slen, data, dlen,
281 NULL, NULL, 0)) != 0) 281 NULL, NULL, NULL, 0)) != 0)
282 fatal("sshkey_sign failed: %s", ssh_err(r)); 282 fatal("sshkey_sign failed: %s", ssh_err(r));
283 free(data); 283 free(data);
284 284
diff --git a/ssh_api.c b/ssh_api.c
index a0358d4be..129404b20 100644
--- a/ssh_api.c
+++ b/ssh_api.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh_api.c,v 1.20 2020/07/01 16:28:31 markus Exp $ */ 1/* $OpenBSD: ssh_api.c,v 1.21 2020/08/27 01:06:18 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2012 Markus Friedl. All rights reserved. 3 * Copyright (c) 2012 Markus Friedl. All rights reserved.
4 * 4 *
@@ -54,7 +54,7 @@ int _ssh_host_key_sign(struct ssh *, struct sshkey *, struct sshkey *,
54 */ 54 */
55int use_privsep = 0; 55int use_privsep = 0;
56int mm_sshkey_sign(struct sshkey *, u_char **, u_int *, 56int mm_sshkey_sign(struct sshkey *, u_char **, u_int *,
57 const u_char *, u_int, const char *, const char *, u_int); 57 const u_char *, u_int, const char *, const char *, const char *, u_int);
58 58
59#ifdef WITH_OPENSSL 59#ifdef WITH_OPENSSL
60DH *mm_choose_dh(int, int, int); 60DH *mm_choose_dh(int, int, int);
@@ -66,8 +66,8 @@ u_int session_id2_len = 0;
66 66
67int 67int
68mm_sshkey_sign(struct sshkey *key, u_char **sigp, u_int *lenp, 68mm_sshkey_sign(struct sshkey *key, u_char **sigp, u_int *lenp,
69 const u_char *data, u_int datalen, const char *alg, const char *sk_provider, 69 const u_char *data, u_int datalen, const char *alg,
70 u_int compat) 70 const char *sk_provider, const char *sk_pin, u_int compat)
71{ 71{
72 return (-1); 72 return (-1);
73} 73}
@@ -567,5 +567,5 @@ _ssh_host_key_sign(struct ssh *ssh, struct sshkey *privkey,
567 const u_char *data, size_t dlen, const char *alg) 567 const u_char *data, size_t dlen, const char *alg)
568{ 568{
569 return sshkey_sign(privkey, signature, slen, data, dlen, 569 return sshkey_sign(privkey, signature, slen, data, dlen,
570 alg, NULL, ssh->compat); 570 alg, NULL, NULL, ssh->compat);
571} 571}
diff --git a/sshconnect2.c b/sshconnect2.c
index 74946da0d..347e348c6 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect2.c,v 1.324 2020/06/27 13:39:09 bket Exp $ */ 1/* $OpenBSD: sshconnect2.c,v 1.325 2020/08/27 01:06:18 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * Copyright (c) 2008 Damien Miller. All rights reserved. 4 * Copyright (c) 2008 Damien Miller. All rights reserved.
@@ -1175,7 +1175,7 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
1175 struct sshkey *sign_key = NULL, *prv = NULL; 1175 struct sshkey *sign_key = NULL, *prv = NULL;
1176 int r = SSH_ERR_INTERNAL_ERROR; 1176 int r = SSH_ERR_INTERNAL_ERROR;
1177 struct notifier_ctx *notifier = NULL; 1177 struct notifier_ctx *notifier = NULL;
1178 char *fp = NULL; 1178 char *fp = NULL, *pin = NULL, *prompt = NULL;
1179 1179
1180 *sigp = NULL; 1180 *sigp = NULL;
1181 *lenp = 0; 1181 *lenp = 0;
@@ -1204,20 +1204,28 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
1204 goto out; 1204 goto out;
1205 } 1205 }
1206 sign_key = prv; 1206 sign_key = prv;
1207 if (sshkey_is_sk(sign_key) && 1207 if (sshkey_is_sk(sign_key)) {
1208 (sign_key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) { 1208 if ((sign_key->sk_flags &
1209 /* XXX match batch mode should just skip these keys? */ 1209 SSH_SK_USER_VERIFICATION_REQD)) {
1210 if ((fp = sshkey_fingerprint(sign_key, 1210 xasprintf(&prompt, "Enter PIN for %s key %s: ",
1211 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 1211 sshkey_type(sign_key), id->filename);
1212 fatal("%s: sshkey_fingerprint", __func__); 1212 pin = read_passphrase(prompt, 0);
1213 notifier = notify_start(options.batch_mode, 1213 }
1214 "Confirm user presence for key %s %s", 1214 if ((sign_key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
1215 sshkey_type(sign_key), fp); 1215 /* XXX should batch mode just skip these? */
1216 free(fp); 1216 if ((fp = sshkey_fingerprint(sign_key,
1217 options.fingerprint_hash,
1218 SSH_FP_DEFAULT)) == NULL)
1219 fatal("%s: fingerprint", __func__);
1220 notifier = notify_start(options.batch_mode,
1221 "Confirm user presence for key %s %s",
1222 sshkey_type(sign_key), fp);
1223 free(fp);
1224 }
1217 } 1225 }
1218 } 1226 }
1219 if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen, 1227 if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen,
1220 alg, options.sk_provider, compat)) != 0) { 1228 alg, options.sk_provider, pin, compat)) != 0) {
1221 debug("%s: sshkey_sign: %s", __func__, ssh_err(r)); 1229 debug("%s: sshkey_sign: %s", __func__, ssh_err(r));
1222 goto out; 1230 goto out;
1223 } 1231 }
@@ -1232,6 +1240,9 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
1232 /* success */ 1240 /* success */
1233 r = 0; 1241 r = 0;
1234 out: 1242 out:
1243 free(prompt);
1244 if (pin != NULL)
1245 freezero(pin, strlen(pin));
1235 notify_complete(notifier); 1246 notify_complete(notifier);
1236 sshkey_free(prv); 1247 sshkey_free(prv);
1237 return r; 1248 return r;
diff --git a/sshd.c b/sshd.c
index d9a159f6a..8aa7f3df6 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshd.c,v 1.560 2020/07/03 10:12:26 markus Exp $ */ 1/* $OpenBSD: sshd.c,v 1.561 2020/08/27 01:06:19 djm 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
@@ -2338,19 +2338,19 @@ sshd_hostkey_sign(struct ssh *ssh, struct sshkey *privkey,
2338 if (use_privsep) { 2338 if (use_privsep) {
2339 if (privkey) { 2339 if (privkey) {
2340 if (mm_sshkey_sign(ssh, privkey, signature, slenp, 2340 if (mm_sshkey_sign(ssh, privkey, signature, slenp,
2341 data, dlen, alg, options.sk_provider, 2341 data, dlen, alg, options.sk_provider, NULL,
2342 ssh->compat) < 0) 2342 ssh->compat) < 0)
2343 fatal("%s: privkey sign failed", __func__); 2343 fatal("%s: privkey sign failed", __func__);
2344 } else { 2344 } else {
2345 if (mm_sshkey_sign(ssh, pubkey, signature, slenp, 2345 if (mm_sshkey_sign(ssh, pubkey, signature, slenp,
2346 data, dlen, alg, options.sk_provider, 2346 data, dlen, alg, options.sk_provider, NULL,
2347 ssh->compat) < 0) 2347 ssh->compat) < 0)
2348 fatal("%s: pubkey sign failed", __func__); 2348 fatal("%s: pubkey sign failed", __func__);
2349 } 2349 }
2350 } else { 2350 } else {
2351 if (privkey) { 2351 if (privkey) {
2352 if (sshkey_sign(privkey, signature, slenp, data, dlen, 2352 if (sshkey_sign(privkey, signature, slenp, data, dlen,
2353 alg, options.sk_provider, ssh->compat) < 0) 2353 alg, options.sk_provider, NULL, ssh->compat) < 0)
2354 fatal("%s: privkey sign failed", __func__); 2354 fatal("%s: privkey sign failed", __func__);
2355 } else { 2355 } else {
2356 if ((r = ssh_agent_sign(auth_sock, pubkey, 2356 if ((r = ssh_agent_sign(auth_sock, pubkey,
diff --git a/sshkey.c b/sshkey.c
index 10b9e4676..ac451f1a8 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshkey.c,v 1.110 2020/06/24 15:07:33 markus Exp $ */ 1/* $OpenBSD: sshkey.c,v 1.111 2020/08/27 01:06:19 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
4 * Copyright (c) 2008 Alexander von Gernler. All rights reserved. 4 * Copyright (c) 2008 Alexander von Gernler. All rights reserved.
@@ -2727,7 +2727,7 @@ int
2727sshkey_sign(struct sshkey *key, 2727sshkey_sign(struct sshkey *key,
2728 u_char **sigp, size_t *lenp, 2728 u_char **sigp, size_t *lenp,
2729 const u_char *data, size_t datalen, 2729 const u_char *data, size_t datalen,
2730 const char *alg, const char *sk_provider, u_int compat) 2730 const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
2731{ 2731{
2732 int was_shielded = sshkey_is_shielded(key); 2732 int was_shielded = sshkey_is_shielded(key);
2733 int r2, r = SSH_ERR_INTERNAL_ERROR; 2733 int r2, r = SSH_ERR_INTERNAL_ERROR;
@@ -2766,7 +2766,7 @@ sshkey_sign(struct sshkey *key,
2766 case KEY_ECDSA_SK_CERT: 2766 case KEY_ECDSA_SK_CERT:
2767 case KEY_ECDSA_SK: 2767 case KEY_ECDSA_SK:
2768 r = sshsk_sign(sk_provider, key, sigp, lenp, data, 2768 r = sshsk_sign(sk_provider, key, sigp, lenp, data,
2769 datalen, compat, /* XXX PIN */ NULL); 2769 datalen, compat, sk_pin);
2770 break; 2770 break;
2771#ifdef WITH_XMSS 2771#ifdef WITH_XMSS
2772 case KEY_XMSS: 2772 case KEY_XMSS:
@@ -2888,7 +2888,8 @@ sshkey_drop_cert(struct sshkey *k)
2888/* Sign a certified key, (re-)generating the signed certblob. */ 2888/* Sign a certified key, (re-)generating the signed certblob. */
2889int 2889int
2890sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg, 2890sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
2891 const char *sk_provider, sshkey_certify_signer *signer, void *signer_ctx) 2891 const char *sk_provider, const char *sk_pin,
2892 sshkey_certify_signer *signer, void *signer_ctx)
2892{ 2893{
2893 struct sshbuf *principals = NULL; 2894 struct sshbuf *principals = NULL;
2894 u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32]; 2895 u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32];
@@ -3026,7 +3027,7 @@ sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
3026 3027
3027 /* Sign the whole mess */ 3028 /* Sign the whole mess */
3028 if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert), 3029 if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert),
3029 sshbuf_len(cert), alg, sk_provider, 0, signer_ctx)) != 0) 3030 sshbuf_len(cert), alg, sk_provider, sk_pin, 0, signer_ctx)) != 0)
3030 goto out; 3031 goto out;
3031 /* Check and update signature_type against what was actually used */ 3032 /* Check and update signature_type against what was actually used */
3032 if ((ret = sshkey_get_sigtype(sig_blob, sig_len, &sigtype)) != 0) 3033 if ((ret = sshkey_get_sigtype(sig_blob, sig_len, &sigtype)) != 0)
@@ -3056,19 +3057,20 @@ sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
3056static int 3057static int
3057default_key_sign(struct sshkey *key, u_char **sigp, size_t *lenp, 3058default_key_sign(struct sshkey *key, u_char **sigp, size_t *lenp,
3058 const u_char *data, size_t datalen, 3059 const u_char *data, size_t datalen,
3059 const char *alg, const char *sk_provider, u_int compat, void *ctx) 3060 const char *alg, const char *sk_provider, const char *sk_pin,
3061 u_int compat, void *ctx)
3060{ 3062{
3061 if (ctx != NULL) 3063 if (ctx != NULL)
3062 return SSH_ERR_INVALID_ARGUMENT; 3064 return SSH_ERR_INVALID_ARGUMENT;
3063 return sshkey_sign(key, sigp, lenp, data, datalen, alg, 3065 return sshkey_sign(key, sigp, lenp, data, datalen, alg,
3064 sk_provider, compat); 3066 sk_provider, sk_pin, compat);
3065} 3067}
3066 3068
3067int 3069int
3068sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg, 3070sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg,
3069 const char *sk_provider) 3071 const char *sk_provider, const char *sk_pin)
3070{ 3072{
3071 return sshkey_certify_custom(k, ca, alg, sk_provider, 3073 return sshkey_certify_custom(k, ca, alg, sk_provider, sk_pin,
3072 default_key_sign, NULL); 3074 default_key_sign, NULL);
3073} 3075}
3074 3076
diff --git a/sshkey.h b/sshkey.h
index 9c1d4f637..2d8b62497 100644
--- a/sshkey.h
+++ b/sshkey.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshkey.h,v 1.45 2020/04/08 00:08:46 djm Exp $ */ 1/* $OpenBSD: sshkey.h,v 1.46 2020/08/27 01:06:19 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -200,12 +200,13 @@ size_t sshkey_format_cert_validity(const struct sshkey_cert *,
200int sshkey_check_cert_sigtype(const struct sshkey *, const char *); 200int sshkey_check_cert_sigtype(const struct sshkey *, const char *);
201 201
202int sshkey_certify(struct sshkey *, struct sshkey *, 202int sshkey_certify(struct sshkey *, struct sshkey *,
203 const char *, const char *); 203 const char *, const char *, const char *);
204/* Variant allowing use of a custom signature function (e.g. for ssh-agent) */ 204/* Variant allowing use of a custom signature function (e.g. for ssh-agent) */
205typedef int sshkey_certify_signer(struct sshkey *, u_char **, size_t *, 205typedef int sshkey_certify_signer(struct sshkey *, u_char **, size_t *,
206 const u_char *, size_t, const char *, const char *, u_int, void *); 206 const u_char *, size_t, const char *, const char *, const char *,
207 u_int, void *);
207int sshkey_certify_custom(struct sshkey *, struct sshkey *, const char *, 208int sshkey_certify_custom(struct sshkey *, struct sshkey *, const char *,
208 const char *, sshkey_certify_signer *, void *); 209 const char *, const char *, sshkey_certify_signer *, void *);
209 210
210int sshkey_ecdsa_nid_from_name(const char *); 211int sshkey_ecdsa_nid_from_name(const char *);
211int sshkey_curve_name_to_nid(const char *); 212int sshkey_curve_name_to_nid(const char *);
@@ -234,7 +235,7 @@ int sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *);
234int sshkey_putb_plain(const struct sshkey *, struct sshbuf *); 235int sshkey_putb_plain(const struct sshkey *, struct sshbuf *);
235 236
236int sshkey_sign(struct sshkey *, u_char **, size_t *, 237int sshkey_sign(struct sshkey *, u_char **, size_t *,
237 const u_char *, size_t, const char *, const char *, u_int); 238 const u_char *, size_t, const char *, const char *, const char *, u_int);
238int sshkey_verify(const struct sshkey *, const u_char *, size_t, 239int sshkey_verify(const struct sshkey *, const u_char *, size_t,
239 const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); 240 const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **);
240int sshkey_check_sigtype(const u_char *, size_t, const char *); 241int sshkey_check_sigtype(const u_char *, size_t, const char *);
diff --git a/sshsig.c b/sshsig.c
index 15f9cead6..658b8c852 100644
--- a/sshsig.c
+++ b/sshsig.c
@@ -151,7 +151,7 @@ done:
151 151
152static int 152static int
153sshsig_wrap_sign(struct sshkey *key, const char *hashalg, 153sshsig_wrap_sign(struct sshkey *key, const char *hashalg,
154 const char *sk_provider, const struct sshbuf *h_message, 154 const char *sk_provider, const char *sk_pin, const struct sshbuf *h_message,
155 const char *sig_namespace, struct sshbuf **out, 155 const char *sig_namespace, struct sshbuf **out,
156 sshsig_signer *signer, void *signer_ctx) 156 sshsig_signer *signer, void *signer_ctx)
157{ 157{
@@ -185,14 +185,14 @@ sshsig_wrap_sign(struct sshkey *key, const char *hashalg,
185 if (signer != NULL) { 185 if (signer != NULL) {
186 if ((r = signer(key, &sig, &slen, 186 if ((r = signer(key, &sig, &slen,
187 sshbuf_ptr(tosign), sshbuf_len(tosign), 187 sshbuf_ptr(tosign), sshbuf_len(tosign),
188 sign_alg, sk_provider, 0, signer_ctx)) != 0) { 188 sign_alg, sk_provider, sk_pin, 0, signer_ctx)) != 0) {
189 error("Couldn't sign message: %s", ssh_err(r)); 189 error("Couldn't sign message: %s", ssh_err(r));
190 goto done; 190 goto done;
191 } 191 }
192 } else { 192 } else {
193 if ((r = sshkey_sign(key, &sig, &slen, 193 if ((r = sshkey_sign(key, &sig, &slen,
194 sshbuf_ptr(tosign), sshbuf_len(tosign), 194 sshbuf_ptr(tosign), sshbuf_len(tosign),
195 sign_alg, sk_provider, 0)) != 0) { 195 sign_alg, sk_provider, sk_pin, 0)) != 0) {
196 error("Couldn't sign message: %s", ssh_err(r)); 196 error("Couldn't sign message: %s", ssh_err(r));
197 goto done; 197 goto done;
198 } 198 }
@@ -430,7 +430,8 @@ hash_buffer(const struct sshbuf *m, const char *hashalg, struct sshbuf **bp)
430} 430}
431 431
432int 432int
433sshsig_signb(struct sshkey *key, const char *hashalg, const char *sk_provider, 433sshsig_signb(struct sshkey *key, const char *hashalg,
434 const char *sk_provider, const char *sk_pin,
434 const struct sshbuf *message, const char *sig_namespace, 435 const struct sshbuf *message, const char *sig_namespace,
435 struct sshbuf **out, sshsig_signer *signer, void *signer_ctx) 436 struct sshbuf **out, sshsig_signer *signer, void *signer_ctx)
436{ 437{
@@ -445,7 +446,7 @@ sshsig_signb(struct sshkey *key, const char *hashalg, const char *sk_provider,
445 error("%s: hash_buffer failed: %s", __func__, ssh_err(r)); 446 error("%s: hash_buffer failed: %s", __func__, ssh_err(r));
446 goto out; 447 goto out;
447 } 448 }
448 if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, b, 449 if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b,
449 sig_namespace, out, signer, signer_ctx)) != 0) 450 sig_namespace, out, signer, signer_ctx)) != 0)
450 goto out; 451 goto out;
451 /* success */ 452 /* success */
@@ -558,7 +559,8 @@ hash_file(int fd, const char *hashalg, struct sshbuf **bp)
558} 559}
559 560
560int 561int
561sshsig_sign_fd(struct sshkey *key, const char *hashalg, const char *sk_provider, 562sshsig_sign_fd(struct sshkey *key, const char *hashalg,
563 const char *sk_provider, const char *sk_pin,
562 int fd, const char *sig_namespace, struct sshbuf **out, 564 int fd, const char *sig_namespace, struct sshbuf **out,
563 sshsig_signer *signer, void *signer_ctx) 565 sshsig_signer *signer, void *signer_ctx)
564{ 566{
@@ -573,7 +575,7 @@ sshsig_sign_fd(struct sshkey *key, const char *hashalg, const char *sk_provider,
573 error("%s: hash_file failed: %s", __func__, ssh_err(r)); 575 error("%s: hash_file failed: %s", __func__, ssh_err(r));
574 return r; 576 return r;
575 } 577 }
576 if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, b, 578 if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b,
577 sig_namespace, out, signer, signer_ctx)) != 0) 579 sig_namespace, out, signer, signer_ctx)) != 0)
578 goto out; 580 goto out;
579 /* success */ 581 /* success */
diff --git a/sshsig.h b/sshsig.h
index 63cc1ad1a..44157bc2a 100644
--- a/sshsig.h
+++ b/sshsig.h
@@ -23,7 +23,8 @@ struct sshsigopt;
23struct sshkey_sig_details; 23struct sshkey_sig_details;
24 24
25typedef int sshsig_signer(struct sshkey *, u_char **, size_t *, 25typedef int sshsig_signer(struct sshkey *, u_char **, size_t *,
26 const u_char *, size_t, const char *, const char *, u_int, void *); 26 const u_char *, size_t, const char *, const char *, const char *,
27 u_int, void *);
27 28
28/* Buffer-oriented API */ 29/* Buffer-oriented API */
29 30
@@ -33,7 +34,7 @@ typedef int sshsig_signer(struct sshkey *, u_char **, size_t *,
33 * out is populated with the detached signature, or NULL on failure. 34 * out is populated with the detached signature, or NULL on failure.
34 */ 35 */
35int sshsig_signb(struct sshkey *key, const char *hashalg, 36int sshsig_signb(struct sshkey *key, const char *hashalg,
36 const char *sk_provider, const struct sshbuf *message, 37 const char *sk_provider, const char *sk_pin, const struct sshbuf *message,
37 const char *sig_namespace, struct sshbuf **out, 38 const char *sig_namespace, struct sshbuf **out,
38 sshsig_signer *signer, void *signer_ctx); 39 sshsig_signer *signer, void *signer_ctx);
39 40
@@ -54,7 +55,8 @@ int sshsig_verifyb(struct sshbuf *signature,
54 * out is populated with the detached signature, or NULL on failure. 55 * out is populated with the detached signature, or NULL on failure.
55 */ 56 */
56int sshsig_sign_fd(struct sshkey *key, const char *hashalg, 57int sshsig_sign_fd(struct sshkey *key, const char *hashalg,
57 const char *sk_provider, int fd, const char *sig_namespace, 58 const char *sk_provider, const char *sk_pin,
59 int fd, const char *sig_namespace,
58 struct sshbuf **out, sshsig_signer *signer, void *signer_ctx); 60 struct sshbuf **out, sshsig_signer *signer, void *signer_ctx);
59 61
60/* 62/*