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