Deleted Added
full compact
authfd.c (57430) authfd.c (57464)
1/*
2 *
3 * authfd.c
4 *
5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 *
7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 * All rights reserved
9 *
10 * Created: Wed Mar 29 01:30:28 1995 ylo
11 *
12 * Functions for connecting the local authentication agent.
13 *
1/*
2 *
3 * authfd.c
4 *
5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6 *
7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 * All rights reserved
9 *
10 * Created: Wed Mar 29 01:30:28 1995 ylo
11 *
12 * Functions for connecting the local authentication agent.
13 *
14 * $FreeBSD: head/crypto/openssh/authfd.c 57464 2000-02-25 01:53:12Z green $
14 */
15
16#include "includes.h"
17RCSID("$Id: authfd.c,v 1.16 1999/12/15 19:43:10 markus Exp $");
18
19#include "ssh.h"
20#include "rsa.h"
21#include "authfd.h"
22#include "buffer.h"
23#include "bufaux.h"
24#include "xmalloc.h"
25#include "getput.h"
26
15 */
16
17#include "includes.h"
18RCSID("$Id: authfd.c,v 1.16 1999/12/15 19:43:10 markus Exp $");
19
20#include "ssh.h"
21#include "rsa.h"
22#include "authfd.h"
23#include "buffer.h"
24#include "bufaux.h"
25#include "xmalloc.h"
26#include "getput.h"
27
27#include
28#include <openssl/rsa.h>
28
29/* Returns the number of the authentication fd, or -1 if there is none. */
30
31int
32ssh_get_authentication_socket()
33{
34 const char *authsocket;
35 int sock;
36 struct sockaddr_un sunaddr;
37
38 authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
39 if (!authsocket)
40 return -1;
41
42 sunaddr.sun_family = AF_UNIX;
43 strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
44
45 sock = socket(AF_UNIX, SOCK_STREAM, 0);
46 if (sock < 0)
47 return -1;
48
49 /* close on exec */
50 if (fcntl(sock, F_SETFD, 1) == -1) {
51 close(sock);
52 return -1;
53 }
54 if (connect(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
55 close(sock);
56 return -1;
57 }
58 return sock;
59}
60
61/*
62 * Closes the agent socket if it should be closed (depends on how it was
63 * obtained). The argument must have been returned by
64 * ssh_get_authentication_socket().
65 */
66
67void
68ssh_close_authentication_socket(int sock)
69{
70 if (getenv(SSH_AUTHSOCKET_ENV_NAME))
71 close(sock);
72}
73
74/*
75 * Opens and connects a private socket for communication with the
76 * authentication agent. Returns the file descriptor (which must be
77 * shut down and closed by the caller when no longer needed).
78 * Returns NULL if an error occurred and the connection could not be
79 * opened.
80 */
81
82AuthenticationConnection *
83ssh_get_authentication_connection()
84{
85 AuthenticationConnection *auth;
86 int sock;
87
88 sock = ssh_get_authentication_socket();
89
90 /*
91 * Fail if we couldn't obtain a connection. This happens if we
92 * exited due to a timeout.
93 */
94 if (sock < 0)
95 return NULL;
96
97 auth = xmalloc(sizeof(*auth));
98 auth->fd = sock;
99 buffer_init(&auth->packet);
100 buffer_init(&auth->identities);
101 auth->howmany = 0;
102
103 return auth;
104}
105
106/*
107 * Closes the connection to the authentication agent and frees any associated
108 * memory.
109 */
110
111void
112ssh_close_authentication_connection(AuthenticationConnection *ac)
113{
114 buffer_free(&ac->packet);
115 buffer_free(&ac->identities);
116 close(ac->fd);
117 xfree(ac);
118}
119
120/*
121 * Returns the first authentication identity held by the agent.
122 * Returns true if an identity is available, 0 otherwise.
123 * The caller must initialize the integers before the call, and free the
124 * comment after a successful call (before calling ssh_get_next_identity).
125 */
126
127int
128ssh_get_first_identity(AuthenticationConnection *auth,
129 BIGNUM *e, BIGNUM *n, char **comment)
130{
131 unsigned char msg[8192];
132 int len, l;
133
134 /*
135 * Send a message to the agent requesting for a list of the
136 * identities it can represent.
137 */
138 msg[0] = 0;
139 msg[1] = 0;
140 msg[2] = 0;
141 msg[3] = 1;
142 msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
143 if (atomicio(write, auth->fd, msg, 5) != 5) {
144 error("write auth->fd: %.100s", strerror(errno));
145 return 0;
146 }
147 /* Read the length of the response. XXX implement timeouts here. */
148 len = 4;
149 while (len > 0) {
150 l = read(auth->fd, msg + 4 - len, len);
151 if (l <= 0) {
152 error("read auth->fd: %.100s", strerror(errno));
153 return 0;
154 }
155 len -= l;
156 }
157
158 /*
159 * Extract the length, and check it for sanity. (We cannot trust
160 * authentication agents).
161 */
162 len = GET_32BIT(msg);
163 if (len < 1 || len > 256 * 1024)
164 fatal("Authentication reply message too long: %d\n", len);
165
166 /* Read the packet itself. */
167 buffer_clear(&auth->identities);
168 while (len > 0) {
169 l = len;
170 if (l > sizeof(msg))
171 l = sizeof(msg);
172 l = read(auth->fd, msg, l);
173 if (l <= 0)
174 fatal("Incomplete authentication reply.");
175 buffer_append(&auth->identities, (char *) msg, l);
176 len -= l;
177 }
178
179 /* Get message type, and verify that we got a proper answer. */
180 buffer_get(&auth->identities, (char *) msg, 1);
181 if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
182 fatal("Bad authentication reply message type: %d", msg[0]);
183
184 /* Get the number of entries in the response and check it for sanity. */
185 auth->howmany = buffer_get_int(&auth->identities);
186 if (auth->howmany > 1024)
187 fatal("Too many identities in authentication reply: %d\n", auth->howmany);
188
189 /* Return the first entry (if any). */
190 return ssh_get_next_identity(auth, e, n, comment);
191}
192
193/*
194 * Returns the next authentication identity for the agent. Other functions
195 * can be called between this and ssh_get_first_identity or two calls of this
196 * function. This returns 0 if there are no more identities. The caller
197 * must free comment after a successful return.
198 */
199
200int
201ssh_get_next_identity(AuthenticationConnection *auth,
202 BIGNUM *e, BIGNUM *n, char **comment)
203{
204 unsigned int bits;
205
206 /* Return failure if no more entries. */
207 if (auth->howmany <= 0)
208 return 0;
209
210 /*
211 * Get the next entry from the packet. These will abort with a fatal
212 * error if the packet is too short or contains corrupt data.
213 */
214 bits = buffer_get_int(&auth->identities);
215 buffer_get_bignum(&auth->identities, e);
216 buffer_get_bignum(&auth->identities, n);
217 *comment = buffer_get_string(&auth->identities, NULL);
218
219 if (bits != BN_num_bits(n))
220 error("Warning: identity keysize mismatch: actual %d, announced %u",
221 BN_num_bits(n), bits);
222
223 /* Decrement the number of remaining entries. */
224 auth->howmany--;
225
226 return 1;
227}
228
229/*
230 * Generates a random challenge, sends it to the agent, and waits for
231 * response from the agent. Returns true (non-zero) if the agent gave the
232 * correct answer, zero otherwise. Response type selects the style of
233 * response desired, with 0 corresponding to protocol version 1.0 (no longer
234 * supported) and 1 corresponding to protocol version 1.1.
235 */
236
237int
238ssh_decrypt_challenge(AuthenticationConnection *auth,
239 BIGNUM* e, BIGNUM *n, BIGNUM *challenge,
240 unsigned char session_id[16],
241 unsigned int response_type,
242 unsigned char response[16])
243{
244 Buffer buffer;
245 unsigned char buf[8192];
246 int len, l, i;
247
248 /* Response type 0 is no longer supported. */
249 if (response_type == 0)
250 fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
251
252 /* Format a message to the agent. */
253 buf[0] = SSH_AGENTC_RSA_CHALLENGE;
254 buffer_init(&buffer);
255 buffer_append(&buffer, (char *) buf, 1);
256 buffer_put_int(&buffer, BN_num_bits(n));
257 buffer_put_bignum(&buffer, e);
258 buffer_put_bignum(&buffer, n);
259 buffer_put_bignum(&buffer, challenge);
260 buffer_append(&buffer, (char *) session_id, 16);
261 buffer_put_int(&buffer, response_type);
262
263 /* Get the length of the message, and format it in the buffer. */
264 len = buffer_len(&buffer);
265 PUT_32BIT(buf, len);
266
267 /* Send the length and then the packet to the agent. */
268 if (atomicio(write, auth->fd, buf, 4) != 4 ||
269 atomicio(write, auth->fd, buffer_ptr(&buffer),
270 buffer_len(&buffer)) != buffer_len(&buffer)) {
271 error("Error writing to authentication socket.");
272error_cleanup:
273 buffer_free(&buffer);
274 return 0;
275 }
276 /*
277 * Wait for response from the agent. First read the length of the
278 * response packet.
279 */
280 len = 4;
281 while (len > 0) {
282 l = read(auth->fd, buf + 4 - len, len);
283 if (l <= 0) {
284 error("Error reading response length from authentication socket.");
285 goto error_cleanup;
286 }
287 len -= l;
288 }
289
290 /* Extract the length, and check it for sanity. */
291 len = GET_32BIT(buf);
292 if (len > 256 * 1024)
293 fatal("Authentication response too long: %d", len);
294
295 /* Read the rest of the response in tothe buffer. */
296 buffer_clear(&buffer);
297 while (len > 0) {
298 l = len;
299 if (l > sizeof(buf))
300 l = sizeof(buf);
301 l = read(auth->fd, buf, l);
302 if (l <= 0) {
303 error("Error reading response from authentication socket.");
304 goto error_cleanup;
305 }
306 buffer_append(&buffer, (char *) buf, l);
307 len -= l;
308 }
309
310 /* Get the type of the packet. */
311 buffer_get(&buffer, (char *) buf, 1);
312
313 /* Check for agent failure message. */
314 if (buf[0] == SSH_AGENT_FAILURE) {
315 log("Agent admitted failure to authenticate using the key.");
316 goto error_cleanup;
317 }
318 /* Now it must be an authentication response packet. */
319 if (buf[0] != SSH_AGENT_RSA_RESPONSE)
320 fatal("Bad authentication response: %d", buf[0]);
321
322 /*
323 * Get the response from the packet. This will abort with a fatal
324 * error if the packet is corrupt.
325 */
326 for (i = 0; i < 16; i++)
327 response[i] = buffer_get_char(&buffer);
328
329 /* The buffer containing the packet is no longer needed. */
330 buffer_free(&buffer);
331
332 /* Correct answer. */
333 return 1;
334}
335
336/*
337 * Adds an identity to the authentication server. This call is not meant to
338 * be used by normal applications.
339 */
340
341int
342ssh_add_identity(AuthenticationConnection *auth,
343 RSA * key, const char *comment)
344{
345 Buffer buffer;
346 unsigned char buf[8192];
347 int len, l, type;
348
349 /* Format a message to the agent. */
350 buffer_init(&buffer);
351 buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
352 buffer_put_int(&buffer, BN_num_bits(key->n));
353 buffer_put_bignum(&buffer, key->n);
354 buffer_put_bignum(&buffer, key->e);
355 buffer_put_bignum(&buffer, key->d);
356 /* To keep within the protocol: p < q for ssh. in SSL p > q */
357 buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
358 buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
359 buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
360 buffer_put_string(&buffer, comment, strlen(comment));
361
362 /* Get the length of the message, and format it in the buffer. */
363 len = buffer_len(&buffer);
364 PUT_32BIT(buf, len);
365
366 /* Send the length and then the packet to the agent. */
367 if (atomicio(write, auth->fd, buf, 4) != 4 ||
368 atomicio(write, auth->fd, buffer_ptr(&buffer),
369 buffer_len(&buffer)) != buffer_len(&buffer)) {
370 error("Error writing to authentication socket.");
371error_cleanup:
372 buffer_free(&buffer);
373 return 0;
374 }
375 /* Wait for response from the agent. First read the length of the
376 response packet. */
377 len = 4;
378 while (len > 0) {
379 l = read(auth->fd, buf + 4 - len, len);
380 if (l <= 0) {
381 error("Error reading response length from authentication socket.");
382 goto error_cleanup;
383 }
384 len -= l;
385 }
386
387 /* Extract the length, and check it for sanity. */
388 len = GET_32BIT(buf);
389 if (len > 256 * 1024)
390 fatal("Add identity response too long: %d", len);
391
392 /* Read the rest of the response in tothe buffer. */
393 buffer_clear(&buffer);
394 while (len > 0) {
395 l = len;
396 if (l > sizeof(buf))
397 l = sizeof(buf);
398 l = read(auth->fd, buf, l);
399 if (l <= 0) {
400 error("Error reading response from authentication socket.");
401 goto error_cleanup;
402 }
403 buffer_append(&buffer, (char *) buf, l);
404 len -= l;
405 }
406
407 /* Get the type of the packet. */
408 type = buffer_get_char(&buffer);
409 switch (type) {
410 case SSH_AGENT_FAILURE:
411 buffer_free(&buffer);
412 return 0;
413 case SSH_AGENT_SUCCESS:
414 buffer_free(&buffer);
415 return 1;
416 default:
417 fatal("Bad response to add identity from authentication agent: %d",
418 type);
419 }
420 /* NOTREACHED */
421 return 0;
422}
423
424/*
425 * Removes an identity from the authentication server. This call is not
426 * meant to be used by normal applications.
427 */
428
429int
430ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
431{
432 Buffer buffer;
433 unsigned char buf[8192];
434 int len, l, type;
435
436 /* Format a message to the agent. */
437 buffer_init(&buffer);
438 buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
439 buffer_put_int(&buffer, BN_num_bits(key->n));
440 buffer_put_bignum(&buffer, key->e);
441 buffer_put_bignum(&buffer, key->n);
442
443 /* Get the length of the message, and format it in the buffer. */
444 len = buffer_len(&buffer);
445 PUT_32BIT(buf, len);
446
447 /* Send the length and then the packet to the agent. */
448 if (atomicio(write, auth->fd, buf, 4) != 4 ||
449 atomicio(write, auth->fd, buffer_ptr(&buffer),
450 buffer_len(&buffer)) != buffer_len(&buffer)) {
451 error("Error writing to authentication socket.");
452error_cleanup:
453 buffer_free(&buffer);
454 return 0;
455 }
456 /*
457 * Wait for response from the agent. First read the length of the
458 * response packet.
459 */
460 len = 4;
461 while (len > 0) {
462 l = read(auth->fd, buf + 4 - len, len);
463 if (l <= 0) {
464 error("Error reading response length from authentication socket.");
465 goto error_cleanup;
466 }
467 len -= l;
468 }
469
470 /* Extract the length, and check it for sanity. */
471 len = GET_32BIT(buf);
472 if (len > 256 * 1024)
473 fatal("Remove identity response too long: %d", len);
474
475 /* Read the rest of the response in tothe buffer. */
476 buffer_clear(&buffer);
477 while (len > 0) {
478 l = len;
479 if (l > sizeof(buf))
480 l = sizeof(buf);
481 l = read(auth->fd, buf, l);
482 if (l <= 0) {
483 error("Error reading response from authentication socket.");
484 goto error_cleanup;
485 }
486 buffer_append(&buffer, (char *) buf, l);
487 len -= l;
488 }
489
490 /* Get the type of the packet. */
491 type = buffer_get_char(&buffer);
492 switch (type) {
493 case SSH_AGENT_FAILURE:
494 buffer_free(&buffer);
495 return 0;
496 case SSH_AGENT_SUCCESS:
497 buffer_free(&buffer);
498 return 1;
499 default:
500 fatal("Bad response to remove identity from authentication agent: %d",
501 type);
502 }
503 /* NOTREACHED */
504 return 0;
505}
506
507/*
508 * Removes all identities from the agent. This call is not meant to be used
509 * by normal applications.
510 */
511
512int
513ssh_remove_all_identities(AuthenticationConnection *auth)
514{
515 Buffer buffer;
516 unsigned char buf[8192];
517 int len, l, type;
518
519 /* Get the length of the message, and format it in the buffer. */
520 PUT_32BIT(buf, 1);
521 buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
522
523 /* Send the length and then the packet to the agent. */
524 if (atomicio(write, auth->fd, buf, 5) != 5) {
525 error("Error writing to authentication socket.");
526 return 0;
527 }
528 /*
529 * Wait for response from the agent. First read the length of the
530 * response packet.
531 */
532 len = 4;
533 while (len > 0) {
534 l = read(auth->fd, buf + 4 - len, len);
535 if (l <= 0) {
536 error("Error reading response length from authentication socket.");
537 return 0;
538 }
539 len -= l;
540 }
541
542 /* Extract the length, and check it for sanity. */
543 len = GET_32BIT(buf);
544 if (len > 256 * 1024)
545 fatal("Remove identity response too long: %d", len);
546
547 /* Read the rest of the response into the buffer. */
548 buffer_init(&buffer);
549 while (len > 0) {
550 l = len;
551 if (l > sizeof(buf))
552 l = sizeof(buf);
553 l = read(auth->fd, buf, l);
554 if (l <= 0) {
555 error("Error reading response from authentication socket.");
556 buffer_free(&buffer);
557 return 0;
558 }
559 buffer_append(&buffer, (char *) buf, l);
560 len -= l;
561 }
562
563 /* Get the type of the packet. */
564 type = buffer_get_char(&buffer);
565 switch (type) {
566 case SSH_AGENT_FAILURE:
567 buffer_free(&buffer);
568 return 0;
569 case SSH_AGENT_SUCCESS:
570 buffer_free(&buffer);
571 return 1;
572 default:
573 fatal("Bad response to remove identity from authentication agent: %d",
574 type);
575 }
576 /* NOTREACHED */
577 return 0;
578}
29
30/* Returns the number of the authentication fd, or -1 if there is none. */
31
32int
33ssh_get_authentication_socket()
34{
35 const char *authsocket;
36 int sock;
37 struct sockaddr_un sunaddr;
38
39 authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
40 if (!authsocket)
41 return -1;
42
43 sunaddr.sun_family = AF_UNIX;
44 strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
45
46 sock = socket(AF_UNIX, SOCK_STREAM, 0);
47 if (sock < 0)
48 return -1;
49
50 /* close on exec */
51 if (fcntl(sock, F_SETFD, 1) == -1) {
52 close(sock);
53 return -1;
54 }
55 if (connect(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
56 close(sock);
57 return -1;
58 }
59 return sock;
60}
61
62/*
63 * Closes the agent socket if it should be closed (depends on how it was
64 * obtained). The argument must have been returned by
65 * ssh_get_authentication_socket().
66 */
67
68void
69ssh_close_authentication_socket(int sock)
70{
71 if (getenv(SSH_AUTHSOCKET_ENV_NAME))
72 close(sock);
73}
74
75/*
76 * Opens and connects a private socket for communication with the
77 * authentication agent. Returns the file descriptor (which must be
78 * shut down and closed by the caller when no longer needed).
79 * Returns NULL if an error occurred and the connection could not be
80 * opened.
81 */
82
83AuthenticationConnection *
84ssh_get_authentication_connection()
85{
86 AuthenticationConnection *auth;
87 int sock;
88
89 sock = ssh_get_authentication_socket();
90
91 /*
92 * Fail if we couldn't obtain a connection. This happens if we
93 * exited due to a timeout.
94 */
95 if (sock < 0)
96 return NULL;
97
98 auth = xmalloc(sizeof(*auth));
99 auth->fd = sock;
100 buffer_init(&auth->packet);
101 buffer_init(&auth->identities);
102 auth->howmany = 0;
103
104 return auth;
105}
106
107/*
108 * Closes the connection to the authentication agent and frees any associated
109 * memory.
110 */
111
112void
113ssh_close_authentication_connection(AuthenticationConnection *ac)
114{
115 buffer_free(&ac->packet);
116 buffer_free(&ac->identities);
117 close(ac->fd);
118 xfree(ac);
119}
120
121/*
122 * Returns the first authentication identity held by the agent.
123 * Returns true if an identity is available, 0 otherwise.
124 * The caller must initialize the integers before the call, and free the
125 * comment after a successful call (before calling ssh_get_next_identity).
126 */
127
128int
129ssh_get_first_identity(AuthenticationConnection *auth,
130 BIGNUM *e, BIGNUM *n, char **comment)
131{
132 unsigned char msg[8192];
133 int len, l;
134
135 /*
136 * Send a message to the agent requesting for a list of the
137 * identities it can represent.
138 */
139 msg[0] = 0;
140 msg[1] = 0;
141 msg[2] = 0;
142 msg[3] = 1;
143 msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
144 if (atomicio(write, auth->fd, msg, 5) != 5) {
145 error("write auth->fd: %.100s", strerror(errno));
146 return 0;
147 }
148 /* Read the length of the response. XXX implement timeouts here. */
149 len = 4;
150 while (len > 0) {
151 l = read(auth->fd, msg + 4 - len, len);
152 if (l <= 0) {
153 error("read auth->fd: %.100s", strerror(errno));
154 return 0;
155 }
156 len -= l;
157 }
158
159 /*
160 * Extract the length, and check it for sanity. (We cannot trust
161 * authentication agents).
162 */
163 len = GET_32BIT(msg);
164 if (len < 1 || len > 256 * 1024)
165 fatal("Authentication reply message too long: %d\n", len);
166
167 /* Read the packet itself. */
168 buffer_clear(&auth->identities);
169 while (len > 0) {
170 l = len;
171 if (l > sizeof(msg))
172 l = sizeof(msg);
173 l = read(auth->fd, msg, l);
174 if (l <= 0)
175 fatal("Incomplete authentication reply.");
176 buffer_append(&auth->identities, (char *) msg, l);
177 len -= l;
178 }
179
180 /* Get message type, and verify that we got a proper answer. */
181 buffer_get(&auth->identities, (char *) msg, 1);
182 if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
183 fatal("Bad authentication reply message type: %d", msg[0]);
184
185 /* Get the number of entries in the response and check it for sanity. */
186 auth->howmany = buffer_get_int(&auth->identities);
187 if (auth->howmany > 1024)
188 fatal("Too many identities in authentication reply: %d\n", auth->howmany);
189
190 /* Return the first entry (if any). */
191 return ssh_get_next_identity(auth, e, n, comment);
192}
193
194/*
195 * Returns the next authentication identity for the agent. Other functions
196 * can be called between this and ssh_get_first_identity or two calls of this
197 * function. This returns 0 if there are no more identities. The caller
198 * must free comment after a successful return.
199 */
200
201int
202ssh_get_next_identity(AuthenticationConnection *auth,
203 BIGNUM *e, BIGNUM *n, char **comment)
204{
205 unsigned int bits;
206
207 /* Return failure if no more entries. */
208 if (auth->howmany <= 0)
209 return 0;
210
211 /*
212 * Get the next entry from the packet. These will abort with a fatal
213 * error if the packet is too short or contains corrupt data.
214 */
215 bits = buffer_get_int(&auth->identities);
216 buffer_get_bignum(&auth->identities, e);
217 buffer_get_bignum(&auth->identities, n);
218 *comment = buffer_get_string(&auth->identities, NULL);
219
220 if (bits != BN_num_bits(n))
221 error("Warning: identity keysize mismatch: actual %d, announced %u",
222 BN_num_bits(n), bits);
223
224 /* Decrement the number of remaining entries. */
225 auth->howmany--;
226
227 return 1;
228}
229
230/*
231 * Generates a random challenge, sends it to the agent, and waits for
232 * response from the agent. Returns true (non-zero) if the agent gave the
233 * correct answer, zero otherwise. Response type selects the style of
234 * response desired, with 0 corresponding to protocol version 1.0 (no longer
235 * supported) and 1 corresponding to protocol version 1.1.
236 */
237
238int
239ssh_decrypt_challenge(AuthenticationConnection *auth,
240 BIGNUM* e, BIGNUM *n, BIGNUM *challenge,
241 unsigned char session_id[16],
242 unsigned int response_type,
243 unsigned char response[16])
244{
245 Buffer buffer;
246 unsigned char buf[8192];
247 int len, l, i;
248
249 /* Response type 0 is no longer supported. */
250 if (response_type == 0)
251 fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
252
253 /* Format a message to the agent. */
254 buf[0] = SSH_AGENTC_RSA_CHALLENGE;
255 buffer_init(&buffer);
256 buffer_append(&buffer, (char *) buf, 1);
257 buffer_put_int(&buffer, BN_num_bits(n));
258 buffer_put_bignum(&buffer, e);
259 buffer_put_bignum(&buffer, n);
260 buffer_put_bignum(&buffer, challenge);
261 buffer_append(&buffer, (char *) session_id, 16);
262 buffer_put_int(&buffer, response_type);
263
264 /* Get the length of the message, and format it in the buffer. */
265 len = buffer_len(&buffer);
266 PUT_32BIT(buf, len);
267
268 /* Send the length and then the packet to the agent. */
269 if (atomicio(write, auth->fd, buf, 4) != 4 ||
270 atomicio(write, auth->fd, buffer_ptr(&buffer),
271 buffer_len(&buffer)) != buffer_len(&buffer)) {
272 error("Error writing to authentication socket.");
273error_cleanup:
274 buffer_free(&buffer);
275 return 0;
276 }
277 /*
278 * Wait for response from the agent. First read the length of the
279 * response packet.
280 */
281 len = 4;
282 while (len > 0) {
283 l = read(auth->fd, buf + 4 - len, len);
284 if (l <= 0) {
285 error("Error reading response length from authentication socket.");
286 goto error_cleanup;
287 }
288 len -= l;
289 }
290
291 /* Extract the length, and check it for sanity. */
292 len = GET_32BIT(buf);
293 if (len > 256 * 1024)
294 fatal("Authentication response too long: %d", len);
295
296 /* Read the rest of the response in tothe buffer. */
297 buffer_clear(&buffer);
298 while (len > 0) {
299 l = len;
300 if (l > sizeof(buf))
301 l = sizeof(buf);
302 l = read(auth->fd, buf, l);
303 if (l <= 0) {
304 error("Error reading response from authentication socket.");
305 goto error_cleanup;
306 }
307 buffer_append(&buffer, (char *) buf, l);
308 len -= l;
309 }
310
311 /* Get the type of the packet. */
312 buffer_get(&buffer, (char *) buf, 1);
313
314 /* Check for agent failure message. */
315 if (buf[0] == SSH_AGENT_FAILURE) {
316 log("Agent admitted failure to authenticate using the key.");
317 goto error_cleanup;
318 }
319 /* Now it must be an authentication response packet. */
320 if (buf[0] != SSH_AGENT_RSA_RESPONSE)
321 fatal("Bad authentication response: %d", buf[0]);
322
323 /*
324 * Get the response from the packet. This will abort with a fatal
325 * error if the packet is corrupt.
326 */
327 for (i = 0; i < 16; i++)
328 response[i] = buffer_get_char(&buffer);
329
330 /* The buffer containing the packet is no longer needed. */
331 buffer_free(&buffer);
332
333 /* Correct answer. */
334 return 1;
335}
336
337/*
338 * Adds an identity to the authentication server. This call is not meant to
339 * be used by normal applications.
340 */
341
342int
343ssh_add_identity(AuthenticationConnection *auth,
344 RSA * key, const char *comment)
345{
346 Buffer buffer;
347 unsigned char buf[8192];
348 int len, l, type;
349
350 /* Format a message to the agent. */
351 buffer_init(&buffer);
352 buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
353 buffer_put_int(&buffer, BN_num_bits(key->n));
354 buffer_put_bignum(&buffer, key->n);
355 buffer_put_bignum(&buffer, key->e);
356 buffer_put_bignum(&buffer, key->d);
357 /* To keep within the protocol: p < q for ssh. in SSL p > q */
358 buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
359 buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
360 buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
361 buffer_put_string(&buffer, comment, strlen(comment));
362
363 /* Get the length of the message, and format it in the buffer. */
364 len = buffer_len(&buffer);
365 PUT_32BIT(buf, len);
366
367 /* Send the length and then the packet to the agent. */
368 if (atomicio(write, auth->fd, buf, 4) != 4 ||
369 atomicio(write, auth->fd, buffer_ptr(&buffer),
370 buffer_len(&buffer)) != buffer_len(&buffer)) {
371 error("Error writing to authentication socket.");
372error_cleanup:
373 buffer_free(&buffer);
374 return 0;
375 }
376 /* Wait for response from the agent. First read the length of the
377 response packet. */
378 len = 4;
379 while (len > 0) {
380 l = read(auth->fd, buf + 4 - len, len);
381 if (l <= 0) {
382 error("Error reading response length from authentication socket.");
383 goto error_cleanup;
384 }
385 len -= l;
386 }
387
388 /* Extract the length, and check it for sanity. */
389 len = GET_32BIT(buf);
390 if (len > 256 * 1024)
391 fatal("Add identity response too long: %d", len);
392
393 /* Read the rest of the response in tothe buffer. */
394 buffer_clear(&buffer);
395 while (len > 0) {
396 l = len;
397 if (l > sizeof(buf))
398 l = sizeof(buf);
399 l = read(auth->fd, buf, l);
400 if (l <= 0) {
401 error("Error reading response from authentication socket.");
402 goto error_cleanup;
403 }
404 buffer_append(&buffer, (char *) buf, l);
405 len -= l;
406 }
407
408 /* Get the type of the packet. */
409 type = buffer_get_char(&buffer);
410 switch (type) {
411 case SSH_AGENT_FAILURE:
412 buffer_free(&buffer);
413 return 0;
414 case SSH_AGENT_SUCCESS:
415 buffer_free(&buffer);
416 return 1;
417 default:
418 fatal("Bad response to add identity from authentication agent: %d",
419 type);
420 }
421 /* NOTREACHED */
422 return 0;
423}
424
425/*
426 * Removes an identity from the authentication server. This call is not
427 * meant to be used by normal applications.
428 */
429
430int
431ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
432{
433 Buffer buffer;
434 unsigned char buf[8192];
435 int len, l, type;
436
437 /* Format a message to the agent. */
438 buffer_init(&buffer);
439 buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
440 buffer_put_int(&buffer, BN_num_bits(key->n));
441 buffer_put_bignum(&buffer, key->e);
442 buffer_put_bignum(&buffer, key->n);
443
444 /* Get the length of the message, and format it in the buffer. */
445 len = buffer_len(&buffer);
446 PUT_32BIT(buf, len);
447
448 /* Send the length and then the packet to the agent. */
449 if (atomicio(write, auth->fd, buf, 4) != 4 ||
450 atomicio(write, auth->fd, buffer_ptr(&buffer),
451 buffer_len(&buffer)) != buffer_len(&buffer)) {
452 error("Error writing to authentication socket.");
453error_cleanup:
454 buffer_free(&buffer);
455 return 0;
456 }
457 /*
458 * Wait for response from the agent. First read the length of the
459 * response packet.
460 */
461 len = 4;
462 while (len > 0) {
463 l = read(auth->fd, buf + 4 - len, len);
464 if (l <= 0) {
465 error("Error reading response length from authentication socket.");
466 goto error_cleanup;
467 }
468 len -= l;
469 }
470
471 /* Extract the length, and check it for sanity. */
472 len = GET_32BIT(buf);
473 if (len > 256 * 1024)
474 fatal("Remove identity response too long: %d", len);
475
476 /* Read the rest of the response in tothe buffer. */
477 buffer_clear(&buffer);
478 while (len > 0) {
479 l = len;
480 if (l > sizeof(buf))
481 l = sizeof(buf);
482 l = read(auth->fd, buf, l);
483 if (l <= 0) {
484 error("Error reading response from authentication socket.");
485 goto error_cleanup;
486 }
487 buffer_append(&buffer, (char *) buf, l);
488 len -= l;
489 }
490
491 /* Get the type of the packet. */
492 type = buffer_get_char(&buffer);
493 switch (type) {
494 case SSH_AGENT_FAILURE:
495 buffer_free(&buffer);
496 return 0;
497 case SSH_AGENT_SUCCESS:
498 buffer_free(&buffer);
499 return 1;
500 default:
501 fatal("Bad response to remove identity from authentication agent: %d",
502 type);
503 }
504 /* NOTREACHED */
505 return 0;
506}
507
508/*
509 * Removes all identities from the agent. This call is not meant to be used
510 * by normal applications.
511 */
512
513int
514ssh_remove_all_identities(AuthenticationConnection *auth)
515{
516 Buffer buffer;
517 unsigned char buf[8192];
518 int len, l, type;
519
520 /* Get the length of the message, and format it in the buffer. */
521 PUT_32BIT(buf, 1);
522 buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
523
524 /* Send the length and then the packet to the agent. */
525 if (atomicio(write, auth->fd, buf, 5) != 5) {
526 error("Error writing to authentication socket.");
527 return 0;
528 }
529 /*
530 * Wait for response from the agent. First read the length of the
531 * response packet.
532 */
533 len = 4;
534 while (len > 0) {
535 l = read(auth->fd, buf + 4 - len, len);
536 if (l <= 0) {
537 error("Error reading response length from authentication socket.");
538 return 0;
539 }
540 len -= l;
541 }
542
543 /* Extract the length, and check it for sanity. */
544 len = GET_32BIT(buf);
545 if (len > 256 * 1024)
546 fatal("Remove identity response too long: %d", len);
547
548 /* Read the rest of the response into the buffer. */
549 buffer_init(&buffer);
550 while (len > 0) {
551 l = len;
552 if (l > sizeof(buf))
553 l = sizeof(buf);
554 l = read(auth->fd, buf, l);
555 if (l <= 0) {
556 error("Error reading response from authentication socket.");
557 buffer_free(&buffer);
558 return 0;
559 }
560 buffer_append(&buffer, (char *) buf, l);
561 len -= l;
562 }
563
564 /* Get the type of the packet. */
565 type = buffer_get_char(&buffer);
566 switch (type) {
567 case SSH_AGENT_FAILURE:
568 buffer_free(&buffer);
569 return 0;
570 case SSH_AGENT_SUCCESS:
571 buffer_free(&buffer);
572 return 1;
573 default:
574 fatal("Bad response to remove identity from authentication agent: %d",
575 type);
576 }
577 /* NOTREACHED */
578 return 0;
579}