summaryrefslogtreecommitdiff
path: root/ssh-pkcs11-client.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2019-01-20 22:51:37 +0000
committerDamien Miller <djm@mindrot.org>2019-01-21 10:54:37 +1100
commit93f02107f44d63a016d8c23ebd2ca9205c495c48 (patch)
tree1d8d6ca8e146c9bd325614f33a59adf7199b40c9 /ssh-pkcs11-client.c
parentaa22c20e0c36c2fc610cfcc793b0d14079c38814 (diff)
upstream: add support for ECDSA keys in PKCS#11 tokens
Work by markus@ and Pedro Martelletto, feedback and ok me@ OpenBSD-Commit-ID: a37d651e221341376636056512bddfc16efb4424
Diffstat (limited to 'ssh-pkcs11-client.c')
-rw-r--r--ssh-pkcs11-client.c103
1 files changed, 92 insertions, 11 deletions
diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c
index d1241ce67..6e16b2f9a 100644
--- a/ssh-pkcs11-client.c
+++ b/ssh-pkcs11-client.c
@@ -1,6 +1,7 @@
1/* $OpenBSD: ssh-pkcs11-client.c,v 1.10 2018/07/09 21:59:10 markus Exp $ */ 1/* $OpenBSD: ssh-pkcs11-client.c,v 1.12 2019/01/20 22:51:37 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2010 Markus Friedl. All rights reserved. 3 * Copyright (c) 2010 Markus Friedl. All rights reserved.
4 * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
4 * 5 *
5 * Permission to use, copy, modify, and distribute this software for any 6 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above 7 * purpose with or without fee is hereby granted, provided that the above
@@ -30,6 +31,7 @@
30#include <unistd.h> 31#include <unistd.h>
31#include <errno.h> 32#include <errno.h>
32 33
34#include <openssl/ecdsa.h>
33#include <openssl/rsa.h> 35#include <openssl/rsa.h>
34 36
35#include "openbsd-compat/openssl-compat.h" 37#include "openbsd-compat/openssl-compat.h"
@@ -113,8 +115,7 @@ pkcs11_terminate(void)
113} 115}
114 116
115static int 117static int
116pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, 118rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
117 int padding)
118{ 119{
119 struct sshkey key; /* XXX */ 120 struct sshkey key; /* XXX */
120 u_char *blob, *signature = NULL; 121 u_char *blob, *signature = NULL;
@@ -154,18 +155,89 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
154 return (ret); 155 return (ret);
155} 156}
156 157
157/* redirect the private key encrypt operation to the ssh-pkcs11-helper */ 158static ECDSA_SIG *
159ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
160 const BIGNUM *rp, EC_KEY *ec)
161{
162 struct sshkey key; /* XXX */
163 u_char *blob, *signature = NULL;
164 const u_char *cp;
165 size_t blen, slen = 0;
166 ECDSA_SIG *ret = NULL;
167 struct sshbuf *msg;
168 int r;
169
170 key.type = KEY_ECDSA;
171 key.ecdsa = ec;
172 key.ecdsa_nid = sshkey_ecdsa_key_to_nid(ec);
173 if (key.ecdsa_nid < 0) {
174 error("%s: couldn't get curve nid", __func__);
175 return (NULL);
176 }
177 if ((r = sshkey_to_blob(&key, &blob, &blen)) != 0) {
178 error("%s: sshkey_to_blob: %s", __func__, ssh_err(r));
179 return (NULL);
180 }
181 if ((msg = sshbuf_new()) == NULL)
182 fatal("%s: sshbuf_new failed", __func__);
183 if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
184 (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
185 (r = sshbuf_put_string(msg, dgst, dgst_len)) != 0 ||
186 (r = sshbuf_put_u32(msg, 0)) != 0)
187 fatal("%s: buffer error: %s", __func__, ssh_err(r));
188 free(blob);
189 send_msg(msg);
190 sshbuf_reset(msg);
191
192 if (recv_msg(msg) == SSH2_AGENT_SIGN_RESPONSE) {
193 if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
194 fatal("%s: buffer error: %s", __func__, ssh_err(r));
195 cp = signature;
196 ret = d2i_ECDSA_SIG(NULL, &cp, slen);
197 free(signature);
198 }
199
200 sshbuf_free(msg);
201 return (ret);
202}
203
204static RSA_METHOD *helper_rsa;
205static EC_KEY_METHOD *helper_ecdsa;
206
207/* redirect private key crypto operations to the ssh-pkcs11-helper */
208static void
209wrap_key(struct sshkey *k)
210{
211 if (k->type == KEY_RSA)
212 RSA_set_method(k->rsa, helper_rsa);
213 else if (k->type == KEY_ECDSA)
214 EC_KEY_set_method(k->ecdsa, helper_ecdsa);
215 else
216 fatal("%s: unknown key type", __func__);
217}
218
158static int 219static int
159wrap_key(RSA *rsa) 220pkcs11_start_helper_methods(void)
160{ 221{
161 static RSA_METHOD *helper_rsa; 222 if (helper_ecdsa != NULL)
223 return (0);
224
225 int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
226 unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
227 if (helper_ecdsa != NULL)
228 return (0);
229 helper_ecdsa = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
230 if (helper_ecdsa == NULL)
231 return (-1);
232 EC_KEY_METHOD_get_sign(helper_ecdsa, &orig_sign, NULL, NULL);
233 EC_KEY_METHOD_set_sign(helper_ecdsa, orig_sign, NULL, ecdsa_do_sign);
162 234
163 if ((helper_rsa = RSA_meth_dup(RSA_get_default_method())) == NULL) 235 if ((helper_rsa = RSA_meth_dup(RSA_get_default_method())) == NULL)
164 fatal("%s: RSA_meth_dup failed", __func__); 236 fatal("%s: RSA_meth_dup failed", __func__);
165 if (!RSA_meth_set1_name(helper_rsa, "ssh-pkcs11-helper") || 237 if (!RSA_meth_set1_name(helper_rsa, "ssh-pkcs11-helper") ||
166 !RSA_meth_set_priv_enc(helper_rsa, pkcs11_rsa_private_encrypt)) 238 !RSA_meth_set_priv_enc(helper_rsa, rsa_encrypt))
167 fatal("%s: failed to prepare method", __func__); 239 fatal("%s: failed to prepare method", __func__);
168 RSA_set_method(rsa, helper_rsa); 240
169 return (0); 241 return (0);
170} 242}
171 243
@@ -174,6 +246,11 @@ pkcs11_start_helper(void)
174{ 246{
175 int pair[2]; 247 int pair[2];
176 248
249 if (pkcs11_start_helper_methods() == -1) {
250 error("pkcs11_start_helper_methods failed");
251 return (-1);
252 }
253
177 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { 254 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
178 error("socketpair: %s", strerror(errno)); 255 error("socketpair: %s", strerror(errno));
179 return (-1); 256 return (-1);
@@ -204,7 +281,7 @@ int
204pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp) 281pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp)
205{ 282{
206 struct sshkey *k; 283 struct sshkey *k;
207 int r; 284 int r, type;
208 u_char *blob; 285 u_char *blob;
209 size_t blen; 286 size_t blen;
210 u_int nkeys, i; 287 u_int nkeys, i;
@@ -222,7 +299,8 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp)
222 send_msg(msg); 299 send_msg(msg);
223 sshbuf_reset(msg); 300 sshbuf_reset(msg);
224 301
225 if (recv_msg(msg) == SSH2_AGENT_IDENTITIES_ANSWER) { 302 type = recv_msg(msg);
303 if (type == SSH2_AGENT_IDENTITIES_ANSWER) {
226 if ((r = sshbuf_get_u32(msg, &nkeys)) != 0) 304 if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
227 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 305 fatal("%s: buffer error: %s", __func__, ssh_err(r));
228 *keysp = xcalloc(nkeys, sizeof(struct sshkey *)); 306 *keysp = xcalloc(nkeys, sizeof(struct sshkey *));
@@ -234,10 +312,13 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp)
234 __func__, ssh_err(r)); 312 __func__, ssh_err(r));
235 if ((r = sshkey_from_blob(blob, blen, &k)) != 0) 313 if ((r = sshkey_from_blob(blob, blen, &k)) != 0)
236 fatal("%s: bad key: %s", __func__, ssh_err(r)); 314 fatal("%s: bad key: %s", __func__, ssh_err(r));
237 wrap_key(k->rsa); 315 wrap_key(k);
238 (*keysp)[i] = k; 316 (*keysp)[i] = k;
239 free(blob); 317 free(blob);
240 } 318 }
319 } else if (type == SSH2_AGENT_FAILURE) {
320 if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
321 nkeys = -1;
241 } else { 322 } else {
242 nkeys = -1; 323 nkeys = -1;
243 } 324 }