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