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