1296781Sdes/* $OpenBSD: ssh-pkcs11-client.c,v 1.6 2015/12/11 00:20:04 mmcc Exp $ */ 2204861Sdes/* 3204861Sdes * Copyright (c) 2010 Markus Friedl. All rights reserved. 4204861Sdes * 5204861Sdes * Permission to use, copy, modify, and distribute this software for any 6204861Sdes * purpose with or without fee is hereby granted, provided that the above 7204861Sdes * copyright notice and this permission notice appear in all copies. 8204861Sdes * 9204861Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10204861Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11204861Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12204861Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13204861Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14204861Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15204861Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16204861Sdes */ 17204861Sdes 18204861Sdes#include "includes.h" 19204861Sdes 20204861Sdes#ifdef ENABLE_PKCS11 21204861Sdes 22204861Sdes#include <sys/types.h> 23204861Sdes#ifdef HAVE_SYS_TIME_H 24204861Sdes# include <sys/time.h> 25204861Sdes#endif 26204861Sdes#include <sys/socket.h> 27204861Sdes 28204861Sdes#include <stdarg.h> 29204861Sdes#include <string.h> 30204861Sdes#include <unistd.h> 31204861Sdes#include <errno.h> 32204861Sdes 33295367Sdes#include <openssl/rsa.h> 34295367Sdes 35204861Sdes#include "pathnames.h" 36204861Sdes#include "xmalloc.h" 37204861Sdes#include "buffer.h" 38204861Sdes#include "log.h" 39204861Sdes#include "misc.h" 40204861Sdes#include "key.h" 41204861Sdes#include "authfd.h" 42204861Sdes#include "atomicio.h" 43204861Sdes#include "ssh-pkcs11.h" 44204861Sdes 45204861Sdes/* borrows code from sftp-server and ssh-agent */ 46204861Sdes 47204861Sdesint fd = -1; 48204861Sdespid_t pid = -1; 49204861Sdes 50204861Sdesstatic void 51204861Sdessend_msg(Buffer *m) 52204861Sdes{ 53204861Sdes u_char buf[4]; 54204861Sdes int mlen = buffer_len(m); 55204861Sdes 56204861Sdes put_u32(buf, mlen); 57204861Sdes if (atomicio(vwrite, fd, buf, 4) != 4 || 58204861Sdes atomicio(vwrite, fd, buffer_ptr(m), 59204861Sdes buffer_len(m)) != buffer_len(m)) 60204861Sdes error("write to helper failed"); 61204861Sdes buffer_consume(m, mlen); 62204861Sdes} 63204861Sdes 64204861Sdesstatic int 65204861Sdesrecv_msg(Buffer *m) 66204861Sdes{ 67204861Sdes u_int l, len; 68204861Sdes u_char buf[1024]; 69204861Sdes 70204861Sdes if ((len = atomicio(read, fd, buf, 4)) != 4) { 71204861Sdes error("read from helper failed: %u", len); 72204861Sdes return (0); /* XXX */ 73204861Sdes } 74204861Sdes len = get_u32(buf); 75204861Sdes if (len > 256 * 1024) 76204861Sdes fatal("response too long: %u", len); 77204861Sdes /* read len bytes into m */ 78204861Sdes buffer_clear(m); 79204861Sdes while (len > 0) { 80204861Sdes l = len; 81204861Sdes if (l > sizeof(buf)) 82204861Sdes l = sizeof(buf); 83204861Sdes if (atomicio(read, fd, buf, l) != l) { 84204861Sdes error("response from helper failed."); 85204861Sdes return (0); /* XXX */ 86204861Sdes } 87204861Sdes buffer_append(m, buf, l); 88204861Sdes len -= l; 89204861Sdes } 90204861Sdes return (buffer_get_char(m)); 91204861Sdes} 92204861Sdes 93204861Sdesint 94204861Sdespkcs11_init(int interactive) 95204861Sdes{ 96204861Sdes return (0); 97204861Sdes} 98204861Sdes 99204861Sdesvoid 100204861Sdespkcs11_terminate(void) 101204861Sdes{ 102204861Sdes close(fd); 103204861Sdes} 104204861Sdes 105204861Sdesstatic int 106204861Sdespkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, 107204861Sdes int padding) 108204861Sdes{ 109204861Sdes Key key; 110204861Sdes u_char *blob, *signature = NULL; 111204861Sdes u_int blen, slen = 0; 112204861Sdes int ret = -1; 113204861Sdes Buffer msg; 114204861Sdes 115204861Sdes if (padding != RSA_PKCS1_PADDING) 116204861Sdes return (-1); 117204861Sdes key.type = KEY_RSA; 118204861Sdes key.rsa = rsa; 119204861Sdes if (key_to_blob(&key, &blob, &blen) == 0) 120204861Sdes return -1; 121204861Sdes buffer_init(&msg); 122204861Sdes buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST); 123204861Sdes buffer_put_string(&msg, blob, blen); 124204861Sdes buffer_put_string(&msg, from, flen); 125204861Sdes buffer_put_int(&msg, 0); 126255767Sdes free(blob); 127204861Sdes send_msg(&msg); 128240075Sdes buffer_clear(&msg); 129204861Sdes 130204861Sdes if (recv_msg(&msg) == SSH2_AGENT_SIGN_RESPONSE) { 131204861Sdes signature = buffer_get_string(&msg, &slen); 132204861Sdes if (slen <= (u_int)RSA_size(rsa)) { 133204861Sdes memcpy(to, signature, slen); 134204861Sdes ret = slen; 135204861Sdes } 136255767Sdes free(signature); 137204861Sdes } 138240075Sdes buffer_free(&msg); 139204861Sdes return (ret); 140204861Sdes} 141204861Sdes 142204861Sdes/* redirect the private key encrypt operation to the ssh-pkcs11-helper */ 143204861Sdesstatic int 144204861Sdeswrap_key(RSA *rsa) 145204861Sdes{ 146204861Sdes static RSA_METHOD helper_rsa; 147204861Sdes 148204861Sdes memcpy(&helper_rsa, RSA_get_default_method(), sizeof(helper_rsa)); 149204861Sdes helper_rsa.name = "ssh-pkcs11-helper"; 150204861Sdes helper_rsa.rsa_priv_enc = pkcs11_rsa_private_encrypt; 151204861Sdes RSA_set_method(rsa, &helper_rsa); 152204861Sdes return (0); 153204861Sdes} 154204861Sdes 155204861Sdesstatic int 156204861Sdespkcs11_start_helper(void) 157204861Sdes{ 158204861Sdes int pair[2]; 159204861Sdes 160204861Sdes if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { 161204861Sdes error("socketpair: %s", strerror(errno)); 162204861Sdes return (-1); 163204861Sdes } 164204861Sdes if ((pid = fork()) == -1) { 165204861Sdes error("fork: %s", strerror(errno)); 166204861Sdes return (-1); 167204861Sdes } else if (pid == 0) { 168204861Sdes if ((dup2(pair[1], STDIN_FILENO) == -1) || 169204861Sdes (dup2(pair[1], STDOUT_FILENO) == -1)) { 170204861Sdes fprintf(stderr, "dup2: %s\n", strerror(errno)); 171204861Sdes _exit(1); 172204861Sdes } 173204861Sdes close(pair[0]); 174204861Sdes close(pair[1]); 175204861Sdes execlp(_PATH_SSH_PKCS11_HELPER, _PATH_SSH_PKCS11_HELPER, 176296781Sdes (char *)NULL); 177204861Sdes fprintf(stderr, "exec: %s: %s\n", _PATH_SSH_PKCS11_HELPER, 178204861Sdes strerror(errno)); 179204861Sdes _exit(1); 180204861Sdes } 181204861Sdes close(pair[1]); 182204861Sdes fd = pair[0]; 183204861Sdes return (0); 184204861Sdes} 185204861Sdes 186204861Sdesint 187204861Sdespkcs11_add_provider(char *name, char *pin, Key ***keysp) 188204861Sdes{ 189204861Sdes Key *k; 190204861Sdes int i, nkeys; 191204861Sdes u_char *blob; 192204861Sdes u_int blen; 193204861Sdes Buffer msg; 194204861Sdes 195204861Sdes if (fd < 0 && pkcs11_start_helper() < 0) 196204861Sdes return (-1); 197204861Sdes 198204861Sdes buffer_init(&msg); 199204861Sdes buffer_put_char(&msg, SSH_AGENTC_ADD_SMARTCARD_KEY); 200204861Sdes buffer_put_cstring(&msg, name); 201204861Sdes buffer_put_cstring(&msg, pin); 202204861Sdes send_msg(&msg); 203204861Sdes buffer_clear(&msg); 204204861Sdes 205204861Sdes if (recv_msg(&msg) == SSH2_AGENT_IDENTITIES_ANSWER) { 206204861Sdes nkeys = buffer_get_int(&msg); 207204861Sdes *keysp = xcalloc(nkeys, sizeof(Key *)); 208204861Sdes for (i = 0; i < nkeys; i++) { 209204861Sdes blob = buffer_get_string(&msg, &blen); 210255767Sdes free(buffer_get_string(&msg, NULL)); 211204861Sdes k = key_from_blob(blob, blen); 212204861Sdes wrap_key(k->rsa); 213204861Sdes (*keysp)[i] = k; 214255767Sdes free(blob); 215204861Sdes } 216204861Sdes } else { 217204861Sdes nkeys = -1; 218204861Sdes } 219204861Sdes buffer_free(&msg); 220204861Sdes return (nkeys); 221204861Sdes} 222204861Sdes 223204861Sdesint 224204861Sdespkcs11_del_provider(char *name) 225204861Sdes{ 226204861Sdes int ret = -1; 227204861Sdes Buffer msg; 228204861Sdes 229204861Sdes buffer_init(&msg); 230204861Sdes buffer_put_char(&msg, SSH_AGENTC_REMOVE_SMARTCARD_KEY); 231204861Sdes buffer_put_cstring(&msg, name); 232204861Sdes buffer_put_cstring(&msg, ""); 233204861Sdes send_msg(&msg); 234204861Sdes buffer_clear(&msg); 235204861Sdes 236204861Sdes if (recv_msg(&msg) == SSH_AGENT_SUCCESS) 237204861Sdes ret = 0; 238204861Sdes buffer_free(&msg); 239204861Sdes return (ret); 240204861Sdes} 241204861Sdes 242204861Sdes#endif /* ENABLE_PKCS11 */ 243