1 /* $OpenBSD: authfd.c,v 1.100 2015/12/04 16:41:28 markus Exp $ */ 2 /* 3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5 * All rights reserved 6 * Functions for connecting the local authentication agent. 7 * 8 * As far as I am concerned, the code I have written for this software 9 * can be used freely for any purpose. Any derived versions of this 10 * software must be clearly marked as such, and if the derived work is 11 * incompatible with the protocol description in the RFC file, it must be 12 * called by a name other than "ssh" or "Secure Shell". 13 * 14 * SSH2 implementation, 15 * Copyright (c) 2000 Markus Friedl. All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include "includes.h" 39 40 #include <sys/types.h> 41 #include <sys/un.h> 42 #include <sys/socket.h> 43 44 #include <fcntl.h> 45 #include <stdlib.h> 46 #include <signal.h> 47 #include <stdarg.h> 48 #include <string.h> 49 #include <unistd.h> 50 #include <errno.h> 51 52 #include "xmalloc.h" 53 #include "ssh.h" 54 #include "rsa.h" 55 #include "sshbuf.h" 56 #include "sshkey.h" 57 #include "authfd.h" 58 #include "cipher.h" 59 #include "compat.h" 60 #include "log.h" 61 #include "atomicio.h" 62 #include "misc.h" 63 #include "ssherr.h" 64 65 #define MAX_AGENT_IDENTITIES 2048 /* Max keys in agent reply */ 66 #define MAX_AGENT_REPLY_LEN (256 * 1024) /* Max bytes in agent reply */ 67 68 /* macro to check for "agent failure" message */ 69 #define agent_failed(x) \ 70 ((x == SSH_AGENT_FAILURE) || \ 71 (x == SSH_COM_AGENT2_FAILURE) || \ 72 (x == SSH2_AGENT_FAILURE)) 73 74 /* Convert success/failure response from agent to a err.h status */ 75 static int 76 decode_reply(u_char type) 77 { 78 if (agent_failed(type)) 79 return SSH_ERR_AGENT_FAILURE; 80 else if (type == SSH_AGENT_SUCCESS) 81 return 0; 82 else 83 return SSH_ERR_INVALID_FORMAT; 84 } 85 86 /* Returns the number of the authentication fd, or -1 if there is none. */ 87 int 88 ssh_get_authentication_socket(int *fdp) 89 { 90 const char *authsocket; 91 int sock, oerrno; 92 struct sockaddr_un sunaddr; 93 94 if (fdp != NULL) 95 *fdp = -1; 96 97 authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); 98 if (!authsocket) 99 return SSH_ERR_AGENT_NOT_PRESENT; 100 101 memset(&sunaddr, 0, sizeof(sunaddr)); 102 sunaddr.sun_family = AF_UNIX; 103 strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); 104 105 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 106 return SSH_ERR_SYSTEM_ERROR; 107 108 /* close on exec */ 109 if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1 || 110 connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) { 111 oerrno = errno; 112 close(sock); 113 errno = oerrno; 114 return SSH_ERR_SYSTEM_ERROR; 115 } 116 if (fdp != NULL) 117 *fdp = sock; 118 else 119 close(sock); 120 return 0; 121 } 122 123 /* Communicate with agent: send request and read reply */ 124 static int 125 ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply) 126 { 127 int r; 128 size_t l, len; 129 char buf[1024]; 130 131 /* Get the length of the message, and format it in the buffer. */ 132 len = sshbuf_len(request); 133 put_u32(buf, len); 134 135 /* Send the length and then the packet to the agent. */ 136 if (atomicio(vwrite, sock, buf, 4) != 4 || 137 atomicio(vwrite, sock, (u_char *)sshbuf_ptr(request), 138 sshbuf_len(request)) != sshbuf_len(request)) 139 return SSH_ERR_AGENT_COMMUNICATION; 140 /* 141 * Wait for response from the agent. First read the length of the 142 * response packet. 143 */ 144 if (atomicio(read, sock, buf, 4) != 4) 145 return SSH_ERR_AGENT_COMMUNICATION; 146 147 /* Extract the length, and check it for sanity. */ 148 len = get_u32(buf); 149 if (len > MAX_AGENT_REPLY_LEN) 150 return SSH_ERR_INVALID_FORMAT; 151 152 /* Read the rest of the response in to the buffer. */ 153 sshbuf_reset(reply); 154 while (len > 0) { 155 l = len; 156 if (l > sizeof(buf)) 157 l = sizeof(buf); 158 if (atomicio(read, sock, buf, l) != l) 159 return SSH_ERR_AGENT_COMMUNICATION; 160 if ((r = sshbuf_put(reply, buf, l)) != 0) 161 return r; 162 len -= l; 163 } 164 return 0; 165 } 166 167 /* 168 * Closes the agent socket if it should be closed (depends on how it was 169 * obtained). The argument must have been returned by 170 * ssh_get_authentication_socket(). 171 */ 172 void 173 ssh_close_authentication_socket(int sock) 174 { 175 if (getenv(SSH_AUTHSOCKET_ENV_NAME)) 176 close(sock); 177 } 178 179 /* Lock/unlock agent */ 180 int 181 ssh_lock_agent(int sock, int lock, const char *password) 182 { 183 int r; 184 u_char type = lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK; 185 struct sshbuf *msg; 186 187 if ((msg = sshbuf_new()) == NULL) 188 return SSH_ERR_ALLOC_FAIL; 189 if ((r = sshbuf_put_u8(msg, type)) != 0 || 190 (r = sshbuf_put_cstring(msg, password)) != 0) 191 goto out; 192 if ((r = ssh_request_reply(sock, msg, msg)) != 0) 193 goto out; 194 if ((r = sshbuf_get_u8(msg, &type)) != 0) 195 goto out; 196 r = decode_reply(type); 197 out: 198 sshbuf_free(msg); 199 return r; 200 } 201 202 #ifdef WITH_SSH1 203 static int 204 deserialise_identity1(struct sshbuf *ids, struct sshkey **keyp, char **commentp) 205 { 206 struct sshkey *key; 207 int r, keybits; 208 u_int32_t bits; 209 char *comment = NULL; 210 211 if ((key = sshkey_new(KEY_RSA1)) == NULL) 212 return SSH_ERR_ALLOC_FAIL; 213 if ((r = sshbuf_get_u32(ids, &bits)) != 0 || 214 (r = sshbuf_get_bignum1(ids, key->rsa->e)) != 0 || 215 (r = sshbuf_get_bignum1(ids, key->rsa->n)) != 0 || 216 (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0) 217 goto out; 218 keybits = BN_num_bits(key->rsa->n); 219 /* XXX previously we just warned here. I think we should be strict */ 220 if (keybits < 0 || bits != (u_int)keybits) { 221 r = SSH_ERR_KEY_BITS_MISMATCH; 222 goto out; 223 } 224 if (keyp != NULL) { 225 *keyp = key; 226 key = NULL; 227 } 228 if (commentp != NULL) { 229 *commentp = comment; 230 comment = NULL; 231 } 232 r = 0; 233 out: 234 sshkey_free(key); 235 free(comment); 236 return r; 237 } 238 #endif 239 240 static int 241 deserialise_identity2(struct sshbuf *ids, struct sshkey **keyp, char **commentp) 242 { 243 int r; 244 char *comment = NULL; 245 const u_char *blob; 246 size_t blen; 247 248 if ((r = sshbuf_get_string_direct(ids, &blob, &blen)) != 0 || 249 (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0) 250 goto out; 251 if ((r = sshkey_from_blob(blob, blen, keyp)) != 0) 252 goto out; 253 if (commentp != NULL) { 254 *commentp = comment; 255 comment = NULL; 256 } 257 r = 0; 258 out: 259 free(comment); 260 return r; 261 } 262 263 /* 264 * Fetch list of identities held by the agent. 265 */ 266 int 267 ssh_fetch_identitylist(int sock, int version, struct ssh_identitylist **idlp) 268 { 269 u_char type, code1 = 0, code2 = 0; 270 u_int32_t num, i; 271 struct sshbuf *msg; 272 struct ssh_identitylist *idl = NULL; 273 int r; 274 275 /* Determine request and expected response types */ 276 switch (version) { 277 case 1: 278 code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES; 279 code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER; 280 break; 281 case 2: 282 code1 = SSH2_AGENTC_REQUEST_IDENTITIES; 283 code2 = SSH2_AGENT_IDENTITIES_ANSWER; 284 break; 285 default: 286 return SSH_ERR_INVALID_ARGUMENT; 287 } 288 289 /* 290 * Send a message to the agent requesting for a list of the 291 * identities it can represent. 292 */ 293 if ((msg = sshbuf_new()) == NULL) 294 return SSH_ERR_ALLOC_FAIL; 295 if ((r = sshbuf_put_u8(msg, code1)) != 0) 296 goto out; 297 298 if ((r = ssh_request_reply(sock, msg, msg)) != 0) 299 goto out; 300 301 /* Get message type, and verify that we got a proper answer. */ 302 if ((r = sshbuf_get_u8(msg, &type)) != 0) 303 goto out; 304 if (agent_failed(type)) { 305 r = SSH_ERR_AGENT_FAILURE; 306 goto out; 307 } else if (type != code2) { 308 r = SSH_ERR_INVALID_FORMAT; 309 goto out; 310 } 311 312 /* Get the number of entries in the response and check it for sanity. */ 313 if ((r = sshbuf_get_u32(msg, &num)) != 0) 314 goto out; 315 if (num > MAX_AGENT_IDENTITIES) { 316 r = SSH_ERR_INVALID_FORMAT; 317 goto out; 318 } 319 if (num == 0) { 320 r = SSH_ERR_AGENT_NO_IDENTITIES; 321 goto out; 322 } 323 324 /* Deserialise the response into a list of keys/comments */ 325 if ((idl = calloc(1, sizeof(*idl))) == NULL || 326 (idl->keys = calloc(num, sizeof(*idl->keys))) == NULL || 327 (idl->comments = calloc(num, sizeof(*idl->comments))) == NULL) { 328 r = SSH_ERR_ALLOC_FAIL; 329 goto out; 330 } 331 for (i = 0; i < num;) { 332 switch (version) { 333 case 1: 334 #ifdef WITH_SSH1 335 if ((r = deserialise_identity1(msg, 336 &(idl->keys[i]), &(idl->comments[i]))) != 0) 337 goto out; 338 #endif 339 break; 340 case 2: 341 if ((r = deserialise_identity2(msg, 342 &(idl->keys[i]), &(idl->comments[i]))) != 0) { 343 if (r == SSH_ERR_KEY_TYPE_UNKNOWN) { 344 /* Gracefully skip unknown key types */ 345 num--; 346 continue; 347 } else 348 goto out; 349 } 350 break; 351 } 352 i++; 353 } 354 idl->nkeys = num; 355 *idlp = idl; 356 idl = NULL; 357 r = 0; 358 out: 359 sshbuf_free(msg); 360 if (idl != NULL) 361 ssh_free_identitylist(idl); 362 return r; 363 } 364 365 void 366 ssh_free_identitylist(struct ssh_identitylist *idl) 367 { 368 size_t i; 369 370 if (idl == NULL) 371 return; 372 for (i = 0; i < idl->nkeys; i++) { 373 if (idl->keys != NULL) 374 sshkey_free(idl->keys[i]); 375 if (idl->comments != NULL) 376 free(idl->comments[i]); 377 } 378 free(idl); 379 } 380 381 /* 382 * Sends a challenge (typically from a server via ssh(1)) to the agent, 383 * and waits for a response from the agent. 384 * Returns true (non-zero) if the agent gave the correct answer, zero 385 * otherwise. 386 */ 387 388 #ifdef WITH_SSH1 389 int 390 ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge, 391 u_char session_id[16], u_char response[16]) 392 { 393 struct sshbuf *msg; 394 int r; 395 u_char type; 396 397 if (key->type != KEY_RSA1) 398 return SSH_ERR_INVALID_ARGUMENT; 399 if ((msg = sshbuf_new()) == NULL) 400 return SSH_ERR_ALLOC_FAIL; 401 if ((r = sshbuf_put_u8(msg, SSH_AGENTC_RSA_CHALLENGE)) != 0 || 402 (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 || 403 (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 || 404 (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0 || 405 (r = sshbuf_put_bignum1(msg, challenge)) != 0 || 406 (r = sshbuf_put(msg, session_id, 16)) != 0 || 407 (r = sshbuf_put_u32(msg, 1)) != 0) /* Response type for proto 1.1 */ 408 goto out; 409 if ((r = ssh_request_reply(sock, msg, msg)) != 0) 410 goto out; 411 if ((r = sshbuf_get_u8(msg, &type)) != 0) 412 goto out; 413 if (agent_failed(type)) { 414 r = SSH_ERR_AGENT_FAILURE; 415 goto out; 416 } else if (type != SSH_AGENT_RSA_RESPONSE) { 417 r = SSH_ERR_INVALID_FORMAT; 418 goto out; 419 } 420 if ((r = sshbuf_get(msg, response, 16)) != 0) 421 goto out; 422 r = 0; 423 out: 424 sshbuf_free(msg); 425 return r; 426 } 427 #endif 428 429 /* encode signature algoritm in flag bits, so we can keep the msg format */ 430 static u_int 431 agent_encode_alg(struct sshkey *key, const char *alg) 432 { 433 if (alg != NULL && key->type == KEY_RSA) { 434 if (strcmp(alg, "rsa-sha2-256") == 0) 435 return SSH_AGENT_RSA_SHA2_256; 436 else if (strcmp(alg, "rsa-sha2-512") == 0) 437 return SSH_AGENT_RSA_SHA2_512; 438 } 439 return 0; 440 } 441 442 /* ask agent to sign data, returns err.h code on error, 0 on success */ 443 int 444 ssh_agent_sign(int sock, struct sshkey *key, 445 u_char **sigp, size_t *lenp, 446 const u_char *data, size_t datalen, const char *alg, u_int compat) 447 { 448 struct sshbuf *msg; 449 u_char *blob = NULL, type; 450 size_t blen = 0, len = 0; 451 u_int flags = 0; 452 int r = SSH_ERR_INTERNAL_ERROR; 453 454 *sigp = NULL; 455 *lenp = 0; 456 457 if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE) 458 return SSH_ERR_INVALID_ARGUMENT; 459 if (compat & SSH_BUG_SIGBLOB) 460 flags |= SSH_AGENT_OLD_SIGNATURE; 461 if ((msg = sshbuf_new()) == NULL) 462 return SSH_ERR_ALLOC_FAIL; 463 if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) 464 goto out; 465 flags |= agent_encode_alg(key, alg); 466 if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 || 467 (r = sshbuf_put_string(msg, blob, blen)) != 0 || 468 (r = sshbuf_put_string(msg, data, datalen)) != 0 || 469 (r = sshbuf_put_u32(msg, flags)) != 0) 470 goto out; 471 if ((r = ssh_request_reply(sock, msg, msg)) != 0) 472 goto out; 473 if ((r = sshbuf_get_u8(msg, &type)) != 0) 474 goto out; 475 if (agent_failed(type)) { 476 r = SSH_ERR_AGENT_FAILURE; 477 goto out; 478 } else if (type != SSH2_AGENT_SIGN_RESPONSE) { 479 r = SSH_ERR_INVALID_FORMAT; 480 goto out; 481 } 482 if ((r = sshbuf_get_string(msg, sigp, &len)) != 0) 483 goto out; 484 *lenp = len; 485 r = 0; 486 out: 487 if (blob != NULL) { 488 explicit_bzero(blob, blen); 489 free(blob); 490 } 491 sshbuf_free(msg); 492 return r; 493 } 494 495 /* Encode key for a message to the agent. */ 496 497 #ifdef WITH_SSH1 498 static int 499 ssh_encode_identity_rsa1(struct sshbuf *b, RSA *key, const char *comment) 500 { 501 int r; 502 503 /* To keep within the protocol: p < q for ssh. in SSL p > q */ 504 if ((r = sshbuf_put_u32(b, BN_num_bits(key->n))) != 0 || 505 (r = sshbuf_put_bignum1(b, key->n)) != 0 || 506 (r = sshbuf_put_bignum1(b, key->e)) != 0 || 507 (r = sshbuf_put_bignum1(b, key->d)) != 0 || 508 (r = sshbuf_put_bignum1(b, key->iqmp)) != 0 || 509 (r = sshbuf_put_bignum1(b, key->q)) != 0 || 510 (r = sshbuf_put_bignum1(b, key->p)) != 0 || 511 (r = sshbuf_put_cstring(b, comment)) != 0) 512 return r; 513 return 0; 514 } 515 #endif 516 517 static int 518 ssh_encode_identity_ssh2(struct sshbuf *b, struct sshkey *key, 519 const char *comment) 520 { 521 int r; 522 523 if ((r = sshkey_private_serialize(key, b)) != 0 || 524 (r = sshbuf_put_cstring(b, comment)) != 0) 525 return r; 526 return 0; 527 } 528 529 static int 530 encode_constraints(struct sshbuf *m, u_int life, u_int confirm) 531 { 532 int r; 533 534 if (life != 0) { 535 if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_LIFETIME)) != 0 || 536 (r = sshbuf_put_u32(m, life)) != 0) 537 goto out; 538 } 539 if (confirm != 0) { 540 if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_CONFIRM)) != 0) 541 goto out; 542 } 543 r = 0; 544 out: 545 return r; 546 } 547 548 /* 549 * Adds an identity to the authentication server. 550 * This call is intended only for use by ssh-add(1) and like applications. 551 */ 552 int 553 ssh_add_identity_constrained(int sock, struct sshkey *key, const char *comment, 554 u_int life, u_int confirm) 555 { 556 struct sshbuf *msg; 557 int r, constrained = (life || confirm); 558 u_char type; 559 560 if ((msg = sshbuf_new()) == NULL) 561 return SSH_ERR_ALLOC_FAIL; 562 563 switch (key->type) { 564 #ifdef WITH_SSH1 565 case KEY_RSA1: 566 type = constrained ? 567 SSH_AGENTC_ADD_RSA_ID_CONSTRAINED : 568 SSH_AGENTC_ADD_RSA_IDENTITY; 569 if ((r = sshbuf_put_u8(msg, type)) != 0 || 570 (r = ssh_encode_identity_rsa1(msg, key->rsa, comment)) != 0) 571 goto out; 572 break; 573 #endif 574 #ifdef WITH_OPENSSL 575 case KEY_RSA: 576 case KEY_RSA_CERT: 577 case KEY_DSA: 578 case KEY_DSA_CERT: 579 case KEY_ECDSA: 580 case KEY_ECDSA_CERT: 581 #endif 582 case KEY_ED25519: 583 case KEY_ED25519_CERT: 584 type = constrained ? 585 SSH2_AGENTC_ADD_ID_CONSTRAINED : 586 SSH2_AGENTC_ADD_IDENTITY; 587 if ((r = sshbuf_put_u8(msg, type)) != 0 || 588 (r = ssh_encode_identity_ssh2(msg, key, comment)) != 0) 589 goto out; 590 break; 591 default: 592 r = SSH_ERR_INVALID_ARGUMENT; 593 goto out; 594 } 595 if (constrained && 596 (r = encode_constraints(msg, life, confirm)) != 0) 597 goto out; 598 if ((r = ssh_request_reply(sock, msg, msg)) != 0) 599 goto out; 600 if ((r = sshbuf_get_u8(msg, &type)) != 0) 601 goto out; 602 r = decode_reply(type); 603 out: 604 sshbuf_free(msg); 605 return r; 606 } 607 608 /* 609 * Removes an identity from the authentication server. 610 * This call is intended only for use by ssh-add(1) and like applications. 611 */ 612 int 613 ssh_remove_identity(int sock, struct sshkey *key) 614 { 615 struct sshbuf *msg; 616 int r; 617 u_char type, *blob = NULL; 618 size_t blen; 619 620 if ((msg = sshbuf_new()) == NULL) 621 return SSH_ERR_ALLOC_FAIL; 622 623 #ifdef WITH_SSH1 624 if (key->type == KEY_RSA1) { 625 if ((r = sshbuf_put_u8(msg, 626 SSH_AGENTC_REMOVE_RSA_IDENTITY)) != 0 || 627 (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 || 628 (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 || 629 (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0) 630 goto out; 631 } else 632 #endif 633 if (key->type != KEY_UNSPEC) { 634 if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) 635 goto out; 636 if ((r = sshbuf_put_u8(msg, 637 SSH2_AGENTC_REMOVE_IDENTITY)) != 0 || 638 (r = sshbuf_put_string(msg, blob, blen)) != 0) 639 goto out; 640 } else { 641 r = SSH_ERR_INVALID_ARGUMENT; 642 goto out; 643 } 644 if ((r = ssh_request_reply(sock, msg, msg)) != 0) 645 goto out; 646 if ((r = sshbuf_get_u8(msg, &type)) != 0) 647 goto out; 648 r = decode_reply(type); 649 out: 650 if (blob != NULL) { 651 explicit_bzero(blob, blen); 652 free(blob); 653 } 654 sshbuf_free(msg); 655 return r; 656 } 657 658 /* 659 * Add/remove an token-based identity from the authentication server. 660 * This call is intended only for use by ssh-add(1) and like applications. 661 */ 662 int 663 ssh_update_card(int sock, int add, const char *reader_id, const char *pin, 664 u_int life, u_int confirm) 665 { 666 struct sshbuf *msg; 667 int r, constrained = (life || confirm); 668 u_char type; 669 670 if (add) { 671 type = constrained ? 672 SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED : 673 SSH_AGENTC_ADD_SMARTCARD_KEY; 674 } else 675 type = SSH_AGENTC_REMOVE_SMARTCARD_KEY; 676 677 if ((msg = sshbuf_new()) == NULL) 678 return SSH_ERR_ALLOC_FAIL; 679 if ((r = sshbuf_put_u8(msg, type)) != 0 || 680 (r = sshbuf_put_cstring(msg, reader_id)) != 0 || 681 (r = sshbuf_put_cstring(msg, pin)) != 0) 682 goto out; 683 if (constrained && 684 (r = encode_constraints(msg, life, confirm)) != 0) 685 goto out; 686 if ((r = ssh_request_reply(sock, msg, msg)) != 0) 687 goto out; 688 if ((r = sshbuf_get_u8(msg, &type)) != 0) 689 goto out; 690 r = decode_reply(type); 691 out: 692 sshbuf_free(msg); 693 return r; 694 } 695 696 /* 697 * Removes all identities from the agent. 698 * This call is intended only for use by ssh-add(1) and like applications. 699 */ 700 int 701 ssh_remove_all_identities(int sock, int version) 702 { 703 struct sshbuf *msg; 704 u_char type = (version == 1) ? 705 SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES : 706 SSH2_AGENTC_REMOVE_ALL_IDENTITIES; 707 int r; 708 709 if ((msg = sshbuf_new()) == NULL) 710 return SSH_ERR_ALLOC_FAIL; 711 if ((r = sshbuf_put_u8(msg, type)) != 0) 712 goto out; 713 if ((r = ssh_request_reply(sock, msg, msg)) != 0) 714 goto out; 715 if ((r = sshbuf_get_u8(msg, &type)) != 0) 716 goto out; 717 r = decode_reply(type); 718 out: 719 sshbuf_free(msg); 720 return r; 721 } 722