Annotation of src/usr.bin/ssh/authfd.c, Revision 1.14
1.1 deraadt 1: /*
1.13 deraadt 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: */
1.1 deraadt 15:
16: #include "includes.h"
1.14 ! markus 17: RCSID("$Id: authfd.c,v 1.13 1999/11/24 00:26:00 deraadt Exp $");
1.1 deraadt 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:
1.2 provos 27: #include <ssl/rsa.h>
28:
1.1 deraadt 29: /* Returns the number of the authentication fd, or -1 if there is none. */
30:
1.2 provos 31: int
1.8 markus 32: ssh_get_authentication_socket()
1.1 deraadt 33: {
1.12 markus 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;
1.1 deraadt 59: }
60:
1.14 ! markus 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: */
1.1 deraadt 66:
1.12 markus 67: void
68: ssh_close_authentication_socket(int sock)
1.1 deraadt 69: {
1.12 markus 70: if (getenv(SSH_AUTHSOCKET_ENV_NAME))
71: close(sock);
1.1 deraadt 72: }
73:
1.14 ! markus 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: */
1.1 deraadt 81:
1.12 markus 82: AuthenticationConnection *
83: ssh_get_authentication_connection()
1.1 deraadt 84: {
1.12 markus 85: AuthenticationConnection *auth;
86: int sock;
1.1 deraadt 87:
1.12 markus 88: sock = ssh_get_authentication_socket();
89:
1.14 ! markus 90: /*
! 91: * Fail if we couldn't obtain a connection. This happens if we
! 92: * exited due to a timeout.
! 93: */
1.12 markus 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;
1.1 deraadt 104: }
105:
1.14 ! markus 106: /*
! 107: * Closes the connection to the authentication agent and frees any associated
! 108: * memory.
! 109: */
1.1 deraadt 110:
1.12 markus 111: void
112: ssh_close_authentication_connection(AuthenticationConnection *ac)
1.1 deraadt 113: {
1.12 markus 114: buffer_free(&ac->packet);
115: buffer_free(&ac->identities);
116: close(ac->fd);
117: xfree(ac);
1.1 deraadt 118: }
119:
1.14 ! markus 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: */
1.1 deraadt 126:
1.2 provos 127: int
128: ssh_get_first_identity(AuthenticationConnection *auth,
1.9 markus 129: BIGNUM *e, BIGNUM *n, char **comment)
1.1 deraadt 130: {
1.12 markus 131: unsigned char msg[8192];
132: int len, l;
1.1 deraadt 133:
1.14 ! markus 134: /*
! 135: * Send a message to the agent requesting for a list of the
! 136: * identities it can represent.
! 137: */
1.12 markus 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 (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:
1.14 ! markus 158: /*
! 159: * Extract the length, and check it for sanity. (We cannot trust
! 160: * authentication agents).
! 161: */
1.12 markus 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: }
1.1 deraadt 178:
1.12 markus 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);
1.1 deraadt 191: }
192:
1.14 ! markus 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: */
1.1 deraadt 199:
1.2 provos 200: int
201: ssh_get_next_identity(AuthenticationConnection *auth,
1.9 markus 202: BIGNUM *e, BIGNUM *n, char **comment)
1.1 deraadt 203: {
1.12 markus 204: unsigned int bits;
1.9 markus 205:
1.12 markus 206: /* Return failure if no more entries. */
207: if (auth->howmany <= 0)
208: return 0;
209:
1.14 ! markus 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: */
1.12 markus 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: keysize mismatch: actual %d, announced %u",
221: BN_num_bits(n), bits);
1.9 markus 222:
1.12 markus 223: /* Decrement the number of remaining entries. */
224: auth->howmany--;
1.1 deraadt 225:
1.12 markus 226: return 1;
1.1 deraadt 227: }
228:
1.14 ! markus 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: */
1.1 deraadt 236:
1.2 provos 237: int
238: ssh_decrypt_challenge(AuthenticationConnection *auth,
1.12 markus 239: BIGNUM* e, BIGNUM *n, BIGNUM *challenge,
1.2 provos 240: unsigned char session_id[16],
241: unsigned int response_type,
242: unsigned char response[16])
1.1 deraadt 243: {
1.12 markus 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 (write(auth->fd, buf, 4) != 4 ||
269: write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
270: buffer_len(&buffer)) {
271: error("Error writing to authentication socket.");
272: error_cleanup:
273: buffer_free(&buffer);
274: return 0;
275: }
1.14 ! markus 276: /*
! 277: * Wait for response from the agent. First read the length of the
! 278: * response packet.
! 279: */
1.12 markus 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:
1.14 ! markus 322: /*
! 323: * Get the response from the packet. This will abort with a fatal
! 324: * error if the packet is corrupt.
! 325: */
1.12 markus 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: }
1.1 deraadt 335:
1.14 ! markus 336: /*
! 337: * Adds an identity to the authentication server. This call is not meant to
! 338: * be used by normal applications.
! 339: */
1.1 deraadt 340:
1.12 markus 341: int
342: ssh_add_identity(AuthenticationConnection *auth,
343: RSA * key, const char *comment)
1.1 deraadt 344: {
1.12 markus 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 (write(auth->fd, buf, 4) != 4 ||
368: write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
369: buffer_len(&buffer)) {
370: error("Error writing to authentication socket.");
371: error_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: }
1.1 deraadt 423:
1.14 ! markus 424: /*
! 425: * Removes an identity from the authentication server. This call is not
! 426: * meant to be used by normal applications.
! 427: */
1.1 deraadt 428:
1.12 markus 429: int
430: ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
1.1 deraadt 431: {
1.12 markus 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 (write(auth->fd, buf, 4) != 4 ||
449: write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
450: buffer_len(&buffer)) {
451: error("Error writing to authentication socket.");
452: error_cleanup:
453: buffer_free(&buffer);
454: return 0;
455: }
1.14 ! markus 456: /*
! 457: * Wait for response from the agent. First read the length of the
! 458: * response packet.
! 459: */
1.12 markus 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: }
1.1 deraadt 489:
1.12 markus 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:
1.14 ! markus 507: /*
! 508: * Removes all identities from the agent. This call is not meant to be used
! 509: * by normal applications.
! 510: */
1.1 deraadt 511:
1.12 markus 512: int
513: ssh_remove_all_identities(AuthenticationConnection *auth)
1.1 deraadt 514: {
1.12 markus 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: error("Error writing to authentication socket.");
526: return 0;
527: }
1.14 ! markus 528: /*
! 529: * Wait for response from the agent. First read the length of the
! 530: * response packet.
! 531: */
1.12 markus 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: }