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.
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);
49 if (connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
58 /* Closes the agent socket if it should be closed (depends on how it was
59 obtained). The argument must have been returned by
60 ssh_get_authentication_socket(). */
62 void ssh_close_authentication_socket(int sock)
64 if (getenv(SSH_AUTHSOCKET_ENV_NAME))
68 /* Opens and connects a private socket for communication with the
69 authentication agent. Returns the file descriptor (which must be
70 shut down and closed by the caller when no longer needed).
71 Returns NULL if an error occurred and the connection could not be
74 AuthenticationConnection *ssh_get_authentication_connection()
76 AuthenticationConnection *auth;
79 sock = ssh_get_authentication_socket();
81 /* Fail if we couldn't obtain a connection. This happens if we exited
86 /* Applocate the connection structure and initialize it. */
87 auth = xmalloc(sizeof(*auth));
89 buffer_init(&auth->packet);
90 buffer_init(&auth->identities);
96 /* Closes the connection to the authentication agent and frees any associated
99 void ssh_close_authentication_connection(AuthenticationConnection *ac)
101 buffer_free(&ac->packet);
102 buffer_free(&ac->identities);
104 /* Free the connection data structure. */
108 /* Returns the first authentication identity held by the agent.
109 Returns true if an identity is available, 0 otherwise.
110 The caller must initialize the integers before the call, and free the
111 comment after a successful call (before calling ssh_get_next_identity). */
114 ssh_get_first_identity(AuthenticationConnection *auth,
115 int *bitsp, BIGNUM *e, BIGNUM *n, char **comment)
117 unsigned char msg[8192];
120 /* Send a message to the agent requesting for a list of the identities
126 msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
127 if (write(auth->fd, msg, 5) != 5)
129 error("write auth->fd: %.100s", strerror(errno));
133 /* Read the length of the response. XXX implement timeouts here. */
137 l = read(auth->fd, msg + 4 - len, len);
140 error("read auth->fd: %.100s", strerror(errno));
146 /* Extract the length, and check it for sanity. (We cannot trust
147 authentication agents). */
148 len = GET_32BIT(msg);
149 if (len < 1 || len > 256*1024)
150 fatal("Authentication reply message too long: %d\n", len);
152 /* Read the packet itself. */
153 buffer_clear(&auth->identities);
159 l = read(auth->fd, msg, l);
161 fatal("Incomplete authentication reply.");
162 buffer_append(&auth->identities, (char *)msg, l);
166 /* Get message type, and verify that we got a proper answer. */
167 buffer_get(&auth->identities, (char *)msg, 1);
168 if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
169 fatal("Bad authentication reply message type: %d", msg[0]);
171 /* Get the number of entries in the response and check it for sanity. */
172 auth->howmany = buffer_get_int(&auth->identities);
173 if (auth->howmany > 1024)
174 fatal("Too many identities in authentication reply: %d\n", auth->howmany);
176 /* Return the first entry (if any). */
177 return ssh_get_next_identity(auth, bitsp, e, n, comment);
180 /* Returns the next authentication identity for the agent. Other functions
181 can be called between this and ssh_get_first_identity or two calls of this
182 function. This returns 0 if there are no more identities. The caller
183 must free comment after a successful return. */
186 ssh_get_next_identity(AuthenticationConnection *auth,
187 int *bitsp, BIGNUM *e, BIGNUM *n, char **comment)
189 /* Return failure if no more entries. */
190 if (auth->howmany <= 0)
193 /* Get the next entry from the packet. These will abort with a fatal
194 error if the packet is too short or contains corrupt data. */
195 *bitsp = buffer_get_int(&auth->identities);
196 buffer_get_bignum(&auth->identities, e);
197 buffer_get_bignum(&auth->identities, n);
198 *comment = buffer_get_string(&auth->identities, NULL);
200 /* Decrement the number of remaining entries. */
206 /* Generates a random challenge, sends it to the agent, and waits for response
207 from the agent. Returns true (non-zero) if the agent gave the correct
208 answer, zero otherwise. Response type selects the style of response
209 desired, with 0 corresponding to protocol version 1.0 (no longer supported)
210 and 1 corresponding to protocol version 1.1. */
213 ssh_decrypt_challenge(AuthenticationConnection *auth,
214 int bits, BIGNUM *e, BIGNUM *n, BIGNUM *challenge,
215 unsigned char session_id[16],
216 unsigned int response_type,
217 unsigned char response[16])
220 unsigned char buf[8192];
223 /* Response type 0 is no longer supported. */
224 if (response_type == 0)
225 fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
227 /* Format a message to the agent. */
228 buf[0] = SSH_AGENTC_RSA_CHALLENGE;
229 buffer_init(&buffer);
230 buffer_append(&buffer, (char *)buf, 1);
231 buffer_put_int(&buffer, bits);
232 buffer_put_bignum(&buffer, e);
233 buffer_put_bignum(&buffer, n);
234 buffer_put_bignum(&buffer, challenge);
235 buffer_append(&buffer, (char *)session_id, 16);
236 buffer_put_int(&buffer, response_type);
238 /* Get the length of the message, and format it in the buffer. */
239 len = buffer_len(&buffer);
242 /* Send the length and then the packet to the agent. */
243 if (write(auth->fd, buf, 4) != 4 ||
244 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
247 error("Error writing to authentication socket.");
249 buffer_free(&buffer);
253 /* Wait for response from the agent. First read the length of the
258 l = read(auth->fd, buf + 4 - len, len);
261 error("Error reading response length from authentication socket.");
267 /* Extract the length, and check it for sanity. */
268 len = GET_32BIT(buf);
270 fatal("Authentication response too long: %d", len);
272 /* Read the rest of the response in tothe buffer. */
273 buffer_clear(&buffer);
279 l = read(auth->fd, buf, l);
282 error("Error reading response from authentication socket.");
285 buffer_append(&buffer, (char *)buf, l);
289 /* Get the type of the packet. */
290 buffer_get(&buffer, (char *)buf, 1);
292 /* Check for agent failure message. */
293 if (buf[0] == SSH_AGENT_FAILURE)
295 log("Agent admitted failure to authenticate using the key.");
299 /* Now it must be an authentication response packet. */
300 if (buf[0] != SSH_AGENT_RSA_RESPONSE)
301 fatal("Bad authentication response: %d", buf[0]);
303 /* Get the response from the packet. This will abort with a fatal error
304 if the packet is corrupt. */
305 for (i = 0; i < 16; i++)
306 response[i] = buffer_get_char(&buffer);
308 /* The buffer containing the packet is no longer needed. */
309 buffer_free(&buffer);
311 /* Correct answer. */
315 /* Adds an identity to the authentication server. This call is not meant to
316 be used by normal applications. */
318 int ssh_add_identity(AuthenticationConnection *auth,
319 RSA *key, const char *comment)
322 unsigned char buf[8192];
325 /* Format a message to the agent. */
326 buffer_init(&buffer);
327 buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
328 buffer_put_int(&buffer, BN_num_bits(key->n));
329 buffer_put_bignum(&buffer, key->n);
330 buffer_put_bignum(&buffer, key->e);
331 buffer_put_bignum(&buffer, key->d);
332 /* To keep within the protocol: p < q for ssh. in SSL p > q */
333 buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
334 buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
335 buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
336 buffer_put_string(&buffer, comment, strlen(comment));
338 /* Get the length of the message, and format it in the buffer. */
339 len = buffer_len(&buffer);
342 /* Send the length and then the packet to the agent. */
343 if (write(auth->fd, buf, 4) != 4 ||
344 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
347 error("Error writing to authentication socket.");
349 buffer_free(&buffer);
353 /* Wait for response from the agent. First read the length of the
358 l = read(auth->fd, buf + 4 - len, len);
361 error("Error reading response length from authentication socket.");
367 /* Extract the length, and check it for sanity. */
368 len = GET_32BIT(buf);
370 fatal("Add identity response too long: %d", len);
372 /* Read the rest of the response in tothe buffer. */
373 buffer_clear(&buffer);
379 l = read(auth->fd, buf, l);
382 error("Error reading response from authentication socket.");
385 buffer_append(&buffer, (char *)buf, l);
389 /* Get the type of the packet. */
390 type = buffer_get_char(&buffer);
393 case SSH_AGENT_FAILURE:
394 buffer_free(&buffer);
396 case SSH_AGENT_SUCCESS:
397 buffer_free(&buffer);
400 fatal("Bad response to add identity from authentication agent: %d",
407 /* Removes an identity from the authentication server. This call is not meant
408 to be used by normal applications. */
410 int ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
413 unsigned char buf[8192];
416 /* Format a message to the agent. */
417 buffer_init(&buffer);
418 buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
419 buffer_put_int(&buffer, BN_num_bits(key->n));
420 buffer_put_bignum(&buffer, key->e);
421 buffer_put_bignum(&buffer, key->n);
423 /* Get the length of the message, and format it in the buffer. */
424 len = buffer_len(&buffer);
427 /* Send the length and then the packet to the agent. */
428 if (write(auth->fd, buf, 4) != 4 ||
429 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
432 error("Error writing to authentication socket.");
434 buffer_free(&buffer);
438 /* Wait for response from the agent. First read the length of the
443 l = read(auth->fd, buf + 4 - len, len);
446 error("Error reading response length from authentication socket.");
452 /* Extract the length, and check it for sanity. */
453 len = GET_32BIT(buf);
455 fatal("Remove identity response too long: %d", len);
457 /* Read the rest of the response in tothe buffer. */
458 buffer_clear(&buffer);
464 l = read(auth->fd, buf, l);
467 error("Error reading response from authentication socket.");
470 buffer_append(&buffer, (char *)buf, l);
474 /* Get the type of the packet. */
475 type = buffer_get_char(&buffer);
478 case SSH_AGENT_FAILURE:
479 buffer_free(&buffer);
481 case SSH_AGENT_SUCCESS:
482 buffer_free(&buffer);
485 fatal("Bad response to remove identity from authentication agent: %d",
492 /* Removes all identities from the agent. This call is not meant
493 to be used by normal applications. */
495 int ssh_remove_all_identities(AuthenticationConnection *auth)
498 unsigned char buf[8192];
501 /* Get the length of the message, and format it in the buffer. */
503 buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
505 /* Send the length and then the packet to the agent. */
506 if (write(auth->fd, buf, 5) != 5)
508 error("Error writing to authentication socket.");
512 /* Wait for response from the agent. First read the length of the
517 l = read(auth->fd, buf + 4 - len, len);
520 error("Error reading response length from authentication socket.");
526 /* Extract the length, and check it for sanity. */
527 len = GET_32BIT(buf);
529 fatal("Remove identity response too long: %d", len);
531 /* Read the rest of the response into the buffer. */
532 buffer_init(&buffer);
538 l = read(auth->fd, buf, l);
541 error("Error reading response from authentication socket.");
542 buffer_free(&buffer);
545 buffer_append(&buffer, (char *)buf, l);
549 /* Get the type of the packet. */
550 type = buffer_get_char(&buffer);
553 case SSH_AGENT_FAILURE:
554 buffer_free(&buffer);
556 case SSH_AGENT_SUCCESS:
557 buffer_free(&buffer);
560 fatal("Bad response to remove identity from authentication agent: %d",