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 03:46:59 1995 ylo
12 The authentication agent program.
31 #include <openssl/md5.h>
40 enum { AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION } type;
45 unsigned int sockets_alloc = 0;
46 SocketEntry *sockets = NULL;
54 unsigned int num_identities = 0;
55 Identity *identities = NULL;
59 /* pid of shell == parent of agent */
62 /* pathname and directory for AUTH_SOCKET */
63 char socket_name[1024];
64 char socket_dir[1024];
67 process_request_identity(SocketEntry *e)
73 buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER);
74 buffer_put_int(&msg, num_identities);
75 for (i = 0; i < num_identities; i++)
77 buffer_put_int(&msg, BN_num_bits(identities[i].key->n));
78 buffer_put_bignum(&msg, identities[i].key->e);
79 buffer_put_bignum(&msg, identities[i].key->n);
80 buffer_put_string(&msg, identities[i].comment,
81 strlen(identities[i].comment));
83 buffer_put_int(&e->output, buffer_len(&msg));
84 buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
89 process_authentication_challenge(SocketEntry *e)
92 BIGNUM *pub_e, *pub_n, *challenge;
95 unsigned char buf[32], mdbuf[16], session_id[16];
96 unsigned int response_type;
101 challenge = BN_new();
102 pub_bits = buffer_get_int(&e->input);
103 buffer_get_bignum(&e->input, pub_e);
104 buffer_get_bignum(&e->input, pub_n);
105 buffer_get_bignum(&e->input, challenge);
106 if (buffer_len(&e->input) == 0)
108 /* Compatibility code for old servers. */
109 memset(session_id, 0, 16);
115 buffer_get(&e->input, (char *)session_id, 16);
116 response_type = buffer_get_int(&e->input);
118 for (i = 0; i < num_identities; i++)
119 if (pub_bits == BN_num_bits(identities[i].key->n) &&
120 BN_cmp(pub_e, identities[i].key->e) == 0 &&
121 BN_cmp(pub_n, identities[i].key->n) == 0)
123 /* Decrypt the challenge using the private key. */
124 rsa_private_decrypt(challenge, challenge, identities[i].key);
126 /* Compute the desired response. */
127 switch (response_type)
129 case 0: /* As of protocol 1.0 */
130 /* This response type is no longer supported. */
131 log("Compatibility with ssh protocol 1.0 no longer supported.");
132 buffer_put_char(&msg, SSH_AGENT_FAILURE);
135 case 1: /* As of protocol 1.1 */
136 /* The response is MD5 of decrypted challenge plus session id. */
137 len = BN_num_bytes(challenge);
138 assert(len <= 32 && len);
140 BN_bn2bin(challenge, buf + 32 - len);
142 MD5_Update(&md, buf, 32);
143 MD5_Update(&md, session_id, 16);
144 MD5_Final(mdbuf, &md);
148 fatal("process_authentication_challenge: bad response_type %d",
153 /* Send the response. */
154 buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
155 for (i = 0; i < 16; i++)
156 buffer_put_char(&msg, mdbuf[i]);
160 /* Unknown identity. Send failure. */
161 buffer_put_char(&msg, SSH_AGENT_FAILURE);
163 buffer_put_int(&e->output, buffer_len(&msg));
164 buffer_append(&e->output, buffer_ptr(&msg),
167 BN_clear_free(pub_e);
168 BN_clear_free(pub_n);
169 BN_clear_free(challenge);
173 process_remove_identity(SocketEntry *e)
182 /* Get the key from the packet. */
183 bits = buffer_get_int(&e->input);
184 buffer_get_bignum(&e->input, dummy);
185 buffer_get_bignum(&e->input, n);
187 /* Check if we have the key. */
188 for (i = 0; i < num_identities; i++)
189 if (BN_cmp(identities[i].key->n, n) == 0)
191 /* We have this key. Free the old key. Since we don\'t want to leave
192 empty slots in the middle of the array, we actually free the
193 key there and copy data from the last entry. */
194 RSA_free(identities[i].key);
195 xfree(identities[i].comment);
196 if (i < num_identities - 1)
197 identities[i] = identities[num_identities - 1];
199 BN_clear_free(dummy);
203 buffer_put_int(&e->output, 1);
204 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
207 /* We did not have the key. */
212 buffer_put_int(&e->output, 1);
213 buffer_put_char(&e->output, SSH_AGENT_FAILURE);
216 /* Removes all identities from the agent. */
219 process_remove_all_identities(SocketEntry *e)
223 /* Loop over all identities and clear the keys. */
224 for (i = 0; i < num_identities; i++)
226 RSA_free(identities[i].key);
227 xfree(identities[i].comment);
230 /* Mark that there are no identities. */
234 buffer_put_int(&e->output, 1);
235 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
239 /* Adds an identity to the agent. */
242 process_add_identity(SocketEntry *e)
249 if (num_identities == 0)
250 identities = xmalloc(sizeof(Identity));
252 identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity));
254 identities[num_identities].key = RSA_new();
255 k = identities[num_identities].key;
256 buffer_get_int(&e->input); /* bits */
258 buffer_get_bignum(&e->input, k->n);
260 buffer_get_bignum(&e->input, k->e);
262 buffer_get_bignum(&e->input, k->d);
264 buffer_get_bignum(&e->input, k->iqmp);
265 /* SSH and SSL have p and q swapped */
267 buffer_get_bignum(&e->input, k->q); /* p */
269 buffer_get_bignum(&e->input, k->p); /* q */
271 /* Generate additional parameters */
275 BN_sub(aux, k->q, BN_value_one());
277 BN_mod(k->dmq1, k->d, aux, ctx);
279 BN_sub(aux, k->p, BN_value_one());
281 BN_mod(k->dmp1, k->d, aux, ctx);
286 identities[num_identities].comment = buffer_get_string(&e->input, NULL);
288 /* Check if we already have the key. */
289 for (i = 0; i < num_identities; i++)
290 if (BN_cmp(identities[i].key->n, k->n) == 0)
292 /* We already have this key. Clear and free the new data and
295 xfree(identities[num_identities].comment);
298 buffer_put_int(&e->output, 1);
299 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
303 /* Increment the number of identities. */
306 /* Send a success message. */
307 buffer_put_int(&e->output, 1);
308 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
312 process_message(SocketEntry *e)
314 unsigned int msg_len;
317 if (buffer_len(&e->input) < 5)
318 return; /* Incomplete message. */
319 cp = (unsigned char *)buffer_ptr(&e->input);
320 msg_len = GET_32BIT(cp);
321 if (msg_len > 256 * 1024)
323 shutdown(e->fd, SHUT_RDWR);
325 e->type = AUTH_UNUSED;
328 if (buffer_len(&e->input) < msg_len + 4)
330 buffer_consume(&e->input, 4);
331 type = buffer_get_char(&e->input);
335 case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
336 process_request_identity(e);
338 case SSH_AGENTC_RSA_CHALLENGE:
339 process_authentication_challenge(e);
341 case SSH_AGENTC_ADD_RSA_IDENTITY:
342 process_add_identity(e);
344 case SSH_AGENTC_REMOVE_RSA_IDENTITY:
345 process_remove_identity(e);
347 case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
348 process_remove_all_identities(e);
351 /* Unknown message. Respond with failure. */
352 error("Unknown message %d", type);
353 buffer_clear(&e->input);
354 buffer_put_int(&e->output, 1);
355 buffer_put_char(&e->output, SSH_AGENT_FAILURE);
361 new_socket(int type, int fd)
363 unsigned int i, old_alloc;
364 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
365 error("fcntl O_NONBLOCK: %s", strerror(errno));
370 for (i = 0; i < sockets_alloc; i++)
371 if (sockets[i].type == AUTH_UNUSED)
374 sockets[i].type = type;
375 buffer_init(&sockets[i].input);
376 buffer_init(&sockets[i].output);
379 old_alloc = sockets_alloc;
382 sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
384 sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
385 for (i = old_alloc; i < sockets_alloc; i++)
386 sockets[i].type = AUTH_UNUSED;
387 sockets[old_alloc].type = type;
388 sockets[old_alloc].fd = fd;
389 buffer_init(&sockets[old_alloc].input);
390 buffer_init(&sockets[old_alloc].output);
394 prepare_select(fd_set *readset, fd_set *writeset)
397 for (i = 0; i < sockets_alloc; i++)
398 switch (sockets[i].type)
401 case AUTH_CONNECTION:
402 FD_SET(sockets[i].fd, readset);
403 if (buffer_len(&sockets[i].output) > 0)
404 FD_SET(sockets[i].fd, writeset);
409 fatal("Unknown socket type %d", sockets[i].type);
414 void after_select(fd_set *readset, fd_set *writeset)
419 struct sockaddr_un sunaddr;
421 for (i = 0; i < sockets_alloc; i++)
422 switch (sockets[i].type)
427 if (FD_ISSET(sockets[i].fd, readset))
429 len = sizeof(sunaddr);
430 sock = accept(sockets[i].fd, (struct sockaddr *)&sunaddr, &len);
433 perror("accept from AUTH_SOCKET");
436 new_socket(AUTH_CONNECTION, sock);
439 case AUTH_CONNECTION:
440 if (buffer_len(&sockets[i].output) > 0 &&
441 FD_ISSET(sockets[i].fd, writeset))
443 len = write(sockets[i].fd, buffer_ptr(&sockets[i].output),
444 buffer_len(&sockets[i].output));
447 shutdown(sockets[i].fd, SHUT_RDWR);
448 close(sockets[i].fd);
449 sockets[i].type = AUTH_UNUSED;
452 buffer_consume(&sockets[i].output, len);
454 if (FD_ISSET(sockets[i].fd, readset))
456 len = read(sockets[i].fd, buf, sizeof(buf));
459 shutdown(sockets[i].fd, SHUT_RDWR);
460 close(sockets[i].fd);
461 sockets[i].type = AUTH_UNUSED;
464 buffer_append(&sockets[i].input, buf, len);
465 process_message(&sockets[i]);
469 fatal("Unknown type %d", sockets[i].type);
474 check_parent_exists(int sig)
476 if (kill(parent_pid, 0) < 0)
478 /* printf("Parent has died - Authentication agent exiting.\n"); */
481 signal(SIGALRM, check_parent_exists);
485 void cleanup_socket(void) {
491 main(int ac, char **av)
493 fd_set readset, writeset;
495 struct sockaddr_un sunaddr;
497 /* check if RSA support exists */
498 if (rsa_alive() == 0) {
499 extern char *__progname;
501 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
508 fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
509 fprintf(stderr, "Usage: %s command\n", av[0]);
513 parent_pid = getpid();
515 /* Create private directory for agent socket */
516 strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
517 if (mkdtemp(socket_dir) == NULL) {
518 perror("mkdtemp: private socket dir");
521 snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir, parent_pid);
523 /* Fork, and have the parent execute the command. The child continues as
524 the authentication agent. */
526 { /* Parent - execute the given command. */
527 setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1);
528 execvp(av[1], av + 1);
533 if (atexit(cleanup_socket) < 0) {
539 /* Create a new session and process group */
541 perror("setsid failed");
545 /* Ignore if a client dies while we are sending a reply */
546 signal(SIGPIPE, SIG_IGN);
548 sock = socket(AF_UNIX, SOCK_STREAM, 0);
554 memset(&sunaddr, 0, sizeof(sunaddr));
555 sunaddr.sun_family = AF_UNIX;
556 strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
557 if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
562 if (listen(sock, 5) < 0)
567 new_socket(AUTH_SOCKET, sock);
568 signal(SIGALRM, check_parent_exists);
571 signal(SIGINT, SIG_IGN);
576 prepare_select(&readset, &writeset);
577 if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0)
584 after_select(&readset, &writeset);