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