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.
28 #include <openssl/rsa.h>
34 /* Returns the number of the authentication fd, or -1 if there is none. */
37 ssh_get_authentication_socket()
39 const char *authsocket;
41 struct sockaddr_un sunaddr;
43 authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
47 sunaddr.sun_family = AF_UNIX;
48 strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
50 sock = socket(AF_UNIX, SOCK_STREAM, 0);
55 if (fcntl(sock, F_SETFD, 1) == -1)
61 if (connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
70 /* Closes the agent socket if it should be closed (depends on how it was
71 obtained). The argument must have been returned by
72 ssh_get_authentication_socket(). */
74 void ssh_close_authentication_socket(int sock)
76 if (getenv(SSH_AUTHSOCKET_ENV_NAME))
80 /* Opens and connects a private socket for communication with the
81 authentication agent. Returns the file descriptor (which must be
82 shut down and closed by the caller when no longer needed).
83 Returns NULL if an error occurred and the connection could not be
86 AuthenticationConnection *ssh_get_authentication_connection()
88 AuthenticationConnection *auth;
91 sock = ssh_get_authentication_socket();
93 /* Fail if we couldn't obtain a connection. This happens if we exited
98 /* Applocate the connection structure and initialize it. */
99 auth = xmalloc(sizeof(*auth));
101 buffer_init(&auth->packet);
102 buffer_init(&auth->identities);
108 /* Closes the connection to the authentication agent and frees any associated
111 void ssh_close_authentication_connection(AuthenticationConnection *ac)
113 buffer_free(&ac->packet);
114 buffer_free(&ac->identities);
116 /* Free the connection data structure. */
120 /* Returns the first authentication identity held by the agent.
121 Returns true if an identity is available, 0 otherwise.
122 The caller must initialize the integers before the call, and free the
123 comment after a successful call (before calling ssh_get_next_identity). */
126 ssh_get_first_identity(AuthenticationConnection *auth,
127 BIGNUM *e, BIGNUM *n, char **comment)
129 unsigned char msg[8192];
132 /* Send a message to the agent requesting for a list of the identities
138 msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
139 if (write(auth->fd, msg, 5) != 5)
141 error("write auth->fd: %.100s", strerror(errno));
145 /* Read the length of the response. XXX implement timeouts here. */
149 l = read(auth->fd, msg + 4 - len, len);
152 error("read auth->fd: %.100s", strerror(errno));
158 /* Extract the length, and check it for sanity. (We cannot trust
159 authentication agents). */
160 len = GET_32BIT(msg);
161 if (len < 1 || len > 256*1024)
162 fatal("Authentication reply message too long: %d\n", len);
164 /* Read the packet itself. */
165 buffer_clear(&auth->identities);
171 l = read(auth->fd, msg, l);
173 fatal("Incomplete authentication reply.");
174 buffer_append(&auth->identities, (char *)msg, l);
178 /* Get message type, and verify that we got a proper answer. */
179 buffer_get(&auth->identities, (char *)msg, 1);
180 if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
181 fatal("Bad authentication reply message type: %d", msg[0]);
183 /* Get the number of entries in the response and check it for sanity. */
184 auth->howmany = buffer_get_int(&auth->identities);
185 if (auth->howmany > 1024)
186 fatal("Too many identities in authentication reply: %d\n", auth->howmany);
188 /* Return the first entry (if any). */
189 return ssh_get_next_identity(auth, e, n, comment);
192 /* Returns the next authentication identity for the agent. Other functions
193 can be called between this and ssh_get_first_identity or two calls of this
194 function. This returns 0 if there are no more identities. The caller
195 must free comment after a successful return. */
198 ssh_get_next_identity(AuthenticationConnection *auth,
199 BIGNUM *e, BIGNUM *n, char **comment)
203 /* Return failure if no more entries. */
204 if (auth->howmany <= 0)
207 /* Get the next entry from the packet. These will abort with a fatal
208 error if the packet is too short or contains corrupt data. */
209 bits = buffer_get_int(&auth->identities);
210 buffer_get_bignum(&auth->identities, e);
211 buffer_get_bignum(&auth->identities, n);
212 *comment = buffer_get_string(&auth->identities, NULL);
214 if (bits != BN_num_bits(n))
215 error("Warning: keysize mismatch: actual %d, announced %u",
216 BN_num_bits(n), bits);
218 /* Decrement the number of remaining entries. */
224 /* Generates a random challenge, sends it to the agent, and waits for response
225 from the agent. Returns true (non-zero) if the agent gave the correct
226 answer, zero otherwise. Response type selects the style of response
227 desired, with 0 corresponding to protocol version 1.0 (no longer supported)
228 and 1 corresponding to protocol version 1.1. */
231 ssh_decrypt_challenge(AuthenticationConnection *auth,
232 BIGNUM *e, BIGNUM *n, BIGNUM *challenge,
233 unsigned char session_id[16],
234 unsigned int response_type,
235 unsigned char response[16])
238 unsigned char buf[8192];
241 /* Response type 0 is no longer supported. */
242 if (response_type == 0)
243 fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
245 /* Format a message to the agent. */
246 buf[0] = SSH_AGENTC_RSA_CHALLENGE;
247 buffer_init(&buffer);
248 buffer_append(&buffer, (char *)buf, 1);
249 buffer_put_int(&buffer, BN_num_bits(n));
250 buffer_put_bignum(&buffer, e);
251 buffer_put_bignum(&buffer, n);
252 buffer_put_bignum(&buffer, challenge);
253 buffer_append(&buffer, (char *)session_id, 16);
254 buffer_put_int(&buffer, response_type);
256 /* Get the length of the message, and format it in the buffer. */
257 len = buffer_len(&buffer);
260 /* Send the length and then the packet to the agent. */
261 if (write(auth->fd, buf, 4) != 4 ||
262 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
265 error("Error writing to authentication socket.");
267 buffer_free(&buffer);
271 /* Wait for response from the agent. First read the length of the
276 l = read(auth->fd, buf + 4 - len, len);
279 error("Error reading response length from authentication socket.");
285 /* Extract the length, and check it for sanity. */
286 len = GET_32BIT(buf);
288 fatal("Authentication response too long: %d", len);
290 /* Read the rest of the response in tothe buffer. */
291 buffer_clear(&buffer);
297 l = read(auth->fd, buf, l);
300 error("Error reading response from authentication socket.");
303 buffer_append(&buffer, (char *)buf, l);
307 /* Get the type of the packet. */
308 buffer_get(&buffer, (char *)buf, 1);
310 /* Check for agent failure message. */
311 if (buf[0] == SSH_AGENT_FAILURE)
313 log("Agent admitted failure to authenticate using the key.");
317 /* Now it must be an authentication response packet. */
318 if (buf[0] != SSH_AGENT_RSA_RESPONSE)
319 fatal("Bad authentication response: %d", buf[0]);
321 /* Get the response from the packet. This will abort with a fatal error
322 if the packet is corrupt. */
323 for (i = 0; i < 16; i++)
324 response[i] = buffer_get_char(&buffer);
326 /* The buffer containing the packet is no longer needed. */
327 buffer_free(&buffer);
329 /* Correct answer. */
333 /* Adds an identity to the authentication server. This call is not meant to
334 be used by normal applications. */
336 int ssh_add_identity(AuthenticationConnection *auth,
337 RSA *key, const char *comment)
340 unsigned char buf[8192];
343 /* Format a message to the agent. */
344 buffer_init(&buffer);
345 buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
346 buffer_put_int(&buffer, BN_num_bits(key->n));
347 buffer_put_bignum(&buffer, key->n);
348 buffer_put_bignum(&buffer, key->e);
349 buffer_put_bignum(&buffer, key->d);
350 /* To keep within the protocol: p < q for ssh. in SSL p > q */
351 buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
352 buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
353 buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
354 buffer_put_string(&buffer, comment, strlen(comment));
356 /* Get the length of the message, and format it in the buffer. */
357 len = buffer_len(&buffer);
360 /* Send the length and then the packet to the agent. */
361 if (write(auth->fd, buf, 4) != 4 ||
362 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
365 error("Error writing to authentication socket.");
367 buffer_free(&buffer);
371 /* Wait for response from the agent. First read the length of the
376 l = read(auth->fd, buf + 4 - len, len);
379 error("Error reading response length from authentication socket.");
385 /* Extract the length, and check it for sanity. */
386 len = GET_32BIT(buf);
388 fatal("Add identity response too long: %d", len);
390 /* Read the rest of the response in tothe buffer. */
391 buffer_clear(&buffer);
397 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);
411 case SSH_AGENT_FAILURE:
412 buffer_free(&buffer);
414 case SSH_AGENT_SUCCESS:
415 buffer_free(&buffer);
418 fatal("Bad response to add identity from authentication agent: %d",
425 /* Removes an identity from the authentication server. This call is not meant
426 to be used by normal applications. */
428 int ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
431 unsigned char buf[8192];
434 /* Format a message to the agent. */
435 buffer_init(&buffer);
436 buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
437 buffer_put_int(&buffer, BN_num_bits(key->n));
438 buffer_put_bignum(&buffer, key->e);
439 buffer_put_bignum(&buffer, key->n);
441 /* Get the length of the message, and format it in the buffer. */
442 len = buffer_len(&buffer);
445 /* Send the length and then the packet to the agent. */
446 if (write(auth->fd, buf, 4) != 4 ||
447 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
450 error("Error writing to authentication socket.");
452 buffer_free(&buffer);
456 /* Wait for response from the agent. First read the length of the
461 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);
473 fatal("Remove identity response too long: %d", len);
475 /* Read the rest of the response in tothe buffer. */
476 buffer_clear(&buffer);
482 l = read(auth->fd, buf, l);
485 error("Error reading response from authentication socket.");
488 buffer_append(&buffer, (char *)buf, l);
492 /* Get the type of the packet. */
493 type = buffer_get_char(&buffer);
496 case SSH_AGENT_FAILURE:
497 buffer_free(&buffer);
499 case SSH_AGENT_SUCCESS:
500 buffer_free(&buffer);
503 fatal("Bad response to remove identity from authentication agent: %d",
510 /* Removes all identities from the agent. This call is not meant
511 to be used by normal applications. */
513 int 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 (write(auth->fd, buf, 5) != 5)
526 error("Error writing to authentication socket.");
530 /* Wait for response from the agent. First read the length of the
535 l = read(auth->fd, buf + 4 - len, len);
538 error("Error reading response length from authentication socket.");
544 /* Extract the length, and check it for sanity. */
545 len = GET_32BIT(buf);
547 fatal("Remove identity response too long: %d", len);
549 /* Read the rest of the response into the buffer. */
550 buffer_init(&buffer);
556 l = read(auth->fd, buf, l);
559 error("Error reading response from authentication socket.");
560 buffer_free(&buffer);
563 buffer_append(&buffer, (char *)buf, l);
567 /* Get the type of the packet. */
568 type = buffer_get_char(&buffer);
571 case SSH_AGENT_FAILURE:
572 buffer_free(&buffer);
574 case SSH_AGENT_SUCCESS:
575 buffer_free(&buffer);
578 fatal("Bad response to remove identity from authentication agent: %d",