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