summaryrefslogtreecommitdiff
path: root/ssh-sk-helper.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2019-12-13 19:11:14 +0000
committerDamien Miller <djm@mindrot.org>2019-12-14 07:20:28 +1100
commit611073fb40ecaf4ac65094e403edea3a08deb700 (patch)
tree5a7f0d7e4bd49f3326dd9eba6913f880e18632be /ssh-sk-helper.c
parent612b1dd1ec91ffb1e01f58cca0c6eb1d47bf4423 (diff)
upstream: perform security key enrollment via ssh-sk-helper too.
This means that ssh-keygen no longer needs to link against ssh-sk-helper, and only ssh-sk-helper needs libfido2 and /dev/uhid* access; feedback & ok markus@ OpenBSD-Commit-ID: 9464233fab95708d2ff059f8bee29c0d1f270800
Diffstat (limited to 'ssh-sk-helper.c')
-rw-r--r--ssh-sk-helper.c160
1 files changed, 121 insertions, 39 deletions
diff --git a/ssh-sk-helper.c b/ssh-sk-helper.c
index 0acb8d172..eade26e3d 100644
--- a/ssh-sk-helper.c
+++ b/ssh-sk-helper.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-sk-helper.c,v 1.3 2019/11/12 19:33:08 markus Exp $ */ 1/* $OpenBSD: ssh-sk-helper.c,v 1.4 2019/12/13 19:11:14 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2019 Google LLC 3 * Copyright (c) 2019 Google LLC
4 * 4 *
@@ -18,20 +18,16 @@
18/* 18/*
19 * This is a tiny program used to isolate the address space used for 19 * This is a tiny program used to isolate the address space used for
20 * security key middleware signing operations from ssh-agent. It is similar 20 * security key middleware signing operations from ssh-agent. It is similar
21 * to ssh-pkcs11-helper.c but considerably simpler as the signing operation 21 * to ssh-pkcs11-helper.c but considerably simpler as the operations for
22 * for this case are stateless. 22 * security keys are stateless.
23 * 23 *
24 * It receives a signing request (key, provider, message, flags) from 24 * Please crank SSH_SK_HELPER_VERSION in sshkey.h for any incompatible
25 * stdin, attempts to perform a signature using the security key provider 25 * protocol changes.
26 * and returns the resultant signature via stdout.
27 *
28 * In the future, this program might gain additional functions to support
29 * FIDO2 tokens such as enumerating resident keys. When this happens it will
30 * be necessary to crank SSH_SK_HELPER_VERSION below.
31 */ 26 */
32 27
33#include "includes.h" 28#include "includes.h"
34 29
30#include <limits.h>
35#include <stdarg.h> 31#include <stdarg.h>
36#include <stdio.h> 32#include <stdio.h>
37#include <stdlib.h> 33#include <stdlib.h>
@@ -54,19 +50,112 @@
54#ifdef ENABLE_SK 50#ifdef ENABLE_SK
55extern char *__progname; 51extern char *__progname;
56 52
57int 53static struct sshbuf *
58main(int argc, char **argv) 54process_sign(struct sshbuf *req)
59{ 55{
60 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; 56 int r = SSH_ERR_INTERNAL_ERROR;
61 LogLevel log_level = SYSLOG_LEVEL_ERROR; 57 struct sshbuf *resp, *kbuf;
62 struct sshbuf *req, *resp, *kbuf;
63 struct sshkey *key; 58 struct sshkey *key;
64 uint32_t compat; 59 uint32_t compat;
65 const u_char *message; 60 const u_char *message;
66 u_char version, *sig; 61 u_char *sig;
67 size_t msglen, siglen; 62 size_t msglen, siglen;
68 char *provider; 63 char *provider;
64
65 if ((r = sshbuf_froms(req, &kbuf)) != 0 ||
66 (r = sshbuf_get_cstring(req, &provider, NULL)) != 0 ||
67 (r = sshbuf_get_string_direct(req, &message, &msglen)) != 0 ||
68 (r = sshbuf_get_cstring(req, NULL, NULL)) != 0 || /* alg */
69 (r = sshbuf_get_u32(req, &compat)) != 0)
70 fatal("%s: buffer error: %s", __progname, ssh_err(r));
71 if (sshbuf_len(req) != 0)
72 fatal("%s: trailing data in request", __progname);
73
74 if ((r = sshkey_private_deserialize(kbuf, &key)) != 0)
75 fatal("Unable to parse private key: %s", ssh_err(r));
76 if (!sshkey_is_sk(key))
77 fatal("Unsupported key type %s", sshkey_ssh_name(key));
78
79 debug("%s: ready to sign with key %s, provider %s: "
80 "msg len %zu, compat 0x%lx", __progname, sshkey_type(key),
81 provider, msglen, (u_long)compat);
82
83 if ((r = sshsk_sign(provider, key, &sig, &siglen,
84 message, msglen, compat)) != 0)
85 fatal("Signing failed: %s", ssh_err(r));
86
87 if ((resp = sshbuf_new()) == NULL)
88 fatal("%s: sshbuf_new failed", __progname);
89
90 if ((r = sshbuf_put_string(resp, sig, siglen)) != 0)
91 fatal("%s: buffer error: %s", __progname, ssh_err(r));
92
93 sshbuf_free(kbuf);
94 free(provider);
95
96 return resp;
97}
98
99static struct sshbuf *
100process_enroll(struct sshbuf *req)
101{
102 int r;
103 u_int type;
104 char *provider;
105 char *application;
106 uint8_t flags;
107 struct sshbuf *challenge, *attest, *kbuf, *resp;
108 struct sshkey *key;
109
110 if ((resp = sshbuf_new()) == NULL ||
111 (attest = sshbuf_new()) == NULL ||
112 (kbuf = sshbuf_new()) == NULL)
113 fatal("%s: sshbuf_new failed", __progname);
114
115 if ((r = sshbuf_get_u32(req, &type)) != 0 ||
116 (r = sshbuf_get_cstring(req, &provider, NULL)) != 0 ||
117 (r = sshbuf_get_cstring(req, &application, NULL)) != 0 ||
118 (r = sshbuf_get_u8(req, &flags)) != 0 ||
119 (r = sshbuf_froms(req, &challenge)) != 0)
120 fatal("%s: buffer error: %s", __progname, ssh_err(r));
121 if (sshbuf_len(req) != 0)
122 fatal("%s: trailing data in request", __progname);
123
124 if (type > INT_MAX)
125 fatal("%s: bad type %u", __progname, type);
126 if (sshbuf_len(challenge) == 0) {
127 sshbuf_free(challenge);
128 challenge = NULL;
129 }
130
131 if ((r = sshsk_enroll((int)type, provider, application, flags,
132 challenge, &key, attest)) != 0)
133 fatal("%s: sshsk_enroll failed: %s", __progname, ssh_err(r));
134
135 if ((r = sshkey_private_serialize(key, kbuf)) != 0)
136 fatal("%s: serialize private key: %s", __progname, ssh_err(r));
137 if ((r = sshbuf_put_stringb(resp, kbuf)) != 0 ||
138 (r = sshbuf_put_stringb(resp, attest)) != 0)
139 fatal("%s: buffer error: %s", __progname, ssh_err(r));
140
141 sshkey_free(key);
142 sshbuf_free(kbuf);
143 sshbuf_free(attest);
144 sshbuf_free(challenge);
145 free(provider);
146 free(application);
147
148 return resp;
149}
150
151int
152main(int argc, char **argv)
153{
154 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
155 LogLevel log_level = SYSLOG_LEVEL_ERROR;
69 int in, out, ch, r, log_stderr = 0; 156 int in, out, ch, r, log_stderr = 0;
157 u_int rtype;
158 uint8_t version;
70 159
71 sanitise_stdfd(); 160 sanitise_stdfd();
72 log_init(__progname, log_level, log_facility, log_stderr); 161 log_init(__progname, log_level, log_facility, log_stderr);
@@ -98,7 +187,7 @@ main(int argc, char **argv)
98 close(STDOUT_FILENO); 187 close(STDOUT_FILENO);
99 sanitise_stdfd(); /* resets to /dev/null */ 188 sanitise_stdfd(); /* resets to /dev/null */
100 189
101 if ((req = sshbuf_new()) == NULL || (resp = sshbuf_new()) == NULL) 190 if ((req = sshbuf_new()) == NULL)
102 fatal("%s: sshbuf_new failed", __progname); 191 fatal("%s: sshbuf_new failed", __progname);
103 if (ssh_msg_recv(in, req) < 0) 192 if (ssh_msg_recv(in, req) < 0)
104 fatal("ssh_msg_recv failed"); 193 fatal("ssh_msg_recv failed");
@@ -111,33 +200,26 @@ main(int argc, char **argv)
111 fatal("unsupported version: received %d, expected %d", 200 fatal("unsupported version: received %d, expected %d",
112 version, SSH_SK_HELPER_VERSION); 201 version, SSH_SK_HELPER_VERSION);
113 } 202 }
114 if ((r = sshbuf_froms(req, &kbuf)) != 0 ||
115 (r = sshkey_private_deserialize(kbuf, &key)) != 0)
116 fatal("Unable to parse key: %s", ssh_err(r));
117 if (!sshkey_is_sk(key))
118 fatal("Unsupported key type %s", sshkey_ssh_name(key));
119 203
120 if ((r = sshbuf_get_cstring(req, &provider, NULL)) != 0 || 204 if ((r = sshbuf_get_u32(req, &rtype)) != 0)
121 (r = sshbuf_get_string_direct(req, &message, &msglen)) != 0 ||
122 (r = sshbuf_get_u32(req, &compat)) != 0)
123 fatal("%s: buffer error: %s", __progname, ssh_err(r)); 205 fatal("%s: buffer error: %s", __progname, ssh_err(r));
124 if (sshbuf_len(req) != 0)
125 fatal("%s: trailing data in request", __progname);
126
127 debug("%s: ready to sign with key %s, provider %s: "
128 "msg len %zu, compat 0x%lx", __progname, sshkey_type(key),
129 provider, msglen, (u_long)compat);
130
131 if ((r = sshsk_sign(provider, key, &sig, &siglen,
132 message, msglen, compat)) != 0)
133 fatal("Signing failed: %s", ssh_err(r));
134 206
135 /* send reply */ 207 switch (rtype) {
136 if ((r = sshbuf_put_string(resp, sig, siglen)) != 0) 208 case SSH_SK_HELPER_SIGN:
137 fatal("%s: buffer error: %s", __progname, ssh_err(r)); 209 resp = process_sign(req);
210 break;
211 case SSH_SK_HELPER_ENROLL:
212 resp = process_enroll(req);
213 break;
214 default:
215 fatal("%s: unsupported request type %u", __progname, rtype);
216 }
217 sshbuf_free(req);
138 debug("%s: reply len %zu", __progname, sshbuf_len(resp)); 218 debug("%s: reply len %zu", __progname, sshbuf_len(resp));
219
139 if (ssh_msg_send(out, SSH_SK_HELPER_VERSION, resp) == -1) 220 if (ssh_msg_send(out, SSH_SK_HELPER_VERSION, resp) == -1)
140 fatal("ssh_msg_send failed"); 221 fatal("ssh_msg_send failed");
222 sshbuf_free(resp);
141 close(out); 223 close(out);
142 224
143 return (0); 225 return (0);