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 * $FreeBSD$ 15 */ 16 17 #include "includes.h" 18 RCSID("$Id: authfd.c,v 1.16 1999/12/15 19:43:10 markus Exp $"); 19 20 #include "ssh.h" 21 #include "rsa.h" 22 #include "authfd.h" 23 #include "buffer.h" 24 #include "bufaux.h" 25 #include "xmalloc.h" 26 #include "getput.h" 27 28 #include <openssl/rsa.h> 29 30 /* Returns the number of the authentication fd, or -1 if there is none. */ 31 32 int 33 ssh_get_authentication_socket() 34 { 35 const char *authsocket; 36 int sock; 37 struct sockaddr_un sunaddr; 38 39 authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); 40 if (!authsocket) 41 return -1; 42 43 sunaddr.sun_family = AF_UNIX; 44 strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); 45 46 sock = socket(AF_UNIX, SOCK_STREAM, 0); 47 if (sock < 0) 48 return -1; 49 50 /* close on exec */ 51 if (fcntl(sock, F_SETFD, 1) == -1) { 52 close(sock); 53 return -1; 54 } 55 if (connect(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) { 56 close(sock); 57 return -1; 58 } 59 return sock; 60 } 61 62 /* 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(). 66 */ 67 68 void 69 ssh_close_authentication_socket(int sock) 70 { 71 if (getenv(SSH_AUTHSOCKET_ENV_NAME)) 72 close(sock); 73 } 74 75 /* 76 * Opens and connects a private socket for communication with the 77 * authentication agent. Returns the file descriptor (which must be 78 * shut down and closed by the caller when no longer needed). 79 * Returns NULL if an error occurred and the connection could not be 80 * opened. 81 */ 82 83 AuthenticationConnection * 84 ssh_get_authentication_connection() 85 { 86 AuthenticationConnection *auth; 87 int sock; 88 89 sock = ssh_get_authentication_socket(); 90 91 /* 92 * Fail if we couldn't obtain a connection. This happens if we 93 * exited due to a timeout. 94 */ 95 if (sock < 0) 96 return NULL; 97 98 auth = xmalloc(sizeof(*auth)); 99 auth->fd = sock; 100 buffer_init(&auth->packet); 101 buffer_init(&auth->identities); 102 auth->howmany = 0; 103 104 return auth; 105 } 106 107 /* 108 * Closes the connection to the authentication agent and frees any associated 109 * memory. 110 */ 111 112 void 113 ssh_close_authentication_connection(AuthenticationConnection *ac) 114 { 115 buffer_free(&ac->packet); 116 buffer_free(&ac->identities); 117 close(ac->fd); 118 xfree(ac); 119 } 120 121 /* 122 * Returns the first authentication identity held by the agent. 123 * Returns true if an identity is available, 0 otherwise. 124 * The caller must initialize the integers before the call, and free the 125 * comment after a successful call (before calling ssh_get_next_identity). 126 */ 127 128 int 129 ssh_get_first_identity(AuthenticationConnection *auth, 130 BIGNUM *e, BIGNUM *n, char **comment) 131 { 132 unsigned char msg[8192]; 133 int len, l; 134 135 /* 136 * Send a message to the agent requesting for a list of the 137 * identities it can represent. 138 */ 139 msg[0] = 0; 140 msg[1] = 0; 141 msg[2] = 0; 142 msg[3] = 1; 143 msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES; 144 if (atomicio(write, auth->fd, msg, 5) != 5) { 145 error("write auth->fd: %.100s", strerror(errno)); 146 return 0; 147 } 148 /* Read the length of the response. XXX implement timeouts here. */ 149 len = 4; 150 while (len > 0) { 151 l = read(auth->fd, msg + 4 - len, len); 152 if (l <= 0) { 153 error("read auth->fd: %.100s", strerror(errno)); 154 return 0; 155 } 156 len -= l; 157 } 158 159 /* 160 * Extract the length, and check it for sanity. (We cannot trust 161 * authentication agents). 162 */ 163 len = GET_32BIT(msg); 164 if (len < 1 || len > 256 * 1024) 165 fatal("Authentication reply message too long: %d\n", len); 166 167 /* Read the packet itself. */ 168 buffer_clear(&auth->identities); 169 while (len > 0) { 170 l = len; 171 if (l > sizeof(msg)) 172 l = sizeof(msg); 173 l = read(auth->fd, msg, l); 174 if (l <= 0) 175 fatal("Incomplete authentication reply."); 176 buffer_append(&auth->identities, (char *) msg, l); 177 len -= l; 178 } 179 180 /* Get message type, and verify that we got a proper answer. */ 181 buffer_get(&auth->identities, (char *) msg, 1); 182 if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER) 183 fatal("Bad authentication reply message type: %d", msg[0]); 184 185 /* Get the number of entries in the response and check it for sanity. */ 186 auth->howmany = buffer_get_int(&auth->identities); 187 if (auth->howmany > 1024) 188 fatal("Too many identities in authentication reply: %d\n", auth->howmany); 189 190 /* Return the first entry (if any). */ 191 return ssh_get_next_identity(auth, e, n, comment); 192 } 193 194 /* 195 * Returns the next authentication identity for the agent. Other functions 196 * can be called between this and ssh_get_first_identity or two calls of this 197 * function. This returns 0 if there are no more identities. The caller 198 * must free comment after a successful return. 199 */ 200 201 int 202 ssh_get_next_identity(AuthenticationConnection *auth, 203 BIGNUM *e, BIGNUM *n, char **comment) 204 { 205 unsigned int bits; 206 207 /* Return failure if no more entries. */ 208 if (auth->howmany <= 0) 209 return 0; 210 211 /* 212 * Get the next entry from the packet. These will abort with a fatal 213 * error if the packet is too short or contains corrupt data. 214 */ 215 bits = buffer_get_int(&auth->identities); 216 buffer_get_bignum(&auth->identities, e); 217 buffer_get_bignum(&auth->identities, n); 218 *comment = buffer_get_string(&auth->identities, NULL); 219 220 if (bits != BN_num_bits(n)) 221 error("Warning: identity keysize mismatch: actual %d, announced %u", 222 BN_num_bits(n), bits); 223 224 /* Decrement the number of remaining entries. */ 225 auth->howmany--; 226 227 return 1; 228 } 229 230 /* 231 * Generates a random challenge, sends it to the agent, and waits for 232 * response from the agent. Returns true (non-zero) if the agent gave the 233 * correct answer, zero otherwise. Response type selects the style of 234 * response desired, with 0 corresponding to protocol version 1.0 (no longer 235 * supported) and 1 corresponding to protocol version 1.1. 236 */ 237 238 int 239 ssh_decrypt_challenge(AuthenticationConnection *auth, 240 BIGNUM* e, BIGNUM *n, BIGNUM *challenge, 241 unsigned char session_id[16], 242 unsigned int response_type, 243 unsigned char response[16]) 244 { 245 Buffer buffer; 246 unsigned char buf[8192]; 247 int len, l, i; 248 249 /* Response type 0 is no longer supported. */ 250 if (response_type == 0) 251 fatal("Compatibility with ssh protocol version 1.0 no longer supported."); 252 253 /* Format a message to the agent. */ 254 buf[0] = SSH_AGENTC_RSA_CHALLENGE; 255 buffer_init(&buffer); 256 buffer_append(&buffer, (char *) buf, 1); 257 buffer_put_int(&buffer, BN_num_bits(n)); 258 buffer_put_bignum(&buffer, e); 259 buffer_put_bignum(&buffer, n); 260 buffer_put_bignum(&buffer, challenge); 261 buffer_append(&buffer, (char *) session_id, 16); 262 buffer_put_int(&buffer, response_type); 263 264 /* Get the length of the message, and format it in the buffer. */ 265 len = buffer_len(&buffer); 266 PUT_32BIT(buf, len); 267 268 /* Send the length and then the packet to the agent. */ 269 if (atomicio(write, auth->fd, buf, 4) != 4 || 270 atomicio(write, auth->fd, buffer_ptr(&buffer), 271 buffer_len(&buffer)) != buffer_len(&buffer)) { 272 error("Error writing to authentication socket."); 273 error_cleanup: 274 buffer_free(&buffer); 275 return 0; 276 } 277 /* 278 * Wait for response from the agent. First read the length of the 279 * response packet. 280 */ 281 len = 4; 282 while (len > 0) { 283 l = read(auth->fd, buf + 4 - len, len); 284 if (l <= 0) { 285 error("Error reading response length from authentication socket."); 286 goto error_cleanup; 287 } 288 len -= l; 289 } 290 291 /* Extract the length, and check it for sanity. */ 292 len = GET_32BIT(buf); 293 if (len > 256 * 1024) 294 fatal("Authentication response too long: %d", len); 295 296 /* Read the rest of the response in tothe buffer. */ 297 buffer_clear(&buffer); 298 while (len > 0) { 299 l = len; 300 if (l > sizeof(buf)) 301 l = sizeof(buf); 302 l = read(auth->fd, buf, l); 303 if (l <= 0) { 304 error("Error reading response from authentication socket."); 305 goto error_cleanup; 306 } 307 buffer_append(&buffer, (char *) buf, l); 308 len -= l; 309 } 310 311 /* Get the type of the packet. */ 312 buffer_get(&buffer, (char *) buf, 1); 313 314 /* Check for agent failure message. */ 315 if (buf[0] == SSH_AGENT_FAILURE) { 316 log("Agent admitted failure to authenticate using the key."); 317 goto error_cleanup; 318 } 319 /* Now it must be an authentication response packet. */ 320 if (buf[0] != SSH_AGENT_RSA_RESPONSE) 321 fatal("Bad authentication response: %d", buf[0]); 322 323 /* 324 * Get the response from the packet. This will abort with a fatal 325 * error if the packet is corrupt. 326 */ 327 for (i = 0; i < 16; i++) 328 response[i] = buffer_get_char(&buffer); 329 330 /* The buffer containing the packet is no longer needed. */ 331 buffer_free(&buffer); 332 333 /* Correct answer. */ 334 return 1; 335 } 336 337 /* 338 * Adds an identity to the authentication server. This call is not meant to 339 * be used by normal applications. 340 */ 341 342 int 343 ssh_add_identity(AuthenticationConnection *auth, 344 RSA * key, const char *comment) 345 { 346 Buffer buffer; 347 unsigned char buf[8192]; 348 int len, l, type; 349 350 /* Format a message to the agent. */ 351 buffer_init(&buffer); 352 buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY); 353 buffer_put_int(&buffer, BN_num_bits(key->n)); 354 buffer_put_bignum(&buffer, key->n); 355 buffer_put_bignum(&buffer, key->e); 356 buffer_put_bignum(&buffer, key->d); 357 /* To keep within the protocol: p < q for ssh. in SSL p > q */ 358 buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */ 359 buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */ 360 buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */ 361 buffer_put_string(&buffer, comment, strlen(comment)); 362 363 /* Get the length of the message, and format it in the buffer. */ 364 len = buffer_len(&buffer); 365 PUT_32BIT(buf, len); 366 367 /* Send the length and then the packet to the agent. */ 368 if (atomicio(write, auth->fd, buf, 4) != 4 || 369 atomicio(write, auth->fd, buffer_ptr(&buffer), 370 buffer_len(&buffer)) != buffer_len(&buffer)) { 371 error("Error writing to authentication socket."); 372 error_cleanup: 373 buffer_free(&buffer); 374 return 0; 375 } 376 /* Wait for response from the agent. First read the length of the 377 response packet. */ 378 len = 4; 379 while (len > 0) { 380 l = read(auth->fd, buf + 4 - len, len); 381 if (l <= 0) { 382 error("Error reading response length from authentication socket."); 383 goto error_cleanup; 384 } 385 len -= l; 386 } 387 388 /* Extract the length, and check it for sanity. */ 389 len = GET_32BIT(buf); 390 if (len > 256 * 1024) 391 fatal("Add identity response too long: %d", len); 392 393 /* Read the rest of the response in tothe buffer. */ 394 buffer_clear(&buffer); 395 while (len > 0) { 396 l = len; 397 if (l > sizeof(buf)) 398 l = sizeof(buf); 399 l = read(auth->fd, buf, l); 400 if (l <= 0) { 401 error("Error reading response from authentication socket."); 402 goto error_cleanup; 403 } 404 buffer_append(&buffer, (char *) buf, l); 405 len -= l; 406 } 407 408 /* Get the type of the packet. */ 409 type = buffer_get_char(&buffer); 410 switch (type) { 411 case SSH_AGENT_FAILURE: 412 buffer_free(&buffer); 413 return 0; 414 case SSH_AGENT_SUCCESS: 415 buffer_free(&buffer); 416 return 1; 417 default: 418 fatal("Bad response to add identity from authentication agent: %d", 419 type); 420 } 421 /* NOTREACHED */ 422 return 0; 423 } 424 425 /* 426 * Removes an identity from the authentication server. This call is not 427 * meant to be used by normal applications. 428 */ 429 430 int 431 ssh_remove_identity(AuthenticationConnection *auth, RSA *key) 432 { 433 Buffer buffer; 434 unsigned char buf[8192]; 435 int len, l, type; 436 437 /* Format a message to the agent. */ 438 buffer_init(&buffer); 439 buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY); 440 buffer_put_int(&buffer, BN_num_bits(key->n)); 441 buffer_put_bignum(&buffer, key->e); 442 buffer_put_bignum(&buffer, key->n); 443 444 /* Get the length of the message, and format it in the buffer. */ 445 len = buffer_len(&buffer); 446 PUT_32BIT(buf, len); 447 448 /* Send the length and then the packet to the agent. */ 449 if (atomicio(write, auth->fd, buf, 4) != 4 || 450 atomicio(write, auth->fd, buffer_ptr(&buffer), 451 buffer_len(&buffer)) != buffer_len(&buffer)) { 452 error("Error writing to authentication socket."); 453 error_cleanup: 454 buffer_free(&buffer); 455 return 0; 456 } 457 /* 458 * Wait for response from the agent. First read the length of the 459 * response packet. 460 */ 461 len = 4; 462 while (len > 0) { 463 l = read(auth->fd, buf + 4 - len, len); 464 if (l <= 0) { 465 error("Error reading response length from authentication socket."); 466 goto error_cleanup; 467 } 468 len -= l; 469 } 470 471 /* Extract the length, and check it for sanity. */ 472 len = GET_32BIT(buf); 473 if (len > 256 * 1024) 474 fatal("Remove identity response too long: %d", len); 475 476 /* Read the rest of the response in tothe buffer. */ 477 buffer_clear(&buffer); 478 while (len > 0) { 479 l = len; 480 if (l > sizeof(buf)) 481 l = sizeof(buf); 482 l = read(auth->fd, buf, l); 483 if (l <= 0) { 484 error("Error reading response from authentication socket."); 485 goto error_cleanup; 486 } 487 buffer_append(&buffer, (char *) buf, l); 488 len -= l; 489 } 490 491 /* Get the type of the packet. */ 492 type = buffer_get_char(&buffer); 493 switch (type) { 494 case SSH_AGENT_FAILURE: 495 buffer_free(&buffer); 496 return 0; 497 case SSH_AGENT_SUCCESS: 498 buffer_free(&buffer); 499 return 1; 500 default: 501 fatal("Bad response to remove identity from authentication agent: %d", 502 type); 503 } 504 /* NOTREACHED */ 505 return 0; 506 } 507 508 /* 509 * Removes all identities from the agent. This call is not meant to be used 510 * by normal applications. 511 */ 512 513 int 514 ssh_remove_all_identities(AuthenticationConnection *auth) 515 { 516 Buffer buffer; 517 unsigned char buf[8192]; 518 int len, l, type; 519 520 /* Get the length of the message, and format it in the buffer. */ 521 PUT_32BIT(buf, 1); 522 buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES; 523 524 /* Send the length and then the packet to the agent. */ 525 if (atomicio(write, auth->fd, buf, 5) != 5) { 526 error("Error writing to authentication socket."); 527 return 0; 528 } 529 /* 530 * Wait for response from the agent. First read the length of the 531 * response packet. 532 */ 533 len = 4; 534 while (len > 0) { 535 l = read(auth->fd, buf + 4 - len, len); 536 if (l <= 0) { 537 error("Error reading response length from authentication socket."); 538 return 0; 539 } 540 len -= l; 541 } 542 543 /* Extract the length, and check it for sanity. */ 544 len = GET_32BIT(buf); 545 if (len > 256 * 1024) 546 fatal("Remove identity response too long: %d", len); 547 548 /* Read the rest of the response into the buffer. */ 549 buffer_init(&buffer); 550 while (len > 0) { 551 l = len; 552 if (l > sizeof(buf)) 553 l = sizeof(buf); 554 l = read(auth->fd, buf, l); 555 if (l <= 0) { 556 error("Error reading response from authentication socket."); 557 buffer_free(&buffer); 558 return 0; 559 } 560 buffer_append(&buffer, (char *) buf, l); 561 len -= l; 562 } 563 564 /* Get the type of the packet. */ 565 type = buffer_get_char(&buffer); 566 switch (type) { 567 case SSH_AGENT_FAILURE: 568 buffer_free(&buffer); 569 return 0; 570 case SSH_AGENT_SUCCESS: 571 buffer_free(&buffer); 572 return 1; 573 default: 574 fatal("Bad response to remove identity from authentication agent: %d", 575 type); 576 } 577 /* NOTREACHED */ 578 return 0; 579 } 580