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