5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
10 * Created: Wed Mar 29 01:30:28 1995 ylo
12 * Functions for connecting the local authentication agent.
17 RCSID("$OpenBSD: authfd.c,v 1.24 2000/08/15 19:20:46 markus Exp $");
26 #include <openssl/rsa.h>
27 #include <openssl/dsa.h>
28 #include <openssl/evp.h>
34 int decode_reply(int type);
36 /* Returns the number of the authentication fd, or -1 if there is none. */
39 ssh_get_authentication_socket()
41 const char *authsocket;
43 struct sockaddr_un sunaddr;
45 authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
49 sunaddr.sun_family = AF_UNIX;
50 strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
51 #ifdef HAVE_SUN_LEN_IN_SOCKADDR_UN
52 sunaddr.sun_len = len = SUN_LEN(&sunaddr)+1;
53 #else /* HAVE_SUN_LEN_IN_SOCKADDR_UN */
54 len = SUN_LEN(&sunaddr)+1;
55 #endif /* HAVE_SUN_LEN_IN_SOCKADDR_UN */
57 sock = socket(AF_UNIX, SOCK_STREAM, 0);
62 if (fcntl(sock, F_SETFD, 1) == -1) {
66 if (connect(sock, (struct sockaddr *) & sunaddr, len) < 0) {
74 ssh_request_reply(AuthenticationConnection *auth,
75 Buffer *request, Buffer *reply)
80 /* Get the length of the message, and format it in the buffer. */
81 len = buffer_len(request);
84 /* Send the length and then the packet to the agent. */
85 if (atomicio(write, auth->fd, buf, 4) != 4 ||
86 atomicio(write, auth->fd, buffer_ptr(request),
87 buffer_len(request)) != buffer_len(request)) {
88 error("Error writing to authentication socket.");
92 * Wait for response from the agent. First read the length of the
97 l = read(auth->fd, buf + 4 - len, len);
99 error("Error reading response length from authentication socket.");
105 /* Extract the length, and check it for sanity. */
106 len = GET_32BIT(buf);
107 if (len > 256 * 1024)
108 fatal("Authentication response too long: %d", len);
110 /* Read the rest of the response in to the buffer. */
116 l = read(auth->fd, buf, l);
118 error("Error reading response from authentication socket.");
121 buffer_append(reply, (char *) buf, l);
128 * Closes the agent socket if it should be closed (depends on how it was
129 * obtained). The argument must have been returned by
130 * ssh_get_authentication_socket().
134 ssh_close_authentication_socket(int sock)
136 if (getenv(SSH_AUTHSOCKET_ENV_NAME))
141 * Opens and connects a private socket for communication with the
142 * authentication agent. Returns the file descriptor (which must be
143 * shut down and closed by the caller when no longer needed).
144 * Returns NULL if an error occurred and the connection could not be
148 AuthenticationConnection *
149 ssh_get_authentication_connection()
151 AuthenticationConnection *auth;
154 sock = ssh_get_authentication_socket();
157 * Fail if we couldn't obtain a connection. This happens if we
158 * exited due to a timeout.
163 auth = xmalloc(sizeof(*auth));
165 buffer_init(&auth->packet);
166 buffer_init(&auth->identities);
173 * Closes the connection to the authentication agent and frees any associated
178 ssh_close_authentication_connection(AuthenticationConnection *ac)
180 buffer_free(&ac->packet);
181 buffer_free(&ac->identities);
187 * Returns the first authentication identity held by the agent.
188 * Returns true if an identity is available, 0 otherwise.
189 * The caller must initialize the integers before the call, and free the
190 * comment after a successful call (before calling ssh_get_next_identity).
194 ssh_get_first_identity(AuthenticationConnection *auth,
195 BIGNUM *e, BIGNUM *n, char **comment)
201 * Send a message to the agent requesting for a list of the
202 * identities it can represent.
204 buffer_init(&request);
205 buffer_put_char(&request, SSH_AGENTC_REQUEST_RSA_IDENTITIES);
207 buffer_clear(&auth->identities);
208 if (ssh_request_reply(auth, &request, &auth->identities) == 0) {
209 buffer_free(&request);
212 buffer_free(&request);
214 /* Get message type, and verify that we got a proper answer. */
215 type = buffer_get_char(&auth->identities);
216 if (type != SSH_AGENT_RSA_IDENTITIES_ANSWER)
217 fatal("Bad authentication reply message type: %d", type);
219 /* Get the number of entries in the response and check it for sanity. */
220 auth->howmany = buffer_get_int(&auth->identities);
221 if (auth->howmany > 1024)
222 fatal("Too many identities in authentication reply: %d\n",
225 /* Return the first entry (if any). */
226 return ssh_get_next_identity(auth, e, n, comment);
230 * Returns the next authentication identity for the agent. Other functions
231 * can be called between this and ssh_get_first_identity or two calls of this
232 * function. This returns 0 if there are no more identities. The caller
233 * must free comment after a successful return.
237 ssh_get_next_identity(AuthenticationConnection *auth,
238 BIGNUM *e, BIGNUM *n, char **comment)
242 /* Return failure if no more entries. */
243 if (auth->howmany <= 0)
247 * Get the next entry from the packet. These will abort with a fatal
248 * error if the packet is too short or contains corrupt data.
250 bits = buffer_get_int(&auth->identities);
251 buffer_get_bignum(&auth->identities, e);
252 buffer_get_bignum(&auth->identities, n);
253 *comment = buffer_get_string(&auth->identities, NULL);
255 if (bits != BN_num_bits(n))
256 log("Warning: identity keysize mismatch: actual %d, announced %u",
257 BN_num_bits(n), bits);
259 /* Decrement the number of remaining entries. */
266 * Generates a random challenge, sends it to the agent, and waits for
267 * response from the agent. Returns true (non-zero) if the agent gave the
268 * correct answer, zero otherwise. Response type selects the style of
269 * response desired, with 0 corresponding to protocol version 1.0 (no longer
270 * supported) and 1 corresponding to protocol version 1.1.
274 ssh_decrypt_challenge(AuthenticationConnection *auth,
275 BIGNUM* e, BIGNUM *n, BIGNUM *challenge,
276 unsigned char session_id[16],
277 unsigned int response_type,
278 unsigned char response[16])
285 if (response_type == 0)
286 fatal("Compatibility with ssh protocol version "
287 "1.0 no longer supported.");
289 buffer_init(&buffer);
290 buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE);
291 buffer_put_int(&buffer, BN_num_bits(n));
292 buffer_put_bignum(&buffer, e);
293 buffer_put_bignum(&buffer, n);
294 buffer_put_bignum(&buffer, challenge);
295 buffer_append(&buffer, (char *) session_id, 16);
296 buffer_put_int(&buffer, response_type);
298 if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
299 buffer_free(&buffer);
302 type = buffer_get_char(&buffer);
304 if (type == SSH_AGENT_FAILURE) {
305 log("Agent admitted failure to authenticate using the key.");
306 } else if (type != SSH_AGENT_RSA_RESPONSE) {
307 fatal("Bad authentication response: %d", type);
311 * Get the response from the packet. This will abort with a
312 * fatal error if the packet is corrupt.
314 for (i = 0; i < 16; i++)
315 response[i] = buffer_get_char(&buffer);
317 buffer_free(&buffer);
321 /* Encode key for a message to the agent. */
324 ssh_encode_identity_rsa(Buffer *b, RSA *key, const char *comment)
327 buffer_put_char(b, SSH_AGENTC_ADD_RSA_IDENTITY);
328 buffer_put_int(b, BN_num_bits(key->n));
329 buffer_put_bignum(b, key->n);
330 buffer_put_bignum(b, key->e);
331 buffer_put_bignum(b, key->d);
332 /* To keep within the protocol: p < q for ssh. in SSL p > q */
333 buffer_put_bignum(b, key->iqmp); /* ssh key->u */
334 buffer_put_bignum(b, key->q); /* ssh key->p, SSL key->q */
335 buffer_put_bignum(b, key->p); /* ssh key->q, SSL key->p */
336 buffer_put_string(b, comment, strlen(comment));
340 ssh_encode_identity_dsa(Buffer *b, DSA *key, const char *comment)
343 buffer_put_char(b, SSH2_AGENTC_ADD_IDENTITY);
344 buffer_put_cstring(b, KEX_DSS);
345 buffer_put_bignum2(b, key->p);
346 buffer_put_bignum2(b, key->q);
347 buffer_put_bignum2(b, key->g);
348 buffer_put_bignum2(b, key->pub_key);
349 buffer_put_bignum2(b, key->priv_key);
350 buffer_put_string(b, comment, strlen(comment));
354 * Adds an identity to the authentication server. This call is not meant to
355 * be used by normal applications.
359 ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
364 buffer_init(&buffer);
368 ssh_encode_identity_rsa(&buffer, key->rsa, comment);
371 ssh_encode_identity_dsa(&buffer, key->dsa, comment);
374 buffer_free(&buffer);
378 if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
379 buffer_free(&buffer);
382 type = buffer_get_char(&buffer);
383 buffer_free(&buffer);
384 return decode_reply(type);
388 * Removes an identity from the authentication server. This call is not
389 * meant to be used by normal applications.
393 ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
398 buffer_init(&buffer);
399 buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
400 buffer_put_int(&buffer, BN_num_bits(key->n));
401 buffer_put_bignum(&buffer, key->e);
402 buffer_put_bignum(&buffer, key->n);
404 if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
405 buffer_free(&buffer);
408 type = buffer_get_char(&buffer);
409 buffer_free(&buffer);
410 return decode_reply(type);
414 * Removes all identities from the agent. This call is not meant to be used
415 * by normal applications.
419 ssh_remove_all_identities(AuthenticationConnection *auth)
424 buffer_init(&buffer);
425 buffer_put_char(&buffer, SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES);
427 if (ssh_request_reply(auth, &buffer, &buffer) == 0) {
428 buffer_free(&buffer);
431 type = buffer_get_char(&buffer);
432 buffer_free(&buffer);
433 return decode_reply(type);
437 decode_reply(int type)
440 case SSH_AGENT_FAILURE:
441 log("SSH_AGENT_FAILURE");
443 case SSH_AGENT_SUCCESS:
446 fatal("Bad response from authentication agent: %d", type);