]> andersk Git - openssh.git/blob - authfd.c
- markus@cvs.openbsd.org 2001/06/26 04:59:59
[openssh.git] / authfd.c
1 /*
2  * Author: Tatu Ylonen <ylo@cs.hut.fi>
3  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4  *                    All rights reserved
5  * Functions for connecting the local authentication agent.
6  *
7  * As far as I am concerned, the code I have written for this software
8  * can be used freely for any purpose.  Any derived versions of this
9  * software must be clearly marked as such, and if the derived work is
10  * incompatible with the protocol description in the RFC file, it must be
11  * called by a name other than "ssh" or "Secure Shell".
12  *
13  * SSH2 implementation,
14  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36
37 #include "includes.h"
38 RCSID("$OpenBSD: authfd.c,v 1.42 2001/06/26 04:59:59 markus Exp $");
39
40 #include <openssl/evp.h>
41
42 #include "ssh.h"
43 #include "rsa.h"
44 #include "buffer.h"
45 #include "bufaux.h"
46 #include "xmalloc.h"
47 #include "getput.h"
48 #include "key.h"
49 #include "authfd.h"
50 #include "cipher.h"
51 #include "kex.h"
52 #include "compat.h"
53 #include "log.h"
54 #include "atomicio.h"
55
56 /* helper */
57 int     decode_reply(int type);
58
59 /* macro to check for "agent failure" message */
60 #define agent_failed(x) \
61     ((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE))
62
63 /* Returns the number of the authentication fd, or -1 if there is none. */
64
65 int
66 ssh_get_authentication_socket(void)
67 {
68         const char *authsocket;
69         int sock, len;
70         struct sockaddr_un sunaddr;
71
72         authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
73         if (!authsocket)
74                 return -1;
75
76         sunaddr.sun_family = AF_UNIX;
77         strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
78         len = SUN_LEN(&sunaddr)+1;
79 #ifdef HAVE_SUN_LEN_IN_SOCKADDR_UN
80         sunaddr.sun_len = len;
81 #endif /* HAVE_SUN_LEN_IN_SOCKADDR_UN */
82
83         sock = socket(AF_UNIX, SOCK_STREAM, 0);
84         if (sock < 0)
85                 return -1;
86
87         /* close on exec */
88         if (fcntl(sock, F_SETFD, 1) == -1) {
89                 close(sock);
90                 return -1;
91         }
92         if (connect(sock, (struct sockaddr *) & sunaddr, len) < 0) {
93                 close(sock);
94                 return -1;
95         }
96         return sock;
97 }
98
99 static int
100 ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply)
101 {
102         int l, len;
103         char buf[1024];
104
105         /* Get the length of the message, and format it in the buffer. */
106         len = buffer_len(request);
107         PUT_32BIT(buf, len);
108
109         /* Send the length and then the packet to the agent. */
110         if (atomicio(write, auth->fd, buf, 4) != 4 ||
111             atomicio(write, auth->fd, buffer_ptr(request),
112             buffer_len(request)) != buffer_len(request)) {
113                 error("Error writing to authentication socket.");
114                 return 0;
115         }
116         /*
117          * Wait for response from the agent.  First read the length of the
118          * response packet.
119          */
120         len = 4;
121         while (len > 0) {
122                 l = read(auth->fd, buf + 4 - len, len);
123                 if (l == -1 && (errno == EAGAIN || errno == EINTR))
124                         continue;
125                 if (l <= 0) {
126                         error("Error reading response length from authentication socket.");
127                         return 0;
128                 }
129                 len -= l;
130         }
131
132         /* Extract the length, and check it for sanity. */
133         len = GET_32BIT(buf);
134         if (len > 256 * 1024)
135                 fatal("Authentication response too long: %d", len);
136
137         /* Read the rest of the response in to the buffer. */
138         buffer_clear(reply);
139         while (len > 0) {
140                 l = len;
141                 if (l > sizeof(buf))
142                         l = sizeof(buf);
143                 l = read(auth->fd, buf, l);
144                 if (l == -1 && (errno == EAGAIN || errno == EINTR))
145                         continue;
146                 if (l <= 0) {
147                         error("Error reading response from authentication socket.");
148                         return 0;
149                 }
150                 buffer_append(reply, (char *) buf, l);
151                 len -= l;
152         }
153         return 1;
154 }
155
156 /*
157  * Closes the agent socket if it should be closed (depends on how it was
158  * obtained).  The argument must have been returned by
159  * ssh_get_authentication_socket().
160  */
161
162 void
163 ssh_close_authentication_socket(int sock)
164 {
165         if (getenv(SSH_AUTHSOCKET_ENV_NAME))
166                 close(sock);
167 }
168
169 /*
170  * Opens and connects a private socket for communication with the
171  * authentication agent.  Returns the file descriptor (which must be
172  * shut down and closed by the caller when no longer needed).
173  * Returns NULL if an error occurred and the connection could not be
174  * opened.
175  */
176
177 AuthenticationConnection *
178 ssh_get_authentication_connection(void)
179 {
180         AuthenticationConnection *auth;
181         int sock;
182
183         sock = ssh_get_authentication_socket();
184
185         /*
186          * Fail if we couldn't obtain a connection.  This happens if we
187          * exited due to a timeout.
188          */
189         if (sock < 0)
190                 return NULL;
191
192         auth = xmalloc(sizeof(*auth));
193         auth->fd = sock;
194         buffer_init(&auth->identities);
195         auth->howmany = 0;
196
197         return auth;
198 }
199
200 /*
201  * Closes the connection to the authentication agent and frees any associated
202  * memory.
203  */
204
205 void
206 ssh_close_authentication_connection(AuthenticationConnection *auth)
207 {
208         buffer_free(&auth->identities);
209         close(auth->fd);
210         xfree(auth);
211 }
212
213 /*
214  * Returns the first authentication identity held by the agent.
215  */
216
217 int
218 ssh_get_num_identities(AuthenticationConnection *auth, int version)
219 {
220         int type, code1 = 0, code2 = 0;
221         Buffer request;
222
223         switch(version){
224         case 1:
225                 code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
226                 code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
227                 break;
228         case 2:
229                 code1 = SSH2_AGENTC_REQUEST_IDENTITIES;
230                 code2 = SSH2_AGENT_IDENTITIES_ANSWER;
231                 break;
232         default:
233                 return 0;
234         }
235
236         /*
237          * Send a message to the agent requesting for a list of the
238          * identities it can represent.
239          */
240         buffer_init(&request);
241         buffer_put_char(&request, code1);
242
243         buffer_clear(&auth->identities);
244         if (ssh_request_reply(auth, &request, &auth->identities) == 0) {
245                 buffer_free(&request);
246                 return 0;
247         }
248         buffer_free(&request);
249
250         /* Get message type, and verify that we got a proper answer. */
251         type = buffer_get_char(&auth->identities);
252         if (agent_failed(type)) {
253                 return 0;
254         } else if (type != code2) {
255                 fatal("Bad authentication reply message type: %d", type);
256         }
257
258         /* Get the number of entries in the response and check it for sanity. */
259         auth->howmany = buffer_get_int(&auth->identities);
260         if (auth->howmany > 1024)
261                 fatal("Too many identities in authentication reply: %d",
262                     auth->howmany);
263
264         return auth->howmany;
265 }
266
267 Key *
268 ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version)
269 {
270         /* get number of identities and return the first entry (if any). */
271         if (ssh_get_num_identities(auth, version) > 0)
272                 return ssh_get_next_identity(auth, comment, version);
273         return NULL;
274 }
275
276 Key *
277 ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version)
278 {
279         u_int bits;
280         u_char *blob;
281         u_int blen;
282         Key *key = NULL;
283
284         /* Return failure if no more entries. */
285         if (auth->howmany <= 0)
286                 return NULL;
287
288         /*
289          * Get the next entry from the packet.  These will abort with a fatal
290          * error if the packet is too short or contains corrupt data.
291          */
292         switch(version){
293         case 1:
294                 key = key_new(KEY_RSA1);
295                 bits = buffer_get_int(&auth->identities);
296                 buffer_get_bignum(&auth->identities, key->rsa->e);
297                 buffer_get_bignum(&auth->identities, key->rsa->n);
298                 *comment = buffer_get_string(&auth->identities, NULL);
299                 if (bits != BN_num_bits(key->rsa->n))
300                         log("Warning: identity keysize mismatch: actual %d, announced %u",
301                             BN_num_bits(key->rsa->n), bits);
302                 break;
303         case 2:
304                 blob = buffer_get_string(&auth->identities, &blen);
305                 *comment = buffer_get_string(&auth->identities, NULL);
306                 key = key_from_blob(blob, blen);
307                 xfree(blob);
308                 break;
309         default:
310                 return NULL;
311                 break;
312         }
313         /* Decrement the number of remaining entries. */
314         auth->howmany--;
315         return key;
316 }
317
318 /*
319  * Generates a random challenge, sends it to the agent, and waits for
320  * response from the agent.  Returns true (non-zero) if the agent gave the
321  * correct answer, zero otherwise.  Response type selects the style of
322  * response desired, with 0 corresponding to protocol version 1.0 (no longer
323  * supported) and 1 corresponding to protocol version 1.1.
324  */
325
326 int
327 ssh_decrypt_challenge(AuthenticationConnection *auth,
328     Key* key, BIGNUM *challenge,
329     u_char session_id[16],
330     u_int response_type,
331     u_char response[16])
332 {
333         Buffer buffer;
334         int success = 0;
335         int i;
336         int type;
337
338         if (key->type != KEY_RSA1)
339                 return 0;
340         if (response_type == 0) {
341                 log("Compatibility with ssh protocol version 1.0 no longer supported.");
342                 return 0;
343         }
344         buffer_init(&buffer);
345         buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE);
346         buffer_put_int(&buffer, BN_num_bits(key->rsa->n));
347         buffer_put_bignum(&buffer, key->rsa->e);
348         buffer_put_bignum(&buffer, key->rsa->n);
349         buffer_put_bignum(&buffer, challenge);
350         buffer_append(&buffer, (char *) session_id, 16);
351         buffer_put_int(&buffer, response_type);
352
353         if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
354                 buffer_free(&buffer);
355                 return 0;
356         }
357         type = buffer_get_char(&buffer);
358
359         if (agent_failed(type)) {
360                 log("Agent admitted failure to authenticate using the key.");
361         } else if (type != SSH_AGENT_RSA_RESPONSE) {
362                 fatal("Bad authentication response: %d", type);
363         } else {
364                 success = 1;
365                 /*
366                  * Get the response from the packet.  This will abort with a
367                  * fatal error if the packet is corrupt.
368                  */
369                 for (i = 0; i < 16; i++)
370                         response[i] = buffer_get_char(&buffer);
371         }
372         buffer_free(&buffer);
373         return success;
374 }
375
376 /* ask agent to sign data, returns -1 on error, 0 on success */
377 int
378 ssh_agent_sign(AuthenticationConnection *auth,
379     Key *key,
380     u_char **sigp, int *lenp,
381     u_char *data, int datalen)
382 {
383         extern int datafellows;
384         Buffer msg;
385         u_char *blob;
386         u_int blen;
387         int type, flags = 0;
388         int ret = -1;
389
390         if (key_to_blob(key, &blob, &blen) == 0)
391                 return -1;
392
393         if (datafellows & SSH_BUG_SIGBLOB)
394                 flags = SSH_AGENT_OLD_SIGNATURE;
395
396         buffer_init(&msg);
397         buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST);
398         buffer_put_string(&msg, blob, blen);
399         buffer_put_string(&msg, data, datalen);
400         buffer_put_int(&msg, flags);
401         xfree(blob);
402
403         if (ssh_request_reply(auth, &msg, &msg) == 0) {
404                 buffer_free(&msg);
405                 return -1;
406         }
407         type = buffer_get_char(&msg);
408         if (agent_failed(type)) {
409                 log("Agent admitted failure to sign using the key.");
410         } else if (type != SSH2_AGENT_SIGN_RESPONSE) {
411                 fatal("Bad authentication response: %d", type);
412         } else {
413                 ret = 0;
414                 *sigp = buffer_get_string(&msg, lenp);
415         }
416         buffer_free(&msg);
417         return ret;
418 }
419
420 /* Encode key for a message to the agent. */
421
422 static void
423 ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
424 {
425         buffer_clear(b);
426         buffer_put_char(b, SSH_AGENTC_ADD_RSA_IDENTITY);
427         buffer_put_int(b, BN_num_bits(key->n));
428         buffer_put_bignum(b, key->n);
429         buffer_put_bignum(b, key->e);
430         buffer_put_bignum(b, key->d);
431         /* To keep within the protocol: p < q for ssh. in SSL p > q */
432         buffer_put_bignum(b, key->iqmp);        /* ssh key->u */
433         buffer_put_bignum(b, key->q);   /* ssh key->p, SSL key->q */
434         buffer_put_bignum(b, key->p);   /* ssh key->q, SSL key->p */
435         buffer_put_cstring(b, comment);
436 }
437
438 static void
439 ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment)
440 {
441         buffer_clear(b);
442         buffer_put_char(b, SSH2_AGENTC_ADD_IDENTITY);
443         buffer_put_cstring(b, key_ssh_name(key));
444         switch(key->type){
445         case KEY_RSA:
446                 buffer_put_bignum2(b, key->rsa->n);
447                 buffer_put_bignum2(b, key->rsa->e);
448                 buffer_put_bignum2(b, key->rsa->d);
449                 buffer_put_bignum2(b, key->rsa->iqmp);
450                 buffer_put_bignum2(b, key->rsa->p);
451                 buffer_put_bignum2(b, key->rsa->q);
452                 break;
453         case KEY_DSA:
454                 buffer_put_bignum2(b, key->dsa->p);
455                 buffer_put_bignum2(b, key->dsa->q);
456                 buffer_put_bignum2(b, key->dsa->g);
457                 buffer_put_bignum2(b, key->dsa->pub_key);
458                 buffer_put_bignum2(b, key->dsa->priv_key);
459                 break;
460         }
461         buffer_put_cstring(b, comment);
462 }
463
464 /*
465  * Adds an identity to the authentication server.  This call is not meant to
466  * be used by normal applications.
467  */
468
469 int
470 ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
471 {
472         Buffer msg;
473         int type;
474
475         buffer_init(&msg);
476
477         switch (key->type) {
478         case KEY_RSA1:
479                 ssh_encode_identity_rsa1(&msg, key->rsa, comment);
480                 break;
481         case KEY_RSA:
482         case KEY_DSA:
483                 ssh_encode_identity_ssh2(&msg, key, comment);
484                 break;
485         default:
486                 buffer_free(&msg);
487                 return 0;
488                 break;
489         }
490         if (ssh_request_reply(auth, &msg, &msg) == 0) {
491                 buffer_free(&msg);
492                 return 0;
493         }
494         type = buffer_get_char(&msg);
495         buffer_free(&msg);
496         return decode_reply(type);
497 }
498
499 /*
500  * Removes an identity from the authentication server.  This call is not
501  * meant to be used by normal applications.
502  */
503
504 int
505 ssh_remove_identity(AuthenticationConnection *auth, Key *key)
506 {
507         Buffer msg;
508         int type;
509         u_char *blob;
510         u_int blen;
511
512         buffer_init(&msg);
513
514         if (key->type == KEY_RSA1) {
515                 buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY);
516                 buffer_put_int(&msg, BN_num_bits(key->rsa->n));
517                 buffer_put_bignum(&msg, key->rsa->e);
518                 buffer_put_bignum(&msg, key->rsa->n);
519         } else if (key->type == KEY_DSA || key->type == KEY_RSA) {
520                 key_to_blob(key, &blob, &blen);
521                 buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY);
522                 buffer_put_string(&msg, blob, blen);
523                 xfree(blob);
524         } else {
525                 buffer_free(&msg);
526                 return 0;
527         }
528         if (ssh_request_reply(auth, &msg, &msg) == 0) {
529                 buffer_free(&msg);
530                 return 0;
531         }
532         type = buffer_get_char(&msg);
533         buffer_free(&msg);
534         return decode_reply(type);
535 }
536
537 int
538 ssh_update_card(AuthenticationConnection *auth, int add, int reader_id)
539 {
540         Buffer msg;
541         int type;
542
543         buffer_init(&msg);
544         buffer_put_char(&msg, add ? SSH_AGENTC_ADD_SMARTCARD_KEY :
545             SSH_AGENTC_REMOVE_SMARTCARD_KEY);
546         buffer_put_int(&msg, reader_id);
547         if (ssh_request_reply(auth, &msg, &msg) == 0) {
548                 buffer_free(&msg);
549                 return 0;
550         }
551         type = buffer_get_char(&msg);
552         buffer_free(&msg);
553         return decode_reply(type);
554 }
555
556 /*
557  * Removes all identities from the agent.  This call is not meant to be used
558  * by normal applications.
559  */
560
561 int
562 ssh_remove_all_identities(AuthenticationConnection *auth, int version)
563 {
564         Buffer msg;
565         int type;
566         int code = (version==1) ?
567                 SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES :
568                 SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
569
570         buffer_init(&msg);
571         buffer_put_char(&msg, code);
572
573         if (ssh_request_reply(auth, &msg, &msg) == 0) {
574                 buffer_free(&msg);
575                 return 0;
576         }
577         type = buffer_get_char(&msg);
578         buffer_free(&msg);
579         return decode_reply(type);
580 }
581
582 int
583 decode_reply(int type)
584 {
585         switch (type) {
586         case SSH_AGENT_FAILURE:
587         case SSH_COM_AGENT2_FAILURE:
588                 log("SSH_AGENT_FAILURE");
589                 return 0;
590         case SSH_AGENT_SUCCESS:
591                 return 1;
592         default:
593                 fatal("Bad response from authentication agent: %d", type);
594         }
595         /* NOTREACHED */
596         return 0;
597 }
This page took 0.097504 seconds and 5 git commands to generate.