5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
10 * Created: Wed Mar 29 01:30:28 1995 ylo
12 * Functions for connecting the local authentication agent.
17 RCSID("$OpenBSD: authfd.c,v 1.20 2000/06/20 01:39:38 markus Exp $");
27 #include <openssl/rsa.h>
29 /* Returns the number of the authentication fd, or -1 if there is none. */
32 ssh_get_authentication_socket()
34 const char *authsocket;
36 struct sockaddr_un sunaddr;
38 authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
42 sunaddr.sun_family = AF_UNIX;
43 strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
45 sock = socket(AF_UNIX, SOCK_STREAM, 0);
50 if (fcntl(sock, F_SETFD, 1) == -1) {
54 if (connect(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
62 * Closes the agent socket if it should be closed (depends on how it was
63 * obtained). The argument must have been returned by
64 * ssh_get_authentication_socket().
68 ssh_close_authentication_socket(int sock)
70 if (getenv(SSH_AUTHSOCKET_ENV_NAME))
75 * Opens and connects a private socket for communication with the
76 * authentication agent. Returns the file descriptor (which must be
77 * shut down and closed by the caller when no longer needed).
78 * Returns NULL if an error occurred and the connection could not be
82 AuthenticationConnection *
83 ssh_get_authentication_connection()
85 AuthenticationConnection *auth;
88 sock = ssh_get_authentication_socket();
91 * Fail if we couldn't obtain a connection. This happens if we
92 * exited due to a timeout.
97 auth = xmalloc(sizeof(*auth));
99 buffer_init(&auth->packet);
100 buffer_init(&auth->identities);
107 * Closes the connection to the authentication agent and frees any associated
112 ssh_close_authentication_connection(AuthenticationConnection *ac)
114 buffer_free(&ac->packet);
115 buffer_free(&ac->identities);
121 * Returns the first authentication identity held by the agent.
122 * Returns true if an identity is available, 0 otherwise.
123 * The caller must initialize the integers before the call, and free the
124 * comment after a successful call (before calling ssh_get_next_identity).
128 ssh_get_first_identity(AuthenticationConnection *auth,
129 BIGNUM *e, BIGNUM *n, char **comment)
131 unsigned char msg[8192];
135 * Send a message to the agent requesting for a list of the
136 * identities it can represent.
142 msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
143 if (atomicio(write, auth->fd, msg, 5) != 5) {
144 error("write auth->fd: %.100s", strerror(errno));
147 /* Read the length of the response. XXX implement timeouts here. */
150 l = read(auth->fd, msg + 4 - len, len);
152 error("read auth->fd: %.100s", strerror(errno));
159 * Extract the length, and check it for sanity. (We cannot trust
160 * authentication agents).
162 len = GET_32BIT(msg);
163 if (len < 1 || len > 256 * 1024)
164 fatal("Authentication reply message too long: %d\n", len);
166 /* Read the packet itself. */
167 buffer_clear(&auth->identities);
172 l = read(auth->fd, msg, l);
174 fatal("Incomplete authentication reply.");
175 buffer_append(&auth->identities, (char *) msg, l);
179 /* Get message type, and verify that we got a proper answer. */
180 buffer_get(&auth->identities, (char *) msg, 1);
181 if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
182 fatal("Bad authentication reply message type: %d", msg[0]);
184 /* Get the number of entries in the response and check it for sanity. */
185 auth->howmany = buffer_get_int(&auth->identities);
186 if (auth->howmany > 1024)
187 fatal("Too many identities in authentication reply: %d\n", auth->howmany);
189 /* Return the first entry (if any). */
190 return ssh_get_next_identity(auth, e, n, comment);
194 * Returns the next authentication identity for the agent. Other functions
195 * can be called between this and ssh_get_first_identity or two calls of this
196 * function. This returns 0 if there are no more identities. The caller
197 * must free comment after a successful return.
201 ssh_get_next_identity(AuthenticationConnection *auth,
202 BIGNUM *e, BIGNUM *n, char **comment)
206 /* Return failure if no more entries. */
207 if (auth->howmany <= 0)
211 * Get the next entry from the packet. These will abort with a fatal
212 * error if the packet is too short or contains corrupt data.
214 bits = buffer_get_int(&auth->identities);
215 buffer_get_bignum(&auth->identities, e);
216 buffer_get_bignum(&auth->identities, n);
217 *comment = buffer_get_string(&auth->identities, NULL);
219 if (bits != BN_num_bits(n))
220 log("Warning: identity keysize mismatch: actual %d, announced %u",
221 BN_num_bits(n), bits);
223 /* Decrement the number of remaining entries. */
230 * Generates a random challenge, sends it to the agent, and waits for
231 * response from the agent. Returns true (non-zero) if the agent gave the
232 * correct answer, zero otherwise. Response type selects the style of
233 * response desired, with 0 corresponding to protocol version 1.0 (no longer
234 * supported) and 1 corresponding to protocol version 1.1.
238 ssh_decrypt_challenge(AuthenticationConnection *auth,
239 BIGNUM* e, BIGNUM *n, BIGNUM *challenge,
240 unsigned char session_id[16],
241 unsigned int response_type,
242 unsigned char response[16])
245 unsigned char buf[8192];
248 /* Response type 0 is no longer supported. */
249 if (response_type == 0)
250 fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
252 /* Format a message to the agent. */
253 buf[0] = SSH_AGENTC_RSA_CHALLENGE;
254 buffer_init(&buffer);
255 buffer_append(&buffer, (char *) buf, 1);
256 buffer_put_int(&buffer, BN_num_bits(n));
257 buffer_put_bignum(&buffer, e);
258 buffer_put_bignum(&buffer, n);
259 buffer_put_bignum(&buffer, challenge);
260 buffer_append(&buffer, (char *) session_id, 16);
261 buffer_put_int(&buffer, response_type);
263 /* Get the length of the message, and format it in the buffer. */
264 len = buffer_len(&buffer);
267 /* Send the length and then the packet to the agent. */
268 if (atomicio(write, auth->fd, buf, 4) != 4 ||
269 atomicio(write, auth->fd, buffer_ptr(&buffer),
270 buffer_len(&buffer)) != buffer_len(&buffer)) {
271 error("Error writing to authentication socket.");
273 buffer_free(&buffer);
277 * Wait for response from the agent. First read the length of the
282 l = read(auth->fd, buf + 4 - len, len);
284 error("Error reading response length from authentication socket.");
290 /* Extract the length, and check it for sanity. */
291 len = GET_32BIT(buf);
292 if (len > 256 * 1024)
293 fatal("Authentication response too long: %d", len);
295 /* Read the rest of the response in tothe buffer. */
296 buffer_clear(&buffer);
301 l = read(auth->fd, buf, l);
303 error("Error reading response from authentication socket.");
306 buffer_append(&buffer, (char *) buf, l);
310 /* Get the type of the packet. */
311 buffer_get(&buffer, (char *) buf, 1);
313 /* Check for agent failure message. */
314 if (buf[0] == SSH_AGENT_FAILURE) {
315 log("Agent admitted failure to authenticate using the key.");
318 /* Now it must be an authentication response packet. */
319 if (buf[0] != SSH_AGENT_RSA_RESPONSE)
320 fatal("Bad authentication response: %d", buf[0]);
323 * Get the response from the packet. This will abort with a fatal
324 * error if the packet is corrupt.
326 for (i = 0; i < 16; i++)
327 response[i] = buffer_get_char(&buffer);
329 /* The buffer containing the packet is no longer needed. */
330 buffer_free(&buffer);
332 /* Correct answer. */
337 * Adds an identity to the authentication server. This call is not meant to
338 * be used by normal applications.
342 ssh_add_identity(AuthenticationConnection *auth,
343 RSA * key, const char *comment)
346 unsigned char buf[8192];
349 /* Format a message to the agent. */
350 buffer_init(&buffer);
351 buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
352 buffer_put_int(&buffer, BN_num_bits(key->n));
353 buffer_put_bignum(&buffer, key->n);
354 buffer_put_bignum(&buffer, key->e);
355 buffer_put_bignum(&buffer, key->d);
356 /* To keep within the protocol: p < q for ssh. in SSL p > q */
357 buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
358 buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
359 buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
360 buffer_put_string(&buffer, comment, strlen(comment));
362 /* Get the length of the message, and format it in the buffer. */
363 len = buffer_len(&buffer);
366 /* Send the length and then the packet to the agent. */
367 if (atomicio(write, auth->fd, buf, 4) != 4 ||
368 atomicio(write, auth->fd, buffer_ptr(&buffer),
369 buffer_len(&buffer)) != buffer_len(&buffer)) {
370 error("Error writing to authentication socket.");
372 buffer_free(&buffer);
375 /* Wait for response from the agent. First read the length of the
379 l = read(auth->fd, buf + 4 - len, len);
381 error("Error reading response length from authentication socket.");
387 /* Extract the length, and check it for sanity. */
388 len = GET_32BIT(buf);
389 if (len > 256 * 1024)
390 fatal("Add identity response too long: %d", len);
392 /* Read the rest of the response in tothe buffer. */
393 buffer_clear(&buffer);
398 l = read(auth->fd, buf, l);
400 error("Error reading response from authentication socket.");
403 buffer_append(&buffer, (char *) buf, l);
407 /* Get the type of the packet. */
408 type = buffer_get_char(&buffer);
410 case SSH_AGENT_FAILURE:
411 buffer_free(&buffer);
413 case SSH_AGENT_SUCCESS:
414 buffer_free(&buffer);
417 fatal("Bad response to add identity from authentication agent: %d",
425 * Removes an identity from the authentication server. This call is not
426 * meant to be used by normal applications.
430 ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
433 unsigned char buf[8192];
436 /* Format a message to the agent. */
437 buffer_init(&buffer);
438 buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
439 buffer_put_int(&buffer, BN_num_bits(key->n));
440 buffer_put_bignum(&buffer, key->e);
441 buffer_put_bignum(&buffer, key->n);
443 /* Get the length of the message, and format it in the buffer. */
444 len = buffer_len(&buffer);
447 /* Send the length and then the packet to the agent. */
448 if (atomicio(write, auth->fd, buf, 4) != 4 ||
449 atomicio(write, auth->fd, buffer_ptr(&buffer),
450 buffer_len(&buffer)) != buffer_len(&buffer)) {
451 error("Error writing to authentication socket.");
453 buffer_free(&buffer);
457 * Wait for response from the agent. First read the length of the
462 l = read(auth->fd, buf + 4 - len, len);
464 error("Error reading response length from authentication socket.");
470 /* Extract the length, and check it for sanity. */
471 len = GET_32BIT(buf);
472 if (len > 256 * 1024)
473 fatal("Remove identity response too long: %d", len);
475 /* Read the rest of the response in tothe buffer. */
476 buffer_clear(&buffer);
481 l = read(auth->fd, buf, l);
483 error("Error reading response from authentication socket.");
486 buffer_append(&buffer, (char *) buf, l);
490 /* Get the type of the packet. */
491 type = buffer_get_char(&buffer);
493 case SSH_AGENT_FAILURE:
494 buffer_free(&buffer);
496 case SSH_AGENT_SUCCESS:
497 buffer_free(&buffer);
500 fatal("Bad response to remove identity from authentication agent: %d",
508 * Removes all identities from the agent. This call is not meant to be used
509 * by normal applications.
513 ssh_remove_all_identities(AuthenticationConnection *auth)
516 unsigned char buf[8192];
519 /* Get the length of the message, and format it in the buffer. */
521 buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
523 /* Send the length and then the packet to the agent. */
524 if (atomicio(write, auth->fd, buf, 5) != 5) {
525 error("Error writing to authentication socket.");
529 * Wait for response from the agent. First read the length of the
534 l = read(auth->fd, buf + 4 - len, len);
536 error("Error reading response length from authentication socket.");
542 /* Extract the length, and check it for sanity. */
543 len = GET_32BIT(buf);
544 if (len > 256 * 1024)
545 fatal("Remove identity response too long: %d", len);
547 /* Read the rest of the response into the buffer. */
548 buffer_init(&buffer);
553 l = read(auth->fd, buf, l);
555 error("Error reading response from authentication socket.");
556 buffer_free(&buffer);
559 buffer_append(&buffer, (char *) buf, l);
563 /* Get the type of the packet. */
564 type = buffer_get_char(&buffer);
566 case SSH_AGENT_FAILURE:
567 buffer_free(&buffer);
569 case SSH_AGENT_SUCCESS:
570 buffer_free(&buffer);
573 fatal("Bad response to remove identity from authentication agent: %d",