xref: /openbsd/usr.bin/ssh/authfd.c (revision 76c6bcb9)
1 /*
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 */
15 
16 #include "includes.h"
17 RCSID("$Id: authfd.c,v 1.2 1999/09/28 04:45:35 provos Exp $");
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 <ssl/rsa.h>
28 
29 /* Returns the number of the authentication fd, or -1 if there is none. */
30 
31 int
32 ssh_get_authentication_fd()
33 {
34   const char *authfd, *authsocket;
35   int sock;
36   struct sockaddr_un sunaddr;
37 
38   /* Get the file descriptor number from environment. */
39   authfd = getenv(SSH_AUTHFD_ENV_NAME);
40 
41   /* Convert the value to an integer and return it if we got a value. */
42   if (authfd)
43     return atoi(authfd);
44 
45   authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
46   if (!authsocket)
47     return -1;
48 
49   sunaddr.sun_family = AF_UNIX;
50   strncpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
51 
52   sock = socket(AF_UNIX, SOCK_STREAM, 0);
53   if (sock < 0)
54     return -1;
55 
56   if (connect(sock, (struct sockaddr *)&sunaddr, AF_UNIX_SIZE(sunaddr)) < 0)
57     {
58       close(sock);
59       return -1;
60     }
61 
62   return sock;
63 }
64 
65 /* Closes the agent socket if it should be closed (depends on how it was
66    obtained).  The argument must have been returned by
67    ssh_get_authentication_fd(). */
68 
69 void ssh_close_authentication_socket(int sock)
70 {
71   if (getenv(SSH_AUTHSOCKET_ENV_NAME))
72     close(sock);
73 }
74 
75 /* Dummy alarm used to prevent waiting for connection from the
76    authentication agent indefinitely. */
77 
78 static RETSIGTYPE dummy_alarm_handler(int sig)
79 {
80   /* Do nothing; a cought signal will just cause accept to return. */
81 }
82 
83 /* Opens a socket to the authentication server.  Returns the number of
84    that socket, or -1 if no connection could be made. */
85 
86 int ssh_get_authentication_connection_fd()
87 {
88   int authfd;
89   int listen_sock, sock, port, addrlen;
90   int old_timeout;
91   RETSIGTYPE (*old_handler)();
92   struct sockaddr_in sin;
93   char msg[3];
94 
95   /* Get the the socket number from the environment.  This is the socket
96      used to obtain the real authentication socket. */
97   authfd = ssh_get_authentication_fd();
98   if (authfd == -1)
99     return -1;
100 
101   /* Create a local socket for listening. */
102   listen_sock = socket(AF_INET, SOCK_STREAM, 0);
103   if (listen_sock == -1)
104     {
105       ssh_close_authentication_socket(authfd);
106       return -1;
107     }
108 
109   /* Bind the socket to random unprivileged port. */
110   memset(&sin, 0, sizeof(sin));
111   sin.sin_family = AF_INET;
112   do
113     {
114       port = 32768 + (rand() % 30000);
115       sin.sin_port = htons(port);
116     }
117   while (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0 &&
118 	 errno == EADDRINUSE);
119 
120   /* Start listening for connections on the socket. */
121   if (listen(listen_sock, 1) < 0)
122     {
123       error("listen: %.100s", strerror(errno));
124       close(listen_sock);
125       ssh_close_authentication_socket(authfd);
126       return -1;
127     }
128 
129   /* Send a message to the authentication fd requesting the agent or its
130      local representative to connect to the given socket.  Note that
131      we use send() to get the packet sent atomically (there can be several
132      clients trying to use the same authentication fd simultaneously). */
133   msg[0] = (char)SSH_AUTHFD_CONNECT;
134   PUT_16BIT(msg + 1, port);
135   if (send(authfd, msg, 3, 0) < 0)
136     {
137       shutdown(listen_sock, 2);
138       close(listen_sock);
139       ssh_close_authentication_socket(authfd);
140       return -1;
141     }
142 
143   /* Setup a timeout so we won't wait for the connection indefinitely. */
144   old_timeout = alarm(120);
145   old_handler = signal(SIGALRM, dummy_alarm_handler);
146 
147   /* Wait for the connection from the agent or its representative. */
148   addrlen = sizeof(sin);
149   sock = accept(listen_sock, (struct sockaddr *)&sin, &addrlen);
150 
151   /* Remove the alarm (restore its old values). */
152   alarm(old_timeout);
153   signal(SIGALRM, old_handler);
154 
155   /* Close the socket we used for listening.  It is no longer needed.
156      (The authentication fd and the new connection still remain open.) */
157   shutdown(listen_sock, 2);
158   close(listen_sock);
159   ssh_close_authentication_socket(authfd);
160 
161   return sock;
162 }
163 
164 /* Opens and connects a private socket for communication with the
165    authentication agent.  Returns the file descriptor (which must be
166    shut down and closed by the caller when no longer needed).
167    Returns NULL if an error occurred and the connection could not be
168    opened. */
169 
170 AuthenticationConnection *ssh_get_authentication_connection()
171 {
172   AuthenticationConnection *auth;
173   int sock;
174 
175   /* Get a connection to the authentication agent. */
176   sock = ssh_get_authentication_connection_fd();
177 
178   /* Fail if we couldn't obtain a connection.  This happens if we exited
179      due to a timeout. */
180   if (sock < 0)
181     return NULL;
182 
183   /* Applocate the connection structure and initialize it. */
184   auth = xmalloc(sizeof(*auth));
185   auth->fd = sock;
186   buffer_init(&auth->packet);
187   buffer_init(&auth->identities);
188   auth->howmany = 0;
189 
190   return auth;
191 }
192 
193 /* Closes the connection to the authentication agent and frees any associated
194    memory. */
195 
196 void ssh_close_authentication_connection(AuthenticationConnection *ac)
197 {
198   buffer_free(&ac->packet);
199   buffer_free(&ac->identities);
200   close(ac->fd);
201 }
202 
203 /* Returns the first authentication identity held by the agent.
204    Returns true if an identity is available, 0 otherwise.
205    The caller must initialize the integers before the call, and free the
206    comment after a successful call (before calling ssh_get_next_identity). */
207 
208 int
209 ssh_get_first_identity(AuthenticationConnection *auth,
210 		       int *bitsp, BIGNUM *e, BIGNUM *n, char **comment)
211 {
212   unsigned char msg[8192];
213   int len, l;
214 
215   /* Send a message to the agent requesting for a list of the identities
216      it can represent. */
217   msg[0] = 0;
218   msg[1] = 0;
219   msg[2] = 0;
220   msg[3] = 1;
221   msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
222   if (write(auth->fd, msg, 5) != 5)
223     {
224       error("write auth->fd: %.100s", strerror(errno));
225       return 0;
226     }
227 
228   /* Read the length of the response.  XXX implement timeouts here. */
229   len = 4;
230   while (len > 0)
231     {
232       l = read(auth->fd, msg + 4 - len, len);
233       if (l <= 0)
234 	{
235 	  error("read auth->fd: %.100s", strerror(errno));
236 	  return 0;
237 	}
238       len -= l;
239     }
240 
241   /* Extract the length, and check it for sanity.  (We cannot trust
242      authentication agents). */
243   len = GET_32BIT(msg);
244   if (len < 1 || len > 256*1024)
245     fatal("Authentication reply message too long: %d\n", len);
246 
247   /* Read the packet itself. */
248   buffer_clear(&auth->identities);
249   while (len > 0)
250     {
251       l = len;
252       if (l > sizeof(msg))
253 	l = sizeof(msg);
254       l = read(auth->fd, msg, l);
255       if (l <= 0)
256 	fatal("Incomplete authentication reply.");
257       buffer_append(&auth->identities, (char *)msg, l);
258       len -= l;
259     }
260 
261   /* Get message type, and verify that we got a proper answer. */
262   buffer_get(&auth->identities, (char *)msg, 1);
263   if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
264     fatal("Bad authentication reply message type: %d", msg[0]);
265 
266   /* Get the number of entries in the response and check it for sanity. */
267   auth->howmany = buffer_get_int(&auth->identities);
268   if (auth->howmany > 1024)
269     fatal("Too many identities in authentication reply: %d\n", auth->howmany);
270 
271   /* Return the first entry (if any). */
272   return ssh_get_next_identity(auth, bitsp, e, n, comment);
273 }
274 
275 /* Returns the next authentication identity for the agent.  Other functions
276    can be called between this and ssh_get_first_identity or two calls of this
277    function.  This returns 0 if there are no more identities.  The caller
278    must free comment after a successful return. */
279 
280 int
281 ssh_get_next_identity(AuthenticationConnection *auth,
282 		      int *bitsp, BIGNUM *e, BIGNUM *n, char **comment)
283 {
284   /* Return failure if no more entries. */
285   if (auth->howmany <= 0)
286     return 0;
287 
288   /* Get the next entry from the packet.  These will abort with a fatal
289      error if the packet is too short or contains corrupt data. */
290   *bitsp = buffer_get_int(&auth->identities);
291   buffer_get_bignum(&auth->identities, e);
292   buffer_get_bignum(&auth->identities, n);
293   *comment = buffer_get_string(&auth->identities, NULL);
294 
295   /* Decrement the number of remaining entries. */
296   auth->howmany--;
297 
298   return 1;
299 }
300 
301 /* Generates a random challenge, sends it to the agent, and waits for response
302    from the agent.  Returns true (non-zero) if the agent gave the correct
303    answer, zero otherwise.  Response type selects the style of response
304    desired, with 0 corresponding to protocol version 1.0 (no longer supported)
305    and 1 corresponding to protocol version 1.1. */
306 
307 int
308 ssh_decrypt_challenge(AuthenticationConnection *auth,
309 		      int bits, BIGNUM *e, BIGNUM *n, BIGNUM *challenge,
310 		      unsigned char session_id[16],
311 		      unsigned int response_type,
312 		      unsigned char response[16])
313 {
314   Buffer buffer;
315   unsigned char buf[8192];
316   int len, l, i;
317 
318   /* Response type 0 is no longer supported. */
319   if (response_type == 0)
320     fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
321 
322   /* Format a message to the agent. */
323   buf[0] = SSH_AGENTC_RSA_CHALLENGE;
324   buffer_init(&buffer);
325   buffer_append(&buffer, (char *)buf, 1);
326   buffer_put_int(&buffer, bits);
327   buffer_put_bignum(&buffer, e);
328   buffer_put_bignum(&buffer, n);
329   buffer_put_bignum(&buffer, challenge);
330   buffer_append(&buffer, (char *)session_id, 16);
331   buffer_put_int(&buffer, response_type);
332 
333   /* Get the length of the message, and format it in the buffer. */
334   len = buffer_len(&buffer);
335   PUT_32BIT(buf, len);
336 
337   /* Send the length and then the packet to the agent. */
338   if (write(auth->fd, buf, 4) != 4 ||
339       write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
340         buffer_len(&buffer))
341     {
342       error("Error writing to authentication socket.");
343     error_cleanup:
344       buffer_free(&buffer);
345       return 0;
346     }
347 
348   /* Wait for response from the agent.  First read the length of the
349      response packet. */
350   len = 4;
351   while (len > 0)
352     {
353       l = read(auth->fd, buf + 4 - len, len);
354       if (l <= 0)
355 	{
356 	  error("Error reading response length from authentication socket.");
357 	  goto error_cleanup;
358 	}
359       len -= l;
360     }
361 
362   /* Extract the length, and check it for sanity. */
363   len = GET_32BIT(buf);
364   if (len > 256*1024)
365     fatal("Authentication response too long: %d", len);
366 
367   /* Read the rest of the response in tothe buffer. */
368   buffer_clear(&buffer);
369   while (len > 0)
370     {
371       l = len;
372       if (l > sizeof(buf))
373 	l = sizeof(buf);
374       l = read(auth->fd, buf, l);
375       if (l <= 0)
376 	{
377 	  error("Error reading response from authentication socket.");
378 	  goto error_cleanup;
379 	}
380       buffer_append(&buffer, (char *)buf, l);
381       len -= l;
382     }
383 
384   /* Get the type of the packet. */
385   buffer_get(&buffer, (char *)buf, 1);
386 
387   /* Check for agent failure message. */
388   if (buf[0] == SSH_AGENT_FAILURE)
389     {
390       log("Agent admitted failure to authenticate using the key.");
391       goto error_cleanup;
392     }
393 
394   /* Now it must be an authentication response packet. */
395   if (buf[0] != SSH_AGENT_RSA_RESPONSE)
396     fatal("Bad authentication response: %d", buf[0]);
397 
398   /* Get the response from the packet.  This will abort with a fatal error
399      if the packet is corrupt. */
400   for (i = 0; i < 16; i++)
401     response[i] = buffer_get_char(&buffer);
402 
403   /* The buffer containing the packet is no longer needed. */
404   buffer_free(&buffer);
405 
406   /* Correct answer. */
407   return 1;
408 }
409 
410 /* Adds an identity to the authentication server.  This call is not meant to
411    be used by normal applications. */
412 
413 int ssh_add_identity(AuthenticationConnection *auth,
414 		     RSA *key, const char *comment)
415 {
416   Buffer buffer;
417   unsigned char buf[8192];
418   int len, l, type;
419 
420   /* Format a message to the agent. */
421   buffer_init(&buffer);
422   buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
423   buffer_put_int(&buffer, BN_num_bits(key->n));
424   buffer_put_bignum(&buffer, key->n);
425   buffer_put_bignum(&buffer, key->e);
426   buffer_put_bignum(&buffer, key->d);
427   /* To keep within the protocol: p < q for ssh. in SSL p > q */
428   buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
429   buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
430   buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
431   buffer_put_string(&buffer, comment, strlen(comment));
432 
433   /* Get the length of the message, and format it in the buffer. */
434   len = buffer_len(&buffer);
435   PUT_32BIT(buf, len);
436 
437   /* Send the length and then the packet to the agent. */
438   if (write(auth->fd, buf, 4) != 4 ||
439       write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
440         buffer_len(&buffer))
441     {
442       error("Error writing to authentication socket.");
443     error_cleanup:
444       buffer_free(&buffer);
445       return 0;
446     }
447 
448   /* Wait for response from the agent.  First read the length of the
449      response packet. */
450   len = 4;
451   while (len > 0)
452     {
453       l = read(auth->fd, buf + 4 - len, len);
454       if (l <= 0)
455 	{
456 	  error("Error reading response length from authentication socket.");
457 	  goto error_cleanup;
458 	}
459       len -= l;
460     }
461 
462   /* Extract the length, and check it for sanity. */
463   len = GET_32BIT(buf);
464   if (len > 256*1024)
465     fatal("Add identity response too long: %d", len);
466 
467   /* Read the rest of the response in tothe buffer. */
468   buffer_clear(&buffer);
469   while (len > 0)
470     {
471       l = len;
472       if (l > sizeof(buf))
473 	l = sizeof(buf);
474       l = read(auth->fd, buf, l);
475       if (l <= 0)
476 	{
477 	  error("Error reading response from authentication socket.");
478 	  goto error_cleanup;
479 	}
480       buffer_append(&buffer, (char *)buf, l);
481       len -= l;
482     }
483 
484   /* Get the type of the packet. */
485   type = buffer_get_char(&buffer);
486   switch (type)
487     {
488     case SSH_AGENT_FAILURE:
489       buffer_free(&buffer);
490       return 0;
491     case SSH_AGENT_SUCCESS:
492       buffer_free(&buffer);
493       return 1;
494     default:
495       fatal("Bad response to add identity from authentication agent: %d",
496 	    type);
497     }
498   /*NOTREACHED*/
499   return 0;
500 }
501 
502 /* Removes an identity from the authentication server.  This call is not meant
503    to be used by normal applications. */
504 
505 int ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
506 {
507   Buffer buffer;
508   unsigned char buf[8192];
509   int len, l, type;
510 
511   /* Format a message to the agent. */
512   buffer_init(&buffer);
513   buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
514   buffer_put_int(&buffer, BN_num_bits(key->n));
515   buffer_put_bignum(&buffer, key->e);
516   buffer_put_bignum(&buffer, key->n);
517 
518   /* Get the length of the message, and format it in the buffer. */
519   len = buffer_len(&buffer);
520   PUT_32BIT(buf, len);
521 
522   /* Send the length and then the packet to the agent. */
523   if (write(auth->fd, buf, 4) != 4 ||
524       write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
525         buffer_len(&buffer))
526     {
527       error("Error writing to authentication socket.");
528     error_cleanup:
529       buffer_free(&buffer);
530       return 0;
531     }
532 
533   /* Wait for response from the agent.  First read the length of the
534      response packet. */
535   len = 4;
536   while (len > 0)
537     {
538       l = read(auth->fd, buf + 4 - len, len);
539       if (l <= 0)
540 	{
541 	  error("Error reading response length from authentication socket.");
542 	  goto error_cleanup;
543 	}
544       len -= l;
545     }
546 
547   /* Extract the length, and check it for sanity. */
548   len = GET_32BIT(buf);
549   if (len > 256*1024)
550     fatal("Remove identity response too long: %d", len);
551 
552   /* Read the rest of the response in tothe buffer. */
553   buffer_clear(&buffer);
554   while (len > 0)
555     {
556       l = len;
557       if (l > sizeof(buf))
558 	l = sizeof(buf);
559       l = read(auth->fd, buf, l);
560       if (l <= 0)
561 	{
562 	  error("Error reading response from authentication socket.");
563 	  goto error_cleanup;
564 	}
565       buffer_append(&buffer, (char *)buf, l);
566       len -= l;
567     }
568 
569   /* Get the type of the packet. */
570   type = buffer_get_char(&buffer);
571   switch (type)
572     {
573     case SSH_AGENT_FAILURE:
574       buffer_free(&buffer);
575       return 0;
576     case SSH_AGENT_SUCCESS:
577       buffer_free(&buffer);
578       return 1;
579     default:
580       fatal("Bad response to remove identity from authentication agent: %d",
581 	    type);
582     }
583   /*NOTREACHED*/
584   return 0;
585 }
586 
587 /* Removes all identities from the agent.  This call is not meant
588    to be used by normal applications. */
589 
590 int ssh_remove_all_identities(AuthenticationConnection *auth)
591 {
592   Buffer buffer;
593   unsigned char buf[8192];
594   int len, l, type;
595 
596   /* Get the length of the message, and format it in the buffer. */
597   PUT_32BIT(buf, 1);
598   buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
599 
600   /* Send the length and then the packet to the agent. */
601   if (write(auth->fd, buf, 5) != 5)
602     {
603       error("Error writing to authentication socket.");
604       return 0;
605     }
606 
607   /* Wait for response from the agent.  First read the length of the
608      response packet. */
609   len = 4;
610   while (len > 0)
611     {
612       l = read(auth->fd, buf + 4 - len, len);
613       if (l <= 0)
614 	{
615 	  error("Error reading response length from authentication socket.");
616 	  return 0;
617 	}
618       len -= l;
619     }
620 
621   /* Extract the length, and check it for sanity. */
622   len = GET_32BIT(buf);
623   if (len > 256*1024)
624     fatal("Remove identity response too long: %d", len);
625 
626   /* Read the rest of the response into the buffer. */
627   buffer_init(&buffer);
628   while (len > 0)
629     {
630       l = len;
631       if (l > sizeof(buf))
632 	l = sizeof(buf);
633       l = read(auth->fd, buf, l);
634       if (l <= 0)
635 	{
636 	  error("Error reading response from authentication socket.");
637 	  buffer_free(&buffer);
638 	  return 0;
639 	}
640       buffer_append(&buffer, (char *)buf, l);
641       len -= l;
642     }
643 
644   /* Get the type of the packet. */
645   type = buffer_get_char(&buffer);
646   switch (type)
647     {
648     case SSH_AGENT_FAILURE:
649       buffer_free(&buffer);
650       return 0;
651     case SSH_AGENT_SUCCESS:
652       buffer_free(&buffer);
653       return 1;
654     default:
655       fatal("Bad response to remove identity from authentication agent: %d",
656 	    type);
657     }
658   /*NOTREACHED*/
659   return 0;
660 }
661 
662 /* Closes the connection to the authentication agent. */
663 
664 void ssh_close_authentication(AuthenticationConnection *auth)
665 {
666   /* Close the connection. */
667   shutdown(auth->fd, 2);
668   close(auth->fd);
669 
670   /* Free the buffers. */
671   buffer_free(&auth->packet);
672   buffer_free(&auth->identities);
673 
674   /* Free the connection data structure. */
675   xfree(auth);
676 }
677