1*a0ee8cc6SDag-Erling Smørgrav /* $OpenBSD: ssh-pkcs11-client.c,v 1.5 2014/06/24 01:13:21 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 33*a0ee8cc6SDag-Erling Smørgrav #include <openssl/rsa.h> 34*a0ee8cc6SDag-Erling Smørgrav 35b15c8340SDag-Erling Smørgrav #include "pathnames.h" 36b15c8340SDag-Erling Smørgrav #include "xmalloc.h" 37b15c8340SDag-Erling Smørgrav #include "buffer.h" 38b15c8340SDag-Erling Smørgrav #include "log.h" 39b15c8340SDag-Erling Smørgrav #include "misc.h" 40b15c8340SDag-Erling Smørgrav #include "key.h" 41b15c8340SDag-Erling Smørgrav #include "authfd.h" 42b15c8340SDag-Erling Smørgrav #include "atomicio.h" 43b15c8340SDag-Erling Smørgrav #include "ssh-pkcs11.h" 44b15c8340SDag-Erling Smørgrav 45b15c8340SDag-Erling Smørgrav /* borrows code from sftp-server and ssh-agent */ 46b15c8340SDag-Erling Smørgrav 47b15c8340SDag-Erling Smørgrav int fd = -1; 48b15c8340SDag-Erling Smørgrav pid_t pid = -1; 49b15c8340SDag-Erling Smørgrav 50b15c8340SDag-Erling Smørgrav static void 51b15c8340SDag-Erling Smørgrav send_msg(Buffer *m) 52b15c8340SDag-Erling Smørgrav { 53b15c8340SDag-Erling Smørgrav u_char buf[4]; 54b15c8340SDag-Erling Smørgrav int mlen = buffer_len(m); 55b15c8340SDag-Erling Smørgrav 56b15c8340SDag-Erling Smørgrav put_u32(buf, mlen); 57b15c8340SDag-Erling Smørgrav if (atomicio(vwrite, fd, buf, 4) != 4 || 58b15c8340SDag-Erling Smørgrav atomicio(vwrite, fd, buffer_ptr(m), 59b15c8340SDag-Erling Smørgrav buffer_len(m)) != buffer_len(m)) 60b15c8340SDag-Erling Smørgrav error("write to helper failed"); 61b15c8340SDag-Erling Smørgrav buffer_consume(m, mlen); 62b15c8340SDag-Erling Smørgrav } 63b15c8340SDag-Erling Smørgrav 64b15c8340SDag-Erling Smørgrav static int 65b15c8340SDag-Erling Smørgrav recv_msg(Buffer *m) 66b15c8340SDag-Erling Smørgrav { 67b15c8340SDag-Erling Smørgrav u_int l, len; 68b15c8340SDag-Erling Smørgrav u_char buf[1024]; 69b15c8340SDag-Erling Smørgrav 70b15c8340SDag-Erling Smørgrav if ((len = atomicio(read, fd, buf, 4)) != 4) { 71b15c8340SDag-Erling Smørgrav error("read from helper failed: %u", len); 72b15c8340SDag-Erling Smørgrav return (0); /* XXX */ 73b15c8340SDag-Erling Smørgrav } 74b15c8340SDag-Erling Smørgrav len = get_u32(buf); 75b15c8340SDag-Erling Smørgrav if (len > 256 * 1024) 76b15c8340SDag-Erling Smørgrav fatal("response too long: %u", len); 77b15c8340SDag-Erling Smørgrav /* read len bytes into m */ 78b15c8340SDag-Erling Smørgrav buffer_clear(m); 79b15c8340SDag-Erling Smørgrav while (len > 0) { 80b15c8340SDag-Erling Smørgrav l = len; 81b15c8340SDag-Erling Smørgrav if (l > sizeof(buf)) 82b15c8340SDag-Erling Smørgrav l = sizeof(buf); 83b15c8340SDag-Erling Smørgrav if (atomicio(read, fd, buf, l) != l) { 84b15c8340SDag-Erling Smørgrav error("response from helper failed."); 85b15c8340SDag-Erling Smørgrav return (0); /* XXX */ 86b15c8340SDag-Erling Smørgrav } 87b15c8340SDag-Erling Smørgrav buffer_append(m, buf, l); 88b15c8340SDag-Erling Smørgrav len -= l; 89b15c8340SDag-Erling Smørgrav } 90b15c8340SDag-Erling Smørgrav return (buffer_get_char(m)); 91b15c8340SDag-Erling Smørgrav } 92b15c8340SDag-Erling Smørgrav 93b15c8340SDag-Erling Smørgrav int 94b15c8340SDag-Erling Smørgrav pkcs11_init(int interactive) 95b15c8340SDag-Erling Smørgrav { 96b15c8340SDag-Erling Smørgrav return (0); 97b15c8340SDag-Erling Smørgrav } 98b15c8340SDag-Erling Smørgrav 99b15c8340SDag-Erling Smørgrav void 100b15c8340SDag-Erling Smørgrav pkcs11_terminate(void) 101b15c8340SDag-Erling Smørgrav { 102b15c8340SDag-Erling Smørgrav close(fd); 103b15c8340SDag-Erling Smørgrav } 104b15c8340SDag-Erling Smørgrav 105b15c8340SDag-Erling Smørgrav static int 106b15c8340SDag-Erling Smørgrav pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, 107b15c8340SDag-Erling Smørgrav int padding) 108b15c8340SDag-Erling Smørgrav { 109b15c8340SDag-Erling Smørgrav Key key; 110b15c8340SDag-Erling Smørgrav u_char *blob, *signature = NULL; 111b15c8340SDag-Erling Smørgrav u_int blen, slen = 0; 112b15c8340SDag-Erling Smørgrav int ret = -1; 113b15c8340SDag-Erling Smørgrav Buffer msg; 114b15c8340SDag-Erling Smørgrav 115b15c8340SDag-Erling Smørgrav if (padding != RSA_PKCS1_PADDING) 116b15c8340SDag-Erling Smørgrav return (-1); 117b15c8340SDag-Erling Smørgrav key.type = KEY_RSA; 118b15c8340SDag-Erling Smørgrav key.rsa = rsa; 119b15c8340SDag-Erling Smørgrav if (key_to_blob(&key, &blob, &blen) == 0) 120b15c8340SDag-Erling Smørgrav return -1; 121b15c8340SDag-Erling Smørgrav buffer_init(&msg); 122b15c8340SDag-Erling Smørgrav buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST); 123b15c8340SDag-Erling Smørgrav buffer_put_string(&msg, blob, blen); 124b15c8340SDag-Erling Smørgrav buffer_put_string(&msg, from, flen); 125b15c8340SDag-Erling Smørgrav buffer_put_int(&msg, 0); 126e4a9863fSDag-Erling Smørgrav free(blob); 127b15c8340SDag-Erling Smørgrav send_msg(&msg); 128462c32cbSDag-Erling Smørgrav buffer_clear(&msg); 129b15c8340SDag-Erling Smørgrav 130b15c8340SDag-Erling Smørgrav if (recv_msg(&msg) == SSH2_AGENT_SIGN_RESPONSE) { 131b15c8340SDag-Erling Smørgrav signature = buffer_get_string(&msg, &slen); 132b15c8340SDag-Erling Smørgrav if (slen <= (u_int)RSA_size(rsa)) { 133b15c8340SDag-Erling Smørgrav memcpy(to, signature, slen); 134b15c8340SDag-Erling Smørgrav ret = slen; 135b15c8340SDag-Erling Smørgrav } 136e4a9863fSDag-Erling Smørgrav free(signature); 137b15c8340SDag-Erling Smørgrav } 138462c32cbSDag-Erling Smørgrav buffer_free(&msg); 139b15c8340SDag-Erling Smørgrav return (ret); 140b15c8340SDag-Erling Smørgrav } 141b15c8340SDag-Erling Smørgrav 142b15c8340SDag-Erling Smørgrav /* redirect the private key encrypt operation to the ssh-pkcs11-helper */ 143b15c8340SDag-Erling Smørgrav static int 144b15c8340SDag-Erling Smørgrav wrap_key(RSA *rsa) 145b15c8340SDag-Erling Smørgrav { 146b15c8340SDag-Erling Smørgrav static RSA_METHOD helper_rsa; 147b15c8340SDag-Erling Smørgrav 148b15c8340SDag-Erling Smørgrav memcpy(&helper_rsa, RSA_get_default_method(), sizeof(helper_rsa)); 149b15c8340SDag-Erling Smørgrav helper_rsa.name = "ssh-pkcs11-helper"; 150b15c8340SDag-Erling Smørgrav helper_rsa.rsa_priv_enc = pkcs11_rsa_private_encrypt; 151b15c8340SDag-Erling Smørgrav RSA_set_method(rsa, &helper_rsa); 152b15c8340SDag-Erling Smørgrav return (0); 153b15c8340SDag-Erling Smørgrav } 154b15c8340SDag-Erling Smørgrav 155b15c8340SDag-Erling Smørgrav static int 156b15c8340SDag-Erling Smørgrav pkcs11_start_helper(void) 157b15c8340SDag-Erling Smørgrav { 158b15c8340SDag-Erling Smørgrav int pair[2]; 159b15c8340SDag-Erling Smørgrav 160b15c8340SDag-Erling Smørgrav if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { 161b15c8340SDag-Erling Smørgrav error("socketpair: %s", strerror(errno)); 162b15c8340SDag-Erling Smørgrav return (-1); 163b15c8340SDag-Erling Smørgrav } 164b15c8340SDag-Erling Smørgrav if ((pid = fork()) == -1) { 165b15c8340SDag-Erling Smørgrav error("fork: %s", strerror(errno)); 166b15c8340SDag-Erling Smørgrav return (-1); 167b15c8340SDag-Erling Smørgrav } else if (pid == 0) { 168b15c8340SDag-Erling Smørgrav if ((dup2(pair[1], STDIN_FILENO) == -1) || 169b15c8340SDag-Erling Smørgrav (dup2(pair[1], STDOUT_FILENO) == -1)) { 170b15c8340SDag-Erling Smørgrav fprintf(stderr, "dup2: %s\n", strerror(errno)); 171b15c8340SDag-Erling Smørgrav _exit(1); 172b15c8340SDag-Erling Smørgrav } 173b15c8340SDag-Erling Smørgrav close(pair[0]); 174b15c8340SDag-Erling Smørgrav close(pair[1]); 175b15c8340SDag-Erling Smørgrav execlp(_PATH_SSH_PKCS11_HELPER, _PATH_SSH_PKCS11_HELPER, 176b15c8340SDag-Erling Smørgrav (char *) 0); 177b15c8340SDag-Erling Smørgrav fprintf(stderr, "exec: %s: %s\n", _PATH_SSH_PKCS11_HELPER, 178b15c8340SDag-Erling Smørgrav strerror(errno)); 179b15c8340SDag-Erling Smørgrav _exit(1); 180b15c8340SDag-Erling Smørgrav } 181b15c8340SDag-Erling Smørgrav close(pair[1]); 182b15c8340SDag-Erling Smørgrav fd = pair[0]; 183b15c8340SDag-Erling Smørgrav return (0); 184b15c8340SDag-Erling Smørgrav } 185b15c8340SDag-Erling Smørgrav 186b15c8340SDag-Erling Smørgrav int 187b15c8340SDag-Erling Smørgrav pkcs11_add_provider(char *name, char *pin, Key ***keysp) 188b15c8340SDag-Erling Smørgrav { 189b15c8340SDag-Erling Smørgrav Key *k; 190b15c8340SDag-Erling Smørgrav int i, nkeys; 191b15c8340SDag-Erling Smørgrav u_char *blob; 192b15c8340SDag-Erling Smørgrav u_int blen; 193b15c8340SDag-Erling Smørgrav Buffer msg; 194b15c8340SDag-Erling Smørgrav 195b15c8340SDag-Erling Smørgrav if (fd < 0 && pkcs11_start_helper() < 0) 196b15c8340SDag-Erling Smørgrav return (-1); 197b15c8340SDag-Erling Smørgrav 198b15c8340SDag-Erling Smørgrav buffer_init(&msg); 199b15c8340SDag-Erling Smørgrav buffer_put_char(&msg, SSH_AGENTC_ADD_SMARTCARD_KEY); 200b15c8340SDag-Erling Smørgrav buffer_put_cstring(&msg, name); 201b15c8340SDag-Erling Smørgrav buffer_put_cstring(&msg, pin); 202b15c8340SDag-Erling Smørgrav send_msg(&msg); 203b15c8340SDag-Erling Smørgrav buffer_clear(&msg); 204b15c8340SDag-Erling Smørgrav 205b15c8340SDag-Erling Smørgrav if (recv_msg(&msg) == SSH2_AGENT_IDENTITIES_ANSWER) { 206b15c8340SDag-Erling Smørgrav nkeys = buffer_get_int(&msg); 207b15c8340SDag-Erling Smørgrav *keysp = xcalloc(nkeys, sizeof(Key *)); 208b15c8340SDag-Erling Smørgrav for (i = 0; i < nkeys; i++) { 209b15c8340SDag-Erling Smørgrav blob = buffer_get_string(&msg, &blen); 210e4a9863fSDag-Erling Smørgrav free(buffer_get_string(&msg, NULL)); 211b15c8340SDag-Erling Smørgrav k = key_from_blob(blob, blen); 212b15c8340SDag-Erling Smørgrav wrap_key(k->rsa); 213b15c8340SDag-Erling Smørgrav (*keysp)[i] = k; 214e4a9863fSDag-Erling Smørgrav free(blob); 215b15c8340SDag-Erling Smørgrav } 216b15c8340SDag-Erling Smørgrav } else { 217b15c8340SDag-Erling Smørgrav nkeys = -1; 218b15c8340SDag-Erling Smørgrav } 219b15c8340SDag-Erling Smørgrav buffer_free(&msg); 220b15c8340SDag-Erling Smørgrav return (nkeys); 221b15c8340SDag-Erling Smørgrav } 222b15c8340SDag-Erling Smørgrav 223b15c8340SDag-Erling Smørgrav int 224b15c8340SDag-Erling Smørgrav pkcs11_del_provider(char *name) 225b15c8340SDag-Erling Smørgrav { 226b15c8340SDag-Erling Smørgrav int ret = -1; 227b15c8340SDag-Erling Smørgrav Buffer msg; 228b15c8340SDag-Erling Smørgrav 229b15c8340SDag-Erling Smørgrav buffer_init(&msg); 230b15c8340SDag-Erling Smørgrav buffer_put_char(&msg, SSH_AGENTC_REMOVE_SMARTCARD_KEY); 231b15c8340SDag-Erling Smørgrav buffer_put_cstring(&msg, name); 232b15c8340SDag-Erling Smørgrav buffer_put_cstring(&msg, ""); 233b15c8340SDag-Erling Smørgrav send_msg(&msg); 234b15c8340SDag-Erling Smørgrav buffer_clear(&msg); 235b15c8340SDag-Erling Smørgrav 236b15c8340SDag-Erling Smørgrav if (recv_msg(&msg) == SSH_AGENT_SUCCESS) 237b15c8340SDag-Erling Smørgrav ret = 0; 238b15c8340SDag-Erling Smørgrav buffer_free(&msg); 239b15c8340SDag-Erling Smørgrav return (ret); 240b15c8340SDag-Erling Smørgrav } 241b15c8340SDag-Erling Smørgrav 242b15c8340SDag-Erling Smørgrav #endif /* ENABLE_PKCS11 */ 243