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