diff options
author | Damien Miller <djm@mindrot.org> | 2000-08-23 10:46:23 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2000-08-23 10:46:23 +1000 |
commit | ad833b3e65c1887674714d514eb818d862bb499a (patch) | |
tree | 16fa75fe42aede072c5d3edac562c2870d1bb0e5 /ssh-agent.c | |
parent | b078567bf5de1dcf12d265d98acb4dc9eba8b325 (diff) |
- (djm) Pick up LOGIN_PROGRAM from environment or PATH if not set by headers
- (djm) OpenBSD CVS updates:
- deraadt@cvs.openbsd.org 2000/08/18 20:07:23
[ssh.c]
accept remsh as a valid name as well; roman@buildpoint.com
- deraadt@cvs.openbsd.org 2000/08/18 20:17:13
[deattack.c crc32.c packet.c]
rename crc32() to ssh_crc32() to avoid zlib name clash. do not move to
libz crc32 function yet, because it has ugly "long"'s in it;
oneill@cs.sfu.ca
- deraadt@cvs.openbsd.org 2000/08/18 20:26:08
[scp.1 scp.c]
-S prog support; tv@debian.org
- deraadt@cvs.openbsd.org 2000/08/18 20:50:07
[scp.c]
knf
- deraadt@cvs.openbsd.org 2000/08/18 20:57:33
[log-client.c]
shorten
- markus@cvs.openbsd.org 2000/08/19 12:48:11
[channels.c channels.h clientloop.c ssh.c ssh.h]
support for ~. in ssh2
- deraadt@cvs.openbsd.org 2000/08/19 15:29:40
[crc32.h]
proper prototype
- markus@cvs.openbsd.org 2000/08/19 15:34:44
[authfd.c authfd.h key.c key.h ssh-add.1 ssh-add.c ssh-agent.1]
[ssh-agent.c ssh-keygen.c sshconnect1.c sshconnect2.c Makefile]
[fingerprint.c fingerprint.h]
add SSH2/DSA support to the agent and some other DSA related cleanups.
(note that we cannot talk to ssh.com's ssh2 agents)
- markus@cvs.openbsd.org 2000/08/19 15:55:52
[channels.c channels.h clientloop.c]
more ~ support for ssh2
- markus@cvs.openbsd.org 2000/08/19 16:21:19
[clientloop.c]
oops
- millert@cvs.openbsd.org 2000/08/20 12:25:53
[session.c]
We have to stash the result of get_remote_name_or_ip() before we
close our socket or getpeername() will get EBADF and the process
will exit. Only a problem for "UseLogin yes".
- millert@cvs.openbsd.org 2000/08/20 12:30:59
[session.c]
Only check /etc/nologin if "UseLogin no" since login(1) may have its
own policy on determining who is allowed to login when /etc/nologin
is present. Also use the _PATH_NOLOGIN define.
- millert@cvs.openbsd.org 2000/08/20 12:42:43
[auth1.c auth2.c session.c ssh.c]
Add calls to setusercontext() and login_get*(). We basically call
setusercontext() in most places where previously we did a setlogin().
Add default login.conf file and put root in the "daemon" login class.
- millert@cvs.openbsd.org 2000/08/21 10:23:31
[session.c]
Fix incorrect PATH setting; noted by Markus.
Diffstat (limited to 'ssh-agent.c')
-rw-r--r-- | ssh-agent.c | 514 |
1 files changed, 320 insertions, 194 deletions
diff --git a/ssh-agent.c b/ssh-agent.c index e8383b5df..56b81a78d 100644 --- a/ssh-agent.c +++ b/ssh-agent.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-agent.c,v 1.32 2000/07/16 08:27:21 markus Exp $ */ | 1 | /* $OpenBSD: ssh-agent.c,v 1.33 2000/08/19 21:34:43 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -6,10 +6,13 @@ | |||
6 | * All rights reserved | 6 | * All rights reserved |
7 | * Created: Wed Mar 29 03:46:59 1995 ylo | 7 | * Created: Wed Mar 29 03:46:59 1995 ylo |
8 | * The authentication agent program. | 8 | * The authentication agent program. |
9 | * | ||
10 | * SSH2 implementation, | ||
11 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | ||
9 | */ | 12 | */ |
10 | 13 | ||
11 | #include "includes.h" | 14 | #include "includes.h" |
12 | RCSID("$OpenBSD: ssh-agent.c,v 1.32 2000/07/16 08:27:21 markus Exp $"); | 15 | RCSID("$OpenBSD: ssh-agent.c,v 1.33 2000/08/19 21:34:43 markus Exp $"); |
13 | 16 | ||
14 | #include "ssh.h" | 17 | #include "ssh.h" |
15 | #include "rsa.h" | 18 | #include "rsa.h" |
@@ -20,11 +23,14 @@ RCSID("$OpenBSD: ssh-agent.c,v 1.32 2000/07/16 08:27:21 markus Exp $"); | |||
20 | #include "getput.h" | 23 | #include "getput.h" |
21 | #include "mpaux.h" | 24 | #include "mpaux.h" |
22 | 25 | ||
26 | #include <openssl/evp.h> | ||
23 | #include <openssl/md5.h> | 27 | #include <openssl/md5.h> |
24 | #include <openssl/dsa.h> | 28 | #include <openssl/dsa.h> |
25 | #include <openssl/rsa.h> | 29 | #include <openssl/rsa.h> |
26 | #include "key.h" | 30 | #include "key.h" |
27 | #include "authfd.h" | 31 | #include "authfd.h" |
32 | #include "dsa.h" | ||
33 | #include "kex.h" | ||
28 | 34 | ||
29 | typedef struct { | 35 | typedef struct { |
30 | int fd; | 36 | int fd; |
@@ -39,12 +45,17 @@ unsigned int sockets_alloc = 0; | |||
39 | SocketEntry *sockets = NULL; | 45 | SocketEntry *sockets = NULL; |
40 | 46 | ||
41 | typedef struct { | 47 | typedef struct { |
42 | RSA *key; | 48 | Key *key; |
43 | char *comment; | 49 | char *comment; |
44 | } Identity; | 50 | } Identity; |
45 | 51 | ||
46 | unsigned int num_identities = 0; | 52 | typedef struct { |
47 | Identity *identities = NULL; | 53 | int nentries; |
54 | Identity *identities; | ||
55 | } Idtab; | ||
56 | |||
57 | /* private key table, one per protocol version */ | ||
58 | Idtab idtable[3]; | ||
48 | 59 | ||
49 | int max_fd = 0; | 60 | int max_fd = 0; |
50 | 61 | ||
@@ -62,175 +73,243 @@ static const char *__progname = "ssh-agent"; | |||
62 | #endif /* HAVE___PROGNAME */ | 73 | #endif /* HAVE___PROGNAME */ |
63 | 74 | ||
64 | void | 75 | void |
65 | process_request_identity(SocketEntry *e) | 76 | idtab_init(void) |
77 | { | ||
78 | int i; | ||
79 | for (i = 0; i <=2; i++){ | ||
80 | idtable[i].identities = NULL; | ||
81 | idtable[i].nentries = 0; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | /* return private key table for requested protocol version */ | ||
86 | Idtab * | ||
87 | idtab_lookup(int version) | ||
88 | { | ||
89 | if (version < 1 || version > 2) | ||
90 | fatal("internal error, bad protocol version %d", version); | ||
91 | return &idtable[version]; | ||
92 | } | ||
93 | |||
94 | /* return matching private key for given public key */ | ||
95 | Key * | ||
96 | lookup_private_key(Key *key, int *idx, int version) | ||
97 | { | ||
98 | int i; | ||
99 | Idtab *tab = idtab_lookup(version); | ||
100 | for (i = 0; i < tab->nentries; i++) { | ||
101 | if (key_equal(key, tab->identities[i].key)) { | ||
102 | if (idx != NULL) | ||
103 | *idx = i; | ||
104 | return tab->identities[i].key; | ||
105 | } | ||
106 | } | ||
107 | return NULL; | ||
108 | } | ||
109 | |||
110 | /* send list of supported public keys to 'client' */ | ||
111 | void | ||
112 | process_request_identities(SocketEntry *e, int version) | ||
66 | { | 113 | { |
114 | Idtab *tab = idtab_lookup(version); | ||
67 | Buffer msg; | 115 | Buffer msg; |
68 | int i; | 116 | int i; |
69 | 117 | ||
70 | buffer_init(&msg); | 118 | buffer_init(&msg); |
71 | buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER); | 119 | buffer_put_char(&msg, (version == 1) ? |
72 | buffer_put_int(&msg, num_identities); | 120 | SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER); |
73 | for (i = 0; i < num_identities; i++) { | 121 | buffer_put_int(&msg, tab->nentries); |
74 | buffer_put_int(&msg, BN_num_bits(identities[i].key->n)); | 122 | for (i = 0; i < tab->nentries; i++) { |
75 | buffer_put_bignum(&msg, identities[i].key->e); | 123 | Identity *id = &tab->identities[i]; |
76 | buffer_put_bignum(&msg, identities[i].key->n); | 124 | if (id->key->type == KEY_RSA) { |
77 | buffer_put_string(&msg, identities[i].comment, | 125 | buffer_put_int(&msg, BN_num_bits(id->key->rsa->n)); |
78 | strlen(identities[i].comment)); | 126 | buffer_put_bignum(&msg, id->key->rsa->e); |
127 | buffer_put_bignum(&msg, id->key->rsa->n); | ||
128 | } else { | ||
129 | unsigned char *blob; | ||
130 | unsigned int blen; | ||
131 | dsa_make_key_blob(id->key, &blob, &blen); | ||
132 | buffer_put_string(&msg, blob, blen); | ||
133 | xfree(blob); | ||
134 | } | ||
135 | buffer_put_cstring(&msg, id->comment); | ||
79 | } | 136 | } |
80 | buffer_put_int(&e->output, buffer_len(&msg)); | 137 | buffer_put_int(&e->output, buffer_len(&msg)); |
81 | buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg)); | 138 | buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg)); |
82 | buffer_free(&msg); | 139 | buffer_free(&msg); |
83 | } | 140 | } |
84 | 141 | ||
142 | /* ssh1 only */ | ||
85 | void | 143 | void |
86 | process_authentication_challenge(SocketEntry *e) | 144 | process_authentication_challenge1(SocketEntry *e) |
87 | { | 145 | { |
88 | int i, pub_bits, len; | 146 | Key *key, *private; |
89 | BIGNUM *pub_e, *pub_n, *challenge; | 147 | BIGNUM *challenge; |
148 | int i, len; | ||
90 | Buffer msg; | 149 | Buffer msg; |
91 | MD5_CTX md; | 150 | MD5_CTX md; |
92 | unsigned char buf[32], mdbuf[16], session_id[16]; | 151 | unsigned char buf[32], mdbuf[16], session_id[16]; |
93 | unsigned int response_type; | 152 | unsigned int response_type; |
94 | 153 | ||
95 | buffer_init(&msg); | 154 | buffer_init(&msg); |
96 | pub_e = BN_new(); | 155 | key = key_new(KEY_RSA); |
97 | pub_n = BN_new(); | ||
98 | challenge = BN_new(); | 156 | challenge = BN_new(); |
99 | pub_bits = buffer_get_int(&e->input); | ||
100 | buffer_get_bignum(&e->input, pub_e); | ||
101 | buffer_get_bignum(&e->input, pub_n); | ||
102 | buffer_get_bignum(&e->input, challenge); | ||
103 | if (buffer_len(&e->input) == 0) { | ||
104 | /* Compatibility code for old servers. */ | ||
105 | memset(session_id, 0, 16); | ||
106 | response_type = 0; | ||
107 | } else { | ||
108 | /* New code. */ | ||
109 | buffer_get(&e->input, (char *) session_id, 16); | ||
110 | response_type = buffer_get_int(&e->input); | ||
111 | } | ||
112 | for (i = 0; i < num_identities; i++) | ||
113 | if (pub_bits == BN_num_bits(identities[i].key->n) && | ||
114 | BN_cmp(pub_e, identities[i].key->e) == 0 && | ||
115 | BN_cmp(pub_n, identities[i].key->n) == 0) { | ||
116 | /* Decrypt the challenge using the private key. */ | ||
117 | rsa_private_decrypt(challenge, challenge, identities[i].key); | ||
118 | |||
119 | /* Compute the desired response. */ | ||
120 | switch (response_type) { | ||
121 | case 0:/* As of protocol 1.0 */ | ||
122 | /* This response type is no longer supported. */ | ||
123 | log("Compatibility with ssh protocol 1.0 no longer supported."); | ||
124 | buffer_put_char(&msg, SSH_AGENT_FAILURE); | ||
125 | goto send; | ||
126 | |||
127 | case 1:/* As of protocol 1.1 */ | ||
128 | /* The response is MD5 of decrypted challenge plus session id. */ | ||
129 | len = BN_num_bytes(challenge); | ||
130 | |||
131 | if (len <= 0 || len > 32) { | ||
132 | fatal("process_authentication_challenge: " | ||
133 | "bad challenge length %d", len); | ||
134 | } | ||
135 | memset(buf, 0, 32); | ||
136 | BN_bn2bin(challenge, buf + 32 - len); | ||
137 | MD5_Init(&md); | ||
138 | MD5_Update(&md, buf, 32); | ||
139 | MD5_Update(&md, session_id, 16); | ||
140 | MD5_Final(mdbuf, &md); | ||
141 | break; | ||
142 | |||
143 | default: | ||
144 | fatal("process_authentication_challenge: bad response_type %d", | ||
145 | response_type); | ||
146 | break; | ||
147 | } | ||
148 | 157 | ||
149 | /* Send the response. */ | 158 | buffer_get_int(&e->input); /* ignored */ |
150 | buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE); | 159 | buffer_get_bignum(&e->input, key->rsa->e); |
151 | for (i = 0; i < 16; i++) | 160 | buffer_get_bignum(&e->input, key->rsa->n); |
152 | buffer_put_char(&msg, mdbuf[i]); | 161 | buffer_get_bignum(&e->input, challenge); |
153 | 162 | ||
154 | goto send; | 163 | /* Only protocol 1.1 is supported */ |
164 | if (buffer_len(&e->input) == 0) | ||
165 | goto failure; | ||
166 | buffer_get(&e->input, (char *) session_id, 16); | ||
167 | response_type = buffer_get_int(&e->input); | ||
168 | if (response_type != 1) | ||
169 | goto failure; | ||
170 | |||
171 | private = lookup_private_key(key, NULL, 1); | ||
172 | if (private != NULL) { | ||
173 | /* Decrypt the challenge using the private key. */ | ||
174 | rsa_private_decrypt(challenge, challenge, private->rsa); | ||
175 | |||
176 | /* The response is MD5 of decrypted challenge plus session id. */ | ||
177 | len = BN_num_bytes(challenge); | ||
178 | if (len <= 0 || len > 32) { | ||
179 | log("process_authentication_challenge: bad challenge length %d", len); | ||
180 | goto failure; | ||
155 | } | 181 | } |
156 | /* Unknown identity. Send failure. */ | 182 | memset(buf, 0, 32); |
183 | BN_bn2bin(challenge, buf + 32 - len); | ||
184 | MD5_Init(&md); | ||
185 | MD5_Update(&md, buf, 32); | ||
186 | MD5_Update(&md, session_id, 16); | ||
187 | MD5_Final(mdbuf, &md); | ||
188 | |||
189 | /* Send the response. */ | ||
190 | buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE); | ||
191 | for (i = 0; i < 16; i++) | ||
192 | buffer_put_char(&msg, mdbuf[i]); | ||
193 | goto send; | ||
194 | } | ||
195 | |||
196 | failure: | ||
197 | /* Unknown identity or protocol error. Send failure. */ | ||
157 | buffer_put_char(&msg, SSH_AGENT_FAILURE); | 198 | buffer_put_char(&msg, SSH_AGENT_FAILURE); |
158 | send: | 199 | send: |
159 | buffer_put_int(&e->output, buffer_len(&msg)); | 200 | buffer_put_int(&e->output, buffer_len(&msg)); |
201 | buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg)); | ||
202 | key_free(key); | ||
203 | BN_clear_free(challenge); | ||
204 | buffer_free(&msg); | ||
205 | } | ||
206 | |||
207 | /* ssh2 only */ | ||
208 | void | ||
209 | process_sign_request2(SocketEntry *e) | ||
210 | { | ||
211 | extern int datafellows; | ||
212 | Key *key, *private; | ||
213 | unsigned char *blob, *data, *signature = NULL; | ||
214 | unsigned int blen, dlen, slen = 0; | ||
215 | Buffer msg; | ||
216 | int ok = -1; | ||
217 | |||
218 | datafellows = 0; | ||
219 | |||
220 | blob = buffer_get_string(&e->input, &blen); | ||
221 | data = buffer_get_string(&e->input, &dlen); | ||
222 | |||
223 | key = dsa_key_from_blob(blob, blen); | ||
224 | if (key != NULL) { | ||
225 | private = lookup_private_key(key, NULL, 2); | ||
226 | if (private != NULL) | ||
227 | ok = dsa_sign(private, &signature, &slen, data, dlen); | ||
228 | } | ||
229 | key_free(key); | ||
230 | buffer_init(&msg); | ||
231 | if (ok == 0) { | ||
232 | buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE); | ||
233 | buffer_put_string(&msg, signature, slen); | ||
234 | } else { | ||
235 | buffer_put_char(&msg, SSH_AGENT_FAILURE); | ||
236 | } | ||
237 | buffer_put_int(&e->output, buffer_len(&msg)); | ||
160 | buffer_append(&e->output, buffer_ptr(&msg), | 238 | buffer_append(&e->output, buffer_ptr(&msg), |
161 | buffer_len(&msg)); | 239 | buffer_len(&msg)); |
162 | buffer_free(&msg); | 240 | buffer_free(&msg); |
163 | BN_clear_free(pub_e); | 241 | xfree(data); |
164 | BN_clear_free(pub_n); | 242 | xfree(blob); |
165 | BN_clear_free(challenge); | 243 | if (signature != NULL) |
244 | xfree(signature); | ||
166 | } | 245 | } |
167 | 246 | ||
247 | /* shared */ | ||
168 | void | 248 | void |
169 | process_remove_identity(SocketEntry *e) | 249 | process_remove_identity(SocketEntry *e, int version) |
170 | { | 250 | { |
251 | Key *key = NULL, *private; | ||
252 | unsigned char *blob; | ||
253 | unsigned int blen; | ||
171 | unsigned int bits; | 254 | unsigned int bits; |
172 | unsigned int i; | 255 | int success = 0; |
173 | BIGNUM *dummy, *n; | 256 | |
174 | 257 | switch(version){ | |
175 | dummy = BN_new(); | 258 | case 1: |
176 | n = BN_new(); | 259 | key = key_new(KEY_RSA); |
177 | 260 | bits = buffer_get_int(&e->input); | |
178 | /* Get the key from the packet. */ | 261 | buffer_get_bignum(&e->input, key->rsa->e); |
179 | bits = buffer_get_int(&e->input); | 262 | buffer_get_bignum(&e->input, key->rsa->n); |
180 | buffer_get_bignum(&e->input, dummy); | 263 | |
181 | buffer_get_bignum(&e->input, n); | 264 | if (bits != key_size(key)) |
182 | 265 | log("Warning: identity keysize mismatch: actual %d, announced %d", | |
183 | if (bits != BN_num_bits(n)) | 266 | key_size(key), bits); |
184 | log("Warning: identity keysize mismatch: actual %d, announced %d", | 267 | break; |
185 | BN_num_bits(n), bits); | 268 | case 2: |
186 | 269 | blob = buffer_get_string(&e->input, &blen); | |
187 | /* Check if we have the key. */ | 270 | key = dsa_key_from_blob(blob, blen); |
188 | for (i = 0; i < num_identities; i++) | 271 | xfree(blob); |
189 | if (BN_cmp(identities[i].key->n, n) == 0) { | 272 | break; |
273 | } | ||
274 | if (key != NULL) { | ||
275 | int idx; | ||
276 | private = lookup_private_key(key, &idx, version); | ||
277 | if (private != NULL) { | ||
190 | /* | 278 | /* |
191 | * We have this key. Free the old key. Since we | 279 | * We have this key. Free the old key. Since we |
192 | * don\'t want to leave empty slots in the middle of | 280 | * don\'t want to leave empty slots in the middle of |
193 | * the array, we actually free the key there and copy | 281 | * the array, we actually free the key there and copy |
194 | * data from the last entry. | 282 | * data from the last entry. |
195 | */ | 283 | */ |
196 | RSA_free(identities[i].key); | 284 | Idtab *tab = idtab_lookup(version); |
197 | xfree(identities[i].comment); | 285 | key_free(tab->identities[idx].key); |
198 | if (i < num_identities - 1) | 286 | xfree(tab->identities[idx].comment); |
199 | identities[i] = identities[num_identities - 1]; | 287 | if (idx != tab->nentries) |
200 | num_identities--; | 288 | tab->identities[idx] = tab->identities[tab->nentries]; |
201 | BN_clear_free(dummy); | 289 | tab->nentries--; |
202 | BN_clear_free(n); | 290 | success = 1; |
203 | |||
204 | /* Send success. */ | ||
205 | buffer_put_int(&e->output, 1); | ||
206 | buffer_put_char(&e->output, SSH_AGENT_SUCCESS); | ||
207 | return; | ||
208 | } | 291 | } |
209 | /* We did not have the key. */ | 292 | key_free(key); |
210 | BN_clear(dummy); | 293 | } |
211 | BN_clear(n); | ||
212 | |||
213 | /* Send failure. */ | ||
214 | buffer_put_int(&e->output, 1); | 294 | buffer_put_int(&e->output, 1); |
215 | buffer_put_char(&e->output, SSH_AGENT_FAILURE); | 295 | buffer_put_char(&e->output, |
296 | success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); | ||
216 | } | 297 | } |
217 | 298 | ||
218 | /* | ||
219 | * Removes all identities from the agent. | ||
220 | */ | ||
221 | void | 299 | void |
222 | process_remove_all_identities(SocketEntry *e) | 300 | process_remove_all_identities(SocketEntry *e, int version) |
223 | { | 301 | { |
224 | unsigned int i; | 302 | unsigned int i; |
303 | Idtab *tab = idtab_lookup(version); | ||
225 | 304 | ||
226 | /* Loop over all identities and clear the keys. */ | 305 | /* Loop over all identities and clear the keys. */ |
227 | for (i = 0; i < num_identities; i++) { | 306 | for (i = 0; i < tab->nentries; i++) { |
228 | RSA_free(identities[i].key); | 307 | key_free(tab->identities[i].key); |
229 | xfree(identities[i].comment); | 308 | xfree(tab->identities[i].comment); |
230 | } | 309 | } |
231 | 310 | ||
232 | /* Mark that there are no identities. */ | 311 | /* Mark that there are no identities. */ |
233 | num_identities = 0; | 312 | tab->nentries = 0; |
234 | 313 | ||
235 | /* Send success. */ | 314 | /* Send success. */ |
236 | buffer_put_int(&e->output, 1); | 315 | buffer_put_int(&e->output, 1); |
@@ -238,79 +317,108 @@ process_remove_all_identities(SocketEntry *e) | |||
238 | return; | 317 | return; |
239 | } | 318 | } |
240 | 319 | ||
241 | /* | ||
242 | * Adds an identity to the agent. | ||
243 | */ | ||
244 | void | 320 | void |
245 | process_add_identity(SocketEntry *e) | 321 | process_add_identity(SocketEntry *e, int version) |
246 | { | 322 | { |
247 | RSA *k; | 323 | Key *k = NULL; |
248 | int i; | 324 | RSA *rsa; |
249 | BIGNUM *aux; | 325 | BIGNUM *aux; |
250 | BN_CTX *ctx; | 326 | BN_CTX *ctx; |
327 | char *type; | ||
328 | char *comment; | ||
329 | int success = 0; | ||
330 | Idtab *tab = idtab_lookup(version); | ||
251 | 331 | ||
252 | if (num_identities == 0) | 332 | switch (version) { |
253 | identities = xmalloc(sizeof(Identity)); | 333 | case 1: |
254 | else | 334 | k = key_new(KEY_RSA); |
255 | identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity)); | 335 | rsa = k->rsa; |
256 | |||
257 | identities[num_identities].key = RSA_new(); | ||
258 | k = identities[num_identities].key; | ||
259 | buffer_get_int(&e->input); /* bits */ | ||
260 | k->n = BN_new(); | ||
261 | buffer_get_bignum(&e->input, k->n); | ||
262 | k->e = BN_new(); | ||
263 | buffer_get_bignum(&e->input, k->e); | ||
264 | k->d = BN_new(); | ||
265 | buffer_get_bignum(&e->input, k->d); | ||
266 | k->iqmp = BN_new(); | ||
267 | buffer_get_bignum(&e->input, k->iqmp); | ||
268 | /* SSH and SSL have p and q swapped */ | ||
269 | k->q = BN_new(); | ||
270 | buffer_get_bignum(&e->input, k->q); /* p */ | ||
271 | k->p = BN_new(); | ||
272 | buffer_get_bignum(&e->input, k->p); /* q */ | ||
273 | |||
274 | /* Generate additional parameters */ | ||
275 | aux = BN_new(); | ||
276 | ctx = BN_CTX_new(); | ||
277 | |||
278 | BN_sub(aux, k->q, BN_value_one()); | ||
279 | k->dmq1 = BN_new(); | ||
280 | BN_mod(k->dmq1, k->d, aux, ctx); | ||
281 | |||
282 | BN_sub(aux, k->p, BN_value_one()); | ||
283 | k->dmp1 = BN_new(); | ||
284 | BN_mod(k->dmp1, k->d, aux, ctx); | ||
285 | |||
286 | BN_clear_free(aux); | ||
287 | BN_CTX_free(ctx); | ||
288 | |||
289 | identities[num_identities].comment = buffer_get_string(&e->input, NULL); | ||
290 | |||
291 | /* Check if we already have the key. */ | ||
292 | for (i = 0; i < num_identities; i++) | ||
293 | if (BN_cmp(identities[i].key->n, k->n) == 0) { | ||
294 | /* | ||
295 | * We already have this key. Clear and free the new | ||
296 | * data and return success. | ||
297 | */ | ||
298 | RSA_free(k); | ||
299 | xfree(identities[num_identities].comment); | ||
300 | 336 | ||
301 | /* Send success. */ | 337 | /* allocate mem for private key */ |
302 | buffer_put_int(&e->output, 1); | 338 | /* XXX rsa->n and rsa->e are already allocated */ |
303 | buffer_put_char(&e->output, SSH_AGENT_SUCCESS); | 339 | rsa->d = BN_new(); |
304 | return; | 340 | rsa->iqmp = BN_new(); |
341 | rsa->q = BN_new(); | ||
342 | rsa->p = BN_new(); | ||
343 | rsa->dmq1 = BN_new(); | ||
344 | rsa->dmp1 = BN_new(); | ||
345 | |||
346 | buffer_get_int(&e->input); /* ignored */ | ||
347 | |||
348 | buffer_get_bignum(&e->input, rsa->n); | ||
349 | buffer_get_bignum(&e->input, rsa->e); | ||
350 | buffer_get_bignum(&e->input, rsa->d); | ||
351 | buffer_get_bignum(&e->input, rsa->iqmp); | ||
352 | |||
353 | /* SSH and SSL have p and q swapped */ | ||
354 | buffer_get_bignum(&e->input, rsa->q); /* p */ | ||
355 | buffer_get_bignum(&e->input, rsa->p); /* q */ | ||
356 | |||
357 | /* Generate additional parameters */ | ||
358 | aux = BN_new(); | ||
359 | ctx = BN_CTX_new(); | ||
360 | |||
361 | BN_sub(aux, rsa->q, BN_value_one()); | ||
362 | BN_mod(rsa->dmq1, rsa->d, aux, ctx); | ||
363 | |||
364 | BN_sub(aux, rsa->p, BN_value_one()); | ||
365 | BN_mod(rsa->dmp1, rsa->d, aux, ctx); | ||
366 | |||
367 | BN_clear_free(aux); | ||
368 | BN_CTX_free(ctx); | ||
369 | |||
370 | break; | ||
371 | case 2: | ||
372 | type = buffer_get_string(&e->input, NULL); | ||
373 | if (strcmp(type, KEX_DSS)) { | ||
374 | buffer_clear(&e->input); | ||
375 | xfree(type); | ||
376 | goto send; | ||
305 | } | 377 | } |
306 | /* Increment the number of identities. */ | 378 | xfree(type); |
307 | num_identities++; | ||
308 | 379 | ||
309 | /* Send a success message. */ | 380 | k = key_new(KEY_DSA); |
381 | |||
382 | /* allocate mem for private key */ | ||
383 | k->dsa->priv_key = BN_new(); | ||
384 | |||
385 | buffer_get_bignum2(&e->input, k->dsa->p); | ||
386 | buffer_get_bignum2(&e->input, k->dsa->q); | ||
387 | buffer_get_bignum2(&e->input, k->dsa->g); | ||
388 | buffer_get_bignum2(&e->input, k->dsa->pub_key); | ||
389 | buffer_get_bignum2(&e->input, k->dsa->priv_key); | ||
390 | |||
391 | break; | ||
392 | } | ||
393 | |||
394 | comment = buffer_get_string(&e->input, NULL); | ||
395 | if (k == NULL) { | ||
396 | xfree(comment); | ||
397 | goto send; | ||
398 | } | ||
399 | success = 1; | ||
400 | if (lookup_private_key(k, NULL, version) == NULL) { | ||
401 | if (tab->nentries == 0) | ||
402 | tab->identities = xmalloc(sizeof(Identity)); | ||
403 | else | ||
404 | tab->identities = xrealloc(tab->identities, | ||
405 | (tab->nentries + 1) * sizeof(Identity)); | ||
406 | tab->identities[tab->nentries].key = k; | ||
407 | tab->identities[tab->nentries].comment = comment; | ||
408 | /* Increment the number of identities. */ | ||
409 | tab->nentries++; | ||
410 | } else { | ||
411 | key_free(k); | ||
412 | xfree(comment); | ||
413 | } | ||
414 | send: | ||
310 | buffer_put_int(&e->output, 1); | 415 | buffer_put_int(&e->output, 1); |
311 | buffer_put_char(&e->output, SSH_AGENT_SUCCESS); | 416 | buffer_put_char(&e->output, |
417 | success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); | ||
312 | } | 418 | } |
313 | 419 | ||
420 | /* dispatch incoming messages */ | ||
421 | |||
314 | void | 422 | void |
315 | process_message(SocketEntry *e) | 423 | process_message(SocketEntry *e) |
316 | { | 424 | { |
@@ -333,20 +441,37 @@ process_message(SocketEntry *e) | |||
333 | type = buffer_get_char(&e->input); | 441 | type = buffer_get_char(&e->input); |
334 | 442 | ||
335 | switch (type) { | 443 | switch (type) { |
336 | case SSH_AGENTC_REQUEST_RSA_IDENTITIES: | 444 | /* ssh1 */ |
337 | process_request_identity(e); | ||
338 | break; | ||
339 | case SSH_AGENTC_RSA_CHALLENGE: | 445 | case SSH_AGENTC_RSA_CHALLENGE: |
340 | process_authentication_challenge(e); | 446 | process_authentication_challenge1(e); |
447 | break; | ||
448 | case SSH_AGENTC_REQUEST_RSA_IDENTITIES: | ||
449 | process_request_identities(e, 1); | ||
341 | break; | 450 | break; |
342 | case SSH_AGENTC_ADD_RSA_IDENTITY: | 451 | case SSH_AGENTC_ADD_RSA_IDENTITY: |
343 | process_add_identity(e); | 452 | process_add_identity(e, 1); |
344 | break; | 453 | break; |
345 | case SSH_AGENTC_REMOVE_RSA_IDENTITY: | 454 | case SSH_AGENTC_REMOVE_RSA_IDENTITY: |
346 | process_remove_identity(e); | 455 | process_remove_identity(e, 1); |
347 | break; | 456 | break; |
348 | case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES: | 457 | case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES: |
349 | process_remove_all_identities(e); | 458 | process_remove_all_identities(e, 1); |
459 | break; | ||
460 | /* ssh2 */ | ||
461 | case SSH2_AGENTC_SIGN_REQUEST: | ||
462 | process_sign_request2(e); | ||
463 | break; | ||
464 | case SSH2_AGENTC_REQUEST_IDENTITIES: | ||
465 | process_request_identities(e, 2); | ||
466 | break; | ||
467 | case SSH2_AGENTC_ADD_IDENTITY: | ||
468 | process_add_identity(e, 2); | ||
469 | break; | ||
470 | case SSH2_AGENTC_REMOVE_IDENTITY: | ||
471 | process_remove_identity(e, 2); | ||
472 | break; | ||
473 | case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: | ||
474 | process_remove_all_identities(e, 2); | ||
350 | break; | 475 | break; |
351 | default: | 476 | default: |
352 | /* Unknown message. Respond with failure. */ | 477 | /* Unknown message. Respond with failure. */ |
@@ -511,9 +636,9 @@ main(int ac, char **av) | |||
511 | pid_t pid; | 636 | pid_t pid; |
512 | char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid]; | 637 | char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid]; |
513 | extern int optind; | 638 | extern int optind; |
514 | 639 | ||
515 | init_rng(); | 640 | init_rng(); |
516 | 641 | ||
517 | /* check if RSA support exists */ | 642 | /* check if RSA support exists */ |
518 | if (rsa_alive() == 0) { | 643 | if (rsa_alive() == 0) { |
519 | fprintf(stderr, | 644 | fprintf(stderr, |
@@ -654,6 +779,7 @@ main(int ac, char **av) | |||
654 | signal(SIGALRM, check_parent_exists); | 779 | signal(SIGALRM, check_parent_exists); |
655 | alarm(10); | 780 | alarm(10); |
656 | } | 781 | } |
782 | idtab_init(); | ||
657 | signal(SIGINT, SIG_IGN); | 783 | signal(SIGINT, SIG_IGN); |
658 | signal(SIGPIPE, SIG_IGN); | 784 | signal(SIGPIPE, SIG_IGN); |
659 | signal(SIGHUP, cleanup_exit); | 785 | signal(SIGHUP, cleanup_exit); |