diff options
-rw-r--r-- | ssh-pkcs11-helper.c | 183 |
1 files changed, 105 insertions, 78 deletions
diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c index fd3039c14..6301033c5 100644 --- a/ssh-pkcs11-helper.c +++ b/ssh-pkcs11-helper.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-pkcs11-helper.c,v 1.13 2017/05/30 08:52:19 markus Exp $ */ | 1 | /* $OpenBSD: ssh-pkcs11-helper.c,v 1.14 2018/01/08 15:18:46 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2010 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2010 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -30,12 +30,13 @@ | |||
30 | #include <errno.h> | 30 | #include <errno.h> |
31 | 31 | ||
32 | #include "xmalloc.h" | 32 | #include "xmalloc.h" |
33 | #include "buffer.h" | 33 | #include "sshbuf.h" |
34 | #include "log.h" | 34 | #include "log.h" |
35 | #include "misc.h" | 35 | #include "misc.h" |
36 | #include "key.h" | 36 | #include "sshkey.h" |
37 | #include "authfd.h" | 37 | #include "authfd.h" |
38 | #include "ssh-pkcs11.h" | 38 | #include "ssh-pkcs11.h" |
39 | #include "ssherr.h" | ||
39 | 40 | ||
40 | #ifdef ENABLE_PKCS11 | 41 | #ifdef ENABLE_PKCS11 |
41 | 42 | ||
@@ -51,13 +52,9 @@ TAILQ_HEAD(, pkcs11_keyinfo) pkcs11_keylist; | |||
51 | 52 | ||
52 | #define MAX_MSG_LENGTH 10240 /*XXX*/ | 53 | #define MAX_MSG_LENGTH 10240 /*XXX*/ |
53 | 54 | ||
54 | /* helper */ | ||
55 | #define get_int() buffer_get_int(&iqueue); | ||
56 | #define get_string(lenp) buffer_get_string(&iqueue, lenp); | ||
57 | |||
58 | /* input and output queue */ | 55 | /* input and output queue */ |
59 | Buffer iqueue; | 56 | struct sshbuf *iqueue; |
60 | Buffer oqueue; | 57 | struct sshbuf *oqueue; |
61 | 58 | ||
62 | static void | 59 | static void |
63 | add_key(struct sshkey *k, char *name) | 60 | add_key(struct sshkey *k, char *name) |
@@ -80,7 +77,7 @@ del_keys_by_name(char *name) | |||
80 | if (!strcmp(ki->providername, name)) { | 77 | if (!strcmp(ki->providername, name)) { |
81 | TAILQ_REMOVE(&pkcs11_keylist, ki, next); | 78 | TAILQ_REMOVE(&pkcs11_keylist, ki, next); |
82 | free(ki->providername); | 79 | free(ki->providername); |
83 | key_free(ki->key); | 80 | sshkey_free(ki->key); |
84 | free(ki); | 81 | free(ki); |
85 | } | 82 | } |
86 | } | 83 | } |
@@ -94,20 +91,19 @@ lookup_key(struct sshkey *k) | |||
94 | 91 | ||
95 | TAILQ_FOREACH(ki, &pkcs11_keylist, next) { | 92 | TAILQ_FOREACH(ki, &pkcs11_keylist, next) { |
96 | debug("check %p %s", ki, ki->providername); | 93 | debug("check %p %s", ki, ki->providername); |
97 | if (key_equal(k, ki->key)) | 94 | if (sshkey_equal(k, ki->key)) |
98 | return (ki->key); | 95 | return (ki->key); |
99 | } | 96 | } |
100 | return (NULL); | 97 | return (NULL); |
101 | } | 98 | } |
102 | 99 | ||
103 | static void | 100 | static void |
104 | send_msg(Buffer *m) | 101 | send_msg(struct sshbuf *m) |
105 | { | 102 | { |
106 | int mlen = buffer_len(m); | 103 | int r; |
107 | 104 | ||
108 | buffer_put_int(&oqueue, mlen); | 105 | if ((r = sshbuf_put_stringb(oqueue, m)) != 0) |
109 | buffer_append(&oqueue, buffer_ptr(m), mlen); | 106 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
110 | buffer_consume(m, mlen); | ||
111 | } | 107 | } |
112 | 108 | ||
113 | static void | 109 | static void |
@@ -115,69 +111,85 @@ process_add(void) | |||
115 | { | 111 | { |
116 | char *name, *pin; | 112 | char *name, *pin; |
117 | struct sshkey **keys; | 113 | struct sshkey **keys; |
118 | int i, nkeys; | 114 | int r, i, nkeys; |
119 | u_char *blob; | 115 | u_char *blob; |
120 | u_int blen; | 116 | size_t blen; |
121 | Buffer msg; | 117 | struct sshbuf *msg; |
122 | 118 | ||
123 | buffer_init(&msg); | 119 | if ((msg = sshbuf_new()) == NULL) |
124 | name = get_string(NULL); | 120 | fatal("%s: sshbuf_new failed", __func__); |
125 | pin = get_string(NULL); | 121 | if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || |
122 | (r = sshbuf_get_cstring(iqueue, &pin, NULL)) != 0) | ||
123 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
126 | if ((nkeys = pkcs11_add_provider(name, pin, &keys)) > 0) { | 124 | if ((nkeys = pkcs11_add_provider(name, pin, &keys)) > 0) { |
127 | buffer_put_char(&msg, SSH2_AGENT_IDENTITIES_ANSWER); | 125 | if ((r = sshbuf_put_u8(msg, |
128 | buffer_put_int(&msg, nkeys); | 126 | SSH2_AGENT_IDENTITIES_ANSWER)) != 0 || |
127 | (r = sshbuf_put_u32(msg, nkeys)) != 0) | ||
128 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
129 | for (i = 0; i < nkeys; i++) { | 129 | for (i = 0; i < nkeys; i++) { |
130 | if (key_to_blob(keys[i], &blob, &blen) == 0) | 130 | if ((r = sshkey_to_blob(keys[i], &blob, &blen)) != 0) { |
131 | debug("%s: sshkey_to_blob: %s", | ||
132 | __func__, ssh_err(r)); | ||
131 | continue; | 133 | continue; |
132 | buffer_put_string(&msg, blob, blen); | 134 | } |
133 | buffer_put_cstring(&msg, name); | 135 | if ((r = sshbuf_put_string(msg, blob, blen)) != 0 || |
136 | (r = sshbuf_put_cstring(msg, name)) != 0) | ||
137 | fatal("%s: buffer error: %s", | ||
138 | __func__, ssh_err(r)); | ||
134 | free(blob); | 139 | free(blob); |
135 | add_key(keys[i], name); | 140 | add_key(keys[i], name); |
136 | } | 141 | } |
137 | free(keys); | 142 | free(keys); |
138 | } else { | 143 | } else { |
139 | buffer_put_char(&msg, SSH_AGENT_FAILURE); | 144 | if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0) |
145 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
140 | } | 146 | } |
141 | free(pin); | 147 | free(pin); |
142 | free(name); | 148 | free(name); |
143 | send_msg(&msg); | 149 | send_msg(msg); |
144 | buffer_free(&msg); | 150 | sshbuf_free(msg); |
145 | } | 151 | } |
146 | 152 | ||
147 | static void | 153 | static void |
148 | process_del(void) | 154 | process_del(void) |
149 | { | 155 | { |
150 | char *name, *pin; | 156 | char *name, *pin; |
151 | Buffer msg; | 157 | struct sshbuf *msg; |
152 | 158 | int r; | |
153 | buffer_init(&msg); | 159 | |
154 | name = get_string(NULL); | 160 | if ((msg = sshbuf_new()) == NULL) |
155 | pin = get_string(NULL); | 161 | fatal("%s: sshbuf_new failed", __func__); |
162 | if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || | ||
163 | (r = sshbuf_get_cstring(iqueue, &pin, NULL)) != 0) | ||
164 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
156 | del_keys_by_name(name); | 165 | del_keys_by_name(name); |
157 | if (pkcs11_del_provider(name) == 0) | 166 | if ((r = sshbuf_put_u8(msg, pkcs11_del_provider(name) == 0 ? |
158 | buffer_put_char(&msg, SSH_AGENT_SUCCESS); | 167 | SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE)) != 0) |
159 | else | 168 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
160 | buffer_put_char(&msg, SSH_AGENT_FAILURE); | ||
161 | free(pin); | 169 | free(pin); |
162 | free(name); | 170 | free(name); |
163 | send_msg(&msg); | 171 | send_msg(msg); |
164 | buffer_free(&msg); | 172 | sshbuf_free(msg); |
165 | } | 173 | } |
166 | 174 | ||
167 | static void | 175 | static void |
168 | process_sign(void) | 176 | process_sign(void) |
169 | { | 177 | { |
170 | u_char *blob, *data, *signature = NULL; | 178 | u_char *blob, *data, *signature = NULL; |
171 | u_int blen, dlen, slen = 0; | 179 | size_t blen, dlen, slen = 0; |
172 | int ok = -1; | 180 | int r, ok = -1; |
173 | struct sshkey *key, *found; | 181 | struct sshkey *key, *found; |
174 | Buffer msg; | 182 | struct sshbuf *msg; |
175 | 183 | ||
176 | blob = get_string(&blen); | 184 | /* XXX support SHA2 signature flags */ |
177 | data = get_string(&dlen); | 185 | if ((r = sshbuf_get_string(iqueue, &blob, &blen)) != 0 || |
178 | (void)get_int(); /* XXX ignore flags */ | 186 | (r = sshbuf_get_string(iqueue, &data, &dlen)) != 0 || |
187 | (r = sshbuf_get_u32(iqueue, NULL)) != 0) | ||
188 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
179 | 189 | ||
180 | if ((key = key_from_blob(blob, blen)) != NULL) { | 190 | if ((r = sshkey_from_blob(blob, blen, &key)) != 0) |
191 | error("%s: sshkey_from_blob: %s", __func__, ssh_err(r)); | ||
192 | else { | ||
181 | if ((found = lookup_key(key)) != NULL) { | 193 | if ((found = lookup_key(key)) != NULL) { |
182 | #ifdef WITH_OPENSSL | 194 | #ifdef WITH_OPENSSL |
183 | int ret; | 195 | int ret; |
@@ -191,20 +203,23 @@ process_sign(void) | |||
191 | } | 203 | } |
192 | #endif /* WITH_OPENSSL */ | 204 | #endif /* WITH_OPENSSL */ |
193 | } | 205 | } |
194 | key_free(key); | 206 | sshkey_free(key); |
195 | } | 207 | } |
196 | buffer_init(&msg); | 208 | if ((msg = sshbuf_new()) == NULL) |
209 | fatal("%s: sshbuf_new failed", __func__); | ||
197 | if (ok == 0) { | 210 | if (ok == 0) { |
198 | buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE); | 211 | if ((r = sshbuf_put_u8(msg, SSH2_AGENT_SIGN_RESPONSE)) != 0 || |
199 | buffer_put_string(&msg, signature, slen); | 212 | (r = sshbuf_put_string(msg, signature, slen)) != 0) |
213 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
200 | } else { | 214 | } else { |
201 | buffer_put_char(&msg, SSH_AGENT_FAILURE); | 215 | if ((r = sshbuf_put_u8(msg, SSH2_AGENT_FAILURE)) != 0) |
216 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
202 | } | 217 | } |
203 | free(data); | 218 | free(data); |
204 | free(blob); | 219 | free(blob); |
205 | free(signature); | 220 | free(signature); |
206 | send_msg(&msg); | 221 | send_msg(msg); |
207 | buffer_free(&msg); | 222 | sshbuf_free(msg); |
208 | } | 223 | } |
209 | 224 | ||
210 | static void | 225 | static void |
@@ -213,13 +228,14 @@ process(void) | |||
213 | u_int msg_len; | 228 | u_int msg_len; |
214 | u_int buf_len; | 229 | u_int buf_len; |
215 | u_int consumed; | 230 | u_int consumed; |
216 | u_int type; | 231 | u_char type; |
217 | u_char *cp; | 232 | const u_char *cp; |
233 | int r; | ||
218 | 234 | ||
219 | buf_len = buffer_len(&iqueue); | 235 | buf_len = sshbuf_len(iqueue); |
220 | if (buf_len < 5) | 236 | if (buf_len < 5) |
221 | return; /* Incomplete message. */ | 237 | return; /* Incomplete message. */ |
222 | cp = buffer_ptr(&iqueue); | 238 | cp = sshbuf_ptr(iqueue); |
223 | msg_len = get_u32(cp); | 239 | msg_len = get_u32(cp); |
224 | if (msg_len > MAX_MSG_LENGTH) { | 240 | if (msg_len > MAX_MSG_LENGTH) { |
225 | error("bad message len %d", msg_len); | 241 | error("bad message len %d", msg_len); |
@@ -227,9 +243,10 @@ process(void) | |||
227 | } | 243 | } |
228 | if (buf_len < msg_len + 4) | 244 | if (buf_len < msg_len + 4) |
229 | return; | 245 | return; |
230 | buffer_consume(&iqueue, 4); | 246 | if ((r = sshbuf_consume(iqueue, 4)) != 0 || |
247 | (r = sshbuf_get_u8(iqueue, &type)) != 0) | ||
248 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
231 | buf_len -= 4; | 249 | buf_len -= 4; |
232 | type = buffer_get_char(&iqueue); | ||
233 | switch (type) { | 250 | switch (type) { |
234 | case SSH_AGENTC_ADD_SMARTCARD_KEY: | 251 | case SSH_AGENTC_ADD_SMARTCARD_KEY: |
235 | debug("process_add"); | 252 | debug("process_add"); |
@@ -248,17 +265,19 @@ process(void) | |||
248 | break; | 265 | break; |
249 | } | 266 | } |
250 | /* discard the remaining bytes from the current packet */ | 267 | /* discard the remaining bytes from the current packet */ |
251 | if (buf_len < buffer_len(&iqueue)) { | 268 | if (buf_len < sshbuf_len(iqueue)) { |
252 | error("iqueue grew unexpectedly"); | 269 | error("iqueue grew unexpectedly"); |
253 | cleanup_exit(255); | 270 | cleanup_exit(255); |
254 | } | 271 | } |
255 | consumed = buf_len - buffer_len(&iqueue); | 272 | consumed = buf_len - sshbuf_len(iqueue); |
256 | if (msg_len < consumed) { | 273 | if (msg_len < consumed) { |
257 | error("msg_len %d < consumed %d", msg_len, consumed); | 274 | error("msg_len %d < consumed %d", msg_len, consumed); |
258 | cleanup_exit(255); | 275 | cleanup_exit(255); |
259 | } | 276 | } |
260 | if (msg_len > consumed) | 277 | if (msg_len > consumed) { |
261 | buffer_consume(&iqueue, msg_len - consumed); | 278 | if ((r = sshbuf_consume(iqueue, msg_len - consumed)) != 0) |
279 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
280 | } | ||
262 | } | 281 | } |
263 | 282 | ||
264 | void | 283 | void |
@@ -272,7 +291,7 @@ int | |||
272 | main(int argc, char **argv) | 291 | main(int argc, char **argv) |
273 | { | 292 | { |
274 | fd_set *rset, *wset; | 293 | fd_set *rset, *wset; |
275 | int in, out, max, log_stderr = 0; | 294 | int r, in, out, max, log_stderr = 0; |
276 | ssize_t len, olen, set_size; | 295 | ssize_t len, olen, set_size; |
277 | SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; | 296 | SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; |
278 | LogLevel log_level = SYSLOG_LEVEL_ERROR; | 297 | LogLevel log_level = SYSLOG_LEVEL_ERROR; |
@@ -298,8 +317,10 @@ main(int argc, char **argv) | |||
298 | if (out > max) | 317 | if (out > max) |
299 | max = out; | 318 | max = out; |
300 | 319 | ||
301 | buffer_init(&iqueue); | 320 | if ((iqueue = sshbuf_new()) == NULL) |
302 | buffer_init(&oqueue); | 321 | fatal("%s: sshbuf_new failed", __func__); |
322 | if ((oqueue = sshbuf_new()) == NULL) | ||
323 | fatal("%s: sshbuf_new failed", __func__); | ||
303 | 324 | ||
304 | set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask); | 325 | set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask); |
305 | rset = xmalloc(set_size); | 326 | rset = xmalloc(set_size); |
@@ -314,11 +335,13 @@ main(int argc, char **argv) | |||
314 | * the worst-case length packet it can generate, | 335 | * the worst-case length packet it can generate, |
315 | * otherwise apply backpressure by stopping reads. | 336 | * otherwise apply backpressure by stopping reads. |
316 | */ | 337 | */ |
317 | if (buffer_check_alloc(&iqueue, sizeof(buf)) && | 338 | if ((r = sshbuf_check_reserve(iqueue, sizeof(buf))) == 0 && |
318 | buffer_check_alloc(&oqueue, MAX_MSG_LENGTH)) | 339 | (r = sshbuf_check_reserve(oqueue, MAX_MSG_LENGTH)) == 0) |
319 | FD_SET(in, rset); | 340 | FD_SET(in, rset); |
341 | else if (r != SSH_ERR_NO_BUFFER_SPACE) | ||
342 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
320 | 343 | ||
321 | olen = buffer_len(&oqueue); | 344 | olen = sshbuf_len(oqueue); |
322 | if (olen > 0) | 345 | if (olen > 0) |
323 | FD_SET(out, wset); | 346 | FD_SET(out, wset); |
324 | 347 | ||
@@ -338,18 +361,20 @@ main(int argc, char **argv) | |||
338 | } else if (len < 0) { | 361 | } else if (len < 0) { |
339 | error("read: %s", strerror(errno)); | 362 | error("read: %s", strerror(errno)); |
340 | cleanup_exit(1); | 363 | cleanup_exit(1); |
341 | } else { | 364 | } else if ((r = sshbuf_put(iqueue, buf, len)) != 0) { |
342 | buffer_append(&iqueue, buf, len); | 365 | fatal("%s: buffer error: %s", |
366 | __func__, ssh_err(r)); | ||
343 | } | 367 | } |
344 | } | 368 | } |
345 | /* send oqueue to stdout */ | 369 | /* send oqueue to stdout */ |
346 | if (FD_ISSET(out, wset)) { | 370 | if (FD_ISSET(out, wset)) { |
347 | len = write(out, buffer_ptr(&oqueue), olen); | 371 | len = write(out, sshbuf_ptr(oqueue), olen); |
348 | if (len < 0) { | 372 | if (len < 0) { |
349 | error("write: %s", strerror(errno)); | 373 | error("write: %s", strerror(errno)); |
350 | cleanup_exit(1); | 374 | cleanup_exit(1); |
351 | } else { | 375 | } else if ((r = sshbuf_consume(oqueue, len)) != 0) { |
352 | buffer_consume(&oqueue, len); | 376 | fatal("%s: buffer error: %s", |
377 | __func__, ssh_err(r)); | ||
353 | } | 378 | } |
354 | } | 379 | } |
355 | 380 | ||
@@ -358,8 +383,10 @@ main(int argc, char **argv) | |||
358 | * into the output buffer, otherwise stop processing input | 383 | * into the output buffer, otherwise stop processing input |
359 | * and let the output queue drain. | 384 | * and let the output queue drain. |
360 | */ | 385 | */ |
361 | if (buffer_check_alloc(&oqueue, MAX_MSG_LENGTH)) | 386 | if ((r = sshbuf_check_reserve(oqueue, MAX_MSG_LENGTH)) == 0) |
362 | process(); | 387 | process(); |
388 | else if (r != SSH_ERR_NO_BUFFER_SPACE) | ||
389 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
363 | } | 390 | } |
364 | } | 391 | } |
365 | #else /* ENABLE_PKCS11 */ | 392 | #else /* ENABLE_PKCS11 */ |