1 /* 2 3 authfd.c 4 5 Author: Tatu Ylonen <ylo@cs.hut.fi> 6 7 Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 8 All rights reserved 9 10 Created: Wed Mar 29 01:30:28 1995 ylo 11 12 Functions for connecting the local authentication agent. 13 14 */ 15 16 #include "includes.h" 17 RCSID("$Id: authfd.c,v 1.2 1999/09/28 04:45:35 provos Exp $"); 18 19 #include "ssh.h" 20 #include "rsa.h" 21 #include "authfd.h" 22 #include "buffer.h" 23 #include "bufaux.h" 24 #include "xmalloc.h" 25 #include "getput.h" 26 27 #include <ssl/rsa.h> 28 29 /* Returns the number of the authentication fd, or -1 if there is none. */ 30 31 int 32 ssh_get_authentication_fd() 33 { 34 const char *authfd, *authsocket; 35 int sock; 36 struct sockaddr_un sunaddr; 37 38 /* Get the file descriptor number from environment. */ 39 authfd = getenv(SSH_AUTHFD_ENV_NAME); 40 41 /* Convert the value to an integer and return it if we got a value. */ 42 if (authfd) 43 return atoi(authfd); 44 45 authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); 46 if (!authsocket) 47 return -1; 48 49 sunaddr.sun_family = AF_UNIX; 50 strncpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); 51 52 sock = socket(AF_UNIX, SOCK_STREAM, 0); 53 if (sock < 0) 54 return -1; 55 56 if (connect(sock, (struct sockaddr *)&sunaddr, AF_UNIX_SIZE(sunaddr)) < 0) 57 { 58 close(sock); 59 return -1; 60 } 61 62 return sock; 63 } 64 65 /* Closes the agent socket if it should be closed (depends on how it was 66 obtained). The argument must have been returned by 67 ssh_get_authentication_fd(). */ 68 69 void ssh_close_authentication_socket(int sock) 70 { 71 if (getenv(SSH_AUTHSOCKET_ENV_NAME)) 72 close(sock); 73 } 74 75 /* Dummy alarm used to prevent waiting for connection from the 76 authentication agent indefinitely. */ 77 78 static RETSIGTYPE dummy_alarm_handler(int sig) 79 { 80 /* Do nothing; a cought signal will just cause accept to return. */ 81 } 82 83 /* Opens a socket to the authentication server. Returns the number of 84 that socket, or -1 if no connection could be made. */ 85 86 int ssh_get_authentication_connection_fd() 87 { 88 int authfd; 89 int listen_sock, sock, port, addrlen; 90 int old_timeout; 91 RETSIGTYPE (*old_handler)(); 92 struct sockaddr_in sin; 93 char msg[3]; 94 95 /* Get the the socket number from the environment. This is the socket 96 used to obtain the real authentication socket. */ 97 authfd = ssh_get_authentication_fd(); 98 if (authfd == -1) 99 return -1; 100 101 /* Create a local socket for listening. */ 102 listen_sock = socket(AF_INET, SOCK_STREAM, 0); 103 if (listen_sock == -1) 104 { 105 ssh_close_authentication_socket(authfd); 106 return -1; 107 } 108 109 /* Bind the socket to random unprivileged port. */ 110 memset(&sin, 0, sizeof(sin)); 111 sin.sin_family = AF_INET; 112 do 113 { 114 port = 32768 + (rand() % 30000); 115 sin.sin_port = htons(port); 116 } 117 while (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0 && 118 errno == EADDRINUSE); 119 120 /* Start listening for connections on the socket. */ 121 if (listen(listen_sock, 1) < 0) 122 { 123 error("listen: %.100s", strerror(errno)); 124 close(listen_sock); 125 ssh_close_authentication_socket(authfd); 126 return -1; 127 } 128 129 /* Send a message to the authentication fd requesting the agent or its 130 local representative to connect to the given socket. Note that 131 we use send() to get the packet sent atomically (there can be several 132 clients trying to use the same authentication fd simultaneously). */ 133 msg[0] = (char)SSH_AUTHFD_CONNECT; 134 PUT_16BIT(msg + 1, port); 135 if (send(authfd, msg, 3, 0) < 0) 136 { 137 shutdown(listen_sock, 2); 138 close(listen_sock); 139 ssh_close_authentication_socket(authfd); 140 return -1; 141 } 142 143 /* Setup a timeout so we won't wait for the connection indefinitely. */ 144 old_timeout = alarm(120); 145 old_handler = signal(SIGALRM, dummy_alarm_handler); 146 147 /* Wait for the connection from the agent or its representative. */ 148 addrlen = sizeof(sin); 149 sock = accept(listen_sock, (struct sockaddr *)&sin, &addrlen); 150 151 /* Remove the alarm (restore its old values). */ 152 alarm(old_timeout); 153 signal(SIGALRM, old_handler); 154 155 /* Close the socket we used for listening. It is no longer needed. 156 (The authentication fd and the new connection still remain open.) */ 157 shutdown(listen_sock, 2); 158 close(listen_sock); 159 ssh_close_authentication_socket(authfd); 160 161 return sock; 162 } 163 164 /* Opens and connects a private socket for communication with the 165 authentication agent. Returns the file descriptor (which must be 166 shut down and closed by the caller when no longer needed). 167 Returns NULL if an error occurred and the connection could not be 168 opened. */ 169 170 AuthenticationConnection *ssh_get_authentication_connection() 171 { 172 AuthenticationConnection *auth; 173 int sock; 174 175 /* Get a connection to the authentication agent. */ 176 sock = ssh_get_authentication_connection_fd(); 177 178 /* Fail if we couldn't obtain a connection. This happens if we exited 179 due to a timeout. */ 180 if (sock < 0) 181 return NULL; 182 183 /* Applocate the connection structure and initialize it. */ 184 auth = xmalloc(sizeof(*auth)); 185 auth->fd = sock; 186 buffer_init(&auth->packet); 187 buffer_init(&auth->identities); 188 auth->howmany = 0; 189 190 return auth; 191 } 192 193 /* Closes the connection to the authentication agent and frees any associated 194 memory. */ 195 196 void ssh_close_authentication_connection(AuthenticationConnection *ac) 197 { 198 buffer_free(&ac->packet); 199 buffer_free(&ac->identities); 200 close(ac->fd); 201 } 202 203 /* Returns the first authentication identity held by the agent. 204 Returns true if an identity is available, 0 otherwise. 205 The caller must initialize the integers before the call, and free the 206 comment after a successful call (before calling ssh_get_next_identity). */ 207 208 int 209 ssh_get_first_identity(AuthenticationConnection *auth, 210 int *bitsp, BIGNUM *e, BIGNUM *n, char **comment) 211 { 212 unsigned char msg[8192]; 213 int len, l; 214 215 /* Send a message to the agent requesting for a list of the identities 216 it can represent. */ 217 msg[0] = 0; 218 msg[1] = 0; 219 msg[2] = 0; 220 msg[3] = 1; 221 msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES; 222 if (write(auth->fd, msg, 5) != 5) 223 { 224 error("write auth->fd: %.100s", strerror(errno)); 225 return 0; 226 } 227 228 /* Read the length of the response. XXX implement timeouts here. */ 229 len = 4; 230 while (len > 0) 231 { 232 l = read(auth->fd, msg + 4 - len, len); 233 if (l <= 0) 234 { 235 error("read auth->fd: %.100s", strerror(errno)); 236 return 0; 237 } 238 len -= l; 239 } 240 241 /* Extract the length, and check it for sanity. (We cannot trust 242 authentication agents). */ 243 len = GET_32BIT(msg); 244 if (len < 1 || len > 256*1024) 245 fatal("Authentication reply message too long: %d\n", len); 246 247 /* Read the packet itself. */ 248 buffer_clear(&auth->identities); 249 while (len > 0) 250 { 251 l = len; 252 if (l > sizeof(msg)) 253 l = sizeof(msg); 254 l = read(auth->fd, msg, l); 255 if (l <= 0) 256 fatal("Incomplete authentication reply."); 257 buffer_append(&auth->identities, (char *)msg, l); 258 len -= l; 259 } 260 261 /* Get message type, and verify that we got a proper answer. */ 262 buffer_get(&auth->identities, (char *)msg, 1); 263 if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER) 264 fatal("Bad authentication reply message type: %d", msg[0]); 265 266 /* Get the number of entries in the response and check it for sanity. */ 267 auth->howmany = buffer_get_int(&auth->identities); 268 if (auth->howmany > 1024) 269 fatal("Too many identities in authentication reply: %d\n", auth->howmany); 270 271 /* Return the first entry (if any). */ 272 return ssh_get_next_identity(auth, bitsp, e, n, comment); 273 } 274 275 /* Returns the next authentication identity for the agent. Other functions 276 can be called between this and ssh_get_first_identity or two calls of this 277 function. This returns 0 if there are no more identities. The caller 278 must free comment after a successful return. */ 279 280 int 281 ssh_get_next_identity(AuthenticationConnection *auth, 282 int *bitsp, BIGNUM *e, BIGNUM *n, char **comment) 283 { 284 /* Return failure if no more entries. */ 285 if (auth->howmany <= 0) 286 return 0; 287 288 /* Get the next entry from the packet. These will abort with a fatal 289 error if the packet is too short or contains corrupt data. */ 290 *bitsp = buffer_get_int(&auth->identities); 291 buffer_get_bignum(&auth->identities, e); 292 buffer_get_bignum(&auth->identities, n); 293 *comment = buffer_get_string(&auth->identities, NULL); 294 295 /* Decrement the number of remaining entries. */ 296 auth->howmany--; 297 298 return 1; 299 } 300 301 /* Generates a random challenge, sends it to the agent, and waits for response 302 from the agent. Returns true (non-zero) if the agent gave the correct 303 answer, zero otherwise. Response type selects the style of response 304 desired, with 0 corresponding to protocol version 1.0 (no longer supported) 305 and 1 corresponding to protocol version 1.1. */ 306 307 int 308 ssh_decrypt_challenge(AuthenticationConnection *auth, 309 int bits, BIGNUM *e, BIGNUM *n, BIGNUM *challenge, 310 unsigned char session_id[16], 311 unsigned int response_type, 312 unsigned char response[16]) 313 { 314 Buffer buffer; 315 unsigned char buf[8192]; 316 int len, l, i; 317 318 /* Response type 0 is no longer supported. */ 319 if (response_type == 0) 320 fatal("Compatibility with ssh protocol version 1.0 no longer supported."); 321 322 /* Format a message to the agent. */ 323 buf[0] = SSH_AGENTC_RSA_CHALLENGE; 324 buffer_init(&buffer); 325 buffer_append(&buffer, (char *)buf, 1); 326 buffer_put_int(&buffer, bits); 327 buffer_put_bignum(&buffer, e); 328 buffer_put_bignum(&buffer, n); 329 buffer_put_bignum(&buffer, challenge); 330 buffer_append(&buffer, (char *)session_id, 16); 331 buffer_put_int(&buffer, response_type); 332 333 /* Get the length of the message, and format it in the buffer. */ 334 len = buffer_len(&buffer); 335 PUT_32BIT(buf, len); 336 337 /* Send the length and then the packet to the agent. */ 338 if (write(auth->fd, buf, 4) != 4 || 339 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) != 340 buffer_len(&buffer)) 341 { 342 error("Error writing to authentication socket."); 343 error_cleanup: 344 buffer_free(&buffer); 345 return 0; 346 } 347 348 /* Wait for response from the agent. First read the length of the 349 response packet. */ 350 len = 4; 351 while (len > 0) 352 { 353 l = read(auth->fd, buf + 4 - len, len); 354 if (l <= 0) 355 { 356 error("Error reading response length from authentication socket."); 357 goto error_cleanup; 358 } 359 len -= l; 360 } 361 362 /* Extract the length, and check it for sanity. */ 363 len = GET_32BIT(buf); 364 if (len > 256*1024) 365 fatal("Authentication response too long: %d", len); 366 367 /* Read the rest of the response in tothe buffer. */ 368 buffer_clear(&buffer); 369 while (len > 0) 370 { 371 l = len; 372 if (l > sizeof(buf)) 373 l = sizeof(buf); 374 l = read(auth->fd, buf, l); 375 if (l <= 0) 376 { 377 error("Error reading response from authentication socket."); 378 goto error_cleanup; 379 } 380 buffer_append(&buffer, (char *)buf, l); 381 len -= l; 382 } 383 384 /* Get the type of the packet. */ 385 buffer_get(&buffer, (char *)buf, 1); 386 387 /* Check for agent failure message. */ 388 if (buf[0] == SSH_AGENT_FAILURE) 389 { 390 log("Agent admitted failure to authenticate using the key."); 391 goto error_cleanup; 392 } 393 394 /* Now it must be an authentication response packet. */ 395 if (buf[0] != SSH_AGENT_RSA_RESPONSE) 396 fatal("Bad authentication response: %d", buf[0]); 397 398 /* Get the response from the packet. This will abort with a fatal error 399 if the packet is corrupt. */ 400 for (i = 0; i < 16; i++) 401 response[i] = buffer_get_char(&buffer); 402 403 /* The buffer containing the packet is no longer needed. */ 404 buffer_free(&buffer); 405 406 /* Correct answer. */ 407 return 1; 408 } 409 410 /* Adds an identity to the authentication server. This call is not meant to 411 be used by normal applications. */ 412 413 int ssh_add_identity(AuthenticationConnection *auth, 414 RSA *key, const char *comment) 415 { 416 Buffer buffer; 417 unsigned char buf[8192]; 418 int len, l, type; 419 420 /* Format a message to the agent. */ 421 buffer_init(&buffer); 422 buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY); 423 buffer_put_int(&buffer, BN_num_bits(key->n)); 424 buffer_put_bignum(&buffer, key->n); 425 buffer_put_bignum(&buffer, key->e); 426 buffer_put_bignum(&buffer, key->d); 427 /* To keep within the protocol: p < q for ssh. in SSL p > q */ 428 buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */ 429 buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */ 430 buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */ 431 buffer_put_string(&buffer, comment, strlen(comment)); 432 433 /* Get the length of the message, and format it in the buffer. */ 434 len = buffer_len(&buffer); 435 PUT_32BIT(buf, len); 436 437 /* Send the length and then the packet to the agent. */ 438 if (write(auth->fd, buf, 4) != 4 || 439 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) != 440 buffer_len(&buffer)) 441 { 442 error("Error writing to authentication socket."); 443 error_cleanup: 444 buffer_free(&buffer); 445 return 0; 446 } 447 448 /* Wait for response from the agent. First read the length of the 449 response packet. */ 450 len = 4; 451 while (len > 0) 452 { 453 l = read(auth->fd, buf + 4 - len, len); 454 if (l <= 0) 455 { 456 error("Error reading response length from authentication socket."); 457 goto error_cleanup; 458 } 459 len -= l; 460 } 461 462 /* Extract the length, and check it for sanity. */ 463 len = GET_32BIT(buf); 464 if (len > 256*1024) 465 fatal("Add identity response too long: %d", len); 466 467 /* Read the rest of the response in tothe buffer. */ 468 buffer_clear(&buffer); 469 while (len > 0) 470 { 471 l = len; 472 if (l > sizeof(buf)) 473 l = sizeof(buf); 474 l = read(auth->fd, buf, l); 475 if (l <= 0) 476 { 477 error("Error reading response from authentication socket."); 478 goto error_cleanup; 479 } 480 buffer_append(&buffer, (char *)buf, l); 481 len -= l; 482 } 483 484 /* Get the type of the packet. */ 485 type = buffer_get_char(&buffer); 486 switch (type) 487 { 488 case SSH_AGENT_FAILURE: 489 buffer_free(&buffer); 490 return 0; 491 case SSH_AGENT_SUCCESS: 492 buffer_free(&buffer); 493 return 1; 494 default: 495 fatal("Bad response to add identity from authentication agent: %d", 496 type); 497 } 498 /*NOTREACHED*/ 499 return 0; 500 } 501 502 /* Removes an identity from the authentication server. This call is not meant 503 to be used by normal applications. */ 504 505 int ssh_remove_identity(AuthenticationConnection *auth, RSA *key) 506 { 507 Buffer buffer; 508 unsigned char buf[8192]; 509 int len, l, type; 510 511 /* Format a message to the agent. */ 512 buffer_init(&buffer); 513 buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY); 514 buffer_put_int(&buffer, BN_num_bits(key->n)); 515 buffer_put_bignum(&buffer, key->e); 516 buffer_put_bignum(&buffer, key->n); 517 518 /* Get the length of the message, and format it in the buffer. */ 519 len = buffer_len(&buffer); 520 PUT_32BIT(buf, len); 521 522 /* Send the length and then the packet to the agent. */ 523 if (write(auth->fd, buf, 4) != 4 || 524 write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) != 525 buffer_len(&buffer)) 526 { 527 error("Error writing to authentication socket."); 528 error_cleanup: 529 buffer_free(&buffer); 530 return 0; 531 } 532 533 /* Wait for response from the agent. First read the length of the 534 response packet. */ 535 len = 4; 536 while (len > 0) 537 { 538 l = read(auth->fd, buf + 4 - len, len); 539 if (l <= 0) 540 { 541 error("Error reading response length from authentication socket."); 542 goto error_cleanup; 543 } 544 len -= l; 545 } 546 547 /* Extract the length, and check it for sanity. */ 548 len = GET_32BIT(buf); 549 if (len > 256*1024) 550 fatal("Remove identity response too long: %d", len); 551 552 /* Read the rest of the response in tothe buffer. */ 553 buffer_clear(&buffer); 554 while (len > 0) 555 { 556 l = len; 557 if (l > sizeof(buf)) 558 l = sizeof(buf); 559 l = read(auth->fd, buf, l); 560 if (l <= 0) 561 { 562 error("Error reading response from authentication socket."); 563 goto error_cleanup; 564 } 565 buffer_append(&buffer, (char *)buf, l); 566 len -= l; 567 } 568 569 /* Get the type of the packet. */ 570 type = buffer_get_char(&buffer); 571 switch (type) 572 { 573 case SSH_AGENT_FAILURE: 574 buffer_free(&buffer); 575 return 0; 576 case SSH_AGENT_SUCCESS: 577 buffer_free(&buffer); 578 return 1; 579 default: 580 fatal("Bad response to remove identity from authentication agent: %d", 581 type); 582 } 583 /*NOTREACHED*/ 584 return 0; 585 } 586 587 /* Removes all identities from the agent. This call is not meant 588 to be used by normal applications. */ 589 590 int ssh_remove_all_identities(AuthenticationConnection *auth) 591 { 592 Buffer buffer; 593 unsigned char buf[8192]; 594 int len, l, type; 595 596 /* Get the length of the message, and format it in the buffer. */ 597 PUT_32BIT(buf, 1); 598 buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES; 599 600 /* Send the length and then the packet to the agent. */ 601 if (write(auth->fd, buf, 5) != 5) 602 { 603 error("Error writing to authentication socket."); 604 return 0; 605 } 606 607 /* Wait for response from the agent. First read the length of the 608 response packet. */ 609 len = 4; 610 while (len > 0) 611 { 612 l = read(auth->fd, buf + 4 - len, len); 613 if (l <= 0) 614 { 615 error("Error reading response length from authentication socket."); 616 return 0; 617 } 618 len -= l; 619 } 620 621 /* Extract the length, and check it for sanity. */ 622 len = GET_32BIT(buf); 623 if (len > 256*1024) 624 fatal("Remove identity response too long: %d", len); 625 626 /* Read the rest of the response into the buffer. */ 627 buffer_init(&buffer); 628 while (len > 0) 629 { 630 l = len; 631 if (l > sizeof(buf)) 632 l = sizeof(buf); 633 l = read(auth->fd, buf, l); 634 if (l <= 0) 635 { 636 error("Error reading response from authentication socket."); 637 buffer_free(&buffer); 638 return 0; 639 } 640 buffer_append(&buffer, (char *)buf, l); 641 len -= l; 642 } 643 644 /* Get the type of the packet. */ 645 type = buffer_get_char(&buffer); 646 switch (type) 647 { 648 case SSH_AGENT_FAILURE: 649 buffer_free(&buffer); 650 return 0; 651 case SSH_AGENT_SUCCESS: 652 buffer_free(&buffer); 653 return 1; 654 default: 655 fatal("Bad response to remove identity from authentication agent: %d", 656 type); 657 } 658 /*NOTREACHED*/ 659 return 0; 660 } 661 662 /* Closes the connection to the authentication agent. */ 663 664 void ssh_close_authentication(AuthenticationConnection *auth) 665 { 666 /* Close the connection. */ 667 shutdown(auth->fd, 2); 668 close(auth->fd); 669 670 /* Free the buffers. */ 671 buffer_free(&auth->packet); 672 buffer_free(&auth->identities); 673 674 /* Free the connection data structure. */ 675 xfree(auth); 676 } 677