diff options
-rw-r--r-- | authfd.c | 840 | ||||
-rw-r--r-- | authfd.h | 60 | ||||
-rw-r--r-- | clientloop.c | 20 | ||||
-rw-r--r-- | monitor.c | 42 | ||||
-rw-r--r-- | session.c | 10 | ||||
-rw-r--r-- | ssh-add.c | 259 | ||||
-rw-r--r-- | ssh.c | 11 | ||||
-rw-r--r-- | sshconnect1.c | 72 | ||||
-rw-r--r-- | sshconnect2.c | 171 | ||||
-rw-r--r-- | sshd.c | 43 |
10 files changed, 846 insertions, 682 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: authfd.c,v 1.93 2014/04/29 18:01:49 markus Exp $ */ | 1 | /* $OpenBSD: authfd.c,v 1.94 2015/01/14 20:05:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -47,124 +47,121 @@ | |||
47 | #include <stdarg.h> | 47 | #include <stdarg.h> |
48 | #include <string.h> | 48 | #include <string.h> |
49 | #include <unistd.h> | 49 | #include <unistd.h> |
50 | #include <errno.h> | ||
50 | 51 | ||
51 | #include "xmalloc.h" | 52 | #include "xmalloc.h" |
52 | #include "ssh.h" | 53 | #include "ssh.h" |
53 | #include "rsa.h" | 54 | #include "rsa.h" |
54 | #include "buffer.h" | 55 | #include "sshbuf.h" |
55 | #include "key.h" | 56 | #include "sshkey.h" |
56 | #include "authfd.h" | 57 | #include "authfd.h" |
57 | #include "cipher.h" | 58 | #include "cipher.h" |
58 | #include "kex.h" | ||
59 | #include "compat.h" | 59 | #include "compat.h" |
60 | #include "log.h" | 60 | #include "log.h" |
61 | #include "atomicio.h" | 61 | #include "atomicio.h" |
62 | #include "misc.h" | 62 | #include "misc.h" |
63 | #include "ssherr.h" | ||
63 | 64 | ||
64 | static int agent_present = 0; | 65 | #define MAX_AGENT_IDENTITIES 2048 /* Max keys in agent reply */ |
65 | 66 | #define MAX_AGENT_REPLY_LEN (256 * 1024) /* Max bytes in agent reply */ | |
66 | /* helper */ | ||
67 | int decode_reply(int type); | ||
68 | 67 | ||
69 | /* macro to check for "agent failure" message */ | 68 | /* macro to check for "agent failure" message */ |
70 | #define agent_failed(x) \ | 69 | #define agent_failed(x) \ |
71 | ((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE) || \ | 70 | ((x == SSH_AGENT_FAILURE) || \ |
71 | (x == SSH_COM_AGENT2_FAILURE) || \ | ||
72 | (x == SSH2_AGENT_FAILURE)) | 72 | (x == SSH2_AGENT_FAILURE)) |
73 | 73 | ||
74 | int | 74 | /* Convert success/failure response from agent to a err.h status */ |
75 | ssh_agent_present(void) | 75 | static int |
76 | decode_reply(u_char type) | ||
76 | { | 77 | { |
77 | int authfd; | 78 | if (agent_failed(type)) |
78 | 79 | return SSH_ERR_AGENT_FAILURE; | |
79 | if (agent_present) | 80 | else if (type == SSH_AGENT_SUCCESS) |
80 | return 1; | ||
81 | if ((authfd = ssh_get_authentication_socket()) == -1) | ||
82 | return 0; | 81 | return 0; |
83 | else { | 82 | else |
84 | ssh_close_authentication_socket(authfd); | 83 | return SSH_ERR_INVALID_FORMAT; |
85 | return 1; | ||
86 | } | ||
87 | } | 84 | } |
88 | 85 | ||
89 | /* Returns the number of the authentication fd, or -1 if there is none. */ | 86 | /* Returns the number of the authentication fd, or -1 if there is none. */ |
90 | |||
91 | int | 87 | int |
92 | ssh_get_authentication_socket(void) | 88 | ssh_get_authentication_socket(int *fdp) |
93 | { | 89 | { |
94 | const char *authsocket; | 90 | const char *authsocket; |
95 | int sock; | 91 | int sock, oerrno; |
96 | struct sockaddr_un sunaddr; | 92 | struct sockaddr_un sunaddr; |
97 | 93 | ||
94 | if (fdp != NULL) | ||
95 | *fdp = -1; | ||
96 | |||
98 | authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); | 97 | authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); |
99 | if (!authsocket) | 98 | if (!authsocket) |
100 | return -1; | 99 | return SSH_ERR_AGENT_NOT_PRESENT; |
101 | 100 | ||
102 | memset(&sunaddr, 0, sizeof(sunaddr)); | 101 | memset(&sunaddr, 0, sizeof(sunaddr)); |
103 | sunaddr.sun_family = AF_UNIX; | 102 | sunaddr.sun_family = AF_UNIX; |
104 | strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); | 103 | strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); |
105 | 104 | ||
106 | sock = socket(AF_UNIX, SOCK_STREAM, 0); | 105 | if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) |
107 | if (sock < 0) | 106 | return SSH_ERR_SYSTEM_ERROR; |
108 | return -1; | ||
109 | 107 | ||
110 | /* close on exec */ | 108 | /* close on exec */ |
111 | if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) { | 109 | if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1 || |
110 | connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) { | ||
111 | oerrno = errno; | ||
112 | close(sock); | 112 | close(sock); |
113 | return -1; | 113 | errno = oerrno; |
114 | return SSH_ERR_SYSTEM_ERROR; | ||
114 | } | 115 | } |
115 | if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { | 116 | if (fdp != NULL) |
117 | *fdp = sock; | ||
118 | else | ||
116 | close(sock); | 119 | close(sock); |
117 | return -1; | 120 | return 0; |
118 | } | ||
119 | agent_present = 1; | ||
120 | return sock; | ||
121 | } | 121 | } |
122 | 122 | ||
123 | /* Communicate with agent: send request and read reply */ | ||
123 | static int | 124 | static int |
124 | ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply) | 125 | ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply) |
125 | { | 126 | { |
126 | u_int l, len; | 127 | int r; |
128 | size_t l, len; | ||
127 | char buf[1024]; | 129 | char buf[1024]; |
128 | 130 | ||
129 | /* Get the length of the message, and format it in the buffer. */ | 131 | /* Get the length of the message, and format it in the buffer. */ |
130 | len = buffer_len(request); | 132 | len = sshbuf_len(request); |
131 | put_u32(buf, len); | 133 | put_u32(buf, len); |
132 | 134 | ||
133 | /* Send the length and then the packet to the agent. */ | 135 | /* Send the length and then the packet to the agent. */ |
134 | if (atomicio(vwrite, auth->fd, buf, 4) != 4 || | 136 | if (atomicio(vwrite, sock, buf, 4) != 4 || |
135 | atomicio(vwrite, auth->fd, buffer_ptr(request), | 137 | atomicio(vwrite, sock, (u_char *)sshbuf_ptr(request), |
136 | buffer_len(request)) != buffer_len(request)) { | 138 | sshbuf_len(request)) != sshbuf_len(request)) |
137 | error("Error writing to authentication socket."); | 139 | return SSH_ERR_AGENT_COMMUNICATION; |
138 | return 0; | ||
139 | } | ||
140 | /* | 140 | /* |
141 | * Wait for response from the agent. First read the length of the | 141 | * Wait for response from the agent. First read the length of the |
142 | * response packet. | 142 | * response packet. |
143 | */ | 143 | */ |
144 | if (atomicio(read, auth->fd, buf, 4) != 4) { | 144 | if (atomicio(read, sock, buf, 4) != 4) |
145 | error("Error reading response length from authentication socket."); | 145 | return SSH_ERR_AGENT_COMMUNICATION; |
146 | return 0; | ||
147 | } | ||
148 | 146 | ||
149 | /* Extract the length, and check it for sanity. */ | 147 | /* Extract the length, and check it for sanity. */ |
150 | len = get_u32(buf); | 148 | len = get_u32(buf); |
151 | if (len > 256 * 1024) | 149 | if (len > MAX_AGENT_REPLY_LEN) |
152 | fatal("Authentication response too long: %u", len); | 150 | return SSH_ERR_INVALID_FORMAT; |
153 | 151 | ||
154 | /* Read the rest of the response in to the buffer. */ | 152 | /* Read the rest of the response in to the buffer. */ |
155 | buffer_clear(reply); | 153 | sshbuf_reset(reply); |
156 | while (len > 0) { | 154 | while (len > 0) { |
157 | l = len; | 155 | l = len; |
158 | if (l > sizeof(buf)) | 156 | if (l > sizeof(buf)) |
159 | l = sizeof(buf); | 157 | l = sizeof(buf); |
160 | if (atomicio(read, auth->fd, buf, l) != l) { | 158 | if (atomicio(read, sock, buf, l) != l) |
161 | error("Error reading response from authentication socket."); | 159 | return SSH_ERR_AGENT_COMMUNICATION; |
162 | return 0; | 160 | if ((r = sshbuf_put(reply, buf, l)) != 0) |
163 | } | 161 | return r; |
164 | buffer_append(reply, buf, l); | ||
165 | len -= l; | 162 | len -= l; |
166 | } | 163 | } |
167 | return 1; | 164 | return 0; |
168 | } | 165 | } |
169 | 166 | ||
170 | /* | 167 | /* |
@@ -172,7 +169,6 @@ ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply | |||
172 | * obtained). The argument must have been returned by | 169 | * obtained). The argument must have been returned by |
173 | * ssh_get_authentication_socket(). | 170 | * ssh_get_authentication_socket(). |
174 | */ | 171 | */ |
175 | |||
176 | void | 172 | void |
177 | ssh_close_authentication_socket(int sock) | 173 | ssh_close_authentication_socket(int sock) |
178 | { | 174 | { |
@@ -180,80 +176,103 @@ ssh_close_authentication_socket(int sock) | |||
180 | close(sock); | 176 | close(sock); |
181 | } | 177 | } |
182 | 178 | ||
183 | /* | 179 | /* Lock/unlock agent */ |
184 | * Opens and connects a private socket for communication with the | 180 | int |
185 | * authentication agent. Returns the file descriptor (which must be | 181 | ssh_lock_agent(int sock, int lock, const char *password) |
186 | * shut down and closed by the caller when no longer needed). | ||
187 | * Returns NULL if an error occurred and the connection could not be | ||
188 | * opened. | ||
189 | */ | ||
190 | |||
191 | AuthenticationConnection * | ||
192 | ssh_get_authentication_connection(void) | ||
193 | { | 182 | { |
194 | AuthenticationConnection *auth; | 183 | int r; |
195 | int sock; | 184 | u_char type = lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK; |
196 | 185 | struct sshbuf *msg; | |
197 | sock = ssh_get_authentication_socket(); | 186 | |
198 | 187 | if ((msg = sshbuf_new()) == NULL) | |
199 | /* | 188 | return SSH_ERR_ALLOC_FAIL; |
200 | * Fail if we couldn't obtain a connection. This happens if we | 189 | if ((r = sshbuf_put_u8(msg, type)) != 0 || |
201 | * exited due to a timeout. | 190 | (r = sshbuf_put_cstring(msg, password)) != 0) |
202 | */ | 191 | goto out; |
203 | if (sock < 0) | 192 | if ((r = ssh_request_reply(sock, msg, msg)) != 0) |
204 | return NULL; | 193 | goto out; |
205 | 194 | if ((r = sshbuf_get_u8(msg, &type)) != 0) | |
206 | auth = xcalloc(1, sizeof(*auth)); | 195 | goto out; |
207 | auth->fd = sock; | 196 | r = decode_reply(type); |
208 | buffer_init(&auth->identities); | 197 | out: |
209 | auth->howmany = 0; | 198 | sshbuf_free(msg); |
210 | 199 | return r; | |
211 | return auth; | ||
212 | } | 200 | } |
213 | 201 | ||
214 | /* | 202 | #ifdef WITH_SSH1 |
215 | * Closes the connection to the authentication agent and frees any associated | 203 | static int |
216 | * memory. | 204 | deserialise_identity1(struct sshbuf *ids, struct sshkey **keyp, char **commentp) |
217 | */ | ||
218 | |||
219 | void | ||
220 | ssh_close_authentication_connection(AuthenticationConnection *auth) | ||
221 | { | 205 | { |
222 | buffer_free(&auth->identities); | 206 | struct sshkey *key; |
223 | close(auth->fd); | 207 | int r, keybits; |
224 | free(auth); | 208 | u_int32_t bits; |
209 | char *comment = NULL; | ||
210 | |||
211 | if ((key = sshkey_new(KEY_RSA1)) == NULL) | ||
212 | return SSH_ERR_ALLOC_FAIL; | ||
213 | if ((r = sshbuf_get_u32(ids, &bits)) != 0 || | ||
214 | (r = sshbuf_get_bignum1(ids, key->rsa->e)) != 0 || | ||
215 | (r = sshbuf_get_bignum1(ids, key->rsa->n)) != 0 || | ||
216 | (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0) | ||
217 | goto out; | ||
218 | keybits = BN_num_bits(key->rsa->n); | ||
219 | /* XXX previously we just warned here. I think we should be strict */ | ||
220 | if (keybits < 0 || bits != (u_int)keybits) { | ||
221 | r = SSH_ERR_KEY_BITS_MISMATCH; | ||
222 | goto out; | ||
223 | } | ||
224 | if (keyp != NULL) { | ||
225 | *keyp = key; | ||
226 | key = NULL; | ||
227 | } | ||
228 | if (commentp != NULL) { | ||
229 | *commentp = comment; | ||
230 | comment = NULL; | ||
231 | } | ||
232 | r = 0; | ||
233 | out: | ||
234 | sshkey_free(key); | ||
235 | free(comment); | ||
236 | return r; | ||
225 | } | 237 | } |
238 | #endif | ||
226 | 239 | ||
227 | /* Lock/unlock agent */ | 240 | static int |
228 | int | 241 | deserialise_identity2(struct sshbuf *ids, struct sshkey **keyp, char **commentp) |
229 | ssh_lock_agent(AuthenticationConnection *auth, int lock, const char *password) | ||
230 | { | 242 | { |
231 | int type; | 243 | int r; |
232 | Buffer msg; | 244 | char *comment = NULL; |
233 | 245 | const u_char *blob; | |
234 | buffer_init(&msg); | 246 | size_t blen; |
235 | buffer_put_char(&msg, lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK); | 247 | |
236 | buffer_put_cstring(&msg, password); | 248 | if ((r = sshbuf_get_string_direct(ids, &blob, &blen)) != 0 || |
237 | 249 | (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0) | |
238 | if (ssh_request_reply(auth, &msg, &msg) == 0) { | 250 | goto out; |
239 | buffer_free(&msg); | 251 | if ((r = sshkey_from_blob(blob, blen, keyp)) != 0) |
240 | return 0; | 252 | goto out; |
253 | if (commentp != NULL) { | ||
254 | *commentp = comment; | ||
255 | comment = NULL; | ||
241 | } | 256 | } |
242 | type = buffer_get_char(&msg); | 257 | r = 0; |
243 | buffer_free(&msg); | 258 | out: |
244 | return decode_reply(type); | 259 | free(comment); |
260 | return r; | ||
245 | } | 261 | } |
246 | 262 | ||
247 | /* | 263 | /* |
248 | * Returns the first authentication identity held by the agent. | 264 | * Fetch list of identities held by the agent. |
249 | */ | 265 | */ |
250 | |||
251 | int | 266 | int |
252 | ssh_get_num_identities(AuthenticationConnection *auth, int version) | 267 | ssh_fetch_identitylist(int sock, int version, struct ssh_identitylist **idlp) |
253 | { | 268 | { |
254 | int type, code1 = 0, code2 = 0; | 269 | u_char type, code1 = 0, code2 = 0; |
255 | Buffer request; | 270 | u_int32_t num, i; |
271 | struct sshbuf *msg; | ||
272 | struct ssh_identitylist *idl = NULL; | ||
273 | int r; | ||
256 | 274 | ||
275 | /* Determine request and expected response types */ | ||
257 | switch (version) { | 276 | switch (version) { |
258 | case 1: | 277 | case 1: |
259 | code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES; | 278 | code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES; |
@@ -264,238 +283,270 @@ ssh_get_num_identities(AuthenticationConnection *auth, int version) | |||
264 | code2 = SSH2_AGENT_IDENTITIES_ANSWER; | 283 | code2 = SSH2_AGENT_IDENTITIES_ANSWER; |
265 | break; | 284 | break; |
266 | default: | 285 | default: |
267 | return 0; | 286 | return SSH_ERR_INVALID_ARGUMENT; |
268 | } | 287 | } |
269 | 288 | ||
270 | /* | 289 | /* |
271 | * Send a message to the agent requesting for a list of the | 290 | * Send a message to the agent requesting for a list of the |
272 | * identities it can represent. | 291 | * identities it can represent. |
273 | */ | 292 | */ |
274 | buffer_init(&request); | 293 | if ((msg = sshbuf_new()) == NULL) |
275 | buffer_put_char(&request, code1); | 294 | return SSH_ERR_ALLOC_FAIL; |
295 | if ((r = sshbuf_put_u8(msg, code1)) != 0) | ||
296 | goto out; | ||
276 | 297 | ||
277 | buffer_clear(&auth->identities); | 298 | if ((r = ssh_request_reply(sock, msg, msg)) != 0) |
278 | if (ssh_request_reply(auth, &request, &auth->identities) == 0) { | 299 | goto out; |
279 | buffer_free(&request); | ||
280 | return 0; | ||
281 | } | ||
282 | buffer_free(&request); | ||
283 | 300 | ||
284 | /* Get message type, and verify that we got a proper answer. */ | 301 | /* Get message type, and verify that we got a proper answer. */ |
285 | type = buffer_get_char(&auth->identities); | 302 | if ((r = sshbuf_get_u8(msg, &type)) != 0) |
303 | goto out; | ||
286 | if (agent_failed(type)) { | 304 | if (agent_failed(type)) { |
287 | return 0; | 305 | r = SSH_ERR_AGENT_FAILURE; |
306 | goto out; | ||
288 | } else if (type != code2) { | 307 | } else if (type != code2) { |
289 | fatal("Bad authentication reply message type: %d", type); | 308 | r = SSH_ERR_INVALID_FORMAT; |
309 | goto out; | ||
290 | } | 310 | } |
291 | 311 | ||
292 | /* Get the number of entries in the response and check it for sanity. */ | 312 | /* Get the number of entries in the response and check it for sanity. */ |
293 | auth->howmany = buffer_get_int(&auth->identities); | 313 | if ((r = sshbuf_get_u32(msg, &num)) != 0) |
294 | if ((u_int)auth->howmany > 1024) | 314 | goto out; |
295 | fatal("Too many identities in authentication reply: %d", | 315 | if (num > MAX_AGENT_IDENTITIES) { |
296 | auth->howmany); | 316 | r = SSH_ERR_INVALID_FORMAT; |
297 | 317 | goto out; | |
298 | return auth->howmany; | 318 | } |
299 | } | 319 | if (num == 0) { |
300 | 320 | r = SSH_ERR_AGENT_NO_IDENTITIES; | |
301 | Key * | 321 | goto out; |
302 | ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version) | 322 | } |
303 | { | ||
304 | /* get number of identities and return the first entry (if any). */ | ||
305 | if (ssh_get_num_identities(auth, version) > 0) | ||
306 | return ssh_get_next_identity(auth, comment, version); | ||
307 | return NULL; | ||
308 | } | ||
309 | 323 | ||
310 | Key * | 324 | /* Deserialise the response into a list of keys/comments */ |
311 | ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version) | 325 | if ((idl = calloc(1, sizeof(*idl))) == NULL || |
312 | { | 326 | (idl->keys = calloc(num, sizeof(*idl->keys))) == NULL || |
327 | (idl->comments = calloc(num, sizeof(*idl->comments))) == NULL) { | ||
328 | r = SSH_ERR_ALLOC_FAIL; | ||
329 | goto out; | ||
330 | } | ||
331 | for (i = 0; i < num;) { | ||
332 | switch (version) { | ||
333 | case 1: | ||
313 | #ifdef WITH_SSH1 | 334 | #ifdef WITH_SSH1 |
314 | int keybits; | 335 | if ((r = deserialise_identity1(msg, |
315 | u_int bits; | 336 | &(idl->keys[i]), &(idl->comments[i]))) != 0) |
337 | goto out; | ||
316 | #endif | 338 | #endif |
317 | u_char *blob; | 339 | break; |
318 | u_int blen; | 340 | case 2: |
319 | Key *key = NULL; | 341 | if ((r = deserialise_identity2(msg, |
320 | 342 | &(idl->keys[i]), &(idl->comments[i]))) != 0) { | |
321 | /* Return failure if no more entries. */ | 343 | if (r == SSH_ERR_KEY_TYPE_UNKNOWN) { |
322 | if (auth->howmany <= 0) | 344 | /* Gracefully skip unknown key types */ |
323 | return NULL; | 345 | num--; |
346 | continue; | ||
347 | } else | ||
348 | goto out; | ||
349 | } | ||
350 | break; | ||
351 | } | ||
352 | i++; | ||
353 | } | ||
354 | idl->nkeys = num; | ||
355 | *idlp = idl; | ||
356 | idl = NULL; | ||
357 | r = 0; | ||
358 | out: | ||
359 | sshbuf_free(msg); | ||
360 | if (idl != NULL) | ||
361 | ssh_free_identitylist(idl); | ||
362 | return r; | ||
363 | } | ||
324 | 364 | ||
325 | /* | 365 | void |
326 | * Get the next entry from the packet. These will abort with a fatal | 366 | ssh_free_identitylist(struct ssh_identitylist *idl) |
327 | * error if the packet is too short or contains corrupt data. | 367 | { |
328 | */ | 368 | size_t i; |
329 | switch (version) { | 369 | |
330 | #ifdef WITH_SSH1 | 370 | if (idl == NULL) |
331 | case 1: | 371 | return; |
332 | key = key_new(KEY_RSA1); | 372 | for (i = 0; i < idl->nkeys; i++) { |
333 | bits = buffer_get_int(&auth->identities); | 373 | if (idl->keys != NULL) |
334 | buffer_get_bignum(&auth->identities, key->rsa->e); | 374 | sshkey_free(idl->keys[i]); |
335 | buffer_get_bignum(&auth->identities, key->rsa->n); | 375 | if (idl->comments != NULL) |
336 | *comment = buffer_get_string(&auth->identities, NULL); | 376 | free(idl->comments[i]); |
337 | keybits = BN_num_bits(key->rsa->n); | ||
338 | if (keybits < 0 || bits != (u_int)keybits) | ||
339 | logit("Warning: identity keysize mismatch: actual %d, announced %u", | ||
340 | BN_num_bits(key->rsa->n), bits); | ||
341 | break; | ||
342 | #endif | ||
343 | case 2: | ||
344 | blob = buffer_get_string(&auth->identities, &blen); | ||
345 | *comment = buffer_get_string(&auth->identities, NULL); | ||
346 | key = key_from_blob(blob, blen); | ||
347 | free(blob); | ||
348 | break; | ||
349 | default: | ||
350 | return NULL; | ||
351 | } | 377 | } |
352 | /* Decrement the number of remaining entries. */ | 378 | free(idl); |
353 | auth->howmany--; | ||
354 | return key; | ||
355 | } | 379 | } |
356 | 380 | ||
357 | /* | 381 | /* |
358 | * Generates a random challenge, sends it to the agent, and waits for | 382 | * Sends a challenge (typically from a server via ssh(1)) to the agent, |
359 | * response from the agent. Returns true (non-zero) if the agent gave the | 383 | * and waits for a response from the agent. |
360 | * correct answer, zero otherwise. Response type selects the style of | 384 | * Returns true (non-zero) if the agent gave the correct answer, zero |
361 | * response desired, with 0 corresponding to protocol version 1.0 (no longer | 385 | * otherwise. |
362 | * supported) and 1 corresponding to protocol version 1.1. | ||
363 | */ | 386 | */ |
364 | 387 | ||
365 | #ifdef WITH_SSH1 | 388 | #ifdef WITH_SSH1 |
366 | int | 389 | int |
367 | ssh_decrypt_challenge(AuthenticationConnection *auth, | 390 | ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge, |
368 | Key* key, BIGNUM *challenge, | 391 | u_char session_id[16], u_char response[16]) |
369 | u_char session_id[16], | ||
370 | u_int response_type, | ||
371 | u_char response[16]) | ||
372 | { | 392 | { |
373 | Buffer buffer; | 393 | struct sshbuf *msg; |
374 | int success = 0; | 394 | int r; |
375 | int i; | 395 | u_char type; |
376 | int type; | ||
377 | 396 | ||
378 | if (key->type != KEY_RSA1) | 397 | if (key->type != KEY_RSA1) |
379 | return 0; | 398 | return SSH_ERR_INVALID_ARGUMENT; |
380 | if (response_type == 0) { | 399 | if ((msg = sshbuf_new()) == NULL) |
381 | logit("Compatibility with ssh protocol version 1.0 no longer supported."); | 400 | return SSH_ERR_ALLOC_FAIL; |
382 | return 0; | 401 | if ((r = sshbuf_put_u8(msg, SSH_AGENTC_RSA_CHALLENGE)) != 0 || |
383 | } | 402 | (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 || |
384 | buffer_init(&buffer); | 403 | (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 || |
385 | buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE); | 404 | (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0 || |
386 | buffer_put_int(&buffer, BN_num_bits(key->rsa->n)); | 405 | (r = sshbuf_put_bignum1(msg, challenge)) != 0 || |
387 | buffer_put_bignum(&buffer, key->rsa->e); | 406 | (r = sshbuf_put(msg, session_id, 16)) != 0 || |
388 | buffer_put_bignum(&buffer, key->rsa->n); | 407 | (r = sshbuf_put_u32(msg, 1)) != 0) /* Response type for proto 1.1 */ |
389 | buffer_put_bignum(&buffer, challenge); | 408 | goto out; |
390 | buffer_append(&buffer, session_id, 16); | 409 | if ((r = ssh_request_reply(sock, msg, msg)) != 0) |
391 | buffer_put_int(&buffer, response_type); | 410 | goto out; |
392 | 411 | if ((r = sshbuf_get_u8(msg, &type)) != 0) | |
393 | if (ssh_request_reply(auth, &buffer, &buffer) == 0) { | 412 | goto out; |
394 | buffer_free(&buffer); | ||
395 | return 0; | ||
396 | } | ||
397 | type = buffer_get_char(&buffer); | ||
398 | |||
399 | if (agent_failed(type)) { | 413 | if (agent_failed(type)) { |
400 | logit("Agent admitted failure to authenticate using the key."); | 414 | r = SSH_ERR_AGENT_FAILURE; |
415 | goto out; | ||
401 | } else if (type != SSH_AGENT_RSA_RESPONSE) { | 416 | } else if (type != SSH_AGENT_RSA_RESPONSE) { |
402 | fatal("Bad authentication response: %d", type); | 417 | r = SSH_ERR_INVALID_FORMAT; |
403 | } else { | 418 | goto out; |
404 | success = 1; | ||
405 | /* | ||
406 | * Get the response from the packet. This will abort with a | ||
407 | * fatal error if the packet is corrupt. | ||
408 | */ | ||
409 | for (i = 0; i < 16; i++) | ||
410 | response[i] = (u_char)buffer_get_char(&buffer); | ||
411 | } | 419 | } |
412 | buffer_free(&buffer); | 420 | if ((r = sshbuf_get(msg, response, 16)) != 0) |
413 | return success; | 421 | goto out; |
422 | r = 0; | ||
423 | out: | ||
424 | sshbuf_free(msg); | ||
425 | return r; | ||
414 | } | 426 | } |
415 | #endif | 427 | #endif |
416 | 428 | ||
417 | /* ask agent to sign data, returns -1 on error, 0 on success */ | 429 | /* ask agent to sign data, returns err.h code on error, 0 on success */ |
418 | int | 430 | int |
419 | ssh_agent_sign(AuthenticationConnection *auth, | 431 | ssh_agent_sign(int sock, struct sshkey *key, |
420 | Key *key, | 432 | u_char **sigp, size_t *lenp, |
421 | u_char **sigp, u_int *lenp, | 433 | const u_char *data, size_t datalen, u_int compat) |
422 | u_char *data, u_int datalen) | ||
423 | { | 434 | { |
424 | extern int datafellows; | 435 | struct sshbuf *msg; |
425 | Buffer msg; | 436 | u_char *blob = NULL, type; |
426 | u_char *blob; | 437 | size_t blen = 0, len = 0; |
427 | u_int blen; | 438 | u_int flags = 0; |
428 | int type, flags = 0; | 439 | int r = SSH_ERR_INTERNAL_ERROR; |
429 | int ret = -1; | 440 | |
430 | 441 | if (sigp != NULL) | |
431 | if (key_to_blob(key, &blob, &blen) == 0) | 442 | *sigp = NULL; |
432 | return -1; | 443 | if (lenp != NULL) |
433 | 444 | *lenp = 0; | |
434 | if (datafellows & SSH_BUG_SIGBLOB) | 445 | |
435 | flags = SSH_AGENT_OLD_SIGNATURE; | 446 | if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE) |
436 | 447 | return SSH_ERR_INVALID_ARGUMENT; | |
437 | buffer_init(&msg); | 448 | if (compat & SSH_BUG_SIGBLOB) |
438 | buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST); | 449 | flags |= SSH_AGENT_OLD_SIGNATURE; |
439 | buffer_put_string(&msg, blob, blen); | 450 | if ((msg = sshbuf_new()) == NULL) |
440 | buffer_put_string(&msg, data, datalen); | 451 | return SSH_ERR_ALLOC_FAIL; |
441 | buffer_put_int(&msg, flags); | 452 | if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) |
442 | free(blob); | 453 | goto out; |
443 | 454 | if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 || | |
444 | if (ssh_request_reply(auth, &msg, &msg) == 0) { | 455 | (r = sshbuf_put_string(msg, blob, blen)) != 0 || |
445 | buffer_free(&msg); | 456 | (r = sshbuf_put_string(msg, data, datalen)) != 0 || |
446 | return -1; | 457 | (r = sshbuf_put_u32(msg, flags)) != 0) |
447 | } | 458 | goto out; |
448 | type = buffer_get_char(&msg); | 459 | if ((r = ssh_request_reply(sock, msg, msg) != 0)) |
460 | goto out; | ||
461 | if ((r = sshbuf_get_u8(msg, &type)) != 0) | ||
462 | goto out; | ||
449 | if (agent_failed(type)) { | 463 | if (agent_failed(type)) { |
450 | logit("Agent admitted failure to sign using the key."); | 464 | r = SSH_ERR_AGENT_FAILURE; |
465 | goto out; | ||
451 | } else if (type != SSH2_AGENT_SIGN_RESPONSE) { | 466 | } else if (type != SSH2_AGENT_SIGN_RESPONSE) { |
452 | fatal("Bad authentication response: %d", type); | 467 | r = SSH_ERR_INVALID_FORMAT; |
453 | } else { | 468 | goto out; |
454 | ret = 0; | 469 | } |
455 | *sigp = buffer_get_string(&msg, lenp); | 470 | if ((r = sshbuf_get_string(msg, sigp, &len)) != 0) |
471 | goto out; | ||
472 | *lenp = len; | ||
473 | r = 0; | ||
474 | out: | ||
475 | if (blob != NULL) { | ||
476 | explicit_bzero(blob, blen); | ||
477 | free(blob); | ||
456 | } | 478 | } |
457 | buffer_free(&msg); | 479 | sshbuf_free(msg); |
458 | return ret; | 480 | return r; |
459 | } | 481 | } |
460 | 482 | ||
461 | /* Encode key for a message to the agent. */ | 483 | /* Encode key for a message to the agent. */ |
462 | 484 | ||
463 | #ifdef WITH_SSH1 | 485 | #ifdef WITH_SSH1 |
464 | static void | 486 | static int |
465 | ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment) | 487 | ssh_encode_identity_rsa1(struct sshbuf *b, RSA *key, const char *comment) |
466 | { | 488 | { |
467 | buffer_put_int(b, BN_num_bits(key->n)); | 489 | int r; |
468 | buffer_put_bignum(b, key->n); | 490 | |
469 | buffer_put_bignum(b, key->e); | ||
470 | buffer_put_bignum(b, key->d); | ||
471 | /* To keep within the protocol: p < q for ssh. in SSL p > q */ | 491 | /* To keep within the protocol: p < q for ssh. in SSL p > q */ |
472 | buffer_put_bignum(b, key->iqmp); /* ssh key->u */ | 492 | if ((r = sshbuf_put_u32(b, BN_num_bits(key->n))) != 0 || |
473 | buffer_put_bignum(b, key->q); /* ssh key->p, SSL key->q */ | 493 | (r = sshbuf_put_bignum1(b, key->n)) != 0 || |
474 | buffer_put_bignum(b, key->p); /* ssh key->q, SSL key->p */ | 494 | (r = sshbuf_put_bignum1(b, key->e)) != 0 || |
475 | buffer_put_cstring(b, comment); | 495 | (r = sshbuf_put_bignum1(b, key->d)) != 0 || |
496 | (r = sshbuf_put_bignum1(b, key->iqmp)) != 0 || | ||
497 | (r = sshbuf_put_bignum1(b, key->q)) != 0 || | ||
498 | (r = sshbuf_put_bignum1(b, key->p)) != 0 || | ||
499 | (r = sshbuf_put_cstring(b, comment)) != 0) | ||
500 | return r; | ||
501 | return 0; | ||
476 | } | 502 | } |
477 | #endif | 503 | #endif |
478 | 504 | ||
479 | static void | 505 | static int |
480 | ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) | 506 | ssh_encode_identity_ssh2(struct sshbuf *b, struct sshkey *key, |
507 | const char *comment) | ||
508 | { | ||
509 | int r; | ||
510 | |||
511 | if ((r = sshkey_private_serialize(key, b)) != 0 || | ||
512 | (r = sshbuf_put_cstring(b, comment)) != 0) | ||
513 | return r; | ||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | static int | ||
518 | encode_constraints(struct sshbuf *m, u_int life, u_int confirm) | ||
481 | { | 519 | { |
482 | key_private_serialize(key, b); | 520 | int r; |
483 | buffer_put_cstring(b, comment); | 521 | |
522 | if (life != 0) { | ||
523 | if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_LIFETIME)) != 0 || | ||
524 | (r = sshbuf_put_u32(m, life)) != 0) | ||
525 | goto out; | ||
526 | } | ||
527 | if (confirm != 0) { | ||
528 | if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_CONFIRM)) != 0) | ||
529 | goto out; | ||
530 | } | ||
531 | r = 0; | ||
532 | out: | ||
533 | return r; | ||
484 | } | 534 | } |
485 | 535 | ||
486 | /* | 536 | /* |
487 | * Adds an identity to the authentication server. This call is not meant to | 537 | * Adds an identity to the authentication server. |
488 | * be used by normal applications. | 538 | * This call is intended only for use by ssh-add(1) and like applications. |
489 | */ | 539 | */ |
490 | |||
491 | int | 540 | int |
492 | ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, | 541 | ssh_add_identity_constrained(int sock, struct sshkey *key, const char *comment, |
493 | const char *comment, u_int life, u_int confirm) | 542 | u_int life, u_int confirm) |
494 | { | 543 | { |
495 | Buffer msg; | 544 | struct sshbuf *msg; |
496 | int type, constrained = (life || confirm); | 545 | int r, constrained = (life || confirm); |
546 | u_char type; | ||
497 | 547 | ||
498 | buffer_init(&msg); | 548 | if ((msg = sshbuf_new()) == NULL) |
549 | return SSH_ERR_ALLOC_FAIL; | ||
499 | 550 | ||
500 | switch (key->type) { | 551 | switch (key->type) { |
501 | #ifdef WITH_SSH1 | 552 | #ifdef WITH_SSH1 |
@@ -503,8 +554,9 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, | |||
503 | type = constrained ? | 554 | type = constrained ? |
504 | SSH_AGENTC_ADD_RSA_ID_CONSTRAINED : | 555 | SSH_AGENTC_ADD_RSA_ID_CONSTRAINED : |
505 | SSH_AGENTC_ADD_RSA_IDENTITY; | 556 | SSH_AGENTC_ADD_RSA_IDENTITY; |
506 | buffer_put_char(&msg, type); | 557 | if ((r = sshbuf_put_u8(msg, type)) != 0 || |
507 | ssh_encode_identity_rsa1(&msg, key->rsa, comment); | 558 | (r = ssh_encode_identity_rsa1(msg, key->rsa, comment)) != 0) |
559 | goto out; | ||
508 | break; | 560 | break; |
509 | #endif | 561 | #endif |
510 | #ifdef WITH_OPENSSL | 562 | #ifdef WITH_OPENSSL |
@@ -522,77 +574,88 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, | |||
522 | type = constrained ? | 574 | type = constrained ? |
523 | SSH2_AGENTC_ADD_ID_CONSTRAINED : | 575 | SSH2_AGENTC_ADD_ID_CONSTRAINED : |
524 | SSH2_AGENTC_ADD_IDENTITY; | 576 | SSH2_AGENTC_ADD_IDENTITY; |
525 | buffer_put_char(&msg, type); | 577 | if ((r = sshbuf_put_u8(msg, type)) != 0 || |
526 | ssh_encode_identity_ssh2(&msg, key, comment); | 578 | (r = ssh_encode_identity_ssh2(msg, key, comment)) != 0) |
579 | goto out; | ||
527 | break; | 580 | break; |
528 | default: | 581 | default: |
529 | buffer_free(&msg); | 582 | r = SSH_ERR_INVALID_ARGUMENT; |
530 | return 0; | 583 | goto out; |
531 | } | ||
532 | if (constrained) { | ||
533 | if (life != 0) { | ||
534 | buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME); | ||
535 | buffer_put_int(&msg, life); | ||
536 | } | ||
537 | if (confirm != 0) | ||
538 | buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM); | ||
539 | } | 584 | } |
540 | if (ssh_request_reply(auth, &msg, &msg) == 0) { | 585 | if (constrained && |
541 | buffer_free(&msg); | 586 | (r = encode_constraints(msg, life, confirm)) != 0) |
542 | return 0; | 587 | goto out; |
543 | } | 588 | if ((r = ssh_request_reply(sock, msg, msg)) != 0) |
544 | type = buffer_get_char(&msg); | 589 | goto out; |
545 | buffer_free(&msg); | 590 | if ((r = sshbuf_get_u8(msg, &type)) != 0) |
546 | return decode_reply(type); | 591 | goto out; |
592 | r = decode_reply(type); | ||
593 | out: | ||
594 | sshbuf_free(msg); | ||
595 | return r; | ||
547 | } | 596 | } |
548 | 597 | ||
549 | /* | 598 | /* |
550 | * Removes an identity from the authentication server. This call is not | 599 | * Removes an identity from the authentication server. |
551 | * meant to be used by normal applications. | 600 | * This call is intended only for use by ssh-add(1) and like applications. |
552 | */ | 601 | */ |
553 | |||
554 | int | 602 | int |
555 | ssh_remove_identity(AuthenticationConnection *auth, Key *key) | 603 | ssh_remove_identity(int sock, struct sshkey *key) |
556 | { | 604 | { |
557 | Buffer msg; | 605 | struct sshbuf *msg; |
558 | int type; | 606 | int r; |
559 | u_char *blob; | 607 | u_char type, *blob = NULL; |
560 | u_int blen; | 608 | size_t blen; |
561 | 609 | ||
562 | buffer_init(&msg); | 610 | if ((msg = sshbuf_new()) == NULL) |
611 | return SSH_ERR_ALLOC_FAIL; | ||
563 | 612 | ||
564 | #ifdef WITH_SSH1 | 613 | #ifdef WITH_SSH1 |
565 | if (key->type == KEY_RSA1) { | 614 | if (key->type == KEY_RSA1) { |
566 | buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY); | 615 | if ((r = sshbuf_put_u8(msg, |
567 | buffer_put_int(&msg, BN_num_bits(key->rsa->n)); | 616 | SSH_AGENTC_REMOVE_RSA_IDENTITY)) != 0 || |
568 | buffer_put_bignum(&msg, key->rsa->e); | 617 | (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 || |
569 | buffer_put_bignum(&msg, key->rsa->n); | 618 | (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 || |
619 | (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0) | ||
620 | goto out; | ||
570 | } else | 621 | } else |
571 | #endif | 622 | #endif |
572 | if (key->type != KEY_UNSPEC) { | 623 | if (key->type != KEY_UNSPEC) { |
573 | key_to_blob(key, &blob, &blen); | 624 | if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) |
574 | buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); | 625 | goto out; |
575 | buffer_put_string(&msg, blob, blen); | 626 | if ((r = sshbuf_put_u8(msg, |
576 | free(blob); | 627 | SSH2_AGENTC_REMOVE_IDENTITY)) != 0 || |
628 | (r = sshbuf_put_string(msg, blob, blen)) != 0) | ||
629 | goto out; | ||
577 | } else { | 630 | } else { |
578 | buffer_free(&msg); | 631 | r = SSH_ERR_INVALID_ARGUMENT; |
579 | return 0; | 632 | goto out; |
580 | } | 633 | } |
581 | if (ssh_request_reply(auth, &msg, &msg) == 0) { | 634 | if ((r = ssh_request_reply(sock, msg, msg)) != 0) |
582 | buffer_free(&msg); | 635 | goto out; |
583 | return 0; | 636 | if ((r = sshbuf_get_u8(msg, &type)) != 0) |
637 | goto out; | ||
638 | r = decode_reply(type); | ||
639 | out: | ||
640 | if (blob != NULL) { | ||
641 | explicit_bzero(blob, blen); | ||
642 | free(blob); | ||
584 | } | 643 | } |
585 | type = buffer_get_char(&msg); | 644 | sshbuf_free(msg); |
586 | buffer_free(&msg); | 645 | return r; |
587 | return decode_reply(type); | ||
588 | } | 646 | } |
589 | 647 | ||
648 | /* | ||
649 | * Add/remove an token-based identity from the authentication server. | ||
650 | * This call is intended only for use by ssh-add(1) and like applications. | ||
651 | */ | ||
590 | int | 652 | int |
591 | ssh_update_card(AuthenticationConnection *auth, int add, | 653 | ssh_update_card(int sock, int add, const char *reader_id, const char *pin, |
592 | const char *reader_id, const char *pin, u_int life, u_int confirm) | 654 | u_int life, u_int confirm) |
593 | { | 655 | { |
594 | Buffer msg; | 656 | struct sshbuf *msg; |
595 | int type, constrained = (life || confirm); | 657 | int r, constrained = (life || confirm); |
658 | u_char type; | ||
596 | 659 | ||
597 | if (add) { | 660 | if (add) { |
598 | type = constrained ? | 661 | type = constrained ? |
@@ -601,69 +664,48 @@ ssh_update_card(AuthenticationConnection *auth, int add, | |||
601 | } else | 664 | } else |
602 | type = SSH_AGENTC_REMOVE_SMARTCARD_KEY; | 665 | type = SSH_AGENTC_REMOVE_SMARTCARD_KEY; |
603 | 666 | ||
604 | buffer_init(&msg); | 667 | if ((msg = sshbuf_new()) == NULL) |
605 | buffer_put_char(&msg, type); | 668 | return SSH_ERR_ALLOC_FAIL; |
606 | buffer_put_cstring(&msg, reader_id); | 669 | if ((r = sshbuf_put_u8(msg, type)) != 0 || |
607 | buffer_put_cstring(&msg, pin); | 670 | (r = sshbuf_put_cstring(msg, reader_id)) != 0 || |
608 | 671 | (r = sshbuf_put_cstring(msg, pin)) != 0) | |
609 | if (constrained) { | 672 | goto out; |
610 | if (life != 0) { | 673 | if (constrained && |
611 | buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME); | 674 | (r = encode_constraints(msg, life, confirm)) != 0) |
612 | buffer_put_int(&msg, life); | 675 | goto out; |
613 | } | 676 | if ((r = ssh_request_reply(sock, msg, msg)) != 0) |
614 | if (confirm != 0) | 677 | goto out; |
615 | buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM); | 678 | if ((r = sshbuf_get_u8(msg, &type)) != 0) |
616 | } | 679 | goto out; |
617 | 680 | r = decode_reply(type); | |
618 | if (ssh_request_reply(auth, &msg, &msg) == 0) { | 681 | out: |
619 | buffer_free(&msg); | 682 | sshbuf_free(msg); |
620 | return 0; | 683 | return r; |
621 | } | ||
622 | type = buffer_get_char(&msg); | ||
623 | buffer_free(&msg); | ||
624 | return decode_reply(type); | ||
625 | } | 684 | } |
626 | 685 | ||
627 | /* | 686 | /* |
628 | * Removes all identities from the agent. This call is not meant to be used | 687 | * Removes all identities from the agent. |
629 | * by normal applications. | 688 | * This call is intended only for use by ssh-add(1) and like applications. |
630 | */ | 689 | */ |
631 | |||
632 | int | ||
633 | ssh_remove_all_identities(AuthenticationConnection *auth, int version) | ||
634 | { | ||
635 | Buffer msg; | ||
636 | int type; | ||
637 | int code = (version==1) ? | ||
638 | SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES : | ||
639 | SSH2_AGENTC_REMOVE_ALL_IDENTITIES; | ||
640 | |||
641 | buffer_init(&msg); | ||
642 | buffer_put_char(&msg, code); | ||
643 | |||
644 | if (ssh_request_reply(auth, &msg, &msg) == 0) { | ||
645 | buffer_free(&msg); | ||
646 | return 0; | ||
647 | } | ||
648 | type = buffer_get_char(&msg); | ||
649 | buffer_free(&msg); | ||
650 | return decode_reply(type); | ||
651 | } | ||
652 | |||
653 | int | 690 | int |
654 | decode_reply(int type) | 691 | ssh_remove_all_identities(int sock, int version) |
655 | { | 692 | { |
656 | switch (type) { | 693 | struct sshbuf *msg; |
657 | case SSH_AGENT_FAILURE: | 694 | u_char type = (version == 1) ? |
658 | case SSH_COM_AGENT2_FAILURE: | 695 | SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES : |
659 | case SSH2_AGENT_FAILURE: | 696 | SSH2_AGENTC_REMOVE_ALL_IDENTITIES; |
660 | logit("SSH_AGENT_FAILURE"); | 697 | int r; |
661 | return 0; | 698 | |
662 | case SSH_AGENT_SUCCESS: | 699 | if ((msg = sshbuf_new()) == NULL) |
663 | return 1; | 700 | return SSH_ERR_ALLOC_FAIL; |
664 | default: | 701 | if ((r = sshbuf_put_u8(msg, type)) != 0) |
665 | fatal("Bad response from authentication agent: %d", type); | 702 | goto out; |
666 | } | 703 | if ((r = ssh_request_reply(sock, msg, msg)) != 0) |
667 | /* NOTREACHED */ | 704 | goto out; |
668 | return 0; | 705 | if ((r = sshbuf_get_u8(msg, &type)) != 0) |
706 | goto out; | ||
707 | r = decode_reply(type); | ||
708 | out: | ||
709 | sshbuf_free(msg); | ||
710 | return r; | ||
669 | } | 711 | } |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: authfd.h,v 1.37 2009/08/27 17:44:52 djm Exp $ */ | 1 | /* $OpenBSD: authfd.h,v 1.38 2015/01/14 20:05:27 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -16,6 +16,33 @@ | |||
16 | #ifndef AUTHFD_H | 16 | #ifndef AUTHFD_H |
17 | #define AUTHFD_H | 17 | #define AUTHFD_H |
18 | 18 | ||
19 | /* List of identities returned by ssh_fetch_identitylist() */ | ||
20 | struct ssh_identitylist { | ||
21 | size_t nkeys; | ||
22 | struct sshkey **keys; | ||
23 | char **comments; | ||
24 | }; | ||
25 | |||
26 | int ssh_get_authentication_socket(int *fdp); | ||
27 | void ssh_close_authentication_socket(int sock); | ||
28 | |||
29 | int ssh_lock_agent(int sock, int lock, const char *password); | ||
30 | int ssh_fetch_identitylist(int sock, int version, | ||
31 | struct ssh_identitylist **idlp); | ||
32 | void ssh_free_identitylist(struct ssh_identitylist *idl); | ||
33 | int ssh_add_identity_constrained(int sock, struct sshkey *key, | ||
34 | const char *comment, u_int life, u_int confirm); | ||
35 | int ssh_remove_identity(int sock, struct sshkey *key); | ||
36 | int ssh_update_card(int sock, int add, const char *reader_id, | ||
37 | const char *pin, u_int life, u_int confirm); | ||
38 | int ssh_remove_all_identities(int sock, int version); | ||
39 | |||
40 | int ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge, | ||
41 | u_char session_id[16], u_char response[16]); | ||
42 | int ssh_agent_sign(int sock, struct sshkey *key, | ||
43 | u_char **sigp, size_t *lenp, | ||
44 | const u_char *data, size_t datalen, u_int compat); | ||
45 | |||
19 | /* Messages for the authentication agent connection. */ | 46 | /* Messages for the authentication agent connection. */ |
20 | #define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1 | 47 | #define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1 |
21 | #define SSH_AGENT_RSA_IDENTITIES_ANSWER 2 | 48 | #define SSH_AGENT_RSA_IDENTITIES_ANSWER 2 |
@@ -60,35 +87,4 @@ | |||
60 | 87 | ||
61 | #define SSH_AGENT_OLD_SIGNATURE 0x01 | 88 | #define SSH_AGENT_OLD_SIGNATURE 0x01 |
62 | 89 | ||
63 | typedef struct { | ||
64 | int fd; | ||
65 | Buffer identities; | ||
66 | int howmany; | ||
67 | } AuthenticationConnection; | ||
68 | |||
69 | int ssh_agent_present(void); | ||
70 | int ssh_get_authentication_socket(void); | ||
71 | void ssh_close_authentication_socket(int); | ||
72 | |||
73 | AuthenticationConnection *ssh_get_authentication_connection(void); | ||
74 | void ssh_close_authentication_connection(AuthenticationConnection *); | ||
75 | int ssh_get_num_identities(AuthenticationConnection *, int); | ||
76 | Key *ssh_get_first_identity(AuthenticationConnection *, char **, int); | ||
77 | Key *ssh_get_next_identity(AuthenticationConnection *, char **, int); | ||
78 | int ssh_add_identity_constrained(AuthenticationConnection *, Key *, | ||
79 | const char *, u_int, u_int); | ||
80 | int ssh_remove_identity(AuthenticationConnection *, Key *); | ||
81 | int ssh_remove_all_identities(AuthenticationConnection *, int); | ||
82 | int ssh_lock_agent(AuthenticationConnection *, int, const char *); | ||
83 | int ssh_update_card(AuthenticationConnection *, int, const char *, | ||
84 | const char *, u_int, u_int); | ||
85 | |||
86 | int | ||
87 | ssh_decrypt_challenge(AuthenticationConnection *, Key *, BIGNUM *, u_char[16], | ||
88 | u_int, u_char[16]); | ||
89 | |||
90 | int | ||
91 | ssh_agent_sign(AuthenticationConnection *, Key *, u_char **, u_int *, u_char *, | ||
92 | u_int); | ||
93 | |||
94 | #endif /* AUTHFD_H */ | 90 | #endif /* AUTHFD_H */ |
diff --git a/clientloop.c b/clientloop.c index 397c96532..2137a81ce 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.261 2014/07/15 15:54:14 millert Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.262 2015/01/14 20:05:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -110,6 +110,7 @@ | |||
110 | #include "match.h" | 110 | #include "match.h" |
111 | #include "msg.h" | 111 | #include "msg.h" |
112 | #include "roaming.h" | 112 | #include "roaming.h" |
113 | #include "ssherr.h" | ||
113 | 114 | ||
114 | /* import options */ | 115 | /* import options */ |
115 | extern Options options; | 116 | extern Options options; |
@@ -1782,7 +1783,7 @@ static void | |||
1782 | client_input_agent_open(int type, u_int32_t seq, void *ctxt) | 1783 | client_input_agent_open(int type, u_int32_t seq, void *ctxt) |
1783 | { | 1784 | { |
1784 | Channel *c = NULL; | 1785 | Channel *c = NULL; |
1785 | int remote_id, sock; | 1786 | int r, remote_id, sock; |
1786 | 1787 | ||
1787 | /* Read the remote channel number from the message. */ | 1788 | /* Read the remote channel number from the message. */ |
1788 | remote_id = packet_get_int(); | 1789 | remote_id = packet_get_int(); |
@@ -1792,7 +1793,11 @@ client_input_agent_open(int type, u_int32_t seq, void *ctxt) | |||
1792 | * Get a connection to the local authentication agent (this may again | 1793 | * Get a connection to the local authentication agent (this may again |
1793 | * get forwarded). | 1794 | * get forwarded). |
1794 | */ | 1795 | */ |
1795 | sock = ssh_get_authentication_socket(); | 1796 | if ((r = ssh_get_authentication_socket(&sock)) != 0 && |
1797 | r != SSH_ERR_AGENT_NOT_PRESENT) | ||
1798 | debug("%s: ssh_get_authentication_socket: %s", | ||
1799 | __func__, ssh_err(r)); | ||
1800 | |||
1796 | 1801 | ||
1797 | /* | 1802 | /* |
1798 | * If we could not connect the agent, send an error message back to | 1803 | * If we could not connect the agent, send an error message back to |
@@ -1910,7 +1915,7 @@ static Channel * | |||
1910 | client_request_agent(const char *request_type, int rchan) | 1915 | client_request_agent(const char *request_type, int rchan) |
1911 | { | 1916 | { |
1912 | Channel *c = NULL; | 1917 | Channel *c = NULL; |
1913 | int sock; | 1918 | int r, sock; |
1914 | 1919 | ||
1915 | if (!options.forward_agent) { | 1920 | if (!options.forward_agent) { |
1916 | error("Warning: ssh server tried agent forwarding."); | 1921 | error("Warning: ssh server tried agent forwarding."); |
@@ -1918,9 +1923,12 @@ client_request_agent(const char *request_type, int rchan) | |||
1918 | "malicious server."); | 1923 | "malicious server."); |
1919 | return NULL; | 1924 | return NULL; |
1920 | } | 1925 | } |
1921 | sock = ssh_get_authentication_socket(); | 1926 | if ((r = ssh_get_authentication_socket(&sock)) != 0) { |
1922 | if (sock < 0) | 1927 | if (r != SSH_ERR_AGENT_NOT_PRESENT) |
1928 | debug("%s: ssh_get_authentication_socket: %s", | ||
1929 | __func__, ssh_err(r)); | ||
1923 | return NULL; | 1930 | return NULL; |
1931 | } | ||
1924 | c = channel_new("authentication agent connection", | 1932 | c = channel_new("authentication agent connection", |
1925 | SSH_CHANNEL_OPEN, sock, sock, -1, | 1933 | SSH_CHANNEL_OPEN, sock, sock, -1, |
1926 | CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, | 1934 | CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: monitor.c,v 1.137 2015/01/13 07:39:19 djm Exp $ */ | 1 | /* $OpenBSD: monitor.c,v 1.138 2015/01/14 20:05:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | 3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> |
4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> | 4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> |
@@ -101,6 +101,7 @@ | |||
101 | #include "roaming.h" | 101 | #include "roaming.h" |
102 | #include "authfd.h" | 102 | #include "authfd.h" |
103 | #include "match.h" | 103 | #include "match.h" |
104 | #include "ssherr.h" | ||
104 | 105 | ||
105 | #ifdef GSSAPI | 106 | #ifdef GSSAPI |
106 | static Gssctxt *gsscontext = NULL; | 107 | static Gssctxt *gsscontext = NULL; |
@@ -685,28 +686,28 @@ mm_answer_moduli(int sock, Buffer *m) | |||
685 | } | 686 | } |
686 | #endif | 687 | #endif |
687 | 688 | ||
688 | extern AuthenticationConnection *auth_conn; | ||
689 | |||
690 | int | 689 | int |
691 | mm_answer_sign(int sock, Buffer *m) | 690 | mm_answer_sign(int sock, Buffer *m) |
692 | { | 691 | { |
693 | Key *key; | 692 | extern int auth_sock; /* XXX move to state struct? */ |
693 | struct sshkey *key; | ||
694 | u_char *p; | 694 | u_char *p; |
695 | u_char *signature; | 695 | u_char *signature; |
696 | u_int siglen, datlen; | 696 | size_t datlen, siglen; |
697 | int keyid; | 697 | int r, keyid; |
698 | 698 | ||
699 | debug3("%s", __func__); | 699 | debug3("%s", __func__); |
700 | 700 | ||
701 | keyid = buffer_get_int(m); | 701 | if ((r = sshbuf_get_u32(m, &keyid)) != 0 || |
702 | p = buffer_get_string(m, &datlen); | 702 | (r = sshbuf_get_string(m, &p, &datlen)) != 0) |
703 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
703 | 704 | ||
704 | /* | 705 | /* |
705 | * Supported KEX types use SHA1 (20 bytes), SHA256 (32 bytes), | 706 | * Supported KEX types use SHA1 (20 bytes), SHA256 (32 bytes), |
706 | * SHA384 (48 bytes) and SHA512 (64 bytes). | 707 | * SHA384 (48 bytes) and SHA512 (64 bytes). |
707 | */ | 708 | */ |
708 | if (datlen != 20 && datlen != 32 && datlen != 48 && datlen != 64) | 709 | if (datlen != 20 && datlen != 32 && datlen != 48 && datlen != 64) |
709 | fatal("%s: data length incorrect: %u", __func__, datlen); | 710 | fatal("%s: data length incorrect: %zu", __func__, datlen); |
710 | 711 | ||
711 | /* save session id, it will be passed on the first call */ | 712 | /* save session id, it will be passed on the first call */ |
712 | if (session_id2_len == 0) { | 713 | if (session_id2_len == 0) { |
@@ -716,20 +717,25 @@ mm_answer_sign(int sock, Buffer *m) | |||
716 | } | 717 | } |
717 | 718 | ||
718 | if ((key = get_hostkey_by_index(keyid)) != NULL) { | 719 | if ((key = get_hostkey_by_index(keyid)) != NULL) { |
719 | if (key_sign(key, &signature, &siglen, p, datlen) < 0) | 720 | if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, |
720 | fatal("%s: key_sign failed", __func__); | 721 | datafellows)) != 0) |
722 | fatal("%s: sshkey_sign failed: %s", | ||
723 | __func__, ssh_err(r)); | ||
721 | } else if ((key = get_hostkey_public_by_index(keyid)) != NULL && | 724 | } else if ((key = get_hostkey_public_by_index(keyid)) != NULL && |
722 | auth_conn != NULL) { | 725 | auth_sock > 0) { |
723 | if (ssh_agent_sign(auth_conn, key, &signature, &siglen, p, | 726 | if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen, |
724 | datlen) < 0) | 727 | p, datlen, datafellows)) != 0) { |
725 | fatal("%s: ssh_agent_sign failed", __func__); | 728 | fatal("%s: ssh_agent_sign failed: %s", |
729 | __func__, ssh_err(r)); | ||
730 | } | ||
726 | } else | 731 | } else |
727 | fatal("%s: no hostkey from index %d", __func__, keyid); | 732 | fatal("%s: no hostkey from index %d", __func__, keyid); |
728 | 733 | ||
729 | debug3("%s: signature %p(%u)", __func__, signature, siglen); | 734 | debug3("%s: signature %p(%zu)", __func__, signature, siglen); |
730 | 735 | ||
731 | buffer_clear(m); | 736 | sshbuf_reset(m); |
732 | buffer_put_string(m, signature, siglen); | 737 | if ((r = sshbuf_put_string(m, signature, siglen)) != 0) |
738 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
733 | 739 | ||
734 | free(p); | 740 | free(p); |
735 | free(signature); | 741 | free(signature); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: session.c,v 1.275 2014/12/22 07:55:51 djm Exp $ */ | 1 | /* $OpenBSD: session.c,v 1.276 2015/01/14 20:05:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
4 | * All rights reserved | 4 | * All rights reserved |
@@ -1620,11 +1620,11 @@ launch_login(struct passwd *pw, const char *hostname) | |||
1620 | static void | 1620 | static void |
1621 | child_close_fds(void) | 1621 | child_close_fds(void) |
1622 | { | 1622 | { |
1623 | extern AuthenticationConnection *auth_conn; | 1623 | extern int auth_sock; |
1624 | 1624 | ||
1625 | if (auth_conn) { | 1625 | if (auth_sock != -1) { |
1626 | ssh_close_authentication_connection(auth_conn); | 1626 | close(auth_sock); |
1627 | auth_conn = NULL; | 1627 | auth_sock = -1; |
1628 | } | 1628 | } |
1629 | 1629 | ||
1630 | if (packet_get_connection_in() == packet_get_connection_out()) | 1630 | if (packet_get_connection_in() == packet_get_connection_out()) |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-add.c,v 1.115 2014/12/21 22:27:56 djm Exp $ */ | 1 | /* $OpenBSD: ssh-add.c,v 1.116 2015/01/14 20:05:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -44,6 +44,7 @@ | |||
44 | #include <openssl/evp.h> | 44 | #include <openssl/evp.h> |
45 | #include "openbsd-compat/openssl-compat.h" | 45 | #include "openbsd-compat/openssl-compat.h" |
46 | 46 | ||
47 | #include <errno.h> | ||
47 | #include <fcntl.h> | 48 | #include <fcntl.h> |
48 | #include <pwd.h> | 49 | #include <pwd.h> |
49 | #include <stdarg.h> | 50 | #include <stdarg.h> |
@@ -56,8 +57,8 @@ | |||
56 | #include "ssh.h" | 57 | #include "ssh.h" |
57 | #include "rsa.h" | 58 | #include "rsa.h" |
58 | #include "log.h" | 59 | #include "log.h" |
59 | #include "key.h" | 60 | #include "sshkey.h" |
60 | #include "buffer.h" | 61 | #include "sshbuf.h" |
61 | #include "authfd.h" | 62 | #include "authfd.h" |
62 | #include "authfile.h" | 63 | #include "authfile.h" |
63 | #include "pathnames.h" | 64 | #include "pathnames.h" |
@@ -103,22 +104,22 @@ clear_pass(void) | |||
103 | } | 104 | } |
104 | 105 | ||
105 | static int | 106 | static int |
106 | delete_file(AuthenticationConnection *ac, const char *filename, int key_only) | 107 | delete_file(int agent_fd, const char *filename, int key_only) |
107 | { | 108 | { |
108 | Key *public = NULL, *cert = NULL; | 109 | struct sshkey *public, *cert = NULL; |
109 | char *certpath = NULL, *comment = NULL; | 110 | char *certpath = NULL, *comment = NULL; |
110 | int ret = -1; | 111 | int r, ret = -1; |
111 | 112 | ||
112 | public = key_load_public(filename, &comment); | 113 | if ((r = sshkey_load_public(filename, &public, &comment)) != 0) { |
113 | if (public == NULL) { | 114 | printf("Bad key file %s: %s\n", filename, ssh_err(r)); |
114 | printf("Bad key file %s\n", filename); | ||
115 | return -1; | 115 | return -1; |
116 | } | 116 | } |
117 | if (ssh_remove_identity(ac, public)) { | 117 | if ((r = ssh_remove_identity(agent_fd, public)) == 0) { |
118 | fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment); | 118 | fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment); |
119 | ret = 0; | 119 | ret = 0; |
120 | } else | 120 | } else |
121 | fprintf(stderr, "Could not remove identity: %s\n", filename); | 121 | fprintf(stderr, "Could not remove identity \"%s\": %s\n", |
122 | filename, ssh_err(r)); | ||
122 | 123 | ||
123 | if (key_only) | 124 | if (key_only) |
124 | goto out; | 125 | goto out; |
@@ -127,13 +128,13 @@ delete_file(AuthenticationConnection *ac, const char *filename, int key_only) | |||
127 | free(comment); | 128 | free(comment); |
128 | comment = NULL; | 129 | comment = NULL; |
129 | xasprintf(&certpath, "%s-cert.pub", filename); | 130 | xasprintf(&certpath, "%s-cert.pub", filename); |
130 | if ((cert = key_load_public(certpath, &comment)) == NULL) | 131 | if ((r = sshkey_load_public(certpath, &cert, &comment)) == 0) |
131 | goto out; | 132 | goto out; |
132 | if (!key_equal_public(cert, public)) | 133 | if (!sshkey_equal_public(cert, public)) |
133 | fatal("Certificate %s does not match private key %s", | 134 | fatal("Certificate %s does not match private key %s", |
134 | certpath, filename); | 135 | certpath, filename); |
135 | 136 | ||
136 | if (ssh_remove_identity(ac, cert)) { | 137 | if (ssh_remove_identity(agent_fd, cert)) { |
137 | fprintf(stderr, "Identity removed: %s (%s)\n", certpath, | 138 | fprintf(stderr, "Identity removed: %s (%s)\n", certpath, |
138 | comment); | 139 | comment); |
139 | ret = 0; | 140 | ret = 0; |
@@ -142,9 +143,9 @@ delete_file(AuthenticationConnection *ac, const char *filename, int key_only) | |||
142 | 143 | ||
143 | out: | 144 | out: |
144 | if (cert != NULL) | 145 | if (cert != NULL) |
145 | key_free(cert); | 146 | sshkey_free(cert); |
146 | if (public != NULL) | 147 | if (public != NULL) |
147 | key_free(public); | 148 | sshkey_free(public); |
148 | free(certpath); | 149 | free(certpath); |
149 | free(comment); | 150 | free(comment); |
150 | 151 | ||
@@ -153,14 +154,15 @@ delete_file(AuthenticationConnection *ac, const char *filename, int key_only) | |||
153 | 154 | ||
154 | /* Send a request to remove all identities. */ | 155 | /* Send a request to remove all identities. */ |
155 | static int | 156 | static int |
156 | delete_all(AuthenticationConnection *ac) | 157 | delete_all(int agent_fd) |
157 | { | 158 | { |
158 | int ret = -1; | 159 | int ret = -1; |
159 | 160 | ||
160 | if (ssh_remove_all_identities(ac, 1)) | 161 | if (ssh_remove_all_identities(agent_fd, 1) == 0) |
161 | ret = 0; | 162 | ret = 0; |
162 | /* ignore error-code for ssh2 */ | 163 | /* ignore error-code for ssh2 */ |
163 | ssh_remove_all_identities(ac, 2); | 164 | /* XXX revisit */ |
165 | ssh_remove_all_identities(agent_fd, 2); | ||
164 | 166 | ||
165 | if (ret == 0) | 167 | if (ret == 0) |
166 | fprintf(stderr, "All identities removed.\n"); | 168 | fprintf(stderr, "All identities removed.\n"); |
@@ -171,13 +173,13 @@ delete_all(AuthenticationConnection *ac) | |||
171 | } | 173 | } |
172 | 174 | ||
173 | static int | 175 | static int |
174 | add_file(AuthenticationConnection *ac, const char *filename, int key_only) | 176 | add_file(int agent_fd, const char *filename, int key_only) |
175 | { | 177 | { |
176 | Key *private, *cert; | 178 | struct sshkey *private, *cert; |
177 | char *comment = NULL; | 179 | char *comment = NULL; |
178 | char msg[1024], *certpath = NULL; | 180 | char msg[1024], *certpath = NULL; |
179 | int r, fd, perms_ok, ret = -1; | 181 | int r, fd, ret = -1; |
180 | Buffer keyblob; | 182 | struct sshbuf *keyblob; |
181 | 183 | ||
182 | if (strcmp(filename, "-") == 0) { | 184 | if (strcmp(filename, "-") == 0) { |
183 | fd = STDIN_FILENO; | 185 | fd = STDIN_FILENO; |
@@ -192,30 +194,38 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only) | |||
192 | * will occur multiple times, so check perms first and bail if wrong. | 194 | * will occur multiple times, so check perms first and bail if wrong. |
193 | */ | 195 | */ |
194 | if (fd != STDIN_FILENO) { | 196 | if (fd != STDIN_FILENO) { |
195 | perms_ok = key_perm_ok(fd, filename); | 197 | if (sshkey_perm_ok(fd, filename) != 0) { |
196 | if (!perms_ok) { | ||
197 | close(fd); | 198 | close(fd); |
198 | return -1; | 199 | return -1; |
199 | } | 200 | } |
200 | } | 201 | } |
201 | buffer_init(&keyblob); | 202 | if ((keyblob = sshbuf_new()) == NULL) |
202 | if (!key_load_file(fd, filename, &keyblob)) { | 203 | fatal("%s: sshbuf_new failed", __func__); |
203 | buffer_free(&keyblob); | 204 | if ((r = sshkey_load_file(fd, keyblob)) != 0) { |
205 | fprintf(stderr, "Error loading key \"%s\": %s\n", | ||
206 | filename, ssh_err(r)); | ||
207 | sshbuf_free(keyblob); | ||
204 | close(fd); | 208 | close(fd); |
205 | return -1; | 209 | return -1; |
206 | } | 210 | } |
207 | close(fd); | 211 | close(fd); |
208 | 212 | ||
209 | /* At first, try empty passphrase */ | 213 | /* At first, try empty passphrase */ |
210 | if ((r = sshkey_parse_private_fileblob(&keyblob, "", filename, | 214 | if ((r = sshkey_parse_private_fileblob(keyblob, "", filename, |
211 | &private, &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) | 215 | &private, &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) { |
212 | fatal("Cannot parse %s: %s", filename, ssh_err(r)); | 216 | fprintf(stderr, "Error loading key \"%s\": %s\n", |
217 | filename, ssh_err(r)); | ||
218 | goto fail_load; | ||
219 | } | ||
213 | /* try last */ | 220 | /* try last */ |
214 | if (private == NULL && pass != NULL) { | 221 | if (private == NULL && pass != NULL) { |
215 | if ((r = sshkey_parse_private_fileblob(&keyblob, pass, filename, | 222 | if ((r = sshkey_parse_private_fileblob(keyblob, pass, filename, |
216 | &private, &comment)) != 0 && | 223 | &private, &comment)) != 0 && |
217 | r != SSH_ERR_KEY_WRONG_PASSPHRASE) | 224 | r != SSH_ERR_KEY_WRONG_PASSPHRASE) { |
218 | fatal("Cannot parse %s: %s", filename, ssh_err(r)); | 225 | fprintf(stderr, "Error loading key \"%s\": %s\n", |
226 | filename, ssh_err(r)); | ||
227 | goto fail_load; | ||
228 | } | ||
219 | } | 229 | } |
220 | if (comment == NULL) | 230 | if (comment == NULL) |
221 | comment = xstrdup(filename); | 231 | comment = xstrdup(filename); |
@@ -226,28 +236,30 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only) | |||
226 | comment); | 236 | comment); |
227 | for (;;) { | 237 | for (;;) { |
228 | pass = read_passphrase(msg, RP_ALLOW_STDIN); | 238 | pass = read_passphrase(msg, RP_ALLOW_STDIN); |
229 | if (strcmp(pass, "") == 0) { | 239 | if (strcmp(pass, "") == 0) |
240 | goto fail_load; | ||
241 | if ((r = sshkey_parse_private_fileblob(keyblob, pass, | ||
242 | filename, &private, NULL)) == 0) | ||
243 | break; | ||
244 | else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) { | ||
245 | fprintf(stderr, | ||
246 | "Error loading key \"%s\": %s\n", | ||
247 | filename, ssh_err(r)); | ||
248 | fail_load: | ||
230 | clear_pass(); | 249 | clear_pass(); |
231 | free(comment); | 250 | free(comment); |
232 | buffer_free(&keyblob); | 251 | sshbuf_free(keyblob); |
233 | return -1; | 252 | return -1; |
234 | } | 253 | } |
235 | if ((r = sshkey_parse_private_fileblob(&keyblob, | ||
236 | pass, filename, &private, NULL)) != 0 && | ||
237 | r != SSH_ERR_KEY_WRONG_PASSPHRASE) | ||
238 | fatal("Cannot parse %s: %s", | ||
239 | filename, ssh_err(r)); | ||
240 | if (private != NULL) | ||
241 | break; | ||
242 | clear_pass(); | 254 | clear_pass(); |
243 | snprintf(msg, sizeof msg, | 255 | snprintf(msg, sizeof msg, |
244 | "Bad passphrase, try again for %.200s: ", comment); | 256 | "Bad passphrase, try again for %.200s: ", comment); |
245 | } | 257 | } |
246 | } | 258 | } |
247 | buffer_free(&keyblob); | 259 | sshbuf_free(keyblob); |
248 | 260 | ||
249 | if (ssh_add_identity_constrained(ac, private, comment, lifetime, | 261 | if ((r = ssh_add_identity_constrained(agent_fd, private, comment, |
250 | confirm)) { | 262 | lifetime, confirm)) == 0) { |
251 | fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); | 263 | fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); |
252 | ret = 0; | 264 | ret = 0; |
253 | if (lifetime != 0) | 265 | if (lifetime != 0) |
@@ -257,7 +269,8 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only) | |||
257 | fprintf(stderr, | 269 | fprintf(stderr, |
258 | "The user must confirm each use of the key\n"); | 270 | "The user must confirm each use of the key\n"); |
259 | } else { | 271 | } else { |
260 | fprintf(stderr, "Could not add identity: %s\n", filename); | 272 | fprintf(stderr, "Could not add identity \"%s\": %s\n", |
273 | filename, ssh_err(r)); | ||
261 | } | 274 | } |
262 | 275 | ||
263 | /* Skip trying to load the cert if requested */ | 276 | /* Skip trying to load the cert if requested */ |
@@ -266,29 +279,39 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only) | |||
266 | 279 | ||
267 | /* Now try to add the certificate flavour too */ | 280 | /* Now try to add the certificate flavour too */ |
268 | xasprintf(&certpath, "%s-cert.pub", filename); | 281 | xasprintf(&certpath, "%s-cert.pub", filename); |
269 | if ((cert = key_load_public(certpath, NULL)) == NULL) | 282 | if ((r = sshkey_load_public(certpath, &cert, NULL)) != 0) { |
283 | if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT) | ||
284 | error("Failed to load certificate \"%s\": %s", | ||
285 | certpath, ssh_err(r)); | ||
270 | goto out; | 286 | goto out; |
287 | } | ||
271 | 288 | ||
272 | if (!key_equal_public(cert, private)) { | 289 | if (!sshkey_equal_public(cert, private)) { |
273 | error("Certificate %s does not match private key %s", | 290 | error("Certificate %s does not match private key %s", |
274 | certpath, filename); | 291 | certpath, filename); |
275 | key_free(cert); | 292 | sshkey_free(cert); |
276 | goto out; | 293 | goto out; |
277 | } | 294 | } |
278 | 295 | ||
279 | /* Graft with private bits */ | 296 | /* Graft with private bits */ |
280 | if (key_to_certified(private, key_cert_is_legacy(cert)) != 0) { | 297 | if ((r = sshkey_to_certified(private, |
281 | error("%s: key_to_certified failed", __func__); | 298 | sshkey_cert_is_legacy(cert))) != 0) { |
282 | key_free(cert); | 299 | error("%s: sshkey_to_certified: %s", __func__, ssh_err(r)); |
300 | sshkey_free(cert); | ||
301 | goto out; | ||
302 | } | ||
303 | if ((r = sshkey_cert_copy(cert, private)) != 0) { | ||
304 | error("%s: key_cert_copy: %s", __func__, ssh_err(r)); | ||
305 | sshkey_free(cert); | ||
283 | goto out; | 306 | goto out; |
284 | } | 307 | } |
285 | key_cert_copy(cert, private); | 308 | sshkey_free(cert); |
286 | key_free(cert); | ||
287 | 309 | ||
288 | if (!ssh_add_identity_constrained(ac, private, comment, | 310 | if ((r = ssh_add_identity_constrained(agent_fd, private, comment, |
289 | lifetime, confirm)) { | 311 | lifetime, confirm)) != 0) { |
290 | error("Certificate %s (%s) add failed", certpath, | 312 | error("Certificate %s (%s) add failed: %s", certpath, |
291 | private->cert->key_id); | 313 | private->cert->key_id, ssh_err(r)); |
314 | goto out; | ||
292 | } | 315 | } |
293 | fprintf(stderr, "Certificate added: %s (%s)\n", certpath, | 316 | fprintf(stderr, "Certificate added: %s (%s)\n", certpath, |
294 | private->cert->key_id); | 317 | private->cert->key_id); |
@@ -297,19 +320,18 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only) | |||
297 | if (confirm != 0) | 320 | if (confirm != 0) |
298 | fprintf(stderr, "The user must confirm each use of the key\n"); | 321 | fprintf(stderr, "The user must confirm each use of the key\n"); |
299 | out: | 322 | out: |
300 | if (certpath != NULL) | 323 | free(certpath); |
301 | free(certpath); | ||
302 | free(comment); | 324 | free(comment); |
303 | key_free(private); | 325 | sshkey_free(private); |
304 | 326 | ||
305 | return ret; | 327 | return ret; |
306 | } | 328 | } |
307 | 329 | ||
308 | static int | 330 | static int |
309 | update_card(AuthenticationConnection *ac, int add, const char *id) | 331 | update_card(int agent_fd, int add, const char *id) |
310 | { | 332 | { |
311 | char *pin = NULL; | 333 | char *pin = NULL; |
312 | int ret = -1; | 334 | int r, ret = -1; |
313 | 335 | ||
314 | if (add) { | 336 | if (add) { |
315 | if ((pin = read_passphrase("Enter passphrase for PKCS#11: ", | 337 | if ((pin = read_passphrase("Enter passphrase for PKCS#11: ", |
@@ -317,14 +339,14 @@ update_card(AuthenticationConnection *ac, int add, const char *id) | |||
317 | return -1; | 339 | return -1; |
318 | } | 340 | } |
319 | 341 | ||
320 | if (ssh_update_card(ac, add, id, pin == NULL ? "" : pin, | 342 | if ((r = ssh_update_card(agent_fd, add, id, pin == NULL ? "" : pin, |
321 | lifetime, confirm)) { | 343 | lifetime, confirm)) == 0) { |
322 | fprintf(stderr, "Card %s: %s\n", | 344 | fprintf(stderr, "Card %s: %s\n", |
323 | add ? "added" : "removed", id); | 345 | add ? "added" : "removed", id); |
324 | ret = 0; | 346 | ret = 0; |
325 | } else { | 347 | } else { |
326 | fprintf(stderr, "Could not %s card: %s\n", | 348 | fprintf(stderr, "Could not %s card \"%s\": %s\n", |
327 | add ? "add" : "remove", id); | 349 | add ? "add" : "remove", id, ssh_err(r)); |
328 | ret = -1; | 350 | ret = -1; |
329 | } | 351 | } |
330 | free(pin); | 352 | free(pin); |
@@ -332,32 +354,42 @@ update_card(AuthenticationConnection *ac, int add, const char *id) | |||
332 | } | 354 | } |
333 | 355 | ||
334 | static int | 356 | static int |
335 | list_identities(AuthenticationConnection *ac, int do_fp) | 357 | list_identities(int agent_fd, int do_fp) |
336 | { | 358 | { |
337 | Key *key; | 359 | char *fp; |
338 | char *comment, *fp; | 360 | int version, r, had_identities = 0; |
339 | int had_identities = 0; | 361 | struct ssh_identitylist *idlist; |
340 | int version; | 362 | size_t i; |
341 | 363 | ||
342 | for (version = 1; version <= 2; version++) { | 364 | for (version = 1; version <= 2; version++) { |
343 | for (key = ssh_get_first_identity(ac, &comment, version); | 365 | if ((r = ssh_fetch_identitylist(agent_fd, version, |
344 | key != NULL; | 366 | &idlist)) != 0) { |
345 | key = ssh_get_next_identity(ac, &comment, version)) { | 367 | if (r != SSH_ERR_AGENT_NO_IDENTITIES) |
368 | fprintf(stderr, "error fetching identities for " | ||
369 | "protocol %d: %s\n", version, ssh_err(r)); | ||
370 | continue; | ||
371 | } | ||
372 | for (i = 0; i < idlist->nkeys; i++) { | ||
346 | had_identities = 1; | 373 | had_identities = 1; |
347 | if (do_fp) { | 374 | if (do_fp) { |
348 | fp = key_fingerprint(key, fingerprint_hash, | 375 | fp = sshkey_fingerprint(idlist->keys[i], |
349 | SSH_FP_DEFAULT); | 376 | fingerprint_hash, SSH_FP_DEFAULT); |
350 | printf("%d %s %s (%s)\n", | 377 | printf("%d %s %s (%s)\n", |
351 | key_size(key), fp, comment, key_type(key)); | 378 | sshkey_size(idlist->keys[i]), fp, |
379 | idlist->comments[i], | ||
380 | sshkey_type(idlist->keys[i])); | ||
352 | free(fp); | 381 | free(fp); |
353 | } else { | 382 | } else { |
354 | if (!key_write(key, stdout)) | 383 | if ((r = sshkey_write(idlist->keys[i], |
355 | fprintf(stderr, "key_write failed"); | 384 | stdout)) != 0) { |
356 | fprintf(stdout, " %s\n", comment); | 385 | fprintf(stderr, "sshkey_write: %s\n", |
386 | ssh_err(r)); | ||
387 | continue; | ||
388 | } | ||
389 | fprintf(stdout, " %s\n", idlist->comments[i]); | ||
357 | } | 390 | } |
358 | key_free(key); | ||
359 | free(comment); | ||
360 | } | 391 | } |
392 | ssh_free_identitylist(idlist); | ||
361 | } | 393 | } |
362 | if (!had_identities) { | 394 | if (!had_identities) { |
363 | printf("The agent has no identities.\n"); | 395 | printf("The agent has no identities.\n"); |
@@ -367,10 +399,10 @@ list_identities(AuthenticationConnection *ac, int do_fp) | |||
367 | } | 399 | } |
368 | 400 | ||
369 | static int | 401 | static int |
370 | lock_agent(AuthenticationConnection *ac, int lock) | 402 | lock_agent(int agent_fd, int lock) |
371 | { | 403 | { |
372 | char prompt[100], *p1, *p2; | 404 | char prompt[100], *p1, *p2; |
373 | int passok = 1, ret = -1; | 405 | int r, passok = 1, ret = -1; |
374 | 406 | ||
375 | strlcpy(prompt, "Enter lock password: ", sizeof(prompt)); | 407 | strlcpy(prompt, "Enter lock password: ", sizeof(prompt)); |
376 | p1 = read_passphrase(prompt, RP_ALLOW_STDIN); | 408 | p1 = read_passphrase(prompt, RP_ALLOW_STDIN); |
@@ -384,24 +416,28 @@ lock_agent(AuthenticationConnection *ac, int lock) | |||
384 | explicit_bzero(p2, strlen(p2)); | 416 | explicit_bzero(p2, strlen(p2)); |
385 | free(p2); | 417 | free(p2); |
386 | } | 418 | } |
387 | if (passok && ssh_lock_agent(ac, lock, p1)) { | 419 | if (passok) { |
388 | fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un"); | 420 | if ((r = ssh_lock_agent(agent_fd, lock, p1)) == 0) { |
389 | ret = 0; | 421 | fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un"); |
390 | } else | 422 | ret = 0; |
391 | fprintf(stderr, "Failed to %slock agent.\n", lock ? "" : "un"); | 423 | } else { |
424 | fprintf(stderr, "Failed to %slock agent: %s\n", | ||
425 | lock ? "" : "un", ssh_err(r)); | ||
426 | } | ||
427 | } | ||
392 | explicit_bzero(p1, strlen(p1)); | 428 | explicit_bzero(p1, strlen(p1)); |
393 | free(p1); | 429 | free(p1); |
394 | return (ret); | 430 | return (ret); |
395 | } | 431 | } |
396 | 432 | ||
397 | static int | 433 | static int |
398 | do_file(AuthenticationConnection *ac, int deleting, int key_only, char *file) | 434 | do_file(int agent_fd, int deleting, int key_only, char *file) |
399 | { | 435 | { |
400 | if (deleting) { | 436 | if (deleting) { |
401 | if (delete_file(ac, file, key_only) == -1) | 437 | if (delete_file(agent_fd, file, key_only) == -1) |
402 | return -1; | 438 | return -1; |
403 | } else { | 439 | } else { |
404 | if (add_file(ac, file, key_only) == -1) | 440 | if (add_file(agent_fd, file, key_only) == -1) |
405 | return -1; | 441 | return -1; |
406 | } | 442 | } |
407 | return 0; | 443 | return 0; |
@@ -431,9 +467,9 @@ main(int argc, char **argv) | |||
431 | { | 467 | { |
432 | extern char *optarg; | 468 | extern char *optarg; |
433 | extern int optind; | 469 | extern int optind; |
434 | AuthenticationConnection *ac = NULL; | 470 | int agent_fd; |
435 | char *pkcs11provider = NULL; | 471 | char *pkcs11provider = NULL; |
436 | int i, ch, deleting = 0, ret = 0, key_only = 0; | 472 | int r, i, ch, deleting = 0, ret = 0, key_only = 0; |
437 | int xflag = 0, lflag = 0, Dflag = 0; | 473 | int xflag = 0, lflag = 0, Dflag = 0; |
438 | 474 | ||
439 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ | 475 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
@@ -448,13 +484,19 @@ main(int argc, char **argv) | |||
448 | 484 | ||
449 | setvbuf(stdout, NULL, _IOLBF, 0); | 485 | setvbuf(stdout, NULL, _IOLBF, 0); |
450 | 486 | ||
451 | /* At first, get a connection to the authentication agent. */ | 487 | /* First, get a connection to the authentication agent. */ |
452 | ac = ssh_get_authentication_connection(); | 488 | switch (r = ssh_get_authentication_socket(&agent_fd)) { |
453 | if (ac == NULL) { | 489 | case 0: |
454 | fprintf(stderr, | 490 | break; |
455 | "Could not open a connection to your authentication agent.\n"); | 491 | case SSH_ERR_AGENT_NOT_PRESENT: |
492 | fprintf(stderr, "Could not open a connection to your " | ||
493 | "authentication agent.\n"); | ||
494 | exit(2); | ||
495 | default: | ||
496 | fprintf(stderr, "Error connecting to agent: %s\n", ssh_err(r)); | ||
456 | exit(2); | 497 | exit(2); |
457 | } | 498 | } |
499 | |||
458 | while ((ch = getopt(argc, argv, "klLcdDxXE:e:s:t:")) != -1) { | 500 | while ((ch = getopt(argc, argv, "klLcdDxXE:e:s:t:")) != -1) { |
459 | switch (ch) { | 501 | switch (ch) { |
460 | case 'E': | 502 | case 'E': |
@@ -510,15 +552,15 @@ main(int argc, char **argv) | |||
510 | if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1) | 552 | if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1) |
511 | fatal("Invalid combination of actions"); | 553 | fatal("Invalid combination of actions"); |
512 | else if (xflag) { | 554 | else if (xflag) { |
513 | if (lock_agent(ac, xflag == 'x' ? 1 : 0) == -1) | 555 | if (lock_agent(agent_fd, xflag == 'x' ? 1 : 0) == -1) |
514 | ret = 1; | 556 | ret = 1; |
515 | goto done; | 557 | goto done; |
516 | } else if (lflag) { | 558 | } else if (lflag) { |
517 | if (list_identities(ac, lflag == 'l' ? 1 : 0) == -1) | 559 | if (list_identities(agent_fd, lflag == 'l' ? 1 : 0) == -1) |
518 | ret = 1; | 560 | ret = 1; |
519 | goto done; | 561 | goto done; |
520 | } else if (Dflag) { | 562 | } else if (Dflag) { |
521 | if (delete_all(ac) == -1) | 563 | if (delete_all(agent_fd) == -1) |
522 | ret = 1; | 564 | ret = 1; |
523 | goto done; | 565 | goto done; |
524 | } | 566 | } |
@@ -526,7 +568,7 @@ main(int argc, char **argv) | |||
526 | argc -= optind; | 568 | argc -= optind; |
527 | argv += optind; | 569 | argv += optind; |
528 | if (pkcs11provider != NULL) { | 570 | if (pkcs11provider != NULL) { |
529 | if (update_card(ac, !deleting, pkcs11provider) == -1) | 571 | if (update_card(agent_fd, !deleting, pkcs11provider) == -1) |
530 | ret = 1; | 572 | ret = 1; |
531 | goto done; | 573 | goto done; |
532 | } | 574 | } |
@@ -548,7 +590,7 @@ main(int argc, char **argv) | |||
548 | default_files[i]); | 590 | default_files[i]); |
549 | if (stat(buf, &st) < 0) | 591 | if (stat(buf, &st) < 0) |
550 | continue; | 592 | continue; |
551 | if (do_file(ac, deleting, key_only, buf) == -1) | 593 | if (do_file(agent_fd, deleting, key_only, buf) == -1) |
552 | ret = 1; | 594 | ret = 1; |
553 | else | 595 | else |
554 | count++; | 596 | count++; |
@@ -557,13 +599,14 @@ main(int argc, char **argv) | |||
557 | ret = 1; | 599 | ret = 1; |
558 | } else { | 600 | } else { |
559 | for (i = 0; i < argc; i++) { | 601 | for (i = 0; i < argc; i++) { |
560 | if (do_file(ac, deleting, key_only, argv[i]) == -1) | 602 | if (do_file(agent_fd, deleting, key_only, |
603 | argv[i]) == -1) | ||
561 | ret = 1; | 604 | ret = 1; |
562 | } | 605 | } |
563 | } | 606 | } |
564 | clear_pass(); | 607 | clear_pass(); |
565 | 608 | ||
566 | done: | 609 | done: |
567 | ssh_close_authentication_connection(ac); | 610 | ssh_close_authentication_socket(agent_fd); |
568 | return ret; | 611 | return ret; |
569 | } | 612 | } |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh.c,v 1.411 2015/01/08 10:15:45 djm Exp $ */ | 1 | /* $OpenBSD: ssh.c,v 1.412 2015/01/14 20:05:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -107,6 +107,7 @@ | |||
107 | #include "uidswap.h" | 107 | #include "uidswap.h" |
108 | #include "roaming.h" | 108 | #include "roaming.h" |
109 | #include "version.h" | 109 | #include "version.h" |
110 | #include "ssherr.h" | ||
110 | 111 | ||
111 | #ifdef ENABLE_PKCS11 | 112 | #ifdef ENABLE_PKCS11 |
112 | #include "ssh-pkcs11.h" | 113 | #include "ssh-pkcs11.h" |
@@ -1502,10 +1503,16 @@ ssh_init_forwarding(void) | |||
1502 | static void | 1503 | static void |
1503 | check_agent_present(void) | 1504 | check_agent_present(void) |
1504 | { | 1505 | { |
1506 | int r; | ||
1507 | |||
1505 | if (options.forward_agent) { | 1508 | if (options.forward_agent) { |
1506 | /* Clear agent forwarding if we don't have an agent. */ | 1509 | /* Clear agent forwarding if we don't have an agent. */ |
1507 | if (!ssh_agent_present()) | 1510 | if ((r = ssh_get_authentication_socket(NULL)) != 0) { |
1508 | options.forward_agent = 0; | 1511 | options.forward_agent = 0; |
1512 | if (r != SSH_ERR_AGENT_NOT_PRESENT) | ||
1513 | debug("ssh_get_authentication_socket: %s", | ||
1514 | ssh_err(r)); | ||
1515 | } | ||
1509 | } | 1516 | } |
1510 | } | 1517 | } |
1511 | 1518 | ||
diff --git a/sshconnect1.c b/sshconnect1.c index 08589f5ee..016abbce5 100644 --- a/sshconnect1.c +++ b/sshconnect1.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect1.c,v 1.76 2014/07/15 15:54:14 millert Exp $ */ | 1 | /* $OpenBSD: sshconnect1.c,v 1.77 2015/01/14 20:05:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <openssl/bn.h> | 23 | #include <openssl/bn.h> |
24 | 24 | ||
25 | #include <errno.h> | ||
25 | #include <stdarg.h> | 26 | #include <stdarg.h> |
26 | #include <stdio.h> | 27 | #include <stdio.h> |
27 | #include <stdlib.h> | 28 | #include <stdlib.h> |
@@ -49,6 +50,7 @@ | |||
49 | #include "hostfile.h" | 50 | #include "hostfile.h" |
50 | #include "auth.h" | 51 | #include "auth.h" |
51 | #include "digest.h" | 52 | #include "digest.h" |
53 | #include "ssherr.h" | ||
52 | 54 | ||
53 | /* Session id for the current session. */ | 55 | /* Session id for the current session. */ |
54 | u_char session_id[16]; | 56 | u_char session_id[16]; |
@@ -64,33 +66,38 @@ extern char *__progname; | |||
64 | static int | 66 | static int |
65 | try_agent_authentication(void) | 67 | try_agent_authentication(void) |
66 | { | 68 | { |
67 | int type; | 69 | int r, type, agent_fd, ret = 0; |
68 | char *comment; | ||
69 | AuthenticationConnection *auth; | ||
70 | u_char response[16]; | 70 | u_char response[16]; |
71 | u_int i; | 71 | size_t i; |
72 | Key *key; | ||
73 | BIGNUM *challenge; | 72 | BIGNUM *challenge; |
73 | struct ssh_identitylist *idlist = NULL; | ||
74 | 74 | ||
75 | /* Get connection to the agent. */ | 75 | /* Get connection to the agent. */ |
76 | auth = ssh_get_authentication_connection(); | 76 | if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) { |
77 | if (!auth) | 77 | if (r != SSH_ERR_AGENT_NOT_PRESENT) |
78 | debug("%s: ssh_get_authentication_socket: %s", | ||
79 | __func__, ssh_err(r)); | ||
78 | return 0; | 80 | return 0; |
81 | } | ||
79 | 82 | ||
80 | if ((challenge = BN_new()) == NULL) | 83 | if ((challenge = BN_new()) == NULL) |
81 | fatal("try_agent_authentication: BN_new failed"); | 84 | fatal("try_agent_authentication: BN_new failed"); |
82 | /* Loop through identities served by the agent. */ | ||
83 | for (key = ssh_get_first_identity(auth, &comment, 1); | ||
84 | key != NULL; | ||
85 | key = ssh_get_next_identity(auth, &comment, 1)) { | ||
86 | 85 | ||
86 | /* Loop through identities served by the agent. */ | ||
87 | if ((r = ssh_fetch_identitylist(agent_fd, 1, &idlist)) != 0) { | ||
88 | if (r != SSH_ERR_AGENT_NO_IDENTITIES) | ||
89 | debug("%s: ssh_fetch_identitylist: %s", | ||
90 | __func__, ssh_err(r)); | ||
91 | goto out; | ||
92 | } | ||
93 | for (i = 0; i < idlist->nkeys; i++) { | ||
87 | /* Try this identity. */ | 94 | /* Try this identity. */ |
88 | debug("Trying RSA authentication via agent with '%.100s'", comment); | 95 | debug("Trying RSA authentication via agent with '%.100s'", |
89 | free(comment); | 96 | idlist->comments[i]); |
90 | 97 | ||
91 | /* Tell the server that we are willing to authenticate using this key. */ | 98 | /* Tell the server that we are willing to authenticate using this key. */ |
92 | packet_start(SSH_CMSG_AUTH_RSA); | 99 | packet_start(SSH_CMSG_AUTH_RSA); |
93 | packet_put_bignum(key->rsa->n); | 100 | packet_put_bignum(idlist->keys[i]->rsa->n); |
94 | packet_send(); | 101 | packet_send(); |
95 | packet_write_wait(); | 102 | packet_write_wait(); |
96 | 103 | ||
@@ -101,7 +108,6 @@ try_agent_authentication(void) | |||
101 | does not support RSA authentication. */ | 108 | does not support RSA authentication. */ |
102 | if (type == SSH_SMSG_FAILURE) { | 109 | if (type == SSH_SMSG_FAILURE) { |
103 | debug("Server refused our key."); | 110 | debug("Server refused our key."); |
104 | key_free(key); | ||
105 | continue; | 111 | continue; |
106 | } | 112 | } |
107 | /* Otherwise it should have sent a challenge. */ | 113 | /* Otherwise it should have sent a challenge. */ |
@@ -115,16 +121,17 @@ try_agent_authentication(void) | |||
115 | debug("Received RSA challenge from server."); | 121 | debug("Received RSA challenge from server."); |
116 | 122 | ||
117 | /* Ask the agent to decrypt the challenge. */ | 123 | /* Ask the agent to decrypt the challenge. */ |
118 | if (!ssh_decrypt_challenge(auth, key, challenge, session_id, 1, response)) { | 124 | if ((r = ssh_decrypt_challenge(agent_fd, idlist->keys[i], |
125 | challenge, session_id, response)) != 0) { | ||
119 | /* | 126 | /* |
120 | * The agent failed to authenticate this identifier | 127 | * The agent failed to authenticate this identifier |
121 | * although it advertised it supports this. Just | 128 | * although it advertised it supports this. Just |
122 | * return a wrong value. | 129 | * return a wrong value. |
123 | */ | 130 | */ |
124 | logit("Authentication agent failed to decrypt challenge."); | 131 | logit("Authentication agent failed to decrypt " |
132 | "challenge: %s", ssh_err(r)); | ||
125 | explicit_bzero(response, sizeof(response)); | 133 | explicit_bzero(response, sizeof(response)); |
126 | } | 134 | } |
127 | key_free(key); | ||
128 | debug("Sending response to RSA challenge."); | 135 | debug("Sending response to RSA challenge."); |
129 | 136 | ||
130 | /* Send the decrypted challenge back to the server. */ | 137 | /* Send the decrypted challenge back to the server. */ |
@@ -137,22 +144,25 @@ try_agent_authentication(void) | |||
137 | /* Wait for response from the server. */ | 144 | /* Wait for response from the server. */ |
138 | type = packet_read(); | 145 | type = packet_read(); |
139 | 146 | ||
140 | /* The server returns success if it accepted the authentication. */ | 147 | /* |
148 | * The server returns success if it accepted the | ||
149 | * authentication. | ||
150 | */ | ||
141 | if (type == SSH_SMSG_SUCCESS) { | 151 | if (type == SSH_SMSG_SUCCESS) { |
142 | ssh_close_authentication_connection(auth); | ||
143 | BN_clear_free(challenge); | ||
144 | debug("RSA authentication accepted by server."); | 152 | debug("RSA authentication accepted by server."); |
145 | return 1; | 153 | ret = 1; |
146 | } | 154 | break; |
147 | /* Otherwise it should return failure. */ | 155 | } else if (type != SSH_SMSG_FAILURE) |
148 | if (type != SSH_SMSG_FAILURE) | 156 | packet_disconnect("Protocol error waiting RSA auth " |
149 | packet_disconnect("Protocol error waiting RSA auth response: %d", | 157 | "response: %d", type); |
150 | type); | ||
151 | } | 158 | } |
152 | ssh_close_authentication_connection(auth); | 159 | if (ret != 1) |
160 | debug("RSA authentication using agent refused."); | ||
161 | out: | ||
162 | ssh_free_identitylist(idlist); | ||
163 | ssh_close_authentication_socket(agent_fd); | ||
153 | BN_clear_free(challenge); | 164 | BN_clear_free(challenge); |
154 | debug("RSA authentication using agent refused."); | 165 | return ret; |
155 | return 0; | ||
156 | } | 166 | } |
157 | 167 | ||
158 | /* | 168 | /* |
diff --git a/sshconnect2.c b/sshconnect2.c index 6a7b69938..343ca7459 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect2.c,v 1.213 2015/01/08 10:14:08 djm Exp $ */ | 1 | /* $OpenBSD: sshconnect2.c,v 1.214 2015/01/14 20:05:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2008 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2008 Damien Miller. All rights reserved. |
@@ -70,6 +70,7 @@ | |||
70 | #include "pathnames.h" | 70 | #include "pathnames.h" |
71 | #include "uidswap.h" | 71 | #include "uidswap.h" |
72 | #include "hostfile.h" | 72 | #include "hostfile.h" |
73 | #include "ssherr.h" | ||
73 | 74 | ||
74 | #ifdef GSSAPI | 75 | #ifdef GSSAPI |
75 | #include "ssh-gss.h" | 76 | #include "ssh-gss.h" |
@@ -131,10 +132,10 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port) | |||
131 | } while (0) | 132 | } while (0) |
132 | 133 | ||
133 | while ((alg = strsep(&avail, ",")) && *alg != '\0') { | 134 | while ((alg = strsep(&avail, ",")) && *alg != '\0') { |
134 | if ((ktype = key_type_from_name(alg)) == KEY_UNSPEC) | 135 | if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC) |
135 | fatal("%s: unknown alg %s", __func__, alg); | 136 | fatal("%s: unknown alg %s", __func__, alg); |
136 | if (lookup_key_in_hostkeys_by_type(hostkeys, | 137 | if (lookup_key_in_hostkeys_by_type(hostkeys, |
137 | key_type_plain(ktype), NULL)) | 138 | sshkey_type_plain(ktype), NULL)) |
138 | ALG_APPEND(first, alg); | 139 | ALG_APPEND(first, alg); |
139 | else | 140 | else |
140 | ALG_APPEND(last, alg); | 141 | ALG_APPEND(last, alg); |
@@ -242,15 +243,15 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
242 | * Authenticate user | 243 | * Authenticate user |
243 | */ | 244 | */ |
244 | 245 | ||
245 | typedef struct Authctxt Authctxt; | 246 | typedef struct cauthctxt Authctxt; |
246 | typedef struct Authmethod Authmethod; | 247 | typedef struct cauthmethod Authmethod; |
247 | typedef struct identity Identity; | 248 | typedef struct identity Identity; |
248 | typedef struct idlist Idlist; | 249 | typedef struct idlist Idlist; |
249 | 250 | ||
250 | struct identity { | 251 | struct identity { |
251 | TAILQ_ENTRY(identity) next; | 252 | TAILQ_ENTRY(identity) next; |
252 | AuthenticationConnection *ac; /* set if agent supports key */ | 253 | int agent_fd; /* >=0 if agent supports key */ |
253 | Key *key; /* public/private key */ | 254 | struct sshkey *key; /* public/private key */ |
254 | char *filename; /* comment for agent-only keys */ | 255 | char *filename; /* comment for agent-only keys */ |
255 | int tried; | 256 | int tried; |
256 | int isprivate; /* key points to the private key */ | 257 | int isprivate; /* key points to the private key */ |
@@ -258,17 +259,18 @@ struct identity { | |||
258 | }; | 259 | }; |
259 | TAILQ_HEAD(idlist, identity); | 260 | TAILQ_HEAD(idlist, identity); |
260 | 261 | ||
261 | struct Authctxt { | 262 | struct cauthctxt { |
262 | const char *server_user; | 263 | const char *server_user; |
263 | const char *local_user; | 264 | const char *local_user; |
264 | const char *host; | 265 | const char *host; |
265 | const char *service; | 266 | const char *service; |
266 | Authmethod *method; | 267 | struct cauthmethod *method; |
267 | sig_atomic_t success; | 268 | sig_atomic_t success; |
268 | char *authlist; | 269 | char *authlist; |
270 | int attempt; | ||
269 | /* pubkey */ | 271 | /* pubkey */ |
270 | Idlist keys; | 272 | struct idlist keys; |
271 | AuthenticationConnection *agent; | 273 | int agent_fd; |
272 | /* hostbased */ | 274 | /* hostbased */ |
273 | Sensitive *sensitive; | 275 | Sensitive *sensitive; |
274 | /* kbd-interactive */ | 276 | /* kbd-interactive */ |
@@ -276,7 +278,8 @@ struct Authctxt { | |||
276 | /* generic */ | 278 | /* generic */ |
277 | void *methoddata; | 279 | void *methoddata; |
278 | }; | 280 | }; |
279 | struct Authmethod { | 281 | |
282 | struct cauthmethod { | ||
280 | char *name; /* string to compare against server's list */ | 283 | char *name; /* string to compare against server's list */ |
281 | int (*userauth)(Authctxt *authctxt); | 284 | int (*userauth)(Authctxt *authctxt); |
282 | void (*cleanup)(Authctxt *authctxt); | 285 | void (*cleanup)(Authctxt *authctxt); |
@@ -582,7 +585,7 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) | |||
582 | key->type, pktype); | 585 | key->type, pktype); |
583 | goto done; | 586 | goto done; |
584 | } | 587 | } |
585 | fp = key_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); | 588 | fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); |
586 | debug2("input_userauth_pk_ok: fp %s", fp); | 589 | debug2("input_userauth_pk_ok: fp %s", fp); |
587 | free(fp); | 590 | free(fp); |
588 | 591 | ||
@@ -956,27 +959,29 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) | |||
956 | } | 959 | } |
957 | 960 | ||
958 | static int | 961 | static int |
959 | identity_sign(Identity *id, u_char **sigp, u_int *lenp, | 962 | identity_sign(struct identity *id, u_char **sigp, size_t *lenp, |
960 | u_char *data, u_int datalen) | 963 | const u_char *data, size_t datalen, u_int compat) |
961 | { | 964 | { |
962 | Key *prv; | 965 | Key *prv; |
963 | int ret; | 966 | int ret; |
964 | 967 | ||
965 | /* the agent supports this key */ | 968 | /* the agent supports this key */ |
966 | if (id->ac) | 969 | if (id->agent_fd) |
967 | return (ssh_agent_sign(id->ac, id->key, sigp, lenp, | 970 | return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp, |
968 | data, datalen)); | 971 | data, datalen, compat); |
972 | |||
969 | /* | 973 | /* |
970 | * we have already loaded the private key or | 974 | * we have already loaded the private key or |
971 | * the private key is stored in external hardware | 975 | * the private key is stored in external hardware |
972 | */ | 976 | */ |
973 | if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)) | 977 | if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)) |
974 | return (key_sign(id->key, sigp, lenp, data, datalen)); | 978 | return (sshkey_sign(id->key, sigp, lenp, data, datalen, |
979 | compat)); | ||
975 | /* load the private key from the file */ | 980 | /* load the private key from the file */ |
976 | if ((prv = load_identity_file(id->filename, id->userprovided)) == NULL) | 981 | if ((prv = load_identity_file(id->filename, id->userprovided)) == NULL) |
977 | return (-1); | 982 | return (-1); /* XXX return decent error code */ |
978 | ret = key_sign(prv, sigp, lenp, data, datalen); | 983 | ret = sshkey_sign(prv, sigp, lenp, data, datalen, compat); |
979 | key_free(prv); | 984 | sshkey_free(prv); |
980 | return (ret); | 985 | return (ret); |
981 | } | 986 | } |
982 | 987 | ||
@@ -985,7 +990,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) | |||
985 | { | 990 | { |
986 | Buffer b; | 991 | Buffer b; |
987 | u_char *blob, *signature; | 992 | u_char *blob, *signature; |
988 | u_int bloblen, slen; | 993 | u_int bloblen; |
994 | size_t slen; | ||
989 | u_int skip = 0; | 995 | u_int skip = 0; |
990 | int ret = -1; | 996 | int ret = -1; |
991 | int have_sig = 1; | 997 | int have_sig = 1; |
@@ -1026,8 +1032,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) | |||
1026 | 1032 | ||
1027 | /* generate signature */ | 1033 | /* generate signature */ |
1028 | ret = identity_sign(id, &signature, &slen, | 1034 | ret = identity_sign(id, &signature, &slen, |
1029 | buffer_ptr(&b), buffer_len(&b)); | 1035 | buffer_ptr(&b), buffer_len(&b), datafellows); |
1030 | if (ret == -1) { | 1036 | if (ret != 0) { |
1031 | free(blob); | 1037 | free(blob); |
1032 | buffer_free(&b); | 1038 | buffer_free(&b); |
1033 | return 0; | 1039 | return 0; |
@@ -1102,7 +1108,7 @@ load_identity_file(char *filename, int userprovided) | |||
1102 | { | 1108 | { |
1103 | Key *private; | 1109 | Key *private; |
1104 | char prompt[300], *passphrase; | 1110 | char prompt[300], *passphrase; |
1105 | int perm_ok = 0, quit, i; | 1111 | int r, perm_ok = 0, quit, i; |
1106 | struct stat st; | 1112 | struct stat st; |
1107 | 1113 | ||
1108 | if (stat(filename, &st) < 0) { | 1114 | if (stat(filename, &st) < 0) { |
@@ -1110,33 +1116,49 @@ load_identity_file(char *filename, int userprovided) | |||
1110 | filename, strerror(errno)); | 1116 | filename, strerror(errno)); |
1111 | return NULL; | 1117 | return NULL; |
1112 | } | 1118 | } |
1113 | private = key_load_private_type(KEY_UNSPEC, filename, "", NULL, &perm_ok); | 1119 | snprintf(prompt, sizeof prompt, |
1114 | if (!perm_ok) { | 1120 | "Enter passphrase for key '%.100s': ", filename); |
1115 | if (private != NULL) | 1121 | for (i = 0; i <= options.number_of_password_prompts; i++) { |
1116 | key_free(private); | 1122 | if (i == 0) |
1117 | return NULL; | 1123 | passphrase = ""; |
1118 | } | 1124 | else { |
1119 | if (private == NULL) { | ||
1120 | if (options.batch_mode) | ||
1121 | return NULL; | ||
1122 | snprintf(prompt, sizeof prompt, | ||
1123 | "Enter passphrase for key '%.100s': ", filename); | ||
1124 | for (i = 0; i < options.number_of_password_prompts; i++) { | ||
1125 | passphrase = read_passphrase(prompt, 0); | 1125 | passphrase = read_passphrase(prompt, 0); |
1126 | if (strcmp(passphrase, "") != 0) { | 1126 | if (*passphrase == '\0') { |
1127 | private = key_load_private_type(KEY_UNSPEC, | ||
1128 | filename, passphrase, NULL, NULL); | ||
1129 | quit = 0; | ||
1130 | } else { | ||
1131 | debug2("no passphrase given, try next key"); | 1127 | debug2("no passphrase given, try next key"); |
1128 | free(passphrase); | ||
1129 | break; | ||
1130 | } | ||
1131 | } | ||
1132 | switch ((r = sshkey_load_private_type(KEY_UNSPEC, filename, | ||
1133 | passphrase, &private, NULL, &perm_ok))) { | ||
1134 | case 0: | ||
1135 | break; | ||
1136 | case SSH_ERR_KEY_WRONG_PASSPHRASE: | ||
1137 | if (options.batch_mode) { | ||
1138 | quit = 1; | ||
1139 | break; | ||
1140 | } | ||
1141 | debug2("bad passphrase given, try again..."); | ||
1142 | break; | ||
1143 | case SSH_ERR_SYSTEM_ERROR: | ||
1144 | if (errno == ENOENT) { | ||
1145 | debug2("Load key \"%s\": %s", | ||
1146 | filename, ssh_err(r)); | ||
1132 | quit = 1; | 1147 | quit = 1; |
1148 | break; | ||
1133 | } | 1149 | } |
1150 | /* FALLTHROUGH */ | ||
1151 | default: | ||
1152 | error("Load key \"%s\": %s", filename, ssh_err(r)); | ||
1153 | quit = 1; | ||
1154 | break; | ||
1155 | } | ||
1156 | if (i > 0) { | ||
1134 | explicit_bzero(passphrase, strlen(passphrase)); | 1157 | explicit_bzero(passphrase, strlen(passphrase)); |
1135 | free(passphrase); | 1158 | free(passphrase); |
1136 | if (private != NULL || quit) | ||
1137 | break; | ||
1138 | debug2("bad passphrase given, try again..."); | ||
1139 | } | 1159 | } |
1160 | if (private != NULL || quit) | ||
1161 | break; | ||
1140 | } | 1162 | } |
1141 | return private; | 1163 | return private; |
1142 | } | 1164 | } |
@@ -1150,12 +1172,12 @@ load_identity_file(char *filename, int userprovided) | |||
1150 | static void | 1172 | static void |
1151 | pubkey_prepare(Authctxt *authctxt) | 1173 | pubkey_prepare(Authctxt *authctxt) |
1152 | { | 1174 | { |
1153 | Identity *id, *id2, *tmp; | 1175 | struct identity *id, *id2, *tmp; |
1154 | Idlist agent, files, *preferred; | 1176 | struct idlist agent, files, *preferred; |
1155 | Key *key; | 1177 | struct sshkey *key; |
1156 | AuthenticationConnection *ac; | 1178 | int agent_fd, i, r, found; |
1157 | char *comment; | 1179 | size_t j; |
1158 | int i, found; | 1180 | struct ssh_identitylist *idlist; |
1159 | 1181 | ||
1160 | TAILQ_INIT(&agent); /* keys from the agent */ | 1182 | TAILQ_INIT(&agent); /* keys from the agent */ |
1161 | TAILQ_INIT(&files); /* keys from the config file */ | 1183 | TAILQ_INIT(&files); /* keys from the config file */ |
@@ -1185,7 +1207,7 @@ pubkey_prepare(Authctxt *authctxt) | |||
1185 | if (id2->key == NULL || | 1207 | if (id2->key == NULL || |
1186 | (id2->key->flags & SSHKEY_FLAG_EXT) == 0) | 1208 | (id2->key->flags & SSHKEY_FLAG_EXT) == 0) |
1187 | continue; | 1209 | continue; |
1188 | if (key_equal(id->key, id2->key)) { | 1210 | if (sshkey_equal(id->key, id2->key)) { |
1189 | TAILQ_REMOVE(&files, id, next); | 1211 | TAILQ_REMOVE(&files, id, next); |
1190 | TAILQ_INSERT_TAIL(preferred, id, next); | 1212 | TAILQ_INSERT_TAIL(preferred, id, next); |
1191 | found = 1; | 1213 | found = 1; |
@@ -1200,37 +1222,48 @@ pubkey_prepare(Authctxt *authctxt) | |||
1200 | } | 1222 | } |
1201 | } | 1223 | } |
1202 | /* list of keys supported by the agent */ | 1224 | /* list of keys supported by the agent */ |
1203 | if ((ac = ssh_get_authentication_connection())) { | 1225 | if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) { |
1204 | for (key = ssh_get_first_identity(ac, &comment, 2); | 1226 | if (r != SSH_ERR_AGENT_NOT_PRESENT) |
1205 | key != NULL; | 1227 | debug("%s: ssh_get_authentication_socket: %s", |
1206 | key = ssh_get_next_identity(ac, &comment, 2)) { | 1228 | __func__, ssh_err(r)); |
1229 | } else if ((r = ssh_fetch_identitylist(agent_fd, 2, &idlist)) != 0) { | ||
1230 | if (r != SSH_ERR_AGENT_NO_IDENTITIES) | ||
1231 | debug("%s: ssh_fetch_identitylist: %s", | ||
1232 | __func__, ssh_err(r)); | ||
1233 | } else { | ||
1234 | for (j = 0; j < idlist->nkeys; j++) { | ||
1207 | found = 0; | 1235 | found = 0; |
1208 | TAILQ_FOREACH(id, &files, next) { | 1236 | TAILQ_FOREACH(id, &files, next) { |
1209 | /* agent keys from the config file are preferred */ | 1237 | /* |
1210 | if (key_equal(key, id->key)) { | 1238 | * agent keys from the config file are |
1211 | key_free(key); | 1239 | * preferred |
1212 | free(comment); | 1240 | */ |
1241 | if (sshkey_equal(idlist->keys[j], id->key)) { | ||
1213 | TAILQ_REMOVE(&files, id, next); | 1242 | TAILQ_REMOVE(&files, id, next); |
1214 | TAILQ_INSERT_TAIL(preferred, id, next); | 1243 | TAILQ_INSERT_TAIL(preferred, id, next); |
1215 | id->ac = ac; | 1244 | id->agent_fd = agent_fd; |
1216 | found = 1; | 1245 | found = 1; |
1217 | break; | 1246 | break; |
1218 | } | 1247 | } |
1219 | } | 1248 | } |
1220 | if (!found && !options.identities_only) { | 1249 | if (!found && !options.identities_only) { |
1221 | id = xcalloc(1, sizeof(*id)); | 1250 | id = xcalloc(1, sizeof(*id)); |
1222 | id->key = key; | 1251 | /* XXX "steals" key/comment from idlist */ |
1223 | id->filename = comment; | 1252 | id->key = idlist->keys[j]; |
1224 | id->ac = ac; | 1253 | id->filename = idlist->comments[j]; |
1254 | idlist->keys[j] = NULL; | ||
1255 | idlist->comments[j] = NULL; | ||
1256 | id->agent_fd = agent_fd; | ||
1225 | TAILQ_INSERT_TAIL(&agent, id, next); | 1257 | TAILQ_INSERT_TAIL(&agent, id, next); |
1226 | } | 1258 | } |
1227 | } | 1259 | } |
1260 | ssh_free_identitylist(idlist); | ||
1228 | /* append remaining agent keys */ | 1261 | /* append remaining agent keys */ |
1229 | for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) { | 1262 | for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) { |
1230 | TAILQ_REMOVE(&agent, id, next); | 1263 | TAILQ_REMOVE(&agent, id, next); |
1231 | TAILQ_INSERT_TAIL(preferred, id, next); | 1264 | TAILQ_INSERT_TAIL(preferred, id, next); |
1232 | } | 1265 | } |
1233 | authctxt->agent = ac; | 1266 | authctxt->agent_fd = agent_fd; |
1234 | } | 1267 | } |
1235 | /* append remaining keys from the config file */ | 1268 | /* append remaining keys from the config file */ |
1236 | for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) { | 1269 | for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) { |
@@ -1248,13 +1281,13 @@ pubkey_cleanup(Authctxt *authctxt) | |||
1248 | { | 1281 | { |
1249 | Identity *id; | 1282 | Identity *id; |
1250 | 1283 | ||
1251 | if (authctxt->agent != NULL) | 1284 | if (authctxt->agent_fd != -1) |
1252 | ssh_close_authentication_connection(authctxt->agent); | 1285 | ssh_close_authentication_socket(authctxt->agent_fd); |
1253 | for (id = TAILQ_FIRST(&authctxt->keys); id; | 1286 | for (id = TAILQ_FIRST(&authctxt->keys); id; |
1254 | id = TAILQ_FIRST(&authctxt->keys)) { | 1287 | id = TAILQ_FIRST(&authctxt->keys)) { |
1255 | TAILQ_REMOVE(&authctxt->keys, id, next); | 1288 | TAILQ_REMOVE(&authctxt->keys, id, next); |
1256 | if (id->key) | 1289 | if (id->key) |
1257 | key_free(id->key); | 1290 | sshkey_free(id->key); |
1258 | free(id->filename); | 1291 | free(id->filename); |
1259 | free(id); | 1292 | free(id); |
1260 | } | 1293 | } |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshd.c,v 1.431 2015/01/07 18:15:07 tedu Exp $ */ | 1 | /* $OpenBSD: sshd.c,v 1.432 2015/01/14 20:05:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -123,6 +123,7 @@ | |||
123 | #include "roaming.h" | 123 | #include "roaming.h" |
124 | #include "ssh-sandbox.h" | 124 | #include "ssh-sandbox.h" |
125 | #include "version.h" | 125 | #include "version.h" |
126 | #include "ssherr.h" | ||
126 | 127 | ||
127 | #ifndef O_NOCTTY | 128 | #ifndef O_NOCTTY |
128 | #define O_NOCTTY 0 | 129 | #define O_NOCTTY 0 |
@@ -191,7 +192,7 @@ char *server_version_string = NULL; | |||
191 | Kex *xxx_kex; | 192 | Kex *xxx_kex; |
192 | 193 | ||
193 | /* Daemon's agent connection */ | 194 | /* Daemon's agent connection */ |
194 | AuthenticationConnection *auth_conn = NULL; | 195 | int auth_sock = -1; |
195 | int have_agent = 0; | 196 | int have_agent = 0; |
196 | 197 | ||
197 | /* | 198 | /* |
@@ -655,7 +656,7 @@ privsep_preauth_child(void) | |||
655 | static int | 656 | static int |
656 | privsep_preauth(Authctxt *authctxt) | 657 | privsep_preauth(Authctxt *authctxt) |
657 | { | 658 | { |
658 | int status; | 659 | int status, r; |
659 | pid_t pid; | 660 | pid_t pid; |
660 | struct ssh_sandbox *box = NULL; | 661 | struct ssh_sandbox *box = NULL; |
661 | 662 | ||
@@ -673,8 +674,14 @@ privsep_preauth(Authctxt *authctxt) | |||
673 | debug2("Network child is on pid %ld", (long)pid); | 674 | debug2("Network child is on pid %ld", (long)pid); |
674 | 675 | ||
675 | pmonitor->m_pid = pid; | 676 | pmonitor->m_pid = pid; |
676 | if (have_agent) | 677 | if (have_agent) { |
677 | auth_conn = ssh_get_authentication_connection(); | 678 | r = ssh_get_authentication_socket(&auth_sock); |
679 | if (r != 0) { | ||
680 | error("Could not get agent socket: %s", | ||
681 | ssh_err(r)); | ||
682 | have_agent = 0; | ||
683 | } | ||
684 | } | ||
678 | if (box != NULL) | 685 | if (box != NULL) |
679 | ssh_sandbox_parent_preauth(box, pid); | 686 | ssh_sandbox_parent_preauth(box, pid); |
680 | monitor_child_preauth(authctxt, pmonitor); | 687 | monitor_child_preauth(authctxt, pmonitor); |
@@ -1397,7 +1404,7 @@ main(int ac, char **av) | |||
1397 | { | 1404 | { |
1398 | extern char *optarg; | 1405 | extern char *optarg; |
1399 | extern int optind; | 1406 | extern int optind; |
1400 | int opt, i, j, on = 1; | 1407 | int r, opt, i, j, on = 1; |
1401 | int sock_in = -1, sock_out = -1, newsock = -1; | 1408 | int sock_in = -1, sock_out = -1, newsock = -1; |
1402 | const char *remote_ip; | 1409 | const char *remote_ip; |
1403 | int remote_port; | 1410 | int remote_port; |
@@ -1706,7 +1713,7 @@ main(int ac, char **av) | |||
1706 | if (strcmp(options.host_key_agent, SSH_AUTHSOCKET_ENV_NAME)) | 1713 | if (strcmp(options.host_key_agent, SSH_AUTHSOCKET_ENV_NAME)) |
1707 | setenv(SSH_AUTHSOCKET_ENV_NAME, | 1714 | setenv(SSH_AUTHSOCKET_ENV_NAME, |
1708 | options.host_key_agent, 1); | 1715 | options.host_key_agent, 1); |
1709 | have_agent = ssh_agent_present(); | 1716 | have_agent = ssh_get_authentication_socket(NULL); |
1710 | } | 1717 | } |
1711 | 1718 | ||
1712 | for (i = 0; i < options.num_host_key_files; i++) { | 1719 | for (i = 0; i < options.num_host_key_files; i++) { |
@@ -2103,8 +2110,12 @@ main(int ac, char **av) | |||
2103 | if (use_privsep) { | 2110 | if (use_privsep) { |
2104 | if (privsep_preauth(authctxt) == 1) | 2111 | if (privsep_preauth(authctxt) == 1) |
2105 | goto authenticated; | 2112 | goto authenticated; |
2106 | } else if (compat20 && have_agent) | 2113 | } else if (compat20 && have_agent) { |
2107 | auth_conn = ssh_get_authentication_connection(); | 2114 | if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) { |
2115 | error("Unable to get agent socket: %s", ssh_err(r)); | ||
2116 | have_agent = -1; | ||
2117 | } | ||
2118 | } | ||
2108 | 2119 | ||
2109 | /* perform the key exchange */ | 2120 | /* perform the key exchange */ |
2110 | /* authenticate user and start session */ | 2121 | /* authenticate user and start session */ |
@@ -2425,6 +2436,8 @@ void | |||
2425 | sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, u_int *slen, | 2436 | sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, u_int *slen, |
2426 | u_char *data, u_int dlen) | 2437 | u_char *data, u_int dlen) |
2427 | { | 2438 | { |
2439 | int r; | ||
2440 | |||
2428 | if (privkey) { | 2441 | if (privkey) { |
2429 | if (PRIVSEP(key_sign(privkey, signature, slen, data, dlen) < 0)) | 2442 | if (PRIVSEP(key_sign(privkey, signature, slen, data, dlen) < 0)) |
2430 | fatal("%s: key_sign failed", __func__); | 2443 | fatal("%s: key_sign failed", __func__); |
@@ -2432,9 +2445,15 @@ sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, u_int *slen, | |||
2432 | if (mm_key_sign(pubkey, signature, slen, data, dlen) < 0) | 2445 | if (mm_key_sign(pubkey, signature, slen, data, dlen) < 0) |
2433 | fatal("%s: pubkey_sign failed", __func__); | 2446 | fatal("%s: pubkey_sign failed", __func__); |
2434 | } else { | 2447 | } else { |
2435 | if (ssh_agent_sign(auth_conn, pubkey, signature, slen, data, | 2448 | size_t xxx_slen; |
2436 | dlen)) | 2449 | |
2437 | fatal("%s: ssh_agent_sign failed", __func__); | 2450 | if ((r = ssh_agent_sign(auth_sock, pubkey, signature, &xxx_slen, |
2451 | data, dlen, datafellows)) != 0) | ||
2452 | fatal("%s: ssh_agent_sign failed: %s", | ||
2453 | __func__, ssh_err(r)); | ||
2454 | /* XXX: Old API is u_int; new size_t */ | ||
2455 | if (slen != NULL) | ||
2456 | *slen = xxx_slen; | ||
2438 | } | 2457 | } |
2439 | } | 2458 | } |
2440 | 2459 | ||