mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-07-31 01:35:11 +02:00
upstream: ssh-agent support for U2F/FIDO keys
feedback & ok markus@ OpenBSD-Commit-ID: bb544a44bc32e45d2ec8bf652db2046f38360acb
This commit is contained in:
parent
eebec620c9
commit
07da39f71d
11
Makefile.in
11
Makefile.in
@ -24,6 +24,7 @@ ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass
|
|||||||
SFTP_SERVER=$(libexecdir)/sftp-server
|
SFTP_SERVER=$(libexecdir)/sftp-server
|
||||||
SSH_KEYSIGN=$(libexecdir)/ssh-keysign
|
SSH_KEYSIGN=$(libexecdir)/ssh-keysign
|
||||||
SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
|
SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
|
||||||
|
SSH_SK_HELPER=$(libexecdir)/ssh-sk-helper
|
||||||
PRIVSEP_PATH=@PRIVSEP_PATH@
|
PRIVSEP_PATH=@PRIVSEP_PATH@
|
||||||
SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
|
SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
|
||||||
STRIP_OPT=@STRIP_OPT@
|
STRIP_OPT=@STRIP_OPT@
|
||||||
@ -35,6 +36,7 @@ PATHS= -DSSHDIR=\"$(sysconfdir)\" \
|
|||||||
-D_PATH_SFTP_SERVER=\"$(SFTP_SERVER)\" \
|
-D_PATH_SFTP_SERVER=\"$(SFTP_SERVER)\" \
|
||||||
-D_PATH_SSH_KEY_SIGN=\"$(SSH_KEYSIGN)\" \
|
-D_PATH_SSH_KEY_SIGN=\"$(SSH_KEYSIGN)\" \
|
||||||
-D_PATH_SSH_PKCS11_HELPER=\"$(SSH_PKCS11_HELPER)\" \
|
-D_PATH_SSH_PKCS11_HELPER=\"$(SSH_PKCS11_HELPER)\" \
|
||||||
|
-D_PATH_SSH_SK_HELPER=\"$(SSH_SK_HELPER)\" \
|
||||||
-D_PATH_SSH_PIDDIR=\"$(piddir)\" \
|
-D_PATH_SSH_PIDDIR=\"$(piddir)\" \
|
||||||
-D_PATH_PRIVSEP_CHROOT_DIR=\"$(PRIVSEP_PATH)\"
|
-D_PATH_PRIVSEP_CHROOT_DIR=\"$(PRIVSEP_PATH)\"
|
||||||
|
|
||||||
@ -60,7 +62,7 @@ EXEEXT=@EXEEXT@
|
|||||||
MANFMT=@MANFMT@
|
MANFMT=@MANFMT@
|
||||||
MKDIR_P=@MKDIR_P@
|
MKDIR_P=@MKDIR_P@
|
||||||
|
|
||||||
TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT)
|
TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT)
|
||||||
|
|
||||||
XMSS_OBJS=\
|
XMSS_OBJS=\
|
||||||
ssh-xmss.o \
|
ssh-xmss.o \
|
||||||
@ -199,6 +201,9 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o readconf.o uidswap.o c
|
|||||||
ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o
|
ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o
|
||||||
$(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
|
$(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
|
||||||
|
|
||||||
|
ssh-sk-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-sk-helper.o
|
||||||
|
$(LD) -o $@ ssh-sk-helper.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
|
||||||
|
|
||||||
ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o
|
ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o
|
||||||
$(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
|
$(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
|
||||||
|
|
||||||
@ -350,6 +355,7 @@ install-files:
|
|||||||
$(INSTALL) -m 0755 $(STRIP_OPT) sshd$(EXEEXT) $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
|
$(INSTALL) -m 0755 $(STRIP_OPT) sshd$(EXEEXT) $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
|
||||||
$(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
|
$(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
|
||||||
$(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
|
$(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
|
||||||
|
$(INSTALL) -m 0755 $(STRIP_OPT) ssh-sk-helper$(EXEEXT) $(DESTDIR)$(SSH_SK_HELPER)$(EXEEXT)
|
||||||
$(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT)
|
$(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT)
|
||||||
$(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
|
$(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
|
||||||
$(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
|
$(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
|
||||||
@ -426,6 +432,7 @@ uninstall:
|
|||||||
-rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
|
-rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
|
||||||
-rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
|
-rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
|
||||||
-rm -f $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
|
-rm -f $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
|
||||||
|
-rm -f $(DESTDIR)$(SSH_SK_HELPER)$(EXEEXT)
|
||||||
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
|
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
|
||||||
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
|
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
|
||||||
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
|
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
|
||||||
@ -616,10 +623,10 @@ interop-tests t-exec file-tests: regress-prep regress-binaries $(TARGETS)
|
|||||||
TEST_SSH_SSHADD="$${BUILDDIR}/ssh-add"; \
|
TEST_SSH_SSHADD="$${BUILDDIR}/ssh-add"; \
|
||||||
TEST_SSH_SSHKEYGEN="$${BUILDDIR}/ssh-keygen"; \
|
TEST_SSH_SSHKEYGEN="$${BUILDDIR}/ssh-keygen"; \
|
||||||
TEST_SSH_SSHPKCS11HELPER="$${BUILDDIR}/ssh-pkcs11-helper"; \
|
TEST_SSH_SSHPKCS11HELPER="$${BUILDDIR}/ssh-pkcs11-helper"; \
|
||||||
|
TEST_SSH_SSHSKHELPER="$${BUILDDIR}/ssh-sk-helper"; \
|
||||||
TEST_SSH_SSHKEYSCAN="$${BUILDDIR}/ssh-keyscan"; \
|
TEST_SSH_SSHKEYSCAN="$${BUILDDIR}/ssh-keyscan"; \
|
||||||
TEST_SSH_SFTP="$${BUILDDIR}/sftp"; \
|
TEST_SSH_SFTP="$${BUILDDIR}/sftp"; \
|
||||||
TEST_SSH_SFTPSERVER="$${BUILDDIR}/sftp-server"; \
|
TEST_SSH_SFTPSERVER="$${BUILDDIR}/sftp-server"; \
|
||||||
TEST_SSH_SSHPKCS11HELPER="$${BUILDDIR}/ssh-pkcs11-helper"; \
|
|
||||||
TEST_SSH_PLINK="plink"; \
|
TEST_SSH_PLINK="plink"; \
|
||||||
TEST_SSH_PUTTYGEN="puttygen"; \
|
TEST_SSH_PUTTYGEN="puttygen"; \
|
||||||
TEST_SSH_CONCH="conch"; \
|
TEST_SSH_CONCH="conch"; \
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: pathnames.h,v 1.29 2019/10/31 21:15:14 djm Exp $ */
|
/* $OpenBSD: pathnames.h,v 1.30 2019/10/31 21:22:01 djm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
@ -133,6 +133,11 @@
|
|||||||
#define _PATH_SSH_PKCS11_HELPER "/usr/libexec/ssh-pkcs11-helper"
|
#define _PATH_SSH_PKCS11_HELPER "/usr/libexec/ssh-pkcs11-helper"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Location of ssh-sk-helper to support keys in security keys */
|
||||||
|
#ifndef _PATH_SSH_SK_HELPER
|
||||||
|
#define _PATH_SSH_SK_HELPER "/usr/libexec/ssh-sk-helper"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* xauth for X11 forwarding */
|
/* xauth for X11 forwarding */
|
||||||
#ifndef _PATH_XAUTH
|
#ifndef _PATH_XAUTH
|
||||||
#define _PATH_XAUTH "/usr/X11R6/bin/xauth"
|
#define _PATH_XAUTH "/usr/X11R6/bin/xauth"
|
||||||
|
20
ssh-agent.1
20
ssh-agent.1
@ -1,4 +1,4 @@
|
|||||||
.\" $OpenBSD: ssh-agent.1,v 1.64 2016/11/30 06:54:26 jmc Exp $
|
.\" $OpenBSD: ssh-agent.1,v 1.65 2019/10/31 21:22:01 djm Exp $
|
||||||
.\"
|
.\"
|
||||||
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
|
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
@ -34,7 +34,7 @@
|
|||||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.Dd $Mdocdate: November 30 2016 $
|
.Dd $Mdocdate: October 31 2019 $
|
||||||
.Dt SSH-AGENT 1
|
.Dt SSH-AGENT 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -46,7 +46,7 @@
|
|||||||
.Op Fl \&Dd
|
.Op Fl \&Dd
|
||||||
.Op Fl a Ar bind_address
|
.Op Fl a Ar bind_address
|
||||||
.Op Fl E Ar fingerprint_hash
|
.Op Fl E Ar fingerprint_hash
|
||||||
.Op Fl P Ar pkcs11_whitelist
|
.Op Fl P Ar provider_whitelist
|
||||||
.Op Fl t Ar life
|
.Op Fl t Ar life
|
||||||
.Op Ar command Op Ar arg ...
|
.Op Ar command Op Ar arg ...
|
||||||
.Nm ssh-agent
|
.Nm ssh-agent
|
||||||
@ -122,15 +122,17 @@ The default is
|
|||||||
Kill the current agent (given by the
|
Kill the current agent (given by the
|
||||||
.Ev SSH_AGENT_PID
|
.Ev SSH_AGENT_PID
|
||||||
environment variable).
|
environment variable).
|
||||||
.It Fl P Ar pkcs11_whitelist
|
.It Fl P Ar provider_whitelist
|
||||||
Specify a pattern-list of acceptable paths for PKCS#11 shared libraries
|
Specify a pattern-list of acceptable paths for PKCS#11 and security key shared
|
||||||
that may be added using the
|
libraries that may be used with the
|
||||||
.Fl s
|
.Fl s
|
||||||
option to
|
or
|
||||||
|
.Fl S
|
||||||
|
options to
|
||||||
.Xr ssh-add 1 .
|
.Xr ssh-add 1 .
|
||||||
The default is to allow loading PKCS#11 libraries from
|
The default is to allow loading libraries from
|
||||||
.Dq /usr/lib/*,/usr/local/lib/* .
|
.Dq /usr/lib/*,/usr/local/lib/* .
|
||||||
PKCS#11 libraries that do not match the whitelist will be refused.
|
Libraries that do not match the whitelist will be refused.
|
||||||
See PATTERNS in
|
See PATTERNS in
|
||||||
.Xr ssh_config 5
|
.Xr ssh_config 5
|
||||||
for a description of pattern-list syntax.
|
for a description of pattern-list syntax.
|
||||||
|
210
ssh-agent.c
210
ssh-agent.c
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: ssh-agent.c,v 1.237 2019/06/28 13:35:04 deraadt Exp $ */
|
/* $OpenBSD: ssh-agent.c,v 1.238 2019/10/31 21:22:01 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
@ -41,6 +41,7 @@
|
|||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#ifdef HAVE_SYS_TIME_H
|
#ifdef HAVE_SYS_TIME_H
|
||||||
# include <sys/time.h>
|
# include <sys/time.h>
|
||||||
#endif
|
#endif
|
||||||
@ -85,13 +86,13 @@
|
|||||||
#include "digest.h"
|
#include "digest.h"
|
||||||
#include "ssherr.h"
|
#include "ssherr.h"
|
||||||
#include "match.h"
|
#include "match.h"
|
||||||
|
#include "msg.h"
|
||||||
#ifdef ENABLE_PKCS11
|
#include "pathnames.h"
|
||||||
#include "ssh-pkcs11.h"
|
#include "ssh-pkcs11.h"
|
||||||
#endif
|
#include "ssh-sk.h"
|
||||||
|
|
||||||
#ifndef DEFAULT_PKCS11_WHITELIST
|
#ifndef DEFAULT_PROVIDER_WHITELIST
|
||||||
# define DEFAULT_PKCS11_WHITELIST "/usr/lib*/*,/usr/local/lib*/*"
|
# define DEFAULT_PROVIDER_WHITELIST "/usr/lib*/*,/usr/local/lib*/*"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Maximum accepted message length */
|
/* Maximum accepted message length */
|
||||||
@ -123,6 +124,7 @@ typedef struct identity {
|
|||||||
char *provider;
|
char *provider;
|
||||||
time_t death;
|
time_t death;
|
||||||
u_int confirm;
|
u_int confirm;
|
||||||
|
char *sk_provider;
|
||||||
} Identity;
|
} Identity;
|
||||||
|
|
||||||
struct idtable {
|
struct idtable {
|
||||||
@ -146,8 +148,8 @@ pid_t cleanup_pid = 0;
|
|||||||
char socket_name[PATH_MAX];
|
char socket_name[PATH_MAX];
|
||||||
char socket_dir[PATH_MAX];
|
char socket_dir[PATH_MAX];
|
||||||
|
|
||||||
/* PKCS#11 path whitelist */
|
/* PKCS#11/Security key path whitelist */
|
||||||
static char *pkcs11_whitelist;
|
static char *provider_whitelist;
|
||||||
|
|
||||||
/* locking */
|
/* locking */
|
||||||
#define LOCK_SIZE 32
|
#define LOCK_SIZE 32
|
||||||
@ -189,6 +191,7 @@ free_identity(Identity *id)
|
|||||||
sshkey_free(id->key);
|
sshkey_free(id->key);
|
||||||
free(id->provider);
|
free(id->provider);
|
||||||
free(id->comment);
|
free(id->comment);
|
||||||
|
free(id->sk_provider);
|
||||||
free(id);
|
free(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,6 +281,121 @@ agent_decode_alg(struct sshkey *key, u_int flags)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
provider_sign(const char *provider, struct sshkey *key,
|
||||||
|
u_char **sigp, size_t *lenp,
|
||||||
|
const u_char *data, size_t datalen,
|
||||||
|
const char *alg, u_int compat)
|
||||||
|
{
|
||||||
|
int status, pair[2], r = SSH_ERR_INTERNAL_ERROR;
|
||||||
|
pid_t pid;
|
||||||
|
char *helper, *verbosity = NULL;
|
||||||
|
struct sshbuf *kbuf, *req, *resp;
|
||||||
|
u_char version;
|
||||||
|
|
||||||
|
debug3("%s: start for provider %s", __func__, provider);
|
||||||
|
|
||||||
|
*sigp = NULL;
|
||||||
|
*lenp = 0;
|
||||||
|
|
||||||
|
helper = getenv("SSH_SK_HELPER");
|
||||||
|
if (helper == NULL || strlen(helper) == 0)
|
||||||
|
helper = _PATH_SSH_SK_HELPER;
|
||||||
|
if (log_level_get() >= SYSLOG_LEVEL_DEBUG1)
|
||||||
|
verbosity = "-vvv";
|
||||||
|
|
||||||
|
/* Start helper */
|
||||||
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
|
||||||
|
error("socketpair: %s", strerror(errno));
|
||||||
|
return SSH_ERR_SYSTEM_ERROR;
|
||||||
|
}
|
||||||
|
if ((pid = fork()) == -1) {
|
||||||
|
error("fork: %s", strerror(errno));
|
||||||
|
close(pair[0]);
|
||||||
|
close(pair[1]);
|
||||||
|
return SSH_ERR_SYSTEM_ERROR;
|
||||||
|
}
|
||||||
|
if (pid == 0) {
|
||||||
|
if ((dup2(pair[1], STDIN_FILENO) == -1) ||
|
||||||
|
(dup2(pair[1], STDOUT_FILENO) == -1))
|
||||||
|
fatal("%s: dup2: %s", __func__, ssh_err(r));
|
||||||
|
close(pair[0]);
|
||||||
|
close(pair[1]);
|
||||||
|
closefrom(STDERR_FILENO + 1);
|
||||||
|
debug("%s: starting %s %s", __func__, helper,
|
||||||
|
verbosity == NULL ? "" : verbosity);
|
||||||
|
execlp(helper, helper, verbosity, (char *)NULL);
|
||||||
|
fatal("%s: execlp: %s", __func__, strerror(errno));
|
||||||
|
}
|
||||||
|
close(pair[1]);
|
||||||
|
|
||||||
|
if ((kbuf = sshbuf_new()) == NULL ||
|
||||||
|
(req = sshbuf_new()) == NULL ||
|
||||||
|
(resp = sshbuf_new()) == NULL)
|
||||||
|
fatal("%s: sshbuf_new failed", __func__);
|
||||||
|
|
||||||
|
if ((r = sshkey_private_serialize(key, kbuf)) != 0 ||
|
||||||
|
(r = sshbuf_put_stringb(req, kbuf)) != 0 ||
|
||||||
|
(r = sshbuf_put_cstring(req, provider)) != 0 ||
|
||||||
|
(r = sshbuf_put_string(req, data, datalen)) != 0 ||
|
||||||
|
(r = sshbuf_put_u32(req, compat)) != 0)
|
||||||
|
fatal("%s: compose: %s", __func__, ssh_err(r));
|
||||||
|
if ((r = ssh_msg_send(pair[0], SSH_SK_HELPER_VERSION, req)) != 0) {
|
||||||
|
error("%s: send: %s", __func__, ssh_err(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((r = ssh_msg_recv(pair[0], resp)) != 0) {
|
||||||
|
error("%s: receive: %s", __func__, ssh_err(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((r = sshbuf_get_u8(resp, &version)) != 0) {
|
||||||
|
error("%s: parse version: %s", __func__, ssh_err(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (version != SSH_SK_HELPER_VERSION) {
|
||||||
|
error("%s: unsupported version: got %u, expected %u",
|
||||||
|
__func__, version, SSH_SK_HELPER_VERSION);
|
||||||
|
r = SSH_ERR_INVALID_FORMAT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if ((r = sshbuf_get_string(resp, sigp, lenp)) != 0) {
|
||||||
|
error("%s: parse signature: %s", __func__, ssh_err(r));
|
||||||
|
r = SSH_ERR_INVALID_FORMAT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (sshbuf_len(resp) != 0) {
|
||||||
|
error("%s: trailing data in response", __func__);
|
||||||
|
r = SSH_ERR_INVALID_FORMAT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* success */
|
||||||
|
r = 0;
|
||||||
|
out:
|
||||||
|
while (waitpid(pid, &status, 0) == -1) {
|
||||||
|
if (errno != EINTR)
|
||||||
|
fatal("%s: waitpid: %s", __func__, ssh_err(r));
|
||||||
|
}
|
||||||
|
if (!WIFEXITED(status)) {
|
||||||
|
error("%s: helper %s exited abnormally", __func__, helper);
|
||||||
|
if (r == 0)
|
||||||
|
r = SSH_ERR_SYSTEM_ERROR;
|
||||||
|
} else if (WEXITSTATUS(status) != 0) {
|
||||||
|
error("%s: helper %s exited with non-zero exit status",
|
||||||
|
__func__, helper);
|
||||||
|
if (r == 0)
|
||||||
|
r = SSH_ERR_SYSTEM_ERROR;
|
||||||
|
}
|
||||||
|
if (r != 0) {
|
||||||
|
freezero(*sigp, *lenp);
|
||||||
|
*sigp = NULL;
|
||||||
|
*lenp = 0;
|
||||||
|
}
|
||||||
|
sshbuf_free(kbuf);
|
||||||
|
sshbuf_free(req);
|
||||||
|
sshbuf_free(resp);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/* ssh2 only */
|
/* ssh2 only */
|
||||||
static void
|
static void
|
||||||
process_sign_request2(SocketEntry *e)
|
process_sign_request2(SocketEntry *e)
|
||||||
@ -308,11 +426,20 @@ process_sign_request2(SocketEntry *e)
|
|||||||
verbose("%s: user refused key", __func__);
|
verbose("%s: user refused key", __func__);
|
||||||
goto send;
|
goto send;
|
||||||
}
|
}
|
||||||
|
if (id->sk_provider != NULL) {
|
||||||
|
if ((r = provider_sign(id->sk_provider, id->key, &signature,
|
||||||
|
&slen, data, dlen, agent_decode_alg(key, flags),
|
||||||
|
compat)) != 0) {
|
||||||
|
error("%s: sshkey_sign: %s", __func__, ssh_err(r));
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if ((r = sshkey_sign(id->key, &signature, &slen,
|
if ((r = sshkey_sign(id->key, &signature, &slen,
|
||||||
data, dlen, agent_decode_alg(key, flags), compat)) != 0) {
|
data, dlen, agent_decode_alg(key, flags), compat)) != 0) {
|
||||||
error("%s: sshkey_sign: %s", __func__, ssh_err(r));
|
error("%s: sshkey_sign: %s", __func__, ssh_err(r));
|
||||||
goto send;
|
goto send;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/* Success */
|
/* Success */
|
||||||
ok = 0;
|
ok = 0;
|
||||||
send:
|
send:
|
||||||
@ -411,7 +538,7 @@ process_add_identity(SocketEntry *e)
|
|||||||
Identity *id;
|
Identity *id;
|
||||||
int success = 0, confirm = 0;
|
int success = 0, confirm = 0;
|
||||||
u_int seconds, maxsign;
|
u_int seconds, maxsign;
|
||||||
char *comment = NULL;
|
char *fp, *comment = NULL, *ext_name = NULL, *sk_provider = NULL;
|
||||||
time_t death = 0;
|
time_t death = 0;
|
||||||
struct sshkey *k = NULL;
|
struct sshkey *k = NULL;
|
||||||
u_char ctype;
|
u_char ctype;
|
||||||
@ -456,15 +583,58 @@ process_add_identity(SocketEntry *e)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SSH_AGENT_CONSTRAIN_EXTENSION:
|
||||||
|
if ((r = sshbuf_get_cstring(e->request,
|
||||||
|
&ext_name, NULL)) != 0) {
|
||||||
|
error("%s: cannot parse extension: %s",
|
||||||
|
__func__, ssh_err(r));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
debug("%s: constraint ext %s", __func__, ext_name);
|
||||||
|
if (strcmp(ext_name, "sk-provider@openssh.com") == 0) {
|
||||||
|
if (sk_provider != NULL) {
|
||||||
|
error("%s already set", ext_name);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if ((r = sshbuf_get_cstring(e->request,
|
||||||
|
&sk_provider, NULL)) != 0) {
|
||||||
|
error("%s: cannot parse %s: %s",
|
||||||
|
__func__, ext_name, ssh_err(r));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error("%s: unsupported constraint \"%s\"",
|
||||||
|
__func__, ext_name);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
free(ext_name);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
error("%s: Unknown constraint %d", __func__, ctype);
|
error("%s: Unknown constraint %d", __func__, ctype);
|
||||||
err:
|
err:
|
||||||
|
free(sk_provider);
|
||||||
|
free(ext_name);
|
||||||
sshbuf_reset(e->request);
|
sshbuf_reset(e->request);
|
||||||
free(comment);
|
free(comment);
|
||||||
sshkey_free(k);
|
sshkey_free(k);
|
||||||
goto send;
|
goto send;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sk_provider != NULL) {
|
||||||
|
if (sshkey_type_plain(k->type) != KEY_ECDSA_SK) {
|
||||||
|
error("Cannot add provider: %s is not a security key",
|
||||||
|
sshkey_type(k));
|
||||||
|
free(sk_provider);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
if (match_pattern_list(sk_provider,
|
||||||
|
provider_whitelist, 0) != 1) {
|
||||||
|
error("Refusing add key: provider %s not whitelisted",
|
||||||
|
sk_provider);
|
||||||
|
free(sk_provider);
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
success = 1;
|
success = 1;
|
||||||
if (lifetime && !death)
|
if (lifetime && !death)
|
||||||
@ -478,11 +648,21 @@ process_add_identity(SocketEntry *e)
|
|||||||
/* key state might have been updated */
|
/* key state might have been updated */
|
||||||
sshkey_free(id->key);
|
sshkey_free(id->key);
|
||||||
free(id->comment);
|
free(id->comment);
|
||||||
|
free(id->sk_provider);
|
||||||
}
|
}
|
||||||
id->key = k;
|
id->key = k;
|
||||||
id->comment = comment;
|
id->comment = comment;
|
||||||
id->death = death;
|
id->death = death;
|
||||||
id->confirm = confirm;
|
id->confirm = confirm;
|
||||||
|
id->sk_provider = sk_provider;
|
||||||
|
|
||||||
|
if ((fp = sshkey_fingerprint(k, SSH_FP_HASH_DEFAULT,
|
||||||
|
SSH_FP_DEFAULT)) == NULL)
|
||||||
|
fatal("%s: sshkey_fingerprint failed", __func__);
|
||||||
|
debug("%s: add %s %s \"%.100s\" (life: %u) (confirm: %u) "
|
||||||
|
"(provider: %s)", __func__, sshkey_ssh_name(k), fp, comment,
|
||||||
|
seconds, confirm, sk_provider == NULL ? "none" : sk_provider);
|
||||||
|
free(fp);
|
||||||
send:
|
send:
|
||||||
send_status(e, success);
|
send_status(e, success);
|
||||||
}
|
}
|
||||||
@ -600,7 +780,7 @@ process_add_smartcard_key(SocketEntry *e)
|
|||||||
provider, strerror(errno));
|
provider, strerror(errno));
|
||||||
goto send;
|
goto send;
|
||||||
}
|
}
|
||||||
if (match_pattern_list(canonical_provider, pkcs11_whitelist, 0) != 1) {
|
if (match_pattern_list(canonical_provider, provider_whitelist, 0) != 1) {
|
||||||
verbose("refusing PKCS#11 add of \"%.100s\": "
|
verbose("refusing PKCS#11 add of \"%.100s\": "
|
||||||
"provider not whitelisted", canonical_provider);
|
"provider not whitelisted", canonical_provider);
|
||||||
goto send;
|
goto send;
|
||||||
@ -1079,7 +1259,7 @@ usage(void)
|
|||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"usage: ssh-agent [-c | -s] [-Dd] [-a bind_address] [-E fingerprint_hash]\n"
|
"usage: ssh-agent [-c | -s] [-Dd] [-a bind_address] [-E fingerprint_hash]\n"
|
||||||
" [-P pkcs11_whitelist] [-t life] [command [arg ...]]\n"
|
" [-P provider_whitelist] [-t life] [command [arg ...]]\n"
|
||||||
" ssh-agent [-c | -s] -k\n");
|
" ssh-agent [-c | -s] -k\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -1137,9 +1317,9 @@ main(int ac, char **av)
|
|||||||
k_flag++;
|
k_flag++;
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
if (pkcs11_whitelist != NULL)
|
if (provider_whitelist != NULL)
|
||||||
fatal("-P option already specified");
|
fatal("-P option already specified");
|
||||||
pkcs11_whitelist = xstrdup(optarg);
|
provider_whitelist = xstrdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
if (c_flag)
|
if (c_flag)
|
||||||
@ -1175,8 +1355,8 @@ main(int ac, char **av)
|
|||||||
if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || D_flag))
|
if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || D_flag))
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
if (pkcs11_whitelist == NULL)
|
if (provider_whitelist == NULL)
|
||||||
pkcs11_whitelist = xstrdup(DEFAULT_PKCS11_WHITELIST);
|
provider_whitelist = xstrdup(DEFAULT_PROVIDER_WHITELIST);
|
||||||
|
|
||||||
if (ac == 0 && !c_flag && !s_flag) {
|
if (ac == 0 && !c_flag && !s_flag) {
|
||||||
shell = getenv("SHELL");
|
shell = getenv("SHELL");
|
||||||
|
143
ssh-sk-helper.c
Normal file
143
ssh-sk-helper.c
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/* $OpenBSD: ssh-sk-helper.c,v 1.1 2019/10/31 21:22:01 djm Exp $ */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Google LLC
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a tiny program used to isolate the address space used for
|
||||||
|
* security key middleware signing operations from ssh-agent. It is similar
|
||||||
|
* to ssh-pkcs11-helper.c but considerably simpler as the signing operation
|
||||||
|
* for this case are stateless.
|
||||||
|
*
|
||||||
|
* It receives a signing request (key, provider, message, flags) from
|
||||||
|
* stdin, attempts to perform a signature using the security key provider
|
||||||
|
* and returns the resultant signature via stdout.
|
||||||
|
*
|
||||||
|
* In the future, this program might gain additional functions to support
|
||||||
|
* FIDO2 tokens such as enumerating resident keys. When this happens it will
|
||||||
|
* be necessary to crank SSH_SK_HELPER_VERSION below.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "xmalloc.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "sshkey.h"
|
||||||
|
#include "authfd.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "sshbuf.h"
|
||||||
|
#include "msg.h"
|
||||||
|
#include "uidswap.h"
|
||||||
|
#include "sshkey.h"
|
||||||
|
#include "ssherr.h"
|
||||||
|
#include "ssh-sk.h"
|
||||||
|
|
||||||
|
extern char *__progname;
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
|
||||||
|
LogLevel log_level = SYSLOG_LEVEL_ERROR;
|
||||||
|
struct sshbuf *req, *resp, *kbuf;
|
||||||
|
struct sshkey *key;
|
||||||
|
uint32_t compat;
|
||||||
|
const u_char *message;
|
||||||
|
u_char version, *sig;
|
||||||
|
size_t msglen, siglen;
|
||||||
|
char *provider;
|
||||||
|
int in, out, ch, r, log_stderr = 0;
|
||||||
|
|
||||||
|
sanitise_stdfd();
|
||||||
|
log_init(__progname, log_level, log_facility, log_stderr);
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, "v")) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'v':
|
||||||
|
log_stderr = 1;
|
||||||
|
if (log_level == SYSLOG_LEVEL_ERROR)
|
||||||
|
log_level = SYSLOG_LEVEL_DEBUG1;
|
||||||
|
else if (log_level < SYSLOG_LEVEL_DEBUG3)
|
||||||
|
log_level++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "usage: %s [-v]\n", __progname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log_init(__progname, log_level, log_facility, log_stderr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rearrange our file descriptors a little; we don't trust the
|
||||||
|
* providers not to fiddle with stdin/out.
|
||||||
|
*/
|
||||||
|
closefrom(STDERR_FILENO + 1);
|
||||||
|
if ((in = dup(STDIN_FILENO)) == -1 || (out = dup(STDOUT_FILENO)) == -1)
|
||||||
|
fatal("%s: dup: %s", __progname, strerror(errno));
|
||||||
|
close(STDIN_FILENO);
|
||||||
|
close(STDOUT_FILENO);
|
||||||
|
sanitise_stdfd(); /* resets to /dev/null */
|
||||||
|
|
||||||
|
if ((req = sshbuf_new()) == NULL || (resp = sshbuf_new()) == NULL)
|
||||||
|
fatal("%s: sshbuf_new failed", __progname);
|
||||||
|
if (ssh_msg_recv(in, req) < 0)
|
||||||
|
fatal("ssh_msg_recv failed");
|
||||||
|
close(in);
|
||||||
|
debug("%s: received message len %zu", __progname, sshbuf_len(req));
|
||||||
|
|
||||||
|
if ((r = sshbuf_get_u8(req, &version)) != 0)
|
||||||
|
fatal("%s: buffer error: %s", __progname, ssh_err(r));
|
||||||
|
if (version != SSH_SK_HELPER_VERSION) {
|
||||||
|
fatal("unsupported version: received %d, expected %d",
|
||||||
|
version, SSH_SK_HELPER_VERSION);
|
||||||
|
}
|
||||||
|
if ((r = sshbuf_froms(req, &kbuf)) != 0 ||
|
||||||
|
(r = sshkey_private_deserialize(kbuf, &key)) != 0)
|
||||||
|
fatal("Unable to parse key: %s", ssh_err(r));
|
||||||
|
if (sshkey_type_plain(key->type) != KEY_ECDSA_SK)
|
||||||
|
fatal("Unsupported key type %s", sshkey_ssh_name(key));
|
||||||
|
|
||||||
|
if ((r = sshbuf_get_cstring(req, &provider, NULL)) != 0 ||
|
||||||
|
(r = sshbuf_get_string_direct(req, &message, &msglen)) != 0 ||
|
||||||
|
(r = sshbuf_get_u32(req, &compat)) != 0)
|
||||||
|
fatal("%s: buffer error: %s", __progname, ssh_err(r));
|
||||||
|
if (sshbuf_len(req) != 0)
|
||||||
|
fatal("%s: trailing data in request", __progname);
|
||||||
|
|
||||||
|
debug("%s: ready to sign with key %s, provider %s: "
|
||||||
|
"msg len %zu, compat 0x%lx", __progname, sshkey_type(key),
|
||||||
|
provider, msglen, (u_long)compat);
|
||||||
|
|
||||||
|
if ((r = sshsk_ecdsa_sign(provider, key, &sig, &siglen,
|
||||||
|
message, msglen, compat)) != 0)
|
||||||
|
fatal("Signing failed: %s", ssh_err(r));
|
||||||
|
|
||||||
|
/* send reply */
|
||||||
|
if ((r = sshbuf_put_string(resp, sig, siglen)) != 0)
|
||||||
|
fatal("%s: buffer error: %s", __progname, ssh_err(r));
|
||||||
|
debug("%s: reply len %zu", __progname, sshbuf_len(resp));
|
||||||
|
if (ssh_msg_send(out, SSH_SK_HELPER_VERSION, resp) == -1)
|
||||||
|
fatal("ssh_msg_send failed");
|
||||||
|
close(out);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
5
ssh-sk.h
5
ssh-sk.h
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: ssh-sk.h,v 1.1 2019/10/31 21:16:20 djm Exp $ */
|
/* $OpenBSD: ssh-sk.h,v 1.2 2019/10/31 21:22:01 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 Google LLC
|
* Copyright (c) 2019 Google LLC
|
||||||
*
|
*
|
||||||
@ -21,6 +21,9 @@
|
|||||||
struct sshbuf;
|
struct sshbuf;
|
||||||
struct sshkey;
|
struct sshkey;
|
||||||
|
|
||||||
|
/* Version of protocol between ssh-agent and ssh-sk-helper */
|
||||||
|
#define SSH_SK_HELPER_VERSION 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enroll (generate) a new security-key hosted private key via the specified
|
* Enroll (generate) a new security-key hosted private key via the specified
|
||||||
* provider middleware.
|
* provider middleware.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user