source: trunk/third/openssh/authfd.c @ 18759

Revision 18759, 16.1 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18758, which included commits to RCS files with non-trunk default branches.
Line 
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"
38RCSID("$OpenBSD: authfd.c,v 1.57 2002/09/11 18:27:26 stevesk 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
56static int agent_present = 0;
57
58/* helper */
59int     decode_reply(int type);
60
61/* macro to check for "agent failure" message */
62#define agent_failed(x) \
63    ((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE) || \
64    (x == SSH2_AGENT_FAILURE))
65
66int
67ssh_agent_present(void)
68{
69        int authfd;
70
71        if (agent_present)
72                return 1;
73        if ((authfd = ssh_get_authentication_socket()) == -1)
74                return 0;
75        else {
76                ssh_close_authentication_socket(authfd);
77                return 1;
78        }
79}
80
81/* Returns the number of the authentication fd, or -1 if there is none. */
82
83int
84ssh_get_authentication_socket(void)
85{
86        const char *authsocket;
87        int sock;
88        struct sockaddr_un sunaddr;
89
90        authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
91        if (!authsocket)
92                return -1;
93
94        sunaddr.sun_family = AF_UNIX;
95        strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
96
97        sock = socket(AF_UNIX, SOCK_STREAM, 0);
98        if (sock < 0)
99                return -1;
100
101        /* close on exec */
102        if (fcntl(sock, F_SETFD, 1) == -1) {
103                close(sock);
104                return -1;
105        }
106        if (connect(sock, (struct sockaddr *) &sunaddr, sizeof sunaddr) < 0) {
107                close(sock);
108                return -1;
109        }
110        agent_present = 1;
111        return sock;
112}
113
114static int
115ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply)
116{
117        int l, len;
118        char buf[1024];
119
120        /* Get the length of the message, and format it in the buffer. */
121        len = buffer_len(request);
122        PUT_32BIT(buf, len);
123
124        /* Send the length and then the packet to the agent. */
125        if (atomicio(write, auth->fd, buf, 4) != 4 ||
126            atomicio(write, auth->fd, buffer_ptr(request),
127            buffer_len(request)) != buffer_len(request)) {
128                error("Error writing to authentication socket.");
129                return 0;
130        }
131        /*
132         * Wait for response from the agent.  First read the length of the
133         * response packet.
134         */
135        len = 4;
136        while (len > 0) {
137                l = read(auth->fd, buf + 4 - len, len);
138                if (l == -1 && (errno == EAGAIN || errno == EINTR))
139                        continue;
140                if (l <= 0) {
141                        error("Error reading response length from authentication socket.");
142                        return 0;
143                }
144                len -= l;
145        }
146
147        /* Extract the length, and check it for sanity. */
148        len = GET_32BIT(buf);
149        if (len > 256 * 1024)
150                fatal("Authentication response too long: %d", len);
151
152        /* Read the rest of the response in to the buffer. */
153        buffer_clear(reply);
154        while (len > 0) {
155                l = len;
156                if (l > sizeof(buf))
157                        l = sizeof(buf);
158                l = read(auth->fd, buf, l);
159                if (l == -1 && (errno == EAGAIN || errno == EINTR))
160                        continue;
161                if (l <= 0) {
162                        error("Error reading response from authentication socket.");
163                        return 0;
164                }
165                buffer_append(reply, buf, l);
166                len -= l;
167        }
168        return 1;
169}
170
171/*
172 * Closes the agent socket if it should be closed (depends on how it was
173 * obtained).  The argument must have been returned by
174 * ssh_get_authentication_socket().
175 */
176
177void
178ssh_close_authentication_socket(int sock)
179{
180        if (getenv(SSH_AUTHSOCKET_ENV_NAME))
181                close(sock);
182}
183
184/*
185 * Opens and connects a private socket for communication with the
186 * authentication agent.  Returns the file descriptor (which must be
187 * shut down and closed by the caller when no longer needed).
188 * Returns NULL if an error occurred and the connection could not be
189 * opened.
190 */
191
192AuthenticationConnection *
193ssh_get_authentication_connection(void)
194{
195        AuthenticationConnection *auth;
196        int sock;
197
198        sock = ssh_get_authentication_socket();
199
200        /*
201         * Fail if we couldn't obtain a connection.  This happens if we
202         * exited due to a timeout.
203         */
204        if (sock < 0)
205                return NULL;
206
207        auth = xmalloc(sizeof(*auth));
208        auth->fd = sock;
209        buffer_init(&auth->identities);
210        auth->howmany = 0;
211
212        return auth;
213}
214
215/*
216 * Closes the connection to the authentication agent and frees any associated
217 * memory.
218 */
219
220void
221ssh_close_authentication_connection(AuthenticationConnection *auth)
222{
223        buffer_free(&auth->identities);
224        close(auth->fd);
225        xfree(auth);
226}
227
228/* Lock/unlock agent */
229int
230ssh_lock_agent(AuthenticationConnection *auth, int lock, const char *password)
231{
232        int type;
233        Buffer msg;
234
235        buffer_init(&msg);
236        buffer_put_char(&msg, lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK);
237        buffer_put_cstring(&msg, password);
238
239        if (ssh_request_reply(auth, &msg, &msg) == 0) {
240                buffer_free(&msg);
241                return 0;
242        }
243        type = buffer_get_char(&msg);
244        buffer_free(&msg);
245        return decode_reply(type);
246}
247
248/*
249 * Returns the first authentication identity held by the agent.
250 */
251
252int
253ssh_get_num_identities(AuthenticationConnection *auth, int version)
254{
255        int type, code1 = 0, code2 = 0;
256        Buffer request;
257
258        switch (version) {
259        case 1:
260                code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
261                code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
262                break;
263        case 2:
264                code1 = SSH2_AGENTC_REQUEST_IDENTITIES;
265                code2 = SSH2_AGENT_IDENTITIES_ANSWER;
266                break;
267        default:
268                return 0;
269        }
270
271        /*
272         * Send a message to the agent requesting for a list of the
273         * identities it can represent.
274         */
275        buffer_init(&request);
276        buffer_put_char(&request, code1);
277
278        buffer_clear(&auth->identities);
279        if (ssh_request_reply(auth, &request, &auth->identities) == 0) {
280                buffer_free(&request);
281                return 0;
282        }
283        buffer_free(&request);
284
285        /* Get message type, and verify that we got a proper answer. */
286        type = buffer_get_char(&auth->identities);
287        if (agent_failed(type)) {
288                return 0;
289        } else if (type != code2) {
290                fatal("Bad authentication reply message type: %d", type);
291        }
292
293        /* Get the number of entries in the response and check it for sanity. */
294        auth->howmany = buffer_get_int(&auth->identities);
295        if (auth->howmany > 1024)
296                fatal("Too many identities in authentication reply: %d",
297                    auth->howmany);
298
299        return auth->howmany;
300}
301
302Key *
303ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version)
304{
305        /* get number of identities and return the first entry (if any). */
306        if (ssh_get_num_identities(auth, version) > 0)
307                return ssh_get_next_identity(auth, comment, version);
308        return NULL;
309}
310
311Key *
312ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version)
313{
314        u_int bits;
315        u_char *blob;
316        u_int blen;
317        Key *key = NULL;
318
319        /* Return failure if no more entries. */
320        if (auth->howmany <= 0)
321                return NULL;
322
323        /*
324         * Get the next entry from the packet.  These will abort with a fatal
325         * error if the packet is too short or contains corrupt data.
326         */
327        switch (version) {
328        case 1:
329                key = key_new(KEY_RSA1);
330                bits = buffer_get_int(&auth->identities);
331                buffer_get_bignum(&auth->identities, key->rsa->e);
332                buffer_get_bignum(&auth->identities, key->rsa->n);
333                *comment = buffer_get_string(&auth->identities, NULL);
334                if (bits != BN_num_bits(key->rsa->n))
335                        log("Warning: identity keysize mismatch: actual %d, announced %u",
336                            BN_num_bits(key->rsa->n), bits);
337                break;
338        case 2:
339                blob = buffer_get_string(&auth->identities, &blen);
340                *comment = buffer_get_string(&auth->identities, NULL);
341                key = key_from_blob(blob, blen);
342                xfree(blob);
343                break;
344        default:
345                return NULL;
346                break;
347        }
348        /* Decrement the number of remaining entries. */
349        auth->howmany--;
350        return key;
351}
352
353/*
354 * Generates a random challenge, sends it to the agent, and waits for
355 * response from the agent.  Returns true (non-zero) if the agent gave the
356 * correct answer, zero otherwise.  Response type selects the style of
357 * response desired, with 0 corresponding to protocol version 1.0 (no longer
358 * supported) and 1 corresponding to protocol version 1.1.
359 */
360
361int
362ssh_decrypt_challenge(AuthenticationConnection *auth,
363    Key* key, BIGNUM *challenge,
364    u_char session_id[16],
365    u_int response_type,
366    u_char response[16])
367{
368        Buffer buffer;
369        int success = 0;
370        int i;
371        int type;
372
373        if (key->type != KEY_RSA1)
374                return 0;
375        if (response_type == 0) {
376                log("Compatibility with ssh protocol version 1.0 no longer supported.");
377                return 0;
378        }
379        buffer_init(&buffer);
380        buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE);
381        buffer_put_int(&buffer, BN_num_bits(key->rsa->n));
382        buffer_put_bignum(&buffer, key->rsa->e);
383        buffer_put_bignum(&buffer, key->rsa->n);
384        buffer_put_bignum(&buffer, challenge);
385        buffer_append(&buffer, session_id, 16);
386        buffer_put_int(&buffer, response_type);
387
388        if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
389                buffer_free(&buffer);
390                return 0;
391        }
392        type = buffer_get_char(&buffer);
393
394        if (agent_failed(type)) {
395                log("Agent admitted failure to authenticate using the key.");
396        } else if (type != SSH_AGENT_RSA_RESPONSE) {
397                fatal("Bad authentication response: %d", type);
398        } else {
399                success = 1;
400                /*
401                 * Get the response from the packet.  This will abort with a
402                 * fatal error if the packet is corrupt.
403                 */
404                for (i = 0; i < 16; i++)
405                        response[i] = buffer_get_char(&buffer);
406        }
407        buffer_free(&buffer);
408        return success;
409}
410
411/* ask agent to sign data, returns -1 on error, 0 on success */
412int
413ssh_agent_sign(AuthenticationConnection *auth,
414    Key *key,
415    u_char **sigp, u_int *lenp,
416    u_char *data, u_int datalen)
417{
418        extern int datafellows;
419        Buffer msg;
420        u_char *blob;
421        u_int blen;
422        int type, flags = 0;
423        int ret = -1;
424
425        if (key_to_blob(key, &blob, &blen) == 0)
426                return -1;
427
428        if (datafellows & SSH_BUG_SIGBLOB)
429                flags = SSH_AGENT_OLD_SIGNATURE;
430
431        buffer_init(&msg);
432        buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST);
433        buffer_put_string(&msg, blob, blen);
434        buffer_put_string(&msg, data, datalen);
435        buffer_put_int(&msg, flags);
436        xfree(blob);
437
438        if (ssh_request_reply(auth, &msg, &msg) == 0) {
439                buffer_free(&msg);
440                return -1;
441        }
442        type = buffer_get_char(&msg);
443        if (agent_failed(type)) {
444                log("Agent admitted failure to sign using the key.");
445        } else if (type != SSH2_AGENT_SIGN_RESPONSE) {
446                fatal("Bad authentication response: %d", type);
447        } else {
448                ret = 0;
449                *sigp = buffer_get_string(&msg, lenp);
450        }
451        buffer_free(&msg);
452        return ret;
453}
454
455/* Encode key for a message to the agent. */
456
457static void
458ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment)
459{
460        buffer_put_int(b, BN_num_bits(key->n));
461        buffer_put_bignum(b, key->n);
462        buffer_put_bignum(b, key->e);
463        buffer_put_bignum(b, key->d);
464        /* To keep within the protocol: p < q for ssh. in SSL p > q */
465        buffer_put_bignum(b, key->iqmp);        /* ssh key->u */
466        buffer_put_bignum(b, key->q);   /* ssh key->p, SSL key->q */
467        buffer_put_bignum(b, key->p);   /* ssh key->q, SSL key->p */
468        buffer_put_cstring(b, comment);
469}
470
471static void
472ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment)
473{
474        buffer_put_cstring(b, key_ssh_name(key));
475        switch (key->type) {
476        case KEY_RSA:
477                buffer_put_bignum2(b, key->rsa->n);
478                buffer_put_bignum2(b, key->rsa->e);
479                buffer_put_bignum2(b, key->rsa->d);
480                buffer_put_bignum2(b, key->rsa->iqmp);
481                buffer_put_bignum2(b, key->rsa->p);
482                buffer_put_bignum2(b, key->rsa->q);
483                break;
484        case KEY_DSA:
485                buffer_put_bignum2(b, key->dsa->p);
486                buffer_put_bignum2(b, key->dsa->q);
487                buffer_put_bignum2(b, key->dsa->g);
488                buffer_put_bignum2(b, key->dsa->pub_key);
489                buffer_put_bignum2(b, key->dsa->priv_key);
490                break;
491        }
492        buffer_put_cstring(b, comment);
493}
494
495/*
496 * Adds an identity to the authentication server.  This call is not meant to
497 * be used by normal applications.
498 */
499
500int
501ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key,
502    const char *comment, u_int life)
503{
504        Buffer msg;
505        int type, constrained = (life != 0);
506
507        buffer_init(&msg);
508
509        switch (key->type) {
510        case KEY_RSA1:
511                type = constrained ?
512                    SSH_AGENTC_ADD_RSA_ID_CONSTRAINED :
513                    SSH_AGENTC_ADD_RSA_IDENTITY;
514                buffer_put_char(&msg, type);
515                ssh_encode_identity_rsa1(&msg, key->rsa, comment);
516                break;
517        case KEY_RSA:
518        case KEY_DSA:
519                type = constrained ?
520                    SSH2_AGENTC_ADD_ID_CONSTRAINED :
521                    SSH2_AGENTC_ADD_IDENTITY;
522                buffer_put_char(&msg, type);
523                ssh_encode_identity_ssh2(&msg, key, comment);
524                break;
525        default:
526                buffer_free(&msg);
527                return 0;
528                break;
529        }
530        if (constrained) {
531                if (life != 0) {
532                        buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME);
533                        buffer_put_int(&msg, life);
534                }
535        }
536        if (ssh_request_reply(auth, &msg, &msg) == 0) {
537                buffer_free(&msg);
538                return 0;
539        }
540        type = buffer_get_char(&msg);
541        buffer_free(&msg);
542        return decode_reply(type);
543}
544
545int
546ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
547{
548        return ssh_add_identity_constrained(auth, key, comment, 0);
549}
550
551/*
552 * Removes an identity from the authentication server.  This call is not
553 * meant to be used by normal applications.
554 */
555
556int
557ssh_remove_identity(AuthenticationConnection *auth, Key *key)
558{
559        Buffer msg;
560        int type;
561        u_char *blob;
562        u_int blen;
563
564        buffer_init(&msg);
565
566        if (key->type == KEY_RSA1) {
567                buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY);
568                buffer_put_int(&msg, BN_num_bits(key->rsa->n));
569                buffer_put_bignum(&msg, key->rsa->e);
570                buffer_put_bignum(&msg, key->rsa->n);
571        } else if (key->type == KEY_DSA || key->type == KEY_RSA) {
572                key_to_blob(key, &blob, &blen);
573                buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY);
574                buffer_put_string(&msg, blob, blen);
575                xfree(blob);
576        } else {
577                buffer_free(&msg);
578                return 0;
579        }
580        if (ssh_request_reply(auth, &msg, &msg) == 0) {
581                buffer_free(&msg);
582                return 0;
583        }
584        type = buffer_get_char(&msg);
585        buffer_free(&msg);
586        return decode_reply(type);
587}
588
589int
590ssh_update_card(AuthenticationConnection *auth, int add, const char *reader_id, const char *pin)
591{
592        Buffer msg;
593        int type;
594
595        buffer_init(&msg);
596        buffer_put_char(&msg, add ? SSH_AGENTC_ADD_SMARTCARD_KEY :
597            SSH_AGENTC_REMOVE_SMARTCARD_KEY);
598        buffer_put_cstring(&msg, reader_id);
599        buffer_put_cstring(&msg, pin);
600        if (ssh_request_reply(auth, &msg, &msg) == 0) {
601                buffer_free(&msg);
602                return 0;
603        }
604        type = buffer_get_char(&msg);
605        buffer_free(&msg);
606        return decode_reply(type);
607}
608
609/*
610 * Removes all identities from the agent.  This call is not meant to be used
611 * by normal applications.
612 */
613
614int
615ssh_remove_all_identities(AuthenticationConnection *auth, int version)
616{
617        Buffer msg;
618        int type;
619        int code = (version==1) ?
620                SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES :
621                SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
622
623        buffer_init(&msg);
624        buffer_put_char(&msg, code);
625
626        if (ssh_request_reply(auth, &msg, &msg) == 0) {
627                buffer_free(&msg);
628                return 0;
629        }
630        type = buffer_get_char(&msg);
631        buffer_free(&msg);
632        return decode_reply(type);
633}
634
635int
636decode_reply(int type)
637{
638        switch (type) {
639        case SSH_AGENT_FAILURE:
640        case SSH_COM_AGENT2_FAILURE:
641        case SSH2_AGENT_FAILURE:
642                log("SSH_AGENT_FAILURE");
643                return 0;
644        case SSH_AGENT_SUCCESS:
645                return 1;
646        default:
647                fatal("Bad response from authentication agent: %d", type);
648        }
649        /* NOTREACHED */
650        return 0;
651}
Note: See TracBrowser for help on using the repository browser.