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