]> andersk Git - openssh.git/blob - authfd.c
5317b3309cdfca1175da2510e0d54188dfc30de1
[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                        int *bitsp, 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, bitsp, 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                       int *bitsp, BIGNUM *e, BIGNUM *n, char **comment)
193 {
194   /* Return failure if no more entries. */
195   if (auth->howmany <= 0)
196     return 0;
197
198   /* Get the next entry from the packet.  These will abort with a fatal
199      error if the packet is too short or contains corrupt data. */
200   *bitsp = buffer_get_int(&auth->identities);
201   buffer_get_bignum(&auth->identities, e);
202   buffer_get_bignum(&auth->identities, n);
203   *comment = buffer_get_string(&auth->identities, NULL);
204
205   /* Decrement the number of remaining entries. */
206   auth->howmany--;
207
208   return 1;
209 }
210
211 /* Generates a random challenge, sends it to the agent, and waits for response
212    from the agent.  Returns true (non-zero) if the agent gave the correct
213    answer, zero otherwise.  Response type selects the style of response
214    desired, with 0 corresponding to protocol version 1.0 (no longer supported)
215    and 1 corresponding to protocol version 1.1. */
216
217 int
218 ssh_decrypt_challenge(AuthenticationConnection *auth,
219                       int bits, BIGNUM *e, BIGNUM *n, BIGNUM *challenge,
220                       unsigned char session_id[16],
221                       unsigned int response_type,
222                       unsigned char response[16])
223 {
224   Buffer buffer;
225   unsigned char buf[8192];
226   int len, l, i;
227
228   /* Response type 0 is no longer supported. */
229   if (response_type == 0)
230     fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
231
232   /* Format a message to the agent. */
233   buf[0] = SSH_AGENTC_RSA_CHALLENGE;
234   buffer_init(&buffer);
235   buffer_append(&buffer, (char *)buf, 1);
236   buffer_put_int(&buffer, bits);
237   buffer_put_bignum(&buffer, e);
238   buffer_put_bignum(&buffer, n);
239   buffer_put_bignum(&buffer, challenge);
240   buffer_append(&buffer, (char *)session_id, 16);
241   buffer_put_int(&buffer, response_type);
242
243   /* Get the length of the message, and format it in the buffer. */
244   len = buffer_len(&buffer);
245   PUT_32BIT(buf, len);
246
247   /* Send the length and then the packet to the agent. */
248   if (write(auth->fd, buf, 4) != 4 ||
249       write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
250         buffer_len(&buffer))
251     {
252       error("Error writing to authentication socket.");
253     error_cleanup:
254       buffer_free(&buffer);
255       return 0;
256     }
257
258   /* Wait for response from the agent.  First read the length of the
259      response packet. */
260   len = 4;
261   while (len > 0)
262     {
263       l = read(auth->fd, buf + 4 - len, len);
264       if (l <= 0)
265         {
266           error("Error reading response length from authentication socket.");
267           goto error_cleanup;
268         }
269       len -= l;
270     }
271
272   /* Extract the length, and check it for sanity. */
273   len = GET_32BIT(buf);
274   if (len > 256*1024)
275     fatal("Authentication response too long: %d", len);
276
277   /* Read the rest of the response in tothe buffer. */
278   buffer_clear(&buffer);
279   while (len > 0)
280     {
281       l = len;
282       if (l > sizeof(buf))
283         l = sizeof(buf);
284       l = read(auth->fd, buf, l);
285       if (l <= 0)
286         {
287           error("Error reading response from authentication socket.");
288           goto error_cleanup;
289         }
290       buffer_append(&buffer, (char *)buf, l);
291       len -= l;
292     }
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     {
300       log("Agent admitted failure to authenticate using the key.");
301       goto error_cleanup;
302     }
303       
304   /* Now it must be an authentication response packet. */
305   if (buf[0] != SSH_AGENT_RSA_RESPONSE)
306     fatal("Bad authentication response: %d", buf[0]);
307
308   /* Get the response from the packet.  This will abort with a fatal error
309      if the packet is corrupt. */
310   for (i = 0; i < 16; i++)
311     response[i] = buffer_get_char(&buffer);
312
313   /* The buffer containing the packet is no longer needed. */
314   buffer_free(&buffer);
315
316   /* Correct answer. */
317   return 1;
318 }  
319
320 /* Adds an identity to the authentication server.  This call is not meant to
321    be used by normal applications. */
322
323 int ssh_add_identity(AuthenticationConnection *auth,
324                      RSA *key, const char *comment)
325 {
326   Buffer buffer;
327   unsigned char buf[8192];
328   int len, l, type;
329
330   /* Format a message to the agent. */
331   buffer_init(&buffer);
332   buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
333   buffer_put_int(&buffer, BN_num_bits(key->n));
334   buffer_put_bignum(&buffer, key->n);
335   buffer_put_bignum(&buffer, key->e);
336   buffer_put_bignum(&buffer, key->d);
337   /* To keep within the protocol: p < q for ssh. in SSL p > q */
338   buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
339   buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
340   buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
341   buffer_put_string(&buffer, comment, strlen(comment));
342
343   /* Get the length of the message, and format it in the buffer. */
344   len = buffer_len(&buffer);
345   PUT_32BIT(buf, len);
346
347   /* Send the length and then the packet to the agent. */
348   if (write(auth->fd, buf, 4) != 4 ||
349       write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
350         buffer_len(&buffer))
351     {
352       error("Error writing to authentication socket.");
353     error_cleanup:
354       buffer_free(&buffer);
355       return 0;
356     }
357
358   /* Wait for response from the agent.  First read the length of the
359      response packet. */
360   len = 4;
361   while (len > 0)
362     {
363       l = read(auth->fd, buf + 4 - len, len);
364       if (l <= 0)
365         {
366           error("Error reading response length from authentication socket.");
367           goto error_cleanup;
368         }
369       len -= l;
370     }
371
372   /* Extract the length, and check it for sanity. */
373   len = GET_32BIT(buf);
374   if (len > 256*1024)
375     fatal("Add identity response too long: %d", len);
376
377   /* Read the rest of the response in tothe buffer. */
378   buffer_clear(&buffer);
379   while (len > 0)
380     {
381       l = len;
382       if (l > sizeof(buf))
383         l = sizeof(buf);
384       l = read(auth->fd, buf, l);
385       if (l <= 0)
386         {
387           error("Error reading response from authentication socket.");
388           goto error_cleanup;
389         }
390       buffer_append(&buffer, (char *)buf, l);
391       len -= l;
392     }
393
394   /* Get the type of the packet. */
395   type = buffer_get_char(&buffer);
396   switch (type)
397     {
398     case SSH_AGENT_FAILURE:
399       buffer_free(&buffer);
400       return 0;
401     case SSH_AGENT_SUCCESS:
402       buffer_free(&buffer);
403       return 1;
404     default:
405       fatal("Bad response to add identity from authentication agent: %d", 
406             type);
407     }
408   /*NOTREACHED*/
409   return 0;
410 }  
411
412 /* Removes an identity from the authentication server.  This call is not meant 
413    to be used by normal applications. */
414
415 int ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
416 {
417   Buffer buffer;
418   unsigned char buf[8192];
419   int len, l, type;
420
421   /* Format a message to the agent. */
422   buffer_init(&buffer);
423   buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
424   buffer_put_int(&buffer, BN_num_bits(key->n));
425   buffer_put_bignum(&buffer, key->e);
426   buffer_put_bignum(&buffer, key->n);
427
428   /* Get the length of the message, and format it in the buffer. */
429   len = buffer_len(&buffer);
430   PUT_32BIT(buf, len);
431
432   /* Send the length and then the packet to the agent. */
433   if (write(auth->fd, buf, 4) != 4 ||
434       write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
435         buffer_len(&buffer))
436     {
437       error("Error writing to authentication socket.");
438     error_cleanup:
439       buffer_free(&buffer);
440       return 0;
441     }
442
443   /* Wait for response from the agent.  First read the length of the
444      response packet. */
445   len = 4;
446   while (len > 0)
447     {
448       l = read(auth->fd, buf + 4 - len, len);
449       if (l <= 0)
450         {
451           error("Error reading response length from authentication socket.");
452           goto error_cleanup;
453         }
454       len -= l;
455     }
456
457   /* Extract the length, and check it for sanity. */
458   len = GET_32BIT(buf);
459   if (len > 256*1024)
460     fatal("Remove identity response too long: %d", len);
461
462   /* Read the rest of the response in tothe buffer. */
463   buffer_clear(&buffer);
464   while (len > 0)
465     {
466       l = len;
467       if (l > sizeof(buf))
468         l = sizeof(buf);
469       l = read(auth->fd, buf, l);
470       if (l <= 0)
471         {
472           error("Error reading response from authentication socket.");
473           goto error_cleanup;
474         }
475       buffer_append(&buffer, (char *)buf, l);
476       len -= l;
477     }
478
479   /* Get the type of the packet. */
480   type = buffer_get_char(&buffer);
481   switch (type)
482     {
483     case SSH_AGENT_FAILURE:
484       buffer_free(&buffer);
485       return 0;
486     case SSH_AGENT_SUCCESS:
487       buffer_free(&buffer);
488       return 1;
489     default:
490       fatal("Bad response to remove identity from authentication agent: %d", 
491             type);
492     }
493   /*NOTREACHED*/
494   return 0;
495 }  
496
497 /* Removes all identities from the agent.  This call is not meant 
498    to be used by normal applications. */
499
500 int ssh_remove_all_identities(AuthenticationConnection *auth)
501 {
502   Buffer buffer;
503   unsigned char buf[8192];
504   int len, l, type;
505
506   /* Get the length of the message, and format it in the buffer. */
507   PUT_32BIT(buf, 1);
508   buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
509
510   /* Send the length and then the packet to the agent. */
511   if (write(auth->fd, buf, 5) != 5)
512     {
513       error("Error writing to authentication socket.");
514       return 0;
515     }
516
517   /* Wait for response from the agent.  First read the length of the
518      response packet. */
519   len = 4;
520   while (len > 0)
521     {
522       l = read(auth->fd, buf + 4 - len, len);
523       if (l <= 0)
524         {
525           error("Error reading response length from authentication socket.");
526           return 0;
527         }
528       len -= l;
529     }
530
531   /* Extract the length, and check it for sanity. */
532   len = GET_32BIT(buf);
533   if (len > 256*1024)
534     fatal("Remove identity response too long: %d", len);
535
536   /* Read the rest of the response into the buffer. */
537   buffer_init(&buffer);
538   while (len > 0)
539     {
540       l = len;
541       if (l > sizeof(buf))
542         l = sizeof(buf);
543       l = read(auth->fd, buf, l);
544       if (l <= 0)
545         {
546           error("Error reading response from authentication socket.");
547           buffer_free(&buffer);
548           return 0;
549         }
550       buffer_append(&buffer, (char *)buf, l);
551       len -= l;
552     }
553
554   /* Get the type of the packet. */
555   type = buffer_get_char(&buffer);
556   switch (type)
557     {
558     case SSH_AGENT_FAILURE:
559       buffer_free(&buffer);
560       return 0;
561     case SSH_AGENT_SUCCESS:
562       buffer_free(&buffer);
563       return 1;
564     default:
565       fatal("Bad response to remove identity from authentication agent: %d", 
566             type);
567     }
568   /*NOTREACHED*/
569   return 0;
570 }  
This page took 0.06575 seconds and 3 git commands to generate.