diff options
author | djm@openbsd.org <djm@openbsd.org> | 2019-01-20 22:51:37 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2019-01-21 10:54:37 +1100 |
commit | 93f02107f44d63a016d8c23ebd2ca9205c495c48 (patch) | |
tree | 1d8d6ca8e146c9bd325614f33a59adf7199b40c9 /ssh-pkcs11-client.c | |
parent | aa22c20e0c36c2fc610cfcc793b0d14079c38814 (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.c | 103 |
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 | ||
115 | static int | 117 | static int |
116 | pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, | 118 | rsa_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 */ | 158 | static ECDSA_SIG * |
159 | ecdsa_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 | |||
204 | static RSA_METHOD *helper_rsa; | ||
205 | static EC_KEY_METHOD *helper_ecdsa; | ||
206 | |||
207 | /* redirect private key crypto operations to the ssh-pkcs11-helper */ | ||
208 | static void | ||
209 | wrap_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 | |||
158 | static int | 219 | static int |
159 | wrap_key(RSA *rsa) | 220 | pkcs11_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 | |||
204 | pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp) | 281 | pkcs11_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 | } |