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