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