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