1*e4a9863fSDag-Erling Smørgrav /* $OpenBSD: ssh-pkcs11-client.c,v 1.4 2013/05/17 00:13:14 djm Exp $ */ 2b15c8340SDag-Erling Smørgrav /* 3b15c8340SDag-Erling Smørgrav * Copyright (c) 2010 Markus Friedl. All rights reserved. 4b15c8340SDag-Erling Smørgrav * 5b15c8340SDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 6b15c8340SDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 7b15c8340SDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 8b15c8340SDag-Erling Smørgrav * 9b15c8340SDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10b15c8340SDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11b15c8340SDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12b15c8340SDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13b15c8340SDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14b15c8340SDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15b15c8340SDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16b15c8340SDag-Erling Smørgrav */ 17b15c8340SDag-Erling Smørgrav 18b15c8340SDag-Erling Smørgrav #include "includes.h" 19b15c8340SDag-Erling Smørgrav 20b15c8340SDag-Erling Smørgrav #ifdef ENABLE_PKCS11 21b15c8340SDag-Erling Smørgrav 22b15c8340SDag-Erling Smørgrav #include <sys/types.h> 23b15c8340SDag-Erling Smørgrav #ifdef HAVE_SYS_TIME_H 24b15c8340SDag-Erling Smørgrav # include <sys/time.h> 25b15c8340SDag-Erling Smørgrav #endif 26b15c8340SDag-Erling Smørgrav #include <sys/socket.h> 27b15c8340SDag-Erling Smørgrav 28b15c8340SDag-Erling Smørgrav #include <stdarg.h> 29b15c8340SDag-Erling Smørgrav #include <string.h> 30b15c8340SDag-Erling Smørgrav #include <unistd.h> 31b15c8340SDag-Erling Smørgrav #include <errno.h> 32b15c8340SDag-Erling Smørgrav 33b15c8340SDag-Erling Smørgrav #include "pathnames.h" 34b15c8340SDag-Erling Smørgrav #include "xmalloc.h" 35b15c8340SDag-Erling Smørgrav #include "buffer.h" 36b15c8340SDag-Erling Smørgrav #include "log.h" 37b15c8340SDag-Erling Smørgrav #include "misc.h" 38b15c8340SDag-Erling Smørgrav #include "key.h" 39b15c8340SDag-Erling Smørgrav #include "authfd.h" 40b15c8340SDag-Erling Smørgrav #include "atomicio.h" 41b15c8340SDag-Erling Smørgrav #include "ssh-pkcs11.h" 42b15c8340SDag-Erling Smørgrav 43b15c8340SDag-Erling Smørgrav /* borrows code from sftp-server and ssh-agent */ 44b15c8340SDag-Erling Smørgrav 45b15c8340SDag-Erling Smørgrav int fd = -1; 46b15c8340SDag-Erling Smørgrav pid_t pid = -1; 47b15c8340SDag-Erling Smørgrav 48b15c8340SDag-Erling Smørgrav static void 49b15c8340SDag-Erling Smørgrav send_msg(Buffer *m) 50b15c8340SDag-Erling Smørgrav { 51b15c8340SDag-Erling Smørgrav u_char buf[4]; 52b15c8340SDag-Erling Smørgrav int mlen = buffer_len(m); 53b15c8340SDag-Erling Smørgrav 54b15c8340SDag-Erling Smørgrav put_u32(buf, mlen); 55b15c8340SDag-Erling Smørgrav if (atomicio(vwrite, fd, buf, 4) != 4 || 56b15c8340SDag-Erling Smørgrav atomicio(vwrite, fd, buffer_ptr(m), 57b15c8340SDag-Erling Smørgrav buffer_len(m)) != buffer_len(m)) 58b15c8340SDag-Erling Smørgrav error("write to helper failed"); 59b15c8340SDag-Erling Smørgrav buffer_consume(m, mlen); 60b15c8340SDag-Erling Smørgrav } 61b15c8340SDag-Erling Smørgrav 62b15c8340SDag-Erling Smørgrav static int 63b15c8340SDag-Erling Smørgrav recv_msg(Buffer *m) 64b15c8340SDag-Erling Smørgrav { 65b15c8340SDag-Erling Smørgrav u_int l, len; 66b15c8340SDag-Erling Smørgrav u_char buf[1024]; 67b15c8340SDag-Erling Smørgrav 68b15c8340SDag-Erling Smørgrav if ((len = atomicio(read, fd, buf, 4)) != 4) { 69b15c8340SDag-Erling Smørgrav error("read from helper failed: %u", len); 70b15c8340SDag-Erling Smørgrav return (0); /* XXX */ 71b15c8340SDag-Erling Smørgrav } 72b15c8340SDag-Erling Smørgrav len = get_u32(buf); 73b15c8340SDag-Erling Smørgrav if (len > 256 * 1024) 74b15c8340SDag-Erling Smørgrav fatal("response too long: %u", len); 75b15c8340SDag-Erling Smørgrav /* read len bytes into m */ 76b15c8340SDag-Erling Smørgrav buffer_clear(m); 77b15c8340SDag-Erling Smørgrav while (len > 0) { 78b15c8340SDag-Erling Smørgrav l = len; 79b15c8340SDag-Erling Smørgrav if (l > sizeof(buf)) 80b15c8340SDag-Erling Smørgrav l = sizeof(buf); 81b15c8340SDag-Erling Smørgrav if (atomicio(read, fd, buf, l) != l) { 82b15c8340SDag-Erling Smørgrav error("response from helper failed."); 83b15c8340SDag-Erling Smørgrav return (0); /* XXX */ 84b15c8340SDag-Erling Smørgrav } 85b15c8340SDag-Erling Smørgrav buffer_append(m, buf, l); 86b15c8340SDag-Erling Smørgrav len -= l; 87b15c8340SDag-Erling Smørgrav } 88b15c8340SDag-Erling Smørgrav return (buffer_get_char(m)); 89b15c8340SDag-Erling Smørgrav } 90b15c8340SDag-Erling Smørgrav 91b15c8340SDag-Erling Smørgrav int 92b15c8340SDag-Erling Smørgrav pkcs11_init(int interactive) 93b15c8340SDag-Erling Smørgrav { 94b15c8340SDag-Erling Smørgrav return (0); 95b15c8340SDag-Erling Smørgrav } 96b15c8340SDag-Erling Smørgrav 97b15c8340SDag-Erling Smørgrav void 98b15c8340SDag-Erling Smørgrav pkcs11_terminate(void) 99b15c8340SDag-Erling Smørgrav { 100b15c8340SDag-Erling Smørgrav close(fd); 101b15c8340SDag-Erling Smørgrav } 102b15c8340SDag-Erling Smørgrav 103b15c8340SDag-Erling Smørgrav static int 104b15c8340SDag-Erling Smørgrav pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, 105b15c8340SDag-Erling Smørgrav int padding) 106b15c8340SDag-Erling Smørgrav { 107b15c8340SDag-Erling Smørgrav Key key; 108b15c8340SDag-Erling Smørgrav u_char *blob, *signature = NULL; 109b15c8340SDag-Erling Smørgrav u_int blen, slen = 0; 110b15c8340SDag-Erling Smørgrav int ret = -1; 111b15c8340SDag-Erling Smørgrav Buffer msg; 112b15c8340SDag-Erling Smørgrav 113b15c8340SDag-Erling Smørgrav if (padding != RSA_PKCS1_PADDING) 114b15c8340SDag-Erling Smørgrav return (-1); 115b15c8340SDag-Erling Smørgrav key.type = KEY_RSA; 116b15c8340SDag-Erling Smørgrav key.rsa = rsa; 117b15c8340SDag-Erling Smørgrav if (key_to_blob(&key, &blob, &blen) == 0) 118b15c8340SDag-Erling Smørgrav return -1; 119b15c8340SDag-Erling Smørgrav buffer_init(&msg); 120b15c8340SDag-Erling Smørgrav buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST); 121b15c8340SDag-Erling Smørgrav buffer_put_string(&msg, blob, blen); 122b15c8340SDag-Erling Smørgrav buffer_put_string(&msg, from, flen); 123b15c8340SDag-Erling Smørgrav buffer_put_int(&msg, 0); 124*e4a9863fSDag-Erling Smørgrav free(blob); 125b15c8340SDag-Erling Smørgrav send_msg(&msg); 126462c32cbSDag-Erling Smørgrav buffer_clear(&msg); 127b15c8340SDag-Erling Smørgrav 128b15c8340SDag-Erling Smørgrav if (recv_msg(&msg) == SSH2_AGENT_SIGN_RESPONSE) { 129b15c8340SDag-Erling Smørgrav signature = buffer_get_string(&msg, &slen); 130b15c8340SDag-Erling Smørgrav if (slen <= (u_int)RSA_size(rsa)) { 131b15c8340SDag-Erling Smørgrav memcpy(to, signature, slen); 132b15c8340SDag-Erling Smørgrav ret = slen; 133b15c8340SDag-Erling Smørgrav } 134*e4a9863fSDag-Erling Smørgrav free(signature); 135b15c8340SDag-Erling Smørgrav } 136462c32cbSDag-Erling Smørgrav buffer_free(&msg); 137b15c8340SDag-Erling Smørgrav return (ret); 138b15c8340SDag-Erling Smørgrav } 139b15c8340SDag-Erling Smørgrav 140b15c8340SDag-Erling Smørgrav /* redirect the private key encrypt operation to the ssh-pkcs11-helper */ 141b15c8340SDag-Erling Smørgrav static int 142b15c8340SDag-Erling Smørgrav wrap_key(RSA *rsa) 143b15c8340SDag-Erling Smørgrav { 144b15c8340SDag-Erling Smørgrav static RSA_METHOD helper_rsa; 145b15c8340SDag-Erling Smørgrav 146b15c8340SDag-Erling Smørgrav memcpy(&helper_rsa, RSA_get_default_method(), sizeof(helper_rsa)); 147b15c8340SDag-Erling Smørgrav helper_rsa.name = "ssh-pkcs11-helper"; 148b15c8340SDag-Erling Smørgrav helper_rsa.rsa_priv_enc = pkcs11_rsa_private_encrypt; 149b15c8340SDag-Erling Smørgrav RSA_set_method(rsa, &helper_rsa); 150b15c8340SDag-Erling Smørgrav return (0); 151b15c8340SDag-Erling Smørgrav } 152b15c8340SDag-Erling Smørgrav 153b15c8340SDag-Erling Smørgrav static int 154b15c8340SDag-Erling Smørgrav pkcs11_start_helper(void) 155b15c8340SDag-Erling Smørgrav { 156b15c8340SDag-Erling Smørgrav int pair[2]; 157b15c8340SDag-Erling Smørgrav 158b15c8340SDag-Erling Smørgrav if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { 159b15c8340SDag-Erling Smørgrav error("socketpair: %s", strerror(errno)); 160b15c8340SDag-Erling Smørgrav return (-1); 161b15c8340SDag-Erling Smørgrav } 162b15c8340SDag-Erling Smørgrav if ((pid = fork()) == -1) { 163b15c8340SDag-Erling Smørgrav error("fork: %s", strerror(errno)); 164b15c8340SDag-Erling Smørgrav return (-1); 165b15c8340SDag-Erling Smørgrav } else if (pid == 0) { 166b15c8340SDag-Erling Smørgrav if ((dup2(pair[1], STDIN_FILENO) == -1) || 167b15c8340SDag-Erling Smørgrav (dup2(pair[1], STDOUT_FILENO) == -1)) { 168b15c8340SDag-Erling Smørgrav fprintf(stderr, "dup2: %s\n", strerror(errno)); 169b15c8340SDag-Erling Smørgrav _exit(1); 170b15c8340SDag-Erling Smørgrav } 171b15c8340SDag-Erling Smørgrav close(pair[0]); 172b15c8340SDag-Erling Smørgrav close(pair[1]); 173b15c8340SDag-Erling Smørgrav execlp(_PATH_SSH_PKCS11_HELPER, _PATH_SSH_PKCS11_HELPER, 174b15c8340SDag-Erling Smørgrav (char *) 0); 175b15c8340SDag-Erling Smørgrav fprintf(stderr, "exec: %s: %s\n", _PATH_SSH_PKCS11_HELPER, 176b15c8340SDag-Erling Smørgrav strerror(errno)); 177b15c8340SDag-Erling Smørgrav _exit(1); 178b15c8340SDag-Erling Smørgrav } 179b15c8340SDag-Erling Smørgrav close(pair[1]); 180b15c8340SDag-Erling Smørgrav fd = pair[0]; 181b15c8340SDag-Erling Smørgrav return (0); 182b15c8340SDag-Erling Smørgrav } 183b15c8340SDag-Erling Smørgrav 184b15c8340SDag-Erling Smørgrav int 185b15c8340SDag-Erling Smørgrav pkcs11_add_provider(char *name, char *pin, Key ***keysp) 186b15c8340SDag-Erling Smørgrav { 187b15c8340SDag-Erling Smørgrav Key *k; 188b15c8340SDag-Erling Smørgrav int i, nkeys; 189b15c8340SDag-Erling Smørgrav u_char *blob; 190b15c8340SDag-Erling Smørgrav u_int blen; 191b15c8340SDag-Erling Smørgrav Buffer msg; 192b15c8340SDag-Erling Smørgrav 193b15c8340SDag-Erling Smørgrav if (fd < 0 && pkcs11_start_helper() < 0) 194b15c8340SDag-Erling Smørgrav return (-1); 195b15c8340SDag-Erling Smørgrav 196b15c8340SDag-Erling Smørgrav buffer_init(&msg); 197b15c8340SDag-Erling Smørgrav buffer_put_char(&msg, SSH_AGENTC_ADD_SMARTCARD_KEY); 198b15c8340SDag-Erling Smørgrav buffer_put_cstring(&msg, name); 199b15c8340SDag-Erling Smørgrav buffer_put_cstring(&msg, pin); 200b15c8340SDag-Erling Smørgrav send_msg(&msg); 201b15c8340SDag-Erling Smørgrav buffer_clear(&msg); 202b15c8340SDag-Erling Smørgrav 203b15c8340SDag-Erling Smørgrav if (recv_msg(&msg) == SSH2_AGENT_IDENTITIES_ANSWER) { 204b15c8340SDag-Erling Smørgrav nkeys = buffer_get_int(&msg); 205b15c8340SDag-Erling Smørgrav *keysp = xcalloc(nkeys, sizeof(Key *)); 206b15c8340SDag-Erling Smørgrav for (i = 0; i < nkeys; i++) { 207b15c8340SDag-Erling Smørgrav blob = buffer_get_string(&msg, &blen); 208*e4a9863fSDag-Erling Smørgrav free(buffer_get_string(&msg, NULL)); 209b15c8340SDag-Erling Smørgrav k = key_from_blob(blob, blen); 210b15c8340SDag-Erling Smørgrav wrap_key(k->rsa); 211b15c8340SDag-Erling Smørgrav (*keysp)[i] = k; 212*e4a9863fSDag-Erling Smørgrav free(blob); 213b15c8340SDag-Erling Smørgrav } 214b15c8340SDag-Erling Smørgrav } else { 215b15c8340SDag-Erling Smørgrav nkeys = -1; 216b15c8340SDag-Erling Smørgrav } 217b15c8340SDag-Erling Smørgrav buffer_free(&msg); 218b15c8340SDag-Erling Smørgrav return (nkeys); 219b15c8340SDag-Erling Smørgrav } 220b15c8340SDag-Erling Smørgrav 221b15c8340SDag-Erling Smørgrav int 222b15c8340SDag-Erling Smørgrav pkcs11_del_provider(char *name) 223b15c8340SDag-Erling Smørgrav { 224b15c8340SDag-Erling Smørgrav int ret = -1; 225b15c8340SDag-Erling Smørgrav Buffer msg; 226b15c8340SDag-Erling Smørgrav 227b15c8340SDag-Erling Smørgrav buffer_init(&msg); 228b15c8340SDag-Erling Smørgrav buffer_put_char(&msg, SSH_AGENTC_REMOVE_SMARTCARD_KEY); 229b15c8340SDag-Erling Smørgrav buffer_put_cstring(&msg, name); 230b15c8340SDag-Erling Smørgrav buffer_put_cstring(&msg, ""); 231b15c8340SDag-Erling Smørgrav send_msg(&msg); 232b15c8340SDag-Erling Smørgrav buffer_clear(&msg); 233b15c8340SDag-Erling Smørgrav 234b15c8340SDag-Erling Smørgrav if (recv_msg(&msg) == SSH_AGENT_SUCCESS) 235b15c8340SDag-Erling Smørgrav ret = 0; 236b15c8340SDag-Erling Smørgrav buffer_free(&msg); 237b15c8340SDag-Erling Smørgrav return (ret); 238b15c8340SDag-Erling Smørgrav } 239b15c8340SDag-Erling Smørgrav 240b15c8340SDag-Erling Smørgrav #endif /* ENABLE_PKCS11 */ 241