diff options
Diffstat (limited to 'ssh-sk-helper.c')
-rw-r--r-- | ssh-sk-helper.c | 106 |
1 files changed, 84 insertions, 22 deletions
diff --git a/ssh-sk-helper.c b/ssh-sk-helper.c index ac528cfcf..590ff8501 100644 --- a/ssh-sk-helper.c +++ b/ssh-sk-helper.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-sk-helper.c,v 1.5 2019/12/30 09:21:59 djm Exp $ */ | 1 | /* $OpenBSD: ssh-sk-helper.c,v 1.6 2019/12/30 09:23:28 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2019 Google LLC | 3 | * Copyright (c) 2019 Google LLC |
4 | * | 4 | * |
@@ -50,6 +50,33 @@ | |||
50 | #ifdef ENABLE_SK | 50 | #ifdef ENABLE_SK |
51 | extern char *__progname; | 51 | extern char *__progname; |
52 | 52 | ||
53 | static struct sshbuf *reply_error(int r, char *fmt, ...) | ||
54 | __attribute__((__format__ (printf, 2, 3))); | ||
55 | |||
56 | static struct sshbuf * | ||
57 | reply_error(int r, char *fmt, ...) | ||
58 | { | ||
59 | char *msg; | ||
60 | va_list ap; | ||
61 | struct sshbuf *resp; | ||
62 | |||
63 | va_start(ap, fmt); | ||
64 | xvasprintf(&msg, fmt, ap); | ||
65 | va_end(ap); | ||
66 | error("%s: %s", __progname, msg); | ||
67 | free(msg); | ||
68 | |||
69 | if (r >= 0) | ||
70 | fatal("%s: invalid error code %d", __func__, r); | ||
71 | |||
72 | if ((resp = sshbuf_new()) == NULL) | ||
73 | fatal("%s: sshbuf_new failed", __progname); | ||
74 | if (sshbuf_put_u32(resp, SSH_SK_HELPER_ERROR) != 0 || | ||
75 | sshbuf_put_u32(resp, (u_int)-r) != 0) | ||
76 | fatal("%s: buffer error", __progname); | ||
77 | return resp; | ||
78 | } | ||
79 | |||
53 | static struct sshbuf * | 80 | static struct sshbuf * |
54 | process_sign(struct sshbuf *req) | 81 | process_sign(struct sshbuf *req) |
55 | { | 82 | { |
@@ -60,13 +87,14 @@ process_sign(struct sshbuf *req) | |||
60 | const u_char *message; | 87 | const u_char *message; |
61 | u_char *sig; | 88 | u_char *sig; |
62 | size_t msglen, siglen; | 89 | size_t msglen, siglen; |
63 | char *provider; | 90 | char *provider, *pin; |
64 | 91 | ||
65 | if ((r = sshbuf_froms(req, &kbuf)) != 0 || | 92 | if ((r = sshbuf_froms(req, &kbuf)) != 0 || |
66 | (r = sshbuf_get_cstring(req, &provider, NULL)) != 0 || | 93 | (r = sshbuf_get_cstring(req, &provider, NULL)) != 0 || |
67 | (r = sshbuf_get_string_direct(req, &message, &msglen)) != 0 || | 94 | (r = sshbuf_get_string_direct(req, &message, &msglen)) != 0 || |
68 | (r = sshbuf_get_cstring(req, NULL, NULL)) != 0 || /* alg */ | 95 | (r = sshbuf_get_cstring(req, NULL, NULL)) != 0 || /* alg */ |
69 | (r = sshbuf_get_u32(req, &compat)) != 0) | 96 | (r = sshbuf_get_u32(req, &compat)) != 0 || |
97 | (r = sshbuf_get_cstring(req, &pin, NULL)) != 0) | ||
70 | fatal("%s: buffer error: %s", __progname, ssh_err(r)); | 98 | fatal("%s: buffer error: %s", __progname, ssh_err(r)); |
71 | if (sshbuf_len(req) != 0) | 99 | if (sshbuf_len(req) != 0) |
72 | fatal("%s: trailing data in request", __progname); | 100 | fatal("%s: trailing data in request", __progname); |
@@ -80,19 +108,28 @@ process_sign(struct sshbuf *req) | |||
80 | "msg len %zu, compat 0x%lx", __progname, sshkey_type(key), | 108 | "msg len %zu, compat 0x%lx", __progname, sshkey_type(key), |
81 | provider, msglen, (u_long)compat); | 109 | provider, msglen, (u_long)compat); |
82 | 110 | ||
111 | if (*pin == 0) { | ||
112 | free(pin); | ||
113 | pin = NULL; | ||
114 | } | ||
115 | |||
83 | if ((r = sshsk_sign(provider, key, &sig, &siglen, | 116 | if ((r = sshsk_sign(provider, key, &sig, &siglen, |
84 | message, msglen, compat)) != 0) | 117 | message, msglen, compat, pin)) != 0) { |
85 | fatal("Signing failed: %s", ssh_err(r)); | 118 | resp = reply_error(r, "Signing failed: %s", ssh_err(r)); |
119 | goto out; | ||
120 | } | ||
86 | 121 | ||
87 | if ((resp = sshbuf_new()) == NULL) | 122 | if ((resp = sshbuf_new()) == NULL) |
88 | fatal("%s: sshbuf_new failed", __progname); | 123 | fatal("%s: sshbuf_new failed", __progname); |
89 | 124 | ||
90 | if ((r = sshbuf_put_string(resp, sig, siglen)) != 0) | 125 | if ((r = sshbuf_put_u32(resp, SSH_SK_HELPER_SIGN)) != 0 || |
126 | (r = sshbuf_put_string(resp, sig, siglen)) != 0) | ||
91 | fatal("%s: buffer error: %s", __progname, ssh_err(r)); | 127 | fatal("%s: buffer error: %s", __progname, ssh_err(r)); |
92 | 128 | out: | |
93 | sshbuf_free(kbuf); | 129 | sshbuf_free(kbuf); |
94 | free(provider); | 130 | free(provider); |
95 | 131 | if (pin != NULL) | |
132 | freezero(pin, strlen(pin)); | ||
96 | return resp; | 133 | return resp; |
97 | } | 134 | } |
98 | 135 | ||
@@ -101,14 +138,12 @@ process_enroll(struct sshbuf *req) | |||
101 | { | 138 | { |
102 | int r; | 139 | int r; |
103 | u_int type; | 140 | u_int type; |
104 | char *provider; | 141 | char *provider, *application, *pin; |
105 | char *application; | ||
106 | uint8_t flags; | 142 | uint8_t flags; |
107 | struct sshbuf *challenge, *attest, *kbuf, *resp; | 143 | struct sshbuf *challenge, *attest, *kbuf, *resp; |
108 | struct sshkey *key; | 144 | struct sshkey *key; |
109 | 145 | ||
110 | if ((resp = sshbuf_new()) == NULL || | 146 | if ((attest = sshbuf_new()) == NULL || |
111 | (attest = sshbuf_new()) == NULL || | ||
112 | (kbuf = sshbuf_new()) == NULL) | 147 | (kbuf = sshbuf_new()) == NULL) |
113 | fatal("%s: sshbuf_new failed", __progname); | 148 | fatal("%s: sshbuf_new failed", __progname); |
114 | 149 | ||
@@ -116,6 +151,7 @@ process_enroll(struct sshbuf *req) | |||
116 | (r = sshbuf_get_cstring(req, &provider, NULL)) != 0 || | 151 | (r = sshbuf_get_cstring(req, &provider, NULL)) != 0 || |
117 | (r = sshbuf_get_cstring(req, &application, NULL)) != 0 || | 152 | (r = sshbuf_get_cstring(req, &application, NULL)) != 0 || |
118 | (r = sshbuf_get_u8(req, &flags)) != 0 || | 153 | (r = sshbuf_get_u8(req, &flags)) != 0 || |
154 | (r = sshbuf_get_cstring(req, &pin, NULL)) != 0 || | ||
119 | (r = sshbuf_froms(req, &challenge)) != 0) | 155 | (r = sshbuf_froms(req, &challenge)) != 0) |
120 | fatal("%s: buffer error: %s", __progname, ssh_err(r)); | 156 | fatal("%s: buffer error: %s", __progname, ssh_err(r)); |
121 | if (sshbuf_len(req) != 0) | 157 | if (sshbuf_len(req) != 0) |
@@ -127,23 +163,35 @@ process_enroll(struct sshbuf *req) | |||
127 | sshbuf_free(challenge); | 163 | sshbuf_free(challenge); |
128 | challenge = NULL; | 164 | challenge = NULL; |
129 | } | 165 | } |
166 | if (*pin == 0) { | ||
167 | free(pin); | ||
168 | pin = NULL; | ||
169 | } | ||
130 | 170 | ||
131 | if ((r = sshsk_enroll((int)type, provider, application, flags, | 171 | if ((r = sshsk_enroll((int)type, provider, application, flags, pin, |
132 | challenge, &key, attest)) != 0) | 172 | challenge, &key, attest)) != 0) { |
133 | fatal("%s: sshsk_enroll failed: %s", __progname, ssh_err(r)); | 173 | resp = reply_error(r, "Enrollment failed: %s", ssh_err(r)); |
174 | goto out; | ||
175 | } | ||
134 | 176 | ||
177 | if ((resp = sshbuf_new()) == NULL) | ||
178 | fatal("%s: sshbuf_new failed", __progname); | ||
135 | if ((r = sshkey_private_serialize(key, kbuf)) != 0) | 179 | if ((r = sshkey_private_serialize(key, kbuf)) != 0) |
136 | fatal("%s: serialize private key: %s", __progname, ssh_err(r)); | 180 | fatal("%s: serialize private key: %s", __progname, ssh_err(r)); |
137 | if ((r = sshbuf_put_stringb(resp, kbuf)) != 0 || | 181 | if ((r = sshbuf_put_u32(resp, SSH_SK_HELPER_ENROLL)) != 0 || |
182 | (r = sshbuf_put_stringb(resp, kbuf)) != 0 || | ||
138 | (r = sshbuf_put_stringb(resp, attest)) != 0) | 183 | (r = sshbuf_put_stringb(resp, attest)) != 0) |
139 | fatal("%s: buffer error: %s", __progname, ssh_err(r)); | 184 | fatal("%s: buffer error: %s", __progname, ssh_err(r)); |
140 | 185 | ||
186 | out: | ||
141 | sshkey_free(key); | 187 | sshkey_free(key); |
142 | sshbuf_free(kbuf); | 188 | sshbuf_free(kbuf); |
143 | sshbuf_free(attest); | 189 | sshbuf_free(attest); |
144 | sshbuf_free(challenge); | 190 | sshbuf_free(challenge); |
145 | free(provider); | 191 | free(provider); |
146 | free(application); | 192 | free(application); |
193 | if (pin != NULL) | ||
194 | freezero(pin, strlen(pin)); | ||
147 | 195 | ||
148 | return resp; | 196 | return resp; |
149 | } | 197 | } |
@@ -157,8 +205,7 @@ process_load_resident(struct sshbuf *req) | |||
157 | struct sshkey **keys = NULL; | 205 | struct sshkey **keys = NULL; |
158 | size_t nkeys = 0, i; | 206 | size_t nkeys = 0, i; |
159 | 207 | ||
160 | if ((resp = sshbuf_new()) == NULL || | 208 | if ((kbuf = sshbuf_new()) == NULL) |
161 | (kbuf = sshbuf_new()) == NULL) | ||
162 | fatal("%s: sshbuf_new failed", __progname); | 209 | fatal("%s: sshbuf_new failed", __progname); |
163 | 210 | ||
164 | if ((r = sshbuf_get_cstring(req, &provider, NULL)) != 0 || | 211 | if ((r = sshbuf_get_cstring(req, &provider, NULL)) != 0 || |
@@ -167,9 +214,22 @@ process_load_resident(struct sshbuf *req) | |||
167 | if (sshbuf_len(req) != 0) | 214 | if (sshbuf_len(req) != 0) |
168 | fatal("%s: trailing data in request", __progname); | 215 | fatal("%s: trailing data in request", __progname); |
169 | 216 | ||
170 | if ((r = sshsk_load_resident(provider, pin, &keys, &nkeys)) != 0) | 217 | if (*pin == 0) { |
171 | fatal("%s: sshsk_load_resident failed: %s", | 218 | free(pin); |
172 | __progname, ssh_err(r)); | 219 | pin = NULL; |
220 | } | ||
221 | |||
222 | if ((r = sshsk_load_resident(provider, pin, &keys, &nkeys)) != 0) { | ||
223 | resp = reply_error(r, " sshsk_load_resident failed: %s", | ||
224 | ssh_err(r)); | ||
225 | goto out; | ||
226 | } | ||
227 | |||
228 | if ((resp = sshbuf_new()) == NULL) | ||
229 | fatal("%s: sshbuf_new failed", __progname); | ||
230 | |||
231 | if ((r = sshbuf_put_u32(resp, SSH_SK_HELPER_LOAD_RESIDENT)) != 0) | ||
232 | fatal("%s: buffer error: %s", __progname, ssh_err(r)); | ||
173 | 233 | ||
174 | for (i = 0; i < nkeys; i++) { | 234 | for (i = 0; i < nkeys; i++) { |
175 | debug("%s: key %zu %s %s", __func__, i, | 235 | debug("%s: key %zu %s %s", __func__, i, |
@@ -183,12 +243,14 @@ process_load_resident(struct sshbuf *req) | |||
183 | fatal("%s: buffer error: %s", __progname, ssh_err(r)); | 243 | fatal("%s: buffer error: %s", __progname, ssh_err(r)); |
184 | } | 244 | } |
185 | 245 | ||
246 | out: | ||
186 | for (i = 0; i < nkeys; i++) | 247 | for (i = 0; i < nkeys; i++) |
187 | sshkey_free(keys[i]); | 248 | sshkey_free(keys[i]); |
188 | free(keys); | 249 | free(keys); |
189 | sshbuf_free(kbuf); | 250 | sshbuf_free(kbuf); |
190 | free(provider); | 251 | free(provider); |
191 | freezero(pin, strlen(pin)); | 252 | if (pin != NULL) |
253 | freezero(pin, strlen(pin)); | ||
192 | return resp; | 254 | return resp; |
193 | } | 255 | } |
194 | 256 | ||