]> andersk Git - openssh.git/blame - authfd.c
- (djm) Define USE_PIPES to avoid socketpair problems on HPUX 10 and SunOS 4
[openssh.git] / authfd.c
CommitLineData
8efc0c15 1/*
6ae2364d 2 *
5260325f 3 * authfd.c
6ae2364d 4 *
5260325f 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6ae2364d 6 *
5260325f 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 * All rights reserved
6ae2364d 9 *
5260325f 10 * Created: Wed Mar 29 01:30:28 1995 ylo
6ae2364d 11 *
5260325f 12 * Functions for connecting the local authentication agent.
6ae2364d 13 *
5260325f 14 */
8efc0c15 15
16#include "includes.h"
c345cf9d 17RCSID("$OpenBSD: authfd.c,v 1.24 2000/08/15 19:20:46 markus Exp $");
8efc0c15 18
19#include "ssh.h"
20#include "rsa.h"
8efc0c15 21#include "buffer.h"
22#include "bufaux.h"
23#include "xmalloc.h"
24#include "getput.h"
25
26#include <openssl/rsa.h>
4c8722d9 27#include <openssl/dsa.h>
28#include <openssl/evp.h>
29#include "key.h"
30#include "authfd.h"
31#include "kex.h"
8efc0c15 32
089fbbd2 33/* helper */
c345cf9d 34int decode_reply(int type);
089fbbd2 35
8efc0c15 36/* Returns the number of the authentication fd, or -1 if there is none. */
37
38int
39ssh_get_authentication_socket()
40{
5260325f 41 const char *authsocket;
c345cf9d 42 int sock, len;
5260325f 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));
c345cf9d 51#ifdef HAVE_SUN_LEN_IN_SOCKADDR_UN
52 sunaddr.sun_len = len = SUN_LEN(&sunaddr)+1;
53#else /* HAVE_SUN_LEN_IN_SOCKADDR_UN */
54 len = SUN_LEN(&sunaddr)+1;
55#endif /* HAVE_SUN_LEN_IN_SOCKADDR_UN */
5260325f 56
57 sock = socket(AF_UNIX, SOCK_STREAM, 0);
58 if (sock < 0)
59 return -1;
60
61 /* close on exec */
62 if (fcntl(sock, F_SETFD, 1) == -1) {
63 close(sock);
64 return -1;
65 }
c345cf9d 66 if (connect(sock, (struct sockaddr *) & sunaddr, len) < 0) {
5260325f 67 close(sock);
68 return -1;
69 }
70 return sock;
8efc0c15 71}
72
c345cf9d 73int
74ssh_request_reply(AuthenticationConnection *auth,
75 Buffer *request, Buffer *reply)
76{
77 int l, len;
78 char buf[1024];
79
80 /* Get the length of the message, and format it in the buffer. */
81 len = buffer_len(request);
82 PUT_32BIT(buf, len);
83
84 /* Send the length and then the packet to the agent. */
85 if (atomicio(write, auth->fd, buf, 4) != 4 ||
86 atomicio(write, auth->fd, buffer_ptr(request),
87 buffer_len(request)) != buffer_len(request)) {
88 error("Error writing to authentication socket.");
89 return 0;
90 }
91 /*
92 * Wait for response from the agent. First read the length of the
93 * response packet.
94 */
95 len = 4;
96 while (len > 0) {
97 l = read(auth->fd, buf + 4 - len, len);
98 if (l <= 0) {
99 error("Error reading response length from authentication socket.");
100 return 0;
101 }
102 len -= l;
103 }
104
105 /* Extract the length, and check it for sanity. */
106 len = GET_32BIT(buf);
107 if (len > 256 * 1024)
108 fatal("Authentication response too long: %d", len);
109
110 /* Read the rest of the response in to the buffer. */
111 buffer_clear(reply);
112 while (len > 0) {
113 l = len;
114 if (l > sizeof(buf))
115 l = sizeof(buf);
116 l = read(auth->fd, buf, l);
117 if (l <= 0) {
118 error("Error reading response from authentication socket.");
119 return 0;
120 }
121 buffer_append(reply, (char *) buf, l);
122 len -= l;
123 }
124 return 1;
125}
126
aa3378df 127/*
128 * Closes the agent socket if it should be closed (depends on how it was
129 * obtained). The argument must have been returned by
130 * ssh_get_authentication_socket().
131 */
8efc0c15 132
6ae2364d 133void
5260325f 134ssh_close_authentication_socket(int sock)
8efc0c15 135{
5260325f 136 if (getenv(SSH_AUTHSOCKET_ENV_NAME))
137 close(sock);
8efc0c15 138}
139
aa3378df 140/*
141 * Opens and connects a private socket for communication with the
142 * authentication agent. Returns the file descriptor (which must be
143 * shut down and closed by the caller when no longer needed).
144 * Returns NULL if an error occurred and the connection could not be
145 * opened.
146 */
8efc0c15 147
5260325f 148AuthenticationConnection *
149ssh_get_authentication_connection()
8efc0c15 150{
5260325f 151 AuthenticationConnection *auth;
152 int sock;
153
154 sock = ssh_get_authentication_socket();
155
aa3378df 156 /*
157 * Fail if we couldn't obtain a connection. This happens if we
158 * exited due to a timeout.
159 */
5260325f 160 if (sock < 0)
161 return NULL;
162
5260325f 163 auth = xmalloc(sizeof(*auth));
164 auth->fd = sock;
165 buffer_init(&auth->packet);
166 buffer_init(&auth->identities);
167 auth->howmany = 0;
168
169 return auth;
8efc0c15 170}
171
aa3378df 172/*
173 * Closes the connection to the authentication agent and frees any associated
174 * memory.
175 */
8efc0c15 176
6ae2364d 177void
5260325f 178ssh_close_authentication_connection(AuthenticationConnection *ac)
8efc0c15 179{
5260325f 180 buffer_free(&ac->packet);
181 buffer_free(&ac->identities);
182 close(ac->fd);
183 xfree(ac);
8efc0c15 184}
185
aa3378df 186/*
187 * Returns the first authentication identity held by the agent.
188 * Returns true if an identity is available, 0 otherwise.
189 * The caller must initialize the integers before the call, and free the
190 * comment after a successful call (before calling ssh_get_next_identity).
191 */
8efc0c15 192
193int
194ssh_get_first_identity(AuthenticationConnection *auth,
c345cf9d 195 BIGNUM *e, BIGNUM *n, char **comment)
8efc0c15 196{
c345cf9d 197 Buffer request;
198 int type;
5260325f 199
aa3378df 200 /*
201 * Send a message to the agent requesting for a list of the
202 * identities it can represent.
203 */
c345cf9d 204 buffer_init(&request);
205 buffer_put_char(&request, SSH_AGENTC_REQUEST_RSA_IDENTITIES);
5260325f 206
5260325f 207 buffer_clear(&auth->identities);
c345cf9d 208 if (ssh_request_reply(auth, &request, &auth->identities) == 0) {
209 buffer_free(&request);
210 return 0;
8efc0c15 211 }
c345cf9d 212 buffer_free(&request);
5260325f 213
214 /* Get message type, and verify that we got a proper answer. */
c345cf9d 215 type = buffer_get_char(&auth->identities);
216 if (type != SSH_AGENT_RSA_IDENTITIES_ANSWER)
217 fatal("Bad authentication reply message type: %d", type);
5260325f 218
219 /* Get the number of entries in the response and check it for sanity. */
220 auth->howmany = buffer_get_int(&auth->identities);
221 if (auth->howmany > 1024)
c345cf9d 222 fatal("Too many identities in authentication reply: %d\n",
223 auth->howmany);
5260325f 224
225 /* Return the first entry (if any). */
226 return ssh_get_next_identity(auth, e, n, comment);
8efc0c15 227}
228
aa3378df 229/*
230 * Returns the next authentication identity for the agent. Other functions
231 * can be called between this and ssh_get_first_identity or two calls of this
232 * function. This returns 0 if there are no more identities. The caller
233 * must free comment after a successful return.
234 */
8efc0c15 235
236int
237ssh_get_next_identity(AuthenticationConnection *auth,
c345cf9d 238 BIGNUM *e, BIGNUM *n, char **comment)
8efc0c15 239{
5260325f 240 unsigned int bits;
4d195447 241
5260325f 242 /* Return failure if no more entries. */
243 if (auth->howmany <= 0)
244 return 0;
8efc0c15 245
aa3378df 246 /*
247 * Get the next entry from the packet. These will abort with a fatal
248 * error if the packet is too short or contains corrupt data.
249 */
5260325f 250 bits = buffer_get_int(&auth->identities);
251 buffer_get_bignum(&auth->identities, e);
252 buffer_get_bignum(&auth->identities, n);
253 *comment = buffer_get_string(&auth->identities, NULL);
8efc0c15 254
5260325f 255 if (bits != BN_num_bits(n))
0b242b12 256 log("Warning: identity keysize mismatch: actual %d, announced %u",
257 BN_num_bits(n), bits);
4d195447 258
5260325f 259 /* Decrement the number of remaining entries. */
260 auth->howmany--;
8efc0c15 261
5260325f 262 return 1;
8efc0c15 263}
264
aa3378df 265/*
266 * Generates a random challenge, sends it to the agent, and waits for
267 * response from the agent. Returns true (non-zero) if the agent gave the
268 * correct answer, zero otherwise. Response type selects the style of
269 * response desired, with 0 corresponding to protocol version 1.0 (no longer
270 * supported) and 1 corresponding to protocol version 1.1.
271 */
8efc0c15 272
273int
274ssh_decrypt_challenge(AuthenticationConnection *auth,
c345cf9d 275 BIGNUM* e, BIGNUM *n, BIGNUM *challenge,
276 unsigned char session_id[16],
277 unsigned int response_type,
278 unsigned char response[16])
8efc0c15 279{
5260325f 280 Buffer buffer;
c345cf9d 281 int success = 0;
282 int i;
283 int type;
5260325f 284
5260325f 285 if (response_type == 0)
c345cf9d 286 fatal("Compatibility with ssh protocol version "
287 "1.0 no longer supported.");
5260325f 288
5260325f 289 buffer_init(&buffer);
c345cf9d 290 buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE);
5260325f 291 buffer_put_int(&buffer, BN_num_bits(n));
292 buffer_put_bignum(&buffer, e);
293 buffer_put_bignum(&buffer, n);
294 buffer_put_bignum(&buffer, challenge);
295 buffer_append(&buffer, (char *) session_id, 16);
296 buffer_put_int(&buffer, response_type);
297
c345cf9d 298 if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
5260325f 299 buffer_free(&buffer);
300 return 0;
301 }
c345cf9d 302 type = buffer_get_char(&buffer);
5260325f 303
c345cf9d 304 if (type == SSH_AGENT_FAILURE) {
5260325f 305 log("Agent admitted failure to authenticate using the key.");
c345cf9d 306 } else if (type != SSH_AGENT_RSA_RESPONSE) {
307 fatal("Bad authentication response: %d", type);
308 } else {
309 success = 1;
310 /*
311 * Get the response from the packet. This will abort with a
312 * fatal error if the packet is corrupt.
313 */
314 for (i = 0; i < 16; i++)
315 response[i] = buffer_get_char(&buffer);
8efc0c15 316 }
5260325f 317 buffer_free(&buffer);
c345cf9d 318 return success;
5260325f 319}
8efc0c15 320
4c8722d9 321/* Encode key for a message to the agent. */
322
323void
324ssh_encode_identity_rsa(Buffer *b, RSA *key, const char *comment)
325{
326 buffer_clear(b);
327 buffer_put_char(b, SSH_AGENTC_ADD_RSA_IDENTITY);
328 buffer_put_int(b, BN_num_bits(key->n));
329 buffer_put_bignum(b, key->n);
330 buffer_put_bignum(b, key->e);
331 buffer_put_bignum(b, key->d);
332 /* To keep within the protocol: p < q for ssh. in SSL p > q */
333 buffer_put_bignum(b, key->iqmp); /* ssh key->u */
334 buffer_put_bignum(b, key->q); /* ssh key->p, SSL key->q */
335 buffer_put_bignum(b, key->p); /* ssh key->q, SSL key->p */
336 buffer_put_string(b, comment, strlen(comment));
337}
338
339void
340ssh_encode_identity_dsa(Buffer *b, DSA *key, const char *comment)
341{
342 buffer_clear(b);
343 buffer_put_char(b, SSH2_AGENTC_ADD_IDENTITY);
344 buffer_put_cstring(b, KEX_DSS);
345 buffer_put_bignum2(b, key->p);
346 buffer_put_bignum2(b, key->q);
347 buffer_put_bignum2(b, key->g);
348 buffer_put_bignum2(b, key->pub_key);
349 buffer_put_bignum2(b, key->priv_key);
350 buffer_put_string(b, comment, strlen(comment));
351}
352
aa3378df 353/*
354 * Adds an identity to the authentication server. This call is not meant to
355 * be used by normal applications.
356 */
8efc0c15 357
6ae2364d 358int
4c8722d9 359ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
8efc0c15 360{
5260325f 361 Buffer buffer;
c345cf9d 362 int type;
5260325f 363
5260325f 364 buffer_init(&buffer);
4c8722d9 365
366 switch (key->type) {
367 case KEY_RSA:
368 ssh_encode_identity_rsa(&buffer, key->rsa, comment);
369 break;
370 case KEY_DSA:
371 ssh_encode_identity_dsa(&buffer, key->dsa, comment);
372 break;
373 default:
374 buffer_free(&buffer);
375 return 0;
376 break;
377 }
c345cf9d 378 if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
5260325f 379 buffer_free(&buffer);
380 return 0;
381 }
c345cf9d 382 type = buffer_get_char(&buffer);
089fbbd2 383 buffer_free(&buffer);
c345cf9d 384 return decode_reply(type);
5260325f 385}
386
aa3378df 387/*
388 * Removes an identity from the authentication server. This call is not
389 * meant to be used by normal applications.
390 */
8efc0c15 391
6ae2364d 392int
5260325f 393ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
8efc0c15 394{
5260325f 395 Buffer buffer;
c345cf9d 396 int type;
5260325f 397
5260325f 398 buffer_init(&buffer);
399 buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
400 buffer_put_int(&buffer, BN_num_bits(key->n));
401 buffer_put_bignum(&buffer, key->e);
402 buffer_put_bignum(&buffer, key->n);
403
c345cf9d 404 if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
5260325f 405 buffer_free(&buffer);
406 return 0;
407 }
c345cf9d 408 type = buffer_get_char(&buffer);
089fbbd2 409 buffer_free(&buffer);
c345cf9d 410 return decode_reply(type);
5260325f 411}
412
aa3378df 413/*
414 * Removes all identities from the agent. This call is not meant to be used
415 * by normal applications.
416 */
8efc0c15 417
6ae2364d 418int
5260325f 419ssh_remove_all_identities(AuthenticationConnection *auth)
8efc0c15 420{
c345cf9d 421 Buffer buffer;
422 int type;
5260325f 423
c345cf9d 424 buffer_init(&buffer);
425 buffer_put_char(&buffer, SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES);
5260325f 426
c345cf9d 427 if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
428 buffer_free(&buffer);
5260325f 429 return 0;
430 }
c345cf9d 431 type = buffer_get_char(&buffer);
432 buffer_free(&buffer);
433 return decode_reply(type);
089fbbd2 434}
435
089fbbd2 436int
c345cf9d 437decode_reply(int type)
089fbbd2 438{
5260325f 439 switch (type) {
440 case SSH_AGENT_FAILURE:
c345cf9d 441 log("SSH_AGENT_FAILURE");
5260325f 442 return 0;
443 case SSH_AGENT_SUCCESS:
5260325f 444 return 1;
445 default:
089fbbd2 446 fatal("Bad response from authentication agent: %d", type);
8efc0c15 447 }
5260325f 448 /* NOTREACHED */
449 return 0;
450}
This page took 0.130572 seconds and 5 git commands to generate.