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);
54 if (connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
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(). */
67 void ssh_close_authentication_socket(int sock)
69 if (getenv(SSH_AUTHSOCKET_ENV_NAME))
73 /* Opens and connects a private socket for communication with the
74 authentication agent. Returns the file descriptor (which must be
75 shut down and closed by the caller when no longer needed).
76 Returns NULL if an error occurred and the connection could not be
79 AuthenticationConnection *ssh_get_authentication_connection()
81 AuthenticationConnection *auth;
84 sock = ssh_get_authentication_socket();
86 /* Fail if we couldn't obtain a connection. This happens if we exited
91 /* Applocate the connection structure and initialize it. */
92 auth = xmalloc(sizeof(*auth));
94 buffer_init(&auth->packet);
95 buffer_init(&auth->identities);
101 /* Closes the connection to the authentication agent and frees any associated
104 void ssh_close_authentication_connection(AuthenticationConnection *ac)
106 buffer_free(&ac->packet);
107 buffer_free(&ac->identities);
109 /* Free the connection data structure. */
113 /* Returns the first authentication identity held by the agent.
114 Returns true if an identity is available, 0 otherwise.
115 The caller must initialize the integers before the call, and free the
116 comment after a successful call (before calling ssh_get_next_identity). */
119 ssh_get_first_identity(AuthenticationConnection *auth,
120 BIGNUM *e, BIGNUM *n, char **comment)
122 unsigned char msg[8192];
125 /* Send a message to the agent requesting for a list of the identities
131 msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
132 if (write(auth->fd, msg, 5) != 5)
134 error("write auth->fd: %.100s", strerror(errno));
138 /* Read the length of the response. XXX implement timeouts here. */
142 l = read(auth->fd, msg + 4 - len, len);
145 error("read auth->fd: %.100s", strerror(errno));
151 /* Extract the length, and check it for sanity. (We cannot trust
152 authentication agents). */
153 len = GET_32BIT(msg);
154 if (len < 1 || len > 256*1024)
155 fatal("Authentication reply message too long: %d\n", len);
157 /* Read the packet itself. */
158 buffer_clear(&auth->identities);
164 l = read(auth->fd, msg, l);
166 fatal("Incomplete authentication reply.");
167 buffer_append(&auth->identities, (char *)msg, l);
171 /* Get message type, and verify that we got a proper answer. */
172 buffer_get(&auth->identities, (char *)msg, 1);
173 if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
174 fatal("Bad authentication reply message type: %d", msg[0]);
176 /* Get the number of entries in the response and check it for sanity. */
177 auth->howmany = buffer_get_int(&auth->identities);
178 if (auth->howmany > 1024)
179 fatal("Too many identities in authentication reply: %d\n", auth->howmany);
181 /* Return the first entry (if any). */
182 return ssh_get_next_identity(auth, e, n, comment);
185 /* Returns the next authentication identity for the agent. Other functions
186 can be called between this and ssh_get_first_identity or two calls of this
187 function. This returns 0 if there are no more identities. The caller
188 must free comment after a successful return. */
191 ssh_get_next_identity(AuthenticationConnection *auth,
192 BIGNUM *e, BIGNUM *n, char **comment)
196 /* Return failure if no more entries. */
197 if (auth->howmany <= 0)
200 /* Get the next entry from the packet. These will abort with a fatal
201 error if the packet is too short or contains corrupt data. */
202 bits = buffer_get_int(&auth->identities);
203 buffer_get_bignum(&auth->identities, e);
204 buffer_get_bignum(&auth->identities, n);
205 *comment = buffer_get_string(&auth->identities, NULL);
207 if (bits != BN_num_bits(n))
208 error("Warning: keysize mismatch: actual %d, announced %s",
209 BN_num_bits(n), bits);
211 /* Decrement the number of remaining entries. */
217 /* Generates a random challenge, sends it to the agent, and waits for response
218 from the agent. Returns true (non-zero) if the agent gave the correct
219 answer, zero otherwise. Response type selects the style of response
220 desired, with 0 corresponding to protocol version 1.0 (no longer supported)
221 and 1 corresponding to protocol version 1.1. */
224 ssh_decrypt_challenge(AuthenticationConnection *auth,
225 BIGNUM *e, BIGNUM *n, BIGNUM *challenge,
226 unsigned char session_id[16],
227 unsigned int response_type,
228 unsigned char response[16])
231 unsigned char buf[8192];
234 /* Response type 0 is no longer supported. */
235 if (response_type == 0)
236 fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
238 /* Format a message to the agent. */
239 buf[0] = SSH_AGENTC_RSA_CHALLENGE;
240 buffer_init(&buffer);
241 buffer_append(&buffer, (char *)buf, 1);
242 buffer_put_int(&buffer, BN_num_bits(n));
243 buffer_put_bignum(&buffer, e);
244 buffer_put_bignum(&buffer, n);
245 buffer_put_bignum(&buffer, challenge);
246 buffer_append(&buffer, (char *)session_id, 16);
247 buffer_put_int(&buffer, response_type);
249 /* Get the length of the message, and format it in the buffer. */
250 len = buffer_len(&buffer);
253 /* Send the length and then the packet to the agent. */
254 if (write(auth->fd, buf, 4) != 4 ||
255 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
258 error("Error writing to authentication socket.");
260 buffer_free(&buffer);
264 /* Wait for response from the agent. First read the length of the
269 l = read(auth->fd, buf + 4 - len, len);
272 error("Error reading response length from authentication socket.");
278 /* Extract the length, and check it for sanity. */
279 len = GET_32BIT(buf);
281 fatal("Authentication response too long: %d", len);
283 /* Read the rest of the response in tothe buffer. */
284 buffer_clear(&buffer);
290 l = read(auth->fd, buf, l);
293 error("Error reading response from authentication socket.");
296 buffer_append(&buffer, (char *)buf, l);
300 /* Get the type of the packet. */
301 buffer_get(&buffer, (char *)buf, 1);
303 /* Check for agent failure message. */
304 if (buf[0] == SSH_AGENT_FAILURE)
306 log("Agent admitted failure to authenticate using the key.");
310 /* Now it must be an authentication response packet. */
311 if (buf[0] != SSH_AGENT_RSA_RESPONSE)
312 fatal("Bad authentication response: %d", buf[0]);
314 /* Get the response from the packet. This will abort with a fatal error
315 if the packet is corrupt. */
316 for (i = 0; i < 16; i++)
317 response[i] = buffer_get_char(&buffer);
319 /* The buffer containing the packet is no longer needed. */
320 buffer_free(&buffer);
322 /* Correct answer. */
326 /* Adds an identity to the authentication server. This call is not meant to
327 be used by normal applications. */
329 int ssh_add_identity(AuthenticationConnection *auth,
330 RSA *key, const char *comment)
333 unsigned char buf[8192];
336 /* Format a message to the agent. */
337 buffer_init(&buffer);
338 buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
339 buffer_put_int(&buffer, BN_num_bits(key->n));
340 buffer_put_bignum(&buffer, key->n);
341 buffer_put_bignum(&buffer, key->e);
342 buffer_put_bignum(&buffer, key->d);
343 /* To keep within the protocol: p < q for ssh. in SSL p > q */
344 buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
345 buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
346 buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
347 buffer_put_string(&buffer, comment, strlen(comment));
349 /* Get the length of the message, and format it in the buffer. */
350 len = buffer_len(&buffer);
353 /* Send the length and then the packet to the agent. */
354 if (write(auth->fd, buf, 4) != 4 ||
355 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
358 error("Error writing to authentication socket.");
360 buffer_free(&buffer);
364 /* Wait for response from the agent. First read the length of the
369 l = read(auth->fd, buf + 4 - len, len);
372 error("Error reading response length from authentication socket.");
378 /* Extract the length, and check it for sanity. */
379 len = GET_32BIT(buf);
381 fatal("Add identity response too long: %d", len);
383 /* Read the rest of the response in tothe buffer. */
384 buffer_clear(&buffer);
390 l = read(auth->fd, buf, l);
393 error("Error reading response from authentication socket.");
396 buffer_append(&buffer, (char *)buf, l);
400 /* Get the type of the packet. */
401 type = buffer_get_char(&buffer);
404 case SSH_AGENT_FAILURE:
405 buffer_free(&buffer);
407 case SSH_AGENT_SUCCESS:
408 buffer_free(&buffer);
411 fatal("Bad response to add identity from authentication agent: %d",
418 /* Removes an identity from the authentication server. This call is not meant
419 to be used by normal applications. */
421 int ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
424 unsigned char buf[8192];
427 /* Format a message to the agent. */
428 buffer_init(&buffer);
429 buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
430 buffer_put_int(&buffer, BN_num_bits(key->n));
431 buffer_put_bignum(&buffer, key->e);
432 buffer_put_bignum(&buffer, key->n);
434 /* Get the length of the message, and format it in the buffer. */
435 len = buffer_len(&buffer);
438 /* Send the length and then the packet to the agent. */
439 if (write(auth->fd, buf, 4) != 4 ||
440 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
443 error("Error writing to authentication socket.");
445 buffer_free(&buffer);
449 /* Wait for response from the agent. First read the length of the
454 l = read(auth->fd, buf + 4 - len, len);
457 error("Error reading response length from authentication socket.");
463 /* Extract the length, and check it for sanity. */
464 len = GET_32BIT(buf);
466 fatal("Remove identity response too long: %d", len);
468 /* Read the rest of the response in tothe buffer. */
469 buffer_clear(&buffer);
475 l = read(auth->fd, buf, l);
478 error("Error reading response from authentication socket.");
481 buffer_append(&buffer, (char *)buf, l);
485 /* Get the type of the packet. */
486 type = buffer_get_char(&buffer);
489 case SSH_AGENT_FAILURE:
490 buffer_free(&buffer);
492 case SSH_AGENT_SUCCESS:
493 buffer_free(&buffer);
496 fatal("Bad response to remove identity from authentication agent: %d",
503 /* Removes all identities from the agent. This call is not meant
504 to be used by normal applications. */
506 int ssh_remove_all_identities(AuthenticationConnection *auth)
509 unsigned char buf[8192];
512 /* Get the length of the message, and format it in the buffer. */
514 buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
516 /* Send the length and then the packet to the agent. */
517 if (write(auth->fd, buf, 5) != 5)
519 error("Error writing to authentication socket.");
523 /* Wait for response from the agent. First read the length of the
528 l = read(auth->fd, buf + 4 - len, len);
531 error("Error reading response length from authentication socket.");
537 /* Extract the length, and check it for sanity. */
538 len = GET_32BIT(buf);
540 fatal("Remove identity response too long: %d", len);
542 /* Read the rest of the response into the buffer. */
543 buffer_init(&buffer);
549 l = read(auth->fd, buf, l);
552 error("Error reading response from authentication socket.");
553 buffer_free(&buffer);
556 buffer_append(&buffer, (char *)buf, l);
560 /* Get the type of the packet. */
561 type = buffer_get_char(&buffer);
564 case SSH_AGENT_FAILURE:
565 buffer_free(&buffer);
567 case SSH_AGENT_SUCCESS:
568 buffer_free(&buffer);
571 fatal("Bad response to remove identity from authentication agent: %d",