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