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}
| 29 30/* Returns the number of the authentication fd, or -1 if there is none. */ 31 32int 33ssh_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 68void 69ssh_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 83AuthenticationConnection * 84ssh_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 112void 113ssh_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 128int 129ssh_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 201int 202ssh_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 238int 239ssh_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."); 273error_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 342int 343ssh_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."); 372error_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 430int 431ssh_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."); 453error_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 513int 514ssh_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}
|