From: djm Date: Wed, 14 Jan 2015 20:05:27 +0000 (+0000) Subject: move authfd.c and its tentacles to the new buffer/key API; X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=b7e9f6c7aaa7ed1f45b871f8b184da3bb8c4dc83;p=openbsd move authfd.c and its tentacles to the new buffer/key API; ok markus@ --- diff --git a/usr.bin/ssh/authfd.c b/usr.bin/ssh/authfd.c index b7f0a018c8f..f7e6f1e934b 100644 --- a/usr.bin/ssh/authfd.c +++ b/usr.bin/ssh/authfd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfd.c,v 1.93 2014/04/29 18:01:49 markus Exp $ */ +/* $OpenBSD: authfd.c,v 1.94 2015/01/14 20:05:27 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -45,124 +45,121 @@ #include #include #include +#include #include "xmalloc.h" #include "ssh.h" #include "rsa.h" -#include "buffer.h" -#include "key.h" +#include "sshbuf.h" +#include "sshkey.h" #include "authfd.h" #include "cipher.h" -#include "kex.h" #include "compat.h" #include "log.h" #include "atomicio.h" #include "misc.h" +#include "ssherr.h" -static int agent_present = 0; - -/* helper */ -int decode_reply(int type); +#define MAX_AGENT_IDENTITIES 2048 /* Max keys in agent reply */ +#define MAX_AGENT_REPLY_LEN (256 * 1024) /* Max bytes in agent reply */ /* macro to check for "agent failure" message */ #define agent_failed(x) \ - ((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE) || \ + ((x == SSH_AGENT_FAILURE) || \ + (x == SSH_COM_AGENT2_FAILURE) || \ (x == SSH2_AGENT_FAILURE)) -int -ssh_agent_present(void) +/* Convert success/failure response from agent to a err.h status */ +static int +decode_reply(u_char type) { - int authfd; - - if (agent_present) - return 1; - if ((authfd = ssh_get_authentication_socket()) == -1) + if (agent_failed(type)) + return SSH_ERR_AGENT_FAILURE; + else if (type == SSH_AGENT_SUCCESS) return 0; - else { - ssh_close_authentication_socket(authfd); - return 1; - } + else + return SSH_ERR_INVALID_FORMAT; } /* Returns the number of the authentication fd, or -1 if there is none. */ - int -ssh_get_authentication_socket(void) +ssh_get_authentication_socket(int *fdp) { const char *authsocket; - int sock; + int sock, oerrno; struct sockaddr_un sunaddr; + if (fdp != NULL) + *fdp = -1; + authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); if (!authsocket) - return -1; + return SSH_ERR_AGENT_NOT_PRESENT; memset(&sunaddr, 0, sizeof(sunaddr)); sunaddr.sun_family = AF_UNIX; strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); - sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) - return -1; + if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return SSH_ERR_SYSTEM_ERROR; /* close on exec */ - if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) { + if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1 || + connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) { + oerrno = errno; close(sock); - return -1; + errno = oerrno; + return SSH_ERR_SYSTEM_ERROR; } - if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { + if (fdp != NULL) + *fdp = sock; + else close(sock); - return -1; - } - agent_present = 1; - return sock; + return 0; } +/* Communicate with agent: send request and read reply */ static int -ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply) +ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply) { - u_int l, len; + int r; + size_t l, len; char buf[1024]; /* Get the length of the message, and format it in the buffer. */ - len = buffer_len(request); + len = sshbuf_len(request); put_u32(buf, len); /* Send the length and then the packet to the agent. */ - if (atomicio(vwrite, auth->fd, buf, 4) != 4 || - atomicio(vwrite, auth->fd, buffer_ptr(request), - buffer_len(request)) != buffer_len(request)) { - error("Error writing to authentication socket."); - return 0; - } + if (atomicio(vwrite, sock, buf, 4) != 4 || + atomicio(vwrite, sock, (u_char *)sshbuf_ptr(request), + sshbuf_len(request)) != sshbuf_len(request)) + return SSH_ERR_AGENT_COMMUNICATION; /* * Wait for response from the agent. First read the length of the * response packet. */ - if (atomicio(read, auth->fd, buf, 4) != 4) { - error("Error reading response length from authentication socket."); - return 0; - } + if (atomicio(read, sock, buf, 4) != 4) + return SSH_ERR_AGENT_COMMUNICATION; /* Extract the length, and check it for sanity. */ len = get_u32(buf); - if (len > 256 * 1024) - fatal("Authentication response too long: %u", len); + if (len > MAX_AGENT_REPLY_LEN) + return SSH_ERR_INVALID_FORMAT; /* Read the rest of the response in to the buffer. */ - buffer_clear(reply); + sshbuf_reset(reply); while (len > 0) { l = len; if (l > sizeof(buf)) l = sizeof(buf); - if (atomicio(read, auth->fd, buf, l) != l) { - error("Error reading response from authentication socket."); - return 0; - } - buffer_append(reply, buf, l); + if (atomicio(read, sock, buf, l) != l) + return SSH_ERR_AGENT_COMMUNICATION; + if ((r = sshbuf_put(reply, buf, l)) != 0) + return r; len -= l; } - return 1; + return 0; } /* @@ -170,7 +167,6 @@ ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply * obtained). The argument must have been returned by * ssh_get_authentication_socket(). */ - void ssh_close_authentication_socket(int sock) { @@ -178,80 +174,103 @@ ssh_close_authentication_socket(int sock) close(sock); } -/* - * Opens and connects a private socket for communication with the - * authentication agent. Returns the file descriptor (which must be - * shut down and closed by the caller when no longer needed). - * Returns NULL if an error occurred and the connection could not be - * opened. - */ - -AuthenticationConnection * -ssh_get_authentication_connection(void) +/* Lock/unlock agent */ +int +ssh_lock_agent(int sock, int lock, const char *password) { - AuthenticationConnection *auth; - int sock; - - sock = ssh_get_authentication_socket(); - - /* - * Fail if we couldn't obtain a connection. This happens if we - * exited due to a timeout. - */ - if (sock < 0) - return NULL; - - auth = xcalloc(1, sizeof(*auth)); - auth->fd = sock; - buffer_init(&auth->identities); - auth->howmany = 0; - - return auth; + int r; + u_char type = lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK; + struct sshbuf *msg; + + if ((msg = sshbuf_new()) == NULL) + return SSH_ERR_ALLOC_FAIL; + if ((r = sshbuf_put_u8(msg, type)) != 0 || + (r = sshbuf_put_cstring(msg, password)) != 0) + goto out; + if ((r = ssh_request_reply(sock, msg, msg)) != 0) + goto out; + if ((r = sshbuf_get_u8(msg, &type)) != 0) + goto out; + r = decode_reply(type); + out: + sshbuf_free(msg); + return r; } -/* - * Closes the connection to the authentication agent and frees any associated - * memory. - */ - -void -ssh_close_authentication_connection(AuthenticationConnection *auth) +#ifdef WITH_SSH1 +static int +deserialise_identity1(struct sshbuf *ids, struct sshkey **keyp, char **commentp) { - buffer_free(&auth->identities); - close(auth->fd); - free(auth); + struct sshkey *key; + int r, keybits; + u_int32_t bits; + char *comment = NULL; + + if ((key = sshkey_new(KEY_RSA1)) == NULL) + return SSH_ERR_ALLOC_FAIL; + if ((r = sshbuf_get_u32(ids, &bits)) != 0 || + (r = sshbuf_get_bignum1(ids, key->rsa->e)) != 0 || + (r = sshbuf_get_bignum1(ids, key->rsa->n)) != 0 || + (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0) + goto out; + keybits = BN_num_bits(key->rsa->n); + /* XXX previously we just warned here. I think we should be strict */ + if (keybits < 0 || bits != (u_int)keybits) { + r = SSH_ERR_KEY_BITS_MISMATCH; + goto out; + } + if (keyp != NULL) { + *keyp = key; + key = NULL; + } + if (commentp != NULL) { + *commentp = comment; + comment = NULL; + } + r = 0; + out: + sshkey_free(key); + free(comment); + return r; } +#endif -/* Lock/unlock agent */ -int -ssh_lock_agent(AuthenticationConnection *auth, int lock, const char *password) +static int +deserialise_identity2(struct sshbuf *ids, struct sshkey **keyp, char **commentp) { - int type; - Buffer msg; - - buffer_init(&msg); - buffer_put_char(&msg, lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK); - buffer_put_cstring(&msg, password); - - if (ssh_request_reply(auth, &msg, &msg) == 0) { - buffer_free(&msg); - return 0; + int r; + char *comment = NULL; + const u_char *blob; + size_t blen; + + if ((r = sshbuf_get_string_direct(ids, &blob, &blen)) != 0 || + (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0) + goto out; + if ((r = sshkey_from_blob(blob, blen, keyp)) != 0) + goto out; + if (commentp != NULL) { + *commentp = comment; + comment = NULL; } - type = buffer_get_char(&msg); - buffer_free(&msg); - return decode_reply(type); + r = 0; + out: + free(comment); + return r; } /* - * Returns the first authentication identity held by the agent. + * Fetch list of identities held by the agent. */ - int -ssh_get_num_identities(AuthenticationConnection *auth, int version) +ssh_fetch_identitylist(int sock, int version, struct ssh_identitylist **idlp) { - int type, code1 = 0, code2 = 0; - Buffer request; + u_char type, code1 = 0, code2 = 0; + u_int32_t num, i; + struct sshbuf *msg; + struct ssh_identitylist *idl = NULL; + int r; + /* Determine request and expected response types */ switch (version) { case 1: code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES; @@ -262,238 +281,270 @@ ssh_get_num_identities(AuthenticationConnection *auth, int version) code2 = SSH2_AGENT_IDENTITIES_ANSWER; break; default: - return 0; + return SSH_ERR_INVALID_ARGUMENT; } /* * Send a message to the agent requesting for a list of the * identities it can represent. */ - buffer_init(&request); - buffer_put_char(&request, code1); + if ((msg = sshbuf_new()) == NULL) + return SSH_ERR_ALLOC_FAIL; + if ((r = sshbuf_put_u8(msg, code1)) != 0) + goto out; - buffer_clear(&auth->identities); - if (ssh_request_reply(auth, &request, &auth->identities) == 0) { - buffer_free(&request); - return 0; - } - buffer_free(&request); + if ((r = ssh_request_reply(sock, msg, msg)) != 0) + goto out; /* Get message type, and verify that we got a proper answer. */ - type = buffer_get_char(&auth->identities); + if ((r = sshbuf_get_u8(msg, &type)) != 0) + goto out; if (agent_failed(type)) { - return 0; + r = SSH_ERR_AGENT_FAILURE; + goto out; } else if (type != code2) { - fatal("Bad authentication reply message type: %d", type); + r = SSH_ERR_INVALID_FORMAT; + goto out; } /* Get the number of entries in the response and check it for sanity. */ - auth->howmany = buffer_get_int(&auth->identities); - if ((u_int)auth->howmany > 1024) - fatal("Too many identities in authentication reply: %d", - auth->howmany); - - return auth->howmany; -} - -Key * -ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version) -{ - /* get number of identities and return the first entry (if any). */ - if (ssh_get_num_identities(auth, version) > 0) - return ssh_get_next_identity(auth, comment, version); - return NULL; -} + if ((r = sshbuf_get_u32(msg, &num)) != 0) + goto out; + if (num > MAX_AGENT_IDENTITIES) { + r = SSH_ERR_INVALID_FORMAT; + goto out; + } + if (num == 0) { + r = SSH_ERR_AGENT_NO_IDENTITIES; + goto out; + } -Key * -ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version) -{ + /* Deserialise the response into a list of keys/comments */ + if ((idl = calloc(1, sizeof(*idl))) == NULL || + (idl->keys = calloc(num, sizeof(*idl->keys))) == NULL || + (idl->comments = calloc(num, sizeof(*idl->comments))) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + for (i = 0; i < num;) { + switch (version) { + case 1: #ifdef WITH_SSH1 - int keybits; - u_int bits; + if ((r = deserialise_identity1(msg, + &(idl->keys[i]), &(idl->comments[i]))) != 0) + goto out; #endif - u_char *blob; - u_int blen; - Key *key = NULL; - - /* Return failure if no more entries. */ - if (auth->howmany <= 0) - return NULL; + break; + case 2: + if ((r = deserialise_identity2(msg, + &(idl->keys[i]), &(idl->comments[i]))) != 0) { + if (r == SSH_ERR_KEY_TYPE_UNKNOWN) { + /* Gracefully skip unknown key types */ + num--; + continue; + } else + goto out; + } + break; + } + i++; + } + idl->nkeys = num; + *idlp = idl; + idl = NULL; + r = 0; + out: + sshbuf_free(msg); + if (idl != NULL) + ssh_free_identitylist(idl); + return r; +} - /* - * Get the next entry from the packet. These will abort with a fatal - * error if the packet is too short or contains corrupt data. - */ - switch (version) { -#ifdef WITH_SSH1 - case 1: - key = key_new(KEY_RSA1); - bits = buffer_get_int(&auth->identities); - buffer_get_bignum(&auth->identities, key->rsa->e); - buffer_get_bignum(&auth->identities, key->rsa->n); - *comment = buffer_get_string(&auth->identities, NULL); - keybits = BN_num_bits(key->rsa->n); - if (keybits < 0 || bits != (u_int)keybits) - logit("Warning: identity keysize mismatch: actual %d, announced %u", - BN_num_bits(key->rsa->n), bits); - break; -#endif - case 2: - blob = buffer_get_string(&auth->identities, &blen); - *comment = buffer_get_string(&auth->identities, NULL); - key = key_from_blob(blob, blen); - free(blob); - break; - default: - return NULL; +void +ssh_free_identitylist(struct ssh_identitylist *idl) +{ + size_t i; + + if (idl == NULL) + return; + for (i = 0; i < idl->nkeys; i++) { + if (idl->keys != NULL) + sshkey_free(idl->keys[i]); + if (idl->comments != NULL) + free(idl->comments[i]); } - /* Decrement the number of remaining entries. */ - auth->howmany--; - return key; + free(idl); } /* - * Generates a random challenge, sends it to the agent, and waits for - * response from the agent. Returns true (non-zero) if the agent gave the - * correct answer, zero otherwise. Response type selects the style of - * response desired, with 0 corresponding to protocol version 1.0 (no longer - * supported) and 1 corresponding to protocol version 1.1. + * Sends a challenge (typically from a server via ssh(1)) to the agent, + * and waits for a response from the agent. + * Returns true (non-zero) if the agent gave the correct answer, zero + * otherwise. */ #ifdef WITH_SSH1 int -ssh_decrypt_challenge(AuthenticationConnection *auth, - Key* key, BIGNUM *challenge, - u_char session_id[16], - u_int response_type, - u_char response[16]) +ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge, + u_char session_id[16], u_char response[16]) { - Buffer buffer; - int success = 0; - int i; - int type; + struct sshbuf *msg; + int r; + u_char type; if (key->type != KEY_RSA1) - return 0; - if (response_type == 0) { - logit("Compatibility with ssh protocol version 1.0 no longer supported."); - return 0; - } - buffer_init(&buffer); - buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE); - buffer_put_int(&buffer, BN_num_bits(key->rsa->n)); - buffer_put_bignum(&buffer, key->rsa->e); - buffer_put_bignum(&buffer, key->rsa->n); - buffer_put_bignum(&buffer, challenge); - buffer_append(&buffer, session_id, 16); - buffer_put_int(&buffer, response_type); - - if (ssh_request_reply(auth, &buffer, &buffer) == 0) { - buffer_free(&buffer); - return 0; - } - type = buffer_get_char(&buffer); - + return SSH_ERR_INVALID_ARGUMENT; + if ((msg = sshbuf_new()) == NULL) + return SSH_ERR_ALLOC_FAIL; + if ((r = sshbuf_put_u8(msg, SSH_AGENTC_RSA_CHALLENGE)) != 0 || + (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 || + (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 || + (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0 || + (r = sshbuf_put_bignum1(msg, challenge)) != 0 || + (r = sshbuf_put(msg, session_id, 16)) != 0 || + (r = sshbuf_put_u32(msg, 1)) != 0) /* Response type for proto 1.1 */ + goto out; + if ((r = ssh_request_reply(sock, msg, msg)) != 0) + goto out; + if ((r = sshbuf_get_u8(msg, &type)) != 0) + goto out; if (agent_failed(type)) { - logit("Agent admitted failure to authenticate using the key."); + r = SSH_ERR_AGENT_FAILURE; + goto out; } else if (type != SSH_AGENT_RSA_RESPONSE) { - fatal("Bad authentication response: %d", type); - } else { - success = 1; - /* - * Get the response from the packet. This will abort with a - * fatal error if the packet is corrupt. - */ - for (i = 0; i < 16; i++) - response[i] = (u_char)buffer_get_char(&buffer); + r = SSH_ERR_INVALID_FORMAT; + goto out; } - buffer_free(&buffer); - return success; + if ((r = sshbuf_get(msg, response, 16)) != 0) + goto out; + r = 0; + out: + sshbuf_free(msg); + return r; } #endif -/* ask agent to sign data, returns -1 on error, 0 on success */ +/* ask agent to sign data, returns err.h code on error, 0 on success */ int -ssh_agent_sign(AuthenticationConnection *auth, - Key *key, - u_char **sigp, u_int *lenp, - u_char *data, u_int datalen) +ssh_agent_sign(int sock, struct sshkey *key, + u_char **sigp, size_t *lenp, + const u_char *data, size_t datalen, u_int compat) { - extern int datafellows; - Buffer msg; - u_char *blob; - u_int blen; - int type, flags = 0; - int ret = -1; - - if (key_to_blob(key, &blob, &blen) == 0) - return -1; - - if (datafellows & SSH_BUG_SIGBLOB) - flags = SSH_AGENT_OLD_SIGNATURE; - - buffer_init(&msg); - buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST); - buffer_put_string(&msg, blob, blen); - buffer_put_string(&msg, data, datalen); - buffer_put_int(&msg, flags); - free(blob); - - if (ssh_request_reply(auth, &msg, &msg) == 0) { - buffer_free(&msg); - return -1; - } - type = buffer_get_char(&msg); + struct sshbuf *msg; + u_char *blob = NULL, type; + size_t blen = 0, len = 0; + u_int flags = 0; + int r = SSH_ERR_INTERNAL_ERROR; + + if (sigp != NULL) + *sigp = NULL; + if (lenp != NULL) + *lenp = 0; + + if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE) + return SSH_ERR_INVALID_ARGUMENT; + if (compat & SSH_BUG_SIGBLOB) + flags |= SSH_AGENT_OLD_SIGNATURE; + if ((msg = sshbuf_new()) == NULL) + return SSH_ERR_ALLOC_FAIL; + if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) + goto out; + if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 || + (r = sshbuf_put_string(msg, blob, blen)) != 0 || + (r = sshbuf_put_string(msg, data, datalen)) != 0 || + (r = sshbuf_put_u32(msg, flags)) != 0) + goto out; + if ((r = ssh_request_reply(sock, msg, msg) != 0)) + goto out; + if ((r = sshbuf_get_u8(msg, &type)) != 0) + goto out; if (agent_failed(type)) { - logit("Agent admitted failure to sign using the key."); + r = SSH_ERR_AGENT_FAILURE; + goto out; } else if (type != SSH2_AGENT_SIGN_RESPONSE) { - fatal("Bad authentication response: %d", type); - } else { - ret = 0; - *sigp = buffer_get_string(&msg, lenp); + r = SSH_ERR_INVALID_FORMAT; + goto out; + } + if ((r = sshbuf_get_string(msg, sigp, &len)) != 0) + goto out; + *lenp = len; + r = 0; + out: + if (blob != NULL) { + explicit_bzero(blob, blen); + free(blob); } - buffer_free(&msg); - return ret; + sshbuf_free(msg); + return r; } /* Encode key for a message to the agent. */ #ifdef WITH_SSH1 -static void -ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment) +static int +ssh_encode_identity_rsa1(struct sshbuf *b, RSA *key, const char *comment) { - buffer_put_int(b, BN_num_bits(key->n)); - buffer_put_bignum(b, key->n); - buffer_put_bignum(b, key->e); - buffer_put_bignum(b, key->d); + int r; + /* To keep within the protocol: p < q for ssh. in SSL p > q */ - buffer_put_bignum(b, key->iqmp); /* ssh key->u */ - buffer_put_bignum(b, key->q); /* ssh key->p, SSL key->q */ - buffer_put_bignum(b, key->p); /* ssh key->q, SSL key->p */ - buffer_put_cstring(b, comment); + if ((r = sshbuf_put_u32(b, BN_num_bits(key->n))) != 0 || + (r = sshbuf_put_bignum1(b, key->n)) != 0 || + (r = sshbuf_put_bignum1(b, key->e)) != 0 || + (r = sshbuf_put_bignum1(b, key->d)) != 0 || + (r = sshbuf_put_bignum1(b, key->iqmp)) != 0 || + (r = sshbuf_put_bignum1(b, key->q)) != 0 || + (r = sshbuf_put_bignum1(b, key->p)) != 0 || + (r = sshbuf_put_cstring(b, comment)) != 0) + return r; + return 0; } #endif -static void -ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) +static int +ssh_encode_identity_ssh2(struct sshbuf *b, struct sshkey *key, + const char *comment) +{ + int r; + + if ((r = sshkey_private_serialize(key, b)) != 0 || + (r = sshbuf_put_cstring(b, comment)) != 0) + return r; + return 0; +} + +static int +encode_constraints(struct sshbuf *m, u_int life, u_int confirm) { - key_private_serialize(key, b); - buffer_put_cstring(b, comment); + int r; + + if (life != 0) { + if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_LIFETIME)) != 0 || + (r = sshbuf_put_u32(m, life)) != 0) + goto out; + } + if (confirm != 0) { + if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_CONFIRM)) != 0) + goto out; + } + r = 0; + out: + return r; } /* - * Adds an identity to the authentication server. This call is not meant to - * be used by normal applications. + * Adds an identity to the authentication server. + * This call is intended only for use by ssh-add(1) and like applications. */ - int -ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, - const char *comment, u_int life, u_int confirm) +ssh_add_identity_constrained(int sock, struct sshkey *key, const char *comment, + u_int life, u_int confirm) { - Buffer msg; - int type, constrained = (life || confirm); + struct sshbuf *msg; + int r, constrained = (life || confirm); + u_char type; - buffer_init(&msg); + if ((msg = sshbuf_new()) == NULL) + return SSH_ERR_ALLOC_FAIL; switch (key->type) { #ifdef WITH_SSH1 @@ -501,8 +552,9 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, type = constrained ? SSH_AGENTC_ADD_RSA_ID_CONSTRAINED : SSH_AGENTC_ADD_RSA_IDENTITY; - buffer_put_char(&msg, type); - ssh_encode_identity_rsa1(&msg, key->rsa, comment); + if ((r = sshbuf_put_u8(msg, type)) != 0 || + (r = ssh_encode_identity_rsa1(msg, key->rsa, comment)) != 0) + goto out; break; #endif #ifdef WITH_OPENSSL @@ -520,77 +572,88 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, type = constrained ? SSH2_AGENTC_ADD_ID_CONSTRAINED : SSH2_AGENTC_ADD_IDENTITY; - buffer_put_char(&msg, type); - ssh_encode_identity_ssh2(&msg, key, comment); + if ((r = sshbuf_put_u8(msg, type)) != 0 || + (r = ssh_encode_identity_ssh2(msg, key, comment)) != 0) + goto out; break; default: - buffer_free(&msg); - return 0; - } - if (constrained) { - if (life != 0) { - buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME); - buffer_put_int(&msg, life); - } - if (confirm != 0) - buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM); + r = SSH_ERR_INVALID_ARGUMENT; + goto out; } - if (ssh_request_reply(auth, &msg, &msg) == 0) { - buffer_free(&msg); - return 0; - } - type = buffer_get_char(&msg); - buffer_free(&msg); - return decode_reply(type); + if (constrained && + (r = encode_constraints(msg, life, confirm)) != 0) + goto out; + if ((r = ssh_request_reply(sock, msg, msg)) != 0) + goto out; + if ((r = sshbuf_get_u8(msg, &type)) != 0) + goto out; + r = decode_reply(type); + out: + sshbuf_free(msg); + return r; } /* - * Removes an identity from the authentication server. This call is not - * meant to be used by normal applications. + * Removes an identity from the authentication server. + * This call is intended only for use by ssh-add(1) and like applications. */ - int -ssh_remove_identity(AuthenticationConnection *auth, Key *key) +ssh_remove_identity(int sock, struct sshkey *key) { - Buffer msg; - int type; - u_char *blob; - u_int blen; + struct sshbuf *msg; + int r; + u_char type, *blob = NULL; + size_t blen; - buffer_init(&msg); + if ((msg = sshbuf_new()) == NULL) + return SSH_ERR_ALLOC_FAIL; #ifdef WITH_SSH1 if (key->type == KEY_RSA1) { - buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY); - buffer_put_int(&msg, BN_num_bits(key->rsa->n)); - buffer_put_bignum(&msg, key->rsa->e); - buffer_put_bignum(&msg, key->rsa->n); + if ((r = sshbuf_put_u8(msg, + SSH_AGENTC_REMOVE_RSA_IDENTITY)) != 0 || + (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 || + (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 || + (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0) + goto out; } else #endif if (key->type != KEY_UNSPEC) { - key_to_blob(key, &blob, &blen); - buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); - buffer_put_string(&msg, blob, blen); - free(blob); + if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) + goto out; + if ((r = sshbuf_put_u8(msg, + SSH2_AGENTC_REMOVE_IDENTITY)) != 0 || + (r = sshbuf_put_string(msg, blob, blen)) != 0) + goto out; } else { - buffer_free(&msg); - return 0; + r = SSH_ERR_INVALID_ARGUMENT; + goto out; } - if (ssh_request_reply(auth, &msg, &msg) == 0) { - buffer_free(&msg); - return 0; + if ((r = ssh_request_reply(sock, msg, msg)) != 0) + goto out; + if ((r = sshbuf_get_u8(msg, &type)) != 0) + goto out; + r = decode_reply(type); + out: + if (blob != NULL) { + explicit_bzero(blob, blen); + free(blob); } - type = buffer_get_char(&msg); - buffer_free(&msg); - return decode_reply(type); + sshbuf_free(msg); + return r; } +/* + * Add/remove an token-based identity from the authentication server. + * This call is intended only for use by ssh-add(1) and like applications. + */ int -ssh_update_card(AuthenticationConnection *auth, int add, - const char *reader_id, const char *pin, u_int life, u_int confirm) +ssh_update_card(int sock, int add, const char *reader_id, const char *pin, + u_int life, u_int confirm) { - Buffer msg; - int type, constrained = (life || confirm); + struct sshbuf *msg; + int r, constrained = (life || confirm); + u_char type; if (add) { type = constrained ? @@ -599,69 +662,48 @@ ssh_update_card(AuthenticationConnection *auth, int add, } else type = SSH_AGENTC_REMOVE_SMARTCARD_KEY; - buffer_init(&msg); - buffer_put_char(&msg, type); - buffer_put_cstring(&msg, reader_id); - buffer_put_cstring(&msg, pin); - - if (constrained) { - if (life != 0) { - buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME); - buffer_put_int(&msg, life); - } - if (confirm != 0) - buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM); - } - - if (ssh_request_reply(auth, &msg, &msg) == 0) { - buffer_free(&msg); - return 0; - } - type = buffer_get_char(&msg); - buffer_free(&msg); - return decode_reply(type); + if ((msg = sshbuf_new()) == NULL) + return SSH_ERR_ALLOC_FAIL; + if ((r = sshbuf_put_u8(msg, type)) != 0 || + (r = sshbuf_put_cstring(msg, reader_id)) != 0 || + (r = sshbuf_put_cstring(msg, pin)) != 0) + goto out; + if (constrained && + (r = encode_constraints(msg, life, confirm)) != 0) + goto out; + if ((r = ssh_request_reply(sock, msg, msg)) != 0) + goto out; + if ((r = sshbuf_get_u8(msg, &type)) != 0) + goto out; + r = decode_reply(type); + out: + sshbuf_free(msg); + return r; } /* - * Removes all identities from the agent. This call is not meant to be used - * by normal applications. + * Removes all identities from the agent. + * This call is intended only for use by ssh-add(1) and like applications. */ - -int -ssh_remove_all_identities(AuthenticationConnection *auth, int version) -{ - Buffer msg; - int type; - int code = (version==1) ? - SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES : - SSH2_AGENTC_REMOVE_ALL_IDENTITIES; - - buffer_init(&msg); - buffer_put_char(&msg, code); - - if (ssh_request_reply(auth, &msg, &msg) == 0) { - buffer_free(&msg); - return 0; - } - type = buffer_get_char(&msg); - buffer_free(&msg); - return decode_reply(type); -} - int -decode_reply(int type) +ssh_remove_all_identities(int sock, int version) { - switch (type) { - case SSH_AGENT_FAILURE: - case SSH_COM_AGENT2_FAILURE: - case SSH2_AGENT_FAILURE: - logit("SSH_AGENT_FAILURE"); - return 0; - case SSH_AGENT_SUCCESS: - return 1; - default: - fatal("Bad response from authentication agent: %d", type); - } - /* NOTREACHED */ - return 0; + struct sshbuf *msg; + u_char type = (version == 1) ? + SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES : + SSH2_AGENTC_REMOVE_ALL_IDENTITIES; + int r; + + if ((msg = sshbuf_new()) == NULL) + return SSH_ERR_ALLOC_FAIL; + if ((r = sshbuf_put_u8(msg, type)) != 0) + goto out; + if ((r = ssh_request_reply(sock, msg, msg)) != 0) + goto out; + if ((r = sshbuf_get_u8(msg, &type)) != 0) + goto out; + r = decode_reply(type); + out: + sshbuf_free(msg); + return r; } diff --git a/usr.bin/ssh/authfd.h b/usr.bin/ssh/authfd.h index 2582a27aa52..bea20c26bc9 100644 --- a/usr.bin/ssh/authfd.h +++ b/usr.bin/ssh/authfd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: authfd.h,v 1.37 2009/08/27 17:44:52 djm Exp $ */ +/* $OpenBSD: authfd.h,v 1.38 2015/01/14 20:05:27 djm Exp $ */ /* * Author: Tatu Ylonen @@ -16,6 +16,33 @@ #ifndef AUTHFD_H #define AUTHFD_H +/* List of identities returned by ssh_fetch_identitylist() */ +struct ssh_identitylist { + size_t nkeys; + struct sshkey **keys; + char **comments; +}; + +int ssh_get_authentication_socket(int *fdp); +void ssh_close_authentication_socket(int sock); + +int ssh_lock_agent(int sock, int lock, const char *password); +int ssh_fetch_identitylist(int sock, int version, + struct ssh_identitylist **idlp); +void ssh_free_identitylist(struct ssh_identitylist *idl); +int ssh_add_identity_constrained(int sock, struct sshkey *key, + const char *comment, u_int life, u_int confirm); +int ssh_remove_identity(int sock, struct sshkey *key); +int ssh_update_card(int sock, int add, const char *reader_id, + const char *pin, u_int life, u_int confirm); +int ssh_remove_all_identities(int sock, int version); + +int ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge, + u_char session_id[16], u_char response[16]); +int ssh_agent_sign(int sock, struct sshkey *key, + u_char **sigp, size_t *lenp, + const u_char *data, size_t datalen, u_int compat); + /* Messages for the authentication agent connection. */ #define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1 #define SSH_AGENT_RSA_IDENTITIES_ANSWER 2 @@ -60,35 +87,4 @@ #define SSH_AGENT_OLD_SIGNATURE 0x01 -typedef struct { - int fd; - Buffer identities; - int howmany; -} AuthenticationConnection; - -int ssh_agent_present(void); -int ssh_get_authentication_socket(void); -void ssh_close_authentication_socket(int); - -AuthenticationConnection *ssh_get_authentication_connection(void); -void ssh_close_authentication_connection(AuthenticationConnection *); -int ssh_get_num_identities(AuthenticationConnection *, int); -Key *ssh_get_first_identity(AuthenticationConnection *, char **, int); -Key *ssh_get_next_identity(AuthenticationConnection *, char **, int); -int ssh_add_identity_constrained(AuthenticationConnection *, Key *, - const char *, u_int, u_int); -int ssh_remove_identity(AuthenticationConnection *, Key *); -int ssh_remove_all_identities(AuthenticationConnection *, int); -int ssh_lock_agent(AuthenticationConnection *, int, const char *); -int ssh_update_card(AuthenticationConnection *, int, const char *, - const char *, u_int, u_int); - -int -ssh_decrypt_challenge(AuthenticationConnection *, Key *, BIGNUM *, u_char[16], - u_int, u_char[16]); - -int -ssh_agent_sign(AuthenticationConnection *, Key *, u_char **, u_int *, u_char *, - u_int); - #endif /* AUTHFD_H */ diff --git a/usr.bin/ssh/clientloop.c b/usr.bin/ssh/clientloop.c index 64f4785601e..276a84f78dd 100644 --- a/usr.bin/ssh/clientloop.c +++ b/usr.bin/ssh/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.261 2014/07/15 15:54:14 millert Exp $ */ +/* $OpenBSD: clientloop.c,v 1.262 2015/01/14 20:05:27 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -102,6 +102,7 @@ #include "match.h" #include "msg.h" #include "roaming.h" +#include "ssherr.h" /* import options */ extern Options options; @@ -1770,7 +1771,7 @@ static void client_input_agent_open(int type, u_int32_t seq, void *ctxt) { Channel *c = NULL; - int remote_id, sock; + int r, remote_id, sock; /* Read the remote channel number from the message. */ remote_id = packet_get_int(); @@ -1780,7 +1781,11 @@ client_input_agent_open(int type, u_int32_t seq, void *ctxt) * Get a connection to the local authentication agent (this may again * get forwarded). */ - sock = ssh_get_authentication_socket(); + if ((r = ssh_get_authentication_socket(&sock)) != 0 && + r != SSH_ERR_AGENT_NOT_PRESENT) + debug("%s: ssh_get_authentication_socket: %s", + __func__, ssh_err(r)); + /* * If we could not connect the agent, send an error message back to @@ -1898,7 +1903,7 @@ static Channel * client_request_agent(const char *request_type, int rchan) { Channel *c = NULL; - int sock; + int r, sock; if (!options.forward_agent) { error("Warning: ssh server tried agent forwarding."); @@ -1906,9 +1911,12 @@ client_request_agent(const char *request_type, int rchan) "malicious server."); return NULL; } - sock = ssh_get_authentication_socket(); - if (sock < 0) + if ((r = ssh_get_authentication_socket(&sock)) != 0) { + if (r != SSH_ERR_AGENT_NOT_PRESENT) + debug("%s: ssh_get_authentication_socket: %s", + __func__, ssh_err(r)); return NULL; + } c = channel_new("authentication agent connection", SSH_CHANNEL_OPEN, sock, sock, -1, CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, diff --git a/usr.bin/ssh/monitor.c b/usr.bin/ssh/monitor.c index 85b98dc952a..152e41cacb7 100644 --- a/usr.bin/ssh/monitor.c +++ b/usr.bin/ssh/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.137 2015/01/13 07:39:19 djm Exp $ */ +/* $OpenBSD: monitor.c,v 1.138 2015/01/14 20:05:27 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -80,6 +80,7 @@ #include "roaming.h" #include "authfd.h" #include "match.h" +#include "ssherr.h" #ifdef GSSAPI static Gssctxt *gsscontext = NULL; @@ -591,28 +592,28 @@ mm_answer_moduli(int sock, Buffer *m) } #endif -extern AuthenticationConnection *auth_conn; - int mm_answer_sign(int sock, Buffer *m) { - Key *key; + extern int auth_sock; /* XXX move to state struct? */ + struct sshkey *key; u_char *p; u_char *signature; - u_int siglen, datlen; - int keyid; + size_t datlen, siglen; + int r, keyid; debug3("%s", __func__); - keyid = buffer_get_int(m); - p = buffer_get_string(m, &datlen); + if ((r = sshbuf_get_u32(m, &keyid)) != 0 || + (r = sshbuf_get_string(m, &p, &datlen)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); /* * Supported KEX types use SHA1 (20 bytes), SHA256 (32 bytes), * SHA384 (48 bytes) and SHA512 (64 bytes). */ if (datlen != 20 && datlen != 32 && datlen != 48 && datlen != 64) - fatal("%s: data length incorrect: %u", __func__, datlen); + fatal("%s: data length incorrect: %zu", __func__, datlen); /* save session id, it will be passed on the first call */ if (session_id2_len == 0) { @@ -622,20 +623,25 @@ mm_answer_sign(int sock, Buffer *m) } if ((key = get_hostkey_by_index(keyid)) != NULL) { - if (key_sign(key, &signature, &siglen, p, datlen) < 0) - fatal("%s: key_sign failed", __func__); + if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, + datafellows)) != 0) + fatal("%s: sshkey_sign failed: %s", + __func__, ssh_err(r)); } else if ((key = get_hostkey_public_by_index(keyid)) != NULL && - auth_conn != NULL) { - if (ssh_agent_sign(auth_conn, key, &signature, &siglen, p, - datlen) < 0) - fatal("%s: ssh_agent_sign failed", __func__); + auth_sock > 0) { + if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen, + p, datlen, datafellows)) != 0) { + fatal("%s: ssh_agent_sign failed: %s", + __func__, ssh_err(r)); + } } else fatal("%s: no hostkey from index %d", __func__, keyid); - debug3("%s: signature %p(%u)", __func__, signature, siglen); + debug3("%s: signature %p(%zu)", __func__, signature, siglen); - buffer_clear(m); - buffer_put_string(m, signature, siglen); + sshbuf_reset(m); + if ((r = sshbuf_put_string(m, signature, siglen)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); free(p); free(signature); diff --git a/usr.bin/ssh/session.c b/usr.bin/ssh/session.c index e2039630267..4025bfc03e2 100644 --- a/usr.bin/ssh/session.c +++ b/usr.bin/ssh/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.275 2014/12/22 07:55:51 djm Exp $ */ +/* $OpenBSD: session.c,v 1.276 2015/01/14 20:05:27 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -1274,11 +1274,11 @@ launch_login(struct passwd *pw, const char *hostname) static void child_close_fds(void) { - extern AuthenticationConnection *auth_conn; + extern int auth_sock; - if (auth_conn) { - ssh_close_authentication_connection(auth_conn); - auth_conn = NULL; + if (auth_sock != -1) { + close(auth_sock); + auth_sock = -1; } if (packet_get_connection_in() == packet_get_connection_out()) diff --git a/usr.bin/ssh/ssh-add.c b/usr.bin/ssh/ssh-add.c index 2b7fa11a7b5..33b238dd582 100644 --- a/usr.bin/ssh/ssh-add.c +++ b/usr.bin/ssh/ssh-add.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-add.c,v 1.115 2014/12/21 22:27:56 djm Exp $ */ +/* $OpenBSD: ssh-add.c,v 1.116 2015/01/14 20:05:27 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -41,6 +41,7 @@ #include +#include #include #include #include @@ -52,8 +53,8 @@ #include "ssh.h" #include "rsa.h" #include "log.h" -#include "key.h" -#include "buffer.h" +#include "sshkey.h" +#include "sshbuf.h" #include "authfd.h" #include "authfile.h" #include "pathnames.h" @@ -95,22 +96,22 @@ clear_pass(void) } static int -delete_file(AuthenticationConnection *ac, const char *filename, int key_only) +delete_file(int agent_fd, const char *filename, int key_only) { - Key *public = NULL, *cert = NULL; + struct sshkey *public, *cert = NULL; char *certpath = NULL, *comment = NULL; - int ret = -1; + int r, ret = -1; - public = key_load_public(filename, &comment); - if (public == NULL) { - printf("Bad key file %s\n", filename); + if ((r = sshkey_load_public(filename, &public, &comment)) != 0) { + printf("Bad key file %s: %s\n", filename, ssh_err(r)); return -1; } - if (ssh_remove_identity(ac, public)) { + if ((r = ssh_remove_identity(agent_fd, public)) == 0) { fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment); ret = 0; } else - fprintf(stderr, "Could not remove identity: %s\n", filename); + fprintf(stderr, "Could not remove identity \"%s\": %s\n", + filename, ssh_err(r)); if (key_only) goto out; @@ -119,13 +120,13 @@ delete_file(AuthenticationConnection *ac, const char *filename, int key_only) free(comment); comment = NULL; xasprintf(&certpath, "%s-cert.pub", filename); - if ((cert = key_load_public(certpath, &comment)) == NULL) + if ((r = sshkey_load_public(certpath, &cert, &comment)) == 0) goto out; - if (!key_equal_public(cert, public)) + if (!sshkey_equal_public(cert, public)) fatal("Certificate %s does not match private key %s", certpath, filename); - if (ssh_remove_identity(ac, cert)) { + if (ssh_remove_identity(agent_fd, cert)) { fprintf(stderr, "Identity removed: %s (%s)\n", certpath, comment); ret = 0; @@ -134,9 +135,9 @@ delete_file(AuthenticationConnection *ac, const char *filename, int key_only) out: if (cert != NULL) - key_free(cert); + sshkey_free(cert); if (public != NULL) - key_free(public); + sshkey_free(public); free(certpath); free(comment); @@ -145,14 +146,15 @@ delete_file(AuthenticationConnection *ac, const char *filename, int key_only) /* Send a request to remove all identities. */ static int -delete_all(AuthenticationConnection *ac) +delete_all(int agent_fd) { int ret = -1; - if (ssh_remove_all_identities(ac, 1)) + if (ssh_remove_all_identities(agent_fd, 1) == 0) ret = 0; /* ignore error-code for ssh2 */ - ssh_remove_all_identities(ac, 2); + /* XXX revisit */ + ssh_remove_all_identities(agent_fd, 2); if (ret == 0) fprintf(stderr, "All identities removed.\n"); @@ -163,13 +165,13 @@ delete_all(AuthenticationConnection *ac) } static int -add_file(AuthenticationConnection *ac, const char *filename, int key_only) +add_file(int agent_fd, const char *filename, int key_only) { - Key *private, *cert; + struct sshkey *private, *cert; char *comment = NULL; char msg[1024], *certpath = NULL; - int r, fd, perms_ok, ret = -1; - Buffer keyblob; + int r, fd, ret = -1; + struct sshbuf *keyblob; if (strcmp(filename, "-") == 0) { fd = STDIN_FILENO; @@ -184,30 +186,38 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only) * will occur multiple times, so check perms first and bail if wrong. */ if (fd != STDIN_FILENO) { - perms_ok = key_perm_ok(fd, filename); - if (!perms_ok) { + if (sshkey_perm_ok(fd, filename) != 0) { close(fd); return -1; } } - buffer_init(&keyblob); - if (!key_load_file(fd, filename, &keyblob)) { - buffer_free(&keyblob); + if ((keyblob = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + if ((r = sshkey_load_file(fd, keyblob)) != 0) { + fprintf(stderr, "Error loading key \"%s\": %s\n", + filename, ssh_err(r)); + sshbuf_free(keyblob); close(fd); return -1; } close(fd); /* At first, try empty passphrase */ - if ((r = sshkey_parse_private_fileblob(&keyblob, "", filename, - &private, &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) - fatal("Cannot parse %s: %s", filename, ssh_err(r)); + if ((r = sshkey_parse_private_fileblob(keyblob, "", filename, + &private, &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) { + fprintf(stderr, "Error loading key \"%s\": %s\n", + filename, ssh_err(r)); + goto fail_load; + } /* try last */ if (private == NULL && pass != NULL) { - if ((r = sshkey_parse_private_fileblob(&keyblob, pass, filename, + if ((r = sshkey_parse_private_fileblob(keyblob, pass, filename, &private, &comment)) != 0 && - r != SSH_ERR_KEY_WRONG_PASSPHRASE) - fatal("Cannot parse %s: %s", filename, ssh_err(r)); + r != SSH_ERR_KEY_WRONG_PASSPHRASE) { + fprintf(stderr, "Error loading key \"%s\": %s\n", + filename, ssh_err(r)); + goto fail_load; + } } if (comment == NULL) comment = xstrdup(filename); @@ -218,28 +228,30 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only) comment); for (;;) { pass = read_passphrase(msg, RP_ALLOW_STDIN); - if (strcmp(pass, "") == 0) { + if (strcmp(pass, "") == 0) + goto fail_load; + if ((r = sshkey_parse_private_fileblob(keyblob, pass, + filename, &private, NULL)) == 0) + break; + else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) { + fprintf(stderr, + "Error loading key \"%s\": %s\n", + filename, ssh_err(r)); + fail_load: clear_pass(); free(comment); - buffer_free(&keyblob); + sshbuf_free(keyblob); return -1; } - if ((r = sshkey_parse_private_fileblob(&keyblob, - pass, filename, &private, NULL)) != 0 && - r != SSH_ERR_KEY_WRONG_PASSPHRASE) - fatal("Cannot parse %s: %s", - filename, ssh_err(r)); - if (private != NULL) - break; clear_pass(); snprintf(msg, sizeof msg, "Bad passphrase, try again for %.200s: ", comment); } } - buffer_free(&keyblob); + sshbuf_free(keyblob); - if (ssh_add_identity_constrained(ac, private, comment, lifetime, - confirm)) { + if ((r = ssh_add_identity_constrained(agent_fd, private, comment, + lifetime, confirm)) == 0) { fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); ret = 0; if (lifetime != 0) @@ -249,7 +261,8 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only) fprintf(stderr, "The user must confirm each use of the key\n"); } else { - fprintf(stderr, "Could not add identity: %s\n", filename); + fprintf(stderr, "Could not add identity \"%s\": %s\n", + filename, ssh_err(r)); } /* Skip trying to load the cert if requested */ @@ -258,29 +271,39 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only) /* Now try to add the certificate flavour too */ xasprintf(&certpath, "%s-cert.pub", filename); - if ((cert = key_load_public(certpath, NULL)) == NULL) + if ((r = sshkey_load_public(certpath, &cert, NULL)) != 0) { + if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT) + error("Failed to load certificate \"%s\": %s", + certpath, ssh_err(r)); goto out; + } - if (!key_equal_public(cert, private)) { + if (!sshkey_equal_public(cert, private)) { error("Certificate %s does not match private key %s", certpath, filename); - key_free(cert); + sshkey_free(cert); goto out; } /* Graft with private bits */ - if (key_to_certified(private, key_cert_is_legacy(cert)) != 0) { - error("%s: key_to_certified failed", __func__); - key_free(cert); + if ((r = sshkey_to_certified(private, + sshkey_cert_is_legacy(cert))) != 0) { + error("%s: sshkey_to_certified: %s", __func__, ssh_err(r)); + sshkey_free(cert); + goto out; + } + if ((r = sshkey_cert_copy(cert, private)) != 0) { + error("%s: key_cert_copy: %s", __func__, ssh_err(r)); + sshkey_free(cert); goto out; } - key_cert_copy(cert, private); - key_free(cert); + sshkey_free(cert); - if (!ssh_add_identity_constrained(ac, private, comment, - lifetime, confirm)) { - error("Certificate %s (%s) add failed", certpath, - private->cert->key_id); + if ((r = ssh_add_identity_constrained(agent_fd, private, comment, + lifetime, confirm)) != 0) { + error("Certificate %s (%s) add failed: %s", certpath, + private->cert->key_id, ssh_err(r)); + goto out; } fprintf(stderr, "Certificate added: %s (%s)\n", certpath, private->cert->key_id); @@ -289,19 +312,18 @@ add_file(AuthenticationConnection *ac, const char *filename, int key_only) if (confirm != 0) fprintf(stderr, "The user must confirm each use of the key\n"); out: - if (certpath != NULL) - free(certpath); + free(certpath); free(comment); - key_free(private); + sshkey_free(private); return ret; } static int -update_card(AuthenticationConnection *ac, int add, const char *id) +update_card(int agent_fd, int add, const char *id) { char *pin = NULL; - int ret = -1; + int r, ret = -1; if (add) { if ((pin = read_passphrase("Enter passphrase for PKCS#11: ", @@ -309,14 +331,14 @@ update_card(AuthenticationConnection *ac, int add, const char *id) return -1; } - if (ssh_update_card(ac, add, id, pin == NULL ? "" : pin, - lifetime, confirm)) { + if ((r = ssh_update_card(agent_fd, add, id, pin == NULL ? "" : pin, + lifetime, confirm)) == 0) { fprintf(stderr, "Card %s: %s\n", add ? "added" : "removed", id); ret = 0; } else { - fprintf(stderr, "Could not %s card: %s\n", - add ? "add" : "remove", id); + fprintf(stderr, "Could not %s card \"%s\": %s\n", + add ? "add" : "remove", id, ssh_err(r)); ret = -1; } free(pin); @@ -324,32 +346,42 @@ update_card(AuthenticationConnection *ac, int add, const char *id) } static int -list_identities(AuthenticationConnection *ac, int do_fp) +list_identities(int agent_fd, int do_fp) { - Key *key; - char *comment, *fp; - int had_identities = 0; - int version; + char *fp; + int version, r, had_identities = 0; + struct ssh_identitylist *idlist; + size_t i; for (version = 1; version <= 2; version++) { - for (key = ssh_get_first_identity(ac, &comment, version); - key != NULL; - key = ssh_get_next_identity(ac, &comment, version)) { + if ((r = ssh_fetch_identitylist(agent_fd, version, + &idlist)) != 0) { + if (r != SSH_ERR_AGENT_NO_IDENTITIES) + fprintf(stderr, "error fetching identities for " + "protocol %d: %s\n", version, ssh_err(r)); + continue; + } + for (i = 0; i < idlist->nkeys; i++) { had_identities = 1; if (do_fp) { - fp = key_fingerprint(key, fingerprint_hash, - SSH_FP_DEFAULT); + fp = sshkey_fingerprint(idlist->keys[i], + fingerprint_hash, SSH_FP_DEFAULT); printf("%d %s %s (%s)\n", - key_size(key), fp, comment, key_type(key)); + sshkey_size(idlist->keys[i]), fp, + idlist->comments[i], + sshkey_type(idlist->keys[i])); free(fp); } else { - if (!key_write(key, stdout)) - fprintf(stderr, "key_write failed"); - fprintf(stdout, " %s\n", comment); + if ((r = sshkey_write(idlist->keys[i], + stdout)) != 0) { + fprintf(stderr, "sshkey_write: %s\n", + ssh_err(r)); + continue; + } + fprintf(stdout, " %s\n", idlist->comments[i]); } - key_free(key); - free(comment); } + ssh_free_identitylist(idlist); } if (!had_identities) { printf("The agent has no identities.\n"); @@ -359,10 +391,10 @@ list_identities(AuthenticationConnection *ac, int do_fp) } static int -lock_agent(AuthenticationConnection *ac, int lock) +lock_agent(int agent_fd, int lock) { char prompt[100], *p1, *p2; - int passok = 1, ret = -1; + int r, passok = 1, ret = -1; strlcpy(prompt, "Enter lock password: ", sizeof(prompt)); p1 = read_passphrase(prompt, RP_ALLOW_STDIN); @@ -376,24 +408,28 @@ lock_agent(AuthenticationConnection *ac, int lock) explicit_bzero(p2, strlen(p2)); free(p2); } - if (passok && ssh_lock_agent(ac, lock, p1)) { - fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un"); - ret = 0; - } else - fprintf(stderr, "Failed to %slock agent.\n", lock ? "" : "un"); + if (passok) { + if ((r = ssh_lock_agent(agent_fd, lock, p1)) == 0) { + fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un"); + ret = 0; + } else { + fprintf(stderr, "Failed to %slock agent: %s\n", + lock ? "" : "un", ssh_err(r)); + } + } explicit_bzero(p1, strlen(p1)); free(p1); return (ret); } static int -do_file(AuthenticationConnection *ac, int deleting, int key_only, char *file) +do_file(int agent_fd, int deleting, int key_only, char *file) { if (deleting) { - if (delete_file(ac, file, key_only) == -1) + if (delete_file(agent_fd, file, key_only) == -1) return -1; } else { - if (add_file(ac, file, key_only) == -1) + if (add_file(agent_fd, file, key_only) == -1) return -1; } return 0; @@ -423,9 +459,9 @@ main(int argc, char **argv) { extern char *optarg; extern int optind; - AuthenticationConnection *ac = NULL; + int agent_fd; char *pkcs11provider = NULL; - int i, ch, deleting = 0, ret = 0, key_only = 0; + int r, i, ch, deleting = 0, ret = 0, key_only = 0; int xflag = 0, lflag = 0, Dflag = 0; /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ @@ -435,13 +471,19 @@ main(int argc, char **argv) setvbuf(stdout, NULL, _IOLBF, 0); - /* At first, get a connection to the authentication agent. */ - ac = ssh_get_authentication_connection(); - if (ac == NULL) { - fprintf(stderr, - "Could not open a connection to your authentication agent.\n"); + /* First, get a connection to the authentication agent. */ + switch (r = ssh_get_authentication_socket(&agent_fd)) { + case 0: + break; + case SSH_ERR_AGENT_NOT_PRESENT: + fprintf(stderr, "Could not open a connection to your " + "authentication agent.\n"); + exit(2); + default: + fprintf(stderr, "Error connecting to agent: %s\n", ssh_err(r)); exit(2); } + while ((ch = getopt(argc, argv, "klLcdDxXE:e:s:t:")) != -1) { switch (ch) { case 'E': @@ -497,15 +539,15 @@ main(int argc, char **argv) if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1) fatal("Invalid combination of actions"); else if (xflag) { - if (lock_agent(ac, xflag == 'x' ? 1 : 0) == -1) + if (lock_agent(agent_fd, xflag == 'x' ? 1 : 0) == -1) ret = 1; goto done; } else if (lflag) { - if (list_identities(ac, lflag == 'l' ? 1 : 0) == -1) + if (list_identities(agent_fd, lflag == 'l' ? 1 : 0) == -1) ret = 1; goto done; } else if (Dflag) { - if (delete_all(ac) == -1) + if (delete_all(agent_fd) == -1) ret = 1; goto done; } @@ -513,7 +555,7 @@ main(int argc, char **argv) argc -= optind; argv += optind; if (pkcs11provider != NULL) { - if (update_card(ac, !deleting, pkcs11provider) == -1) + if (update_card(agent_fd, !deleting, pkcs11provider) == -1) ret = 1; goto done; } @@ -535,7 +577,7 @@ main(int argc, char **argv) default_files[i]); if (stat(buf, &st) < 0) continue; - if (do_file(ac, deleting, key_only, buf) == -1) + if (do_file(agent_fd, deleting, key_only, buf) == -1) ret = 1; else count++; @@ -544,13 +586,14 @@ main(int argc, char **argv) ret = 1; } else { for (i = 0; i < argc; i++) { - if (do_file(ac, deleting, key_only, argv[i]) == -1) + if (do_file(agent_fd, deleting, key_only, + argv[i]) == -1) ret = 1; } } clear_pass(); done: - ssh_close_authentication_connection(ac); + ssh_close_authentication_socket(agent_fd); return ret; } diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c index 67513c47dad..62d5fc964c2 100644 --- a/usr.bin/ssh/ssh.c +++ b/usr.bin/ssh/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.411 2015/01/08 10:15:45 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.412 2015/01/14 20:05:27 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -97,6 +97,7 @@ #include "uidswap.h" #include "roaming.h" #include "version.h" +#include "ssherr.h" #ifdef ENABLE_PKCS11 #include "ssh-pkcs11.h" @@ -1452,10 +1453,16 @@ ssh_init_forwarding(void) static void check_agent_present(void) { + int r; + if (options.forward_agent) { /* Clear agent forwarding if we don't have an agent. */ - if (!ssh_agent_present()) + if ((r = ssh_get_authentication_socket(NULL)) != 0) { options.forward_agent = 0; + if (r != SSH_ERR_AGENT_NOT_PRESENT) + debug("ssh_get_authentication_socket: %s", + ssh_err(r)); + } } } diff --git a/usr.bin/ssh/sshconnect1.c b/usr.bin/ssh/sshconnect1.c index 82eeecf2f3a..491017050de 100644 --- a/usr.bin/ssh/sshconnect1.c +++ b/usr.bin/ssh/sshconnect1.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect1.c,v 1.76 2014/07/15 15:54:14 millert Exp $ */ +/* $OpenBSD: sshconnect1.c,v 1.77 2015/01/14 20:05:27 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -18,6 +18,7 @@ #include +#include #include #include #include @@ -44,6 +45,7 @@ #include "hostfile.h" #include "auth.h" #include "digest.h" +#include "ssherr.h" /* Session id for the current session. */ u_char session_id[16]; @@ -59,33 +61,38 @@ extern char *__progname; static int try_agent_authentication(void) { - int type; - char *comment; - AuthenticationConnection *auth; + int r, type, agent_fd, ret = 0; u_char response[16]; - u_int i; - Key *key; + size_t i; BIGNUM *challenge; + struct ssh_identitylist *idlist = NULL; /* Get connection to the agent. */ - auth = ssh_get_authentication_connection(); - if (!auth) + if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) { + if (r != SSH_ERR_AGENT_NOT_PRESENT) + debug("%s: ssh_get_authentication_socket: %s", + __func__, ssh_err(r)); return 0; + } if ((challenge = BN_new()) == NULL) fatal("try_agent_authentication: BN_new failed"); - /* Loop through identities served by the agent. */ - for (key = ssh_get_first_identity(auth, &comment, 1); - key != NULL; - key = ssh_get_next_identity(auth, &comment, 1)) { + /* Loop through identities served by the agent. */ + if ((r = ssh_fetch_identitylist(agent_fd, 1, &idlist)) != 0) { + if (r != SSH_ERR_AGENT_NO_IDENTITIES) + debug("%s: ssh_fetch_identitylist: %s", + __func__, ssh_err(r)); + goto out; + } + for (i = 0; i < idlist->nkeys; i++) { /* Try this identity. */ - debug("Trying RSA authentication via agent with '%.100s'", comment); - free(comment); + debug("Trying RSA authentication via agent with '%.100s'", + idlist->comments[i]); /* Tell the server that we are willing to authenticate using this key. */ packet_start(SSH_CMSG_AUTH_RSA); - packet_put_bignum(key->rsa->n); + packet_put_bignum(idlist->keys[i]->rsa->n); packet_send(); packet_write_wait(); @@ -96,7 +103,6 @@ try_agent_authentication(void) does not support RSA authentication. */ if (type == SSH_SMSG_FAILURE) { debug("Server refused our key."); - key_free(key); continue; } /* Otherwise it should have sent a challenge. */ @@ -110,16 +116,17 @@ try_agent_authentication(void) debug("Received RSA challenge from server."); /* Ask the agent to decrypt the challenge. */ - if (!ssh_decrypt_challenge(auth, key, challenge, session_id, 1, response)) { + if ((r = ssh_decrypt_challenge(agent_fd, idlist->keys[i], + challenge, session_id, response)) != 0) { /* * The agent failed to authenticate this identifier * although it advertised it supports this. Just * return a wrong value. */ - logit("Authentication agent failed to decrypt challenge."); + logit("Authentication agent failed to decrypt " + "challenge: %s", ssh_err(r)); explicit_bzero(response, sizeof(response)); } - key_free(key); debug("Sending response to RSA challenge."); /* Send the decrypted challenge back to the server. */ @@ -132,22 +139,25 @@ try_agent_authentication(void) /* Wait for response from the server. */ type = packet_read(); - /* The server returns success if it accepted the authentication. */ + /* + * The server returns success if it accepted the + * authentication. + */ if (type == SSH_SMSG_SUCCESS) { - ssh_close_authentication_connection(auth); - BN_clear_free(challenge); debug("RSA authentication accepted by server."); - return 1; - } - /* Otherwise it should return failure. */ - if (type != SSH_SMSG_FAILURE) - packet_disconnect("Protocol error waiting RSA auth response: %d", - type); + ret = 1; + break; + } else if (type != SSH_SMSG_FAILURE) + packet_disconnect("Protocol error waiting RSA auth " + "response: %d", type); } - ssh_close_authentication_connection(auth); + if (ret != 1) + debug("RSA authentication using agent refused."); + out: + ssh_free_identitylist(idlist); + ssh_close_authentication_socket(agent_fd); BN_clear_free(challenge); - debug("RSA authentication using agent refused."); - return 0; + return ret; } /* diff --git a/usr.bin/ssh/sshconnect2.c b/usr.bin/ssh/sshconnect2.c index 058381ee4af..532bba82fc7 100644 --- a/usr.bin/ssh/sshconnect2.c +++ b/usr.bin/ssh/sshconnect2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect2.c,v 1.213 2015/01/08 10:14:08 djm Exp $ */ +/* $OpenBSD: sshconnect2.c,v 1.214 2015/01/14 20:05:27 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2008 Damien Miller. All rights reserved. @@ -64,6 +64,7 @@ #include "pathnames.h" #include "uidswap.h" #include "hostfile.h" +#include "ssherr.h" #ifdef GSSAPI #include "ssh-gss.h" @@ -125,10 +126,10 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port) } while (0) while ((alg = strsep(&avail, ",")) && *alg != '\0') { - if ((ktype = key_type_from_name(alg)) == KEY_UNSPEC) + if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC) fatal("%s: unknown alg %s", __func__, alg); if (lookup_key_in_hostkeys_by_type(hostkeys, - key_type_plain(ktype), NULL)) + sshkey_type_plain(ktype), NULL)) ALG_APPEND(first, alg); else ALG_APPEND(last, alg); @@ -236,15 +237,15 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) * Authenticate user */ -typedef struct Authctxt Authctxt; -typedef struct Authmethod Authmethod; +typedef struct cauthctxt Authctxt; +typedef struct cauthmethod Authmethod; typedef struct identity Identity; typedef struct idlist Idlist; struct identity { TAILQ_ENTRY(identity) next; - AuthenticationConnection *ac; /* set if agent supports key */ - Key *key; /* public/private key */ + int agent_fd; /* >=0 if agent supports key */ + struct sshkey *key; /* public/private key */ char *filename; /* comment for agent-only keys */ int tried; int isprivate; /* key points to the private key */ @@ -252,17 +253,18 @@ struct identity { }; TAILQ_HEAD(idlist, identity); -struct Authctxt { +struct cauthctxt { const char *server_user; const char *local_user; const char *host; const char *service; - Authmethod *method; + struct cauthmethod *method; sig_atomic_t success; char *authlist; + int attempt; /* pubkey */ - Idlist keys; - AuthenticationConnection *agent; + struct idlist keys; + int agent_fd; /* hostbased */ Sensitive *sensitive; /* kbd-interactive */ @@ -270,7 +272,8 @@ struct Authctxt { /* generic */ void *methoddata; }; -struct Authmethod { + +struct cauthmethod { char *name; /* string to compare against server's list */ int (*userauth)(Authctxt *authctxt); void (*cleanup)(Authctxt *authctxt); @@ -576,7 +579,7 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) key->type, pktype); goto done; } - fp = key_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); + fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); debug2("input_userauth_pk_ok: fp %s", fp); free(fp); @@ -950,27 +953,29 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) } static int -identity_sign(Identity *id, u_char **sigp, u_int *lenp, - u_char *data, u_int datalen) +identity_sign(struct identity *id, u_char **sigp, size_t *lenp, + const u_char *data, size_t datalen, u_int compat) { Key *prv; int ret; /* the agent supports this key */ - if (id->ac) - return (ssh_agent_sign(id->ac, id->key, sigp, lenp, - data, datalen)); + if (id->agent_fd) + return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp, + data, datalen, compat); + /* * we have already loaded the private key or * the private key is stored in external hardware */ if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)) - return (key_sign(id->key, sigp, lenp, data, datalen)); + return (sshkey_sign(id->key, sigp, lenp, data, datalen, + compat)); /* load the private key from the file */ if ((prv = load_identity_file(id->filename, id->userprovided)) == NULL) - return (-1); - ret = key_sign(prv, sigp, lenp, data, datalen); - key_free(prv); + return (-1); /* XXX return decent error code */ + ret = sshkey_sign(prv, sigp, lenp, data, datalen, compat); + sshkey_free(prv); return (ret); } @@ -979,7 +984,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) { Buffer b; u_char *blob, *signature; - u_int bloblen, slen; + u_int bloblen; + size_t slen; u_int skip = 0; int ret = -1; int have_sig = 1; @@ -1020,8 +1026,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) /* generate signature */ ret = identity_sign(id, &signature, &slen, - buffer_ptr(&b), buffer_len(&b)); - if (ret == -1) { + buffer_ptr(&b), buffer_len(&b), datafellows); + if (ret != 0) { free(blob); buffer_free(&b); return 0; @@ -1096,7 +1102,7 @@ load_identity_file(char *filename, int userprovided) { Key *private; char prompt[300], *passphrase; - int perm_ok = 0, quit, i; + int r, perm_ok = 0, quit, i; struct stat st; if (stat(filename, &st) < 0) { @@ -1104,33 +1110,49 @@ load_identity_file(char *filename, int userprovided) filename, strerror(errno)); return NULL; } - private = key_load_private_type(KEY_UNSPEC, filename, "", NULL, &perm_ok); - if (!perm_ok) { - if (private != NULL) - key_free(private); - return NULL; - } - if (private == NULL) { - if (options.batch_mode) - return NULL; - snprintf(prompt, sizeof prompt, - "Enter passphrase for key '%.100s': ", filename); - for (i = 0; i < options.number_of_password_prompts; i++) { + snprintf(prompt, sizeof prompt, + "Enter passphrase for key '%.100s': ", filename); + for (i = 0; i <= options.number_of_password_prompts; i++) { + if (i == 0) + passphrase = ""; + else { passphrase = read_passphrase(prompt, 0); - if (strcmp(passphrase, "") != 0) { - private = key_load_private_type(KEY_UNSPEC, - filename, passphrase, NULL, NULL); - quit = 0; - } else { + if (*passphrase == '\0') { debug2("no passphrase given, try next key"); + free(passphrase); + break; + } + } + switch ((r = sshkey_load_private_type(KEY_UNSPEC, filename, + passphrase, &private, NULL, &perm_ok))) { + case 0: + break; + case SSH_ERR_KEY_WRONG_PASSPHRASE: + if (options.batch_mode) { + quit = 1; + break; + } + debug2("bad passphrase given, try again..."); + break; + case SSH_ERR_SYSTEM_ERROR: + if (errno == ENOENT) { + debug2("Load key \"%s\": %s", + filename, ssh_err(r)); quit = 1; + break; } + /* FALLTHROUGH */ + default: + error("Load key \"%s\": %s", filename, ssh_err(r)); + quit = 1; + break; + } + if (i > 0) { explicit_bzero(passphrase, strlen(passphrase)); free(passphrase); - if (private != NULL || quit) - break; - debug2("bad passphrase given, try again..."); } + if (private != NULL || quit) + break; } return private; } @@ -1144,12 +1166,12 @@ load_identity_file(char *filename, int userprovided) static void pubkey_prepare(Authctxt *authctxt) { - Identity *id, *id2, *tmp; - Idlist agent, files, *preferred; - Key *key; - AuthenticationConnection *ac; - char *comment; - int i, found; + struct identity *id, *id2, *tmp; + struct idlist agent, files, *preferred; + struct sshkey *key; + int agent_fd, i, r, found; + size_t j; + struct ssh_identitylist *idlist; TAILQ_INIT(&agent); /* keys from the agent */ TAILQ_INIT(&files); /* keys from the config file */ @@ -1179,7 +1201,7 @@ pubkey_prepare(Authctxt *authctxt) if (id2->key == NULL || (id2->key->flags & SSHKEY_FLAG_EXT) == 0) continue; - if (key_equal(id->key, id2->key)) { + if (sshkey_equal(id->key, id2->key)) { TAILQ_REMOVE(&files, id, next); TAILQ_INSERT_TAIL(preferred, id, next); found = 1; @@ -1194,37 +1216,48 @@ pubkey_prepare(Authctxt *authctxt) } } /* list of keys supported by the agent */ - if ((ac = ssh_get_authentication_connection())) { - for (key = ssh_get_first_identity(ac, &comment, 2); - key != NULL; - key = ssh_get_next_identity(ac, &comment, 2)) { + if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) { + if (r != SSH_ERR_AGENT_NOT_PRESENT) + debug("%s: ssh_get_authentication_socket: %s", + __func__, ssh_err(r)); + } else if ((r = ssh_fetch_identitylist(agent_fd, 2, &idlist)) != 0) { + if (r != SSH_ERR_AGENT_NO_IDENTITIES) + debug("%s: ssh_fetch_identitylist: %s", + __func__, ssh_err(r)); + } else { + for (j = 0; j < idlist->nkeys; j++) { found = 0; TAILQ_FOREACH(id, &files, next) { - /* agent keys from the config file are preferred */ - if (key_equal(key, id->key)) { - key_free(key); - free(comment); + /* + * agent keys from the config file are + * preferred + */ + if (sshkey_equal(idlist->keys[j], id->key)) { TAILQ_REMOVE(&files, id, next); TAILQ_INSERT_TAIL(preferred, id, next); - id->ac = ac; + id->agent_fd = agent_fd; found = 1; break; } } if (!found && !options.identities_only) { id = xcalloc(1, sizeof(*id)); - id->key = key; - id->filename = comment; - id->ac = ac; + /* XXX "steals" key/comment from idlist */ + id->key = idlist->keys[j]; + id->filename = idlist->comments[j]; + idlist->keys[j] = NULL; + idlist->comments[j] = NULL; + id->agent_fd = agent_fd; TAILQ_INSERT_TAIL(&agent, id, next); } } + ssh_free_identitylist(idlist); /* append remaining agent keys */ for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) { TAILQ_REMOVE(&agent, id, next); TAILQ_INSERT_TAIL(preferred, id, next); } - authctxt->agent = ac; + authctxt->agent_fd = agent_fd; } /* append remaining keys from the config file */ for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) { @@ -1242,13 +1275,13 @@ pubkey_cleanup(Authctxt *authctxt) { Identity *id; - if (authctxt->agent != NULL) - ssh_close_authentication_connection(authctxt->agent); + if (authctxt->agent_fd != -1) + ssh_close_authentication_socket(authctxt->agent_fd); for (id = TAILQ_FIRST(&authctxt->keys); id; id = TAILQ_FIRST(&authctxt->keys)) { TAILQ_REMOVE(&authctxt->keys, id, next); if (id->key) - key_free(id->key); + sshkey_free(id->key); free(id->filename); free(id); } diff --git a/usr.bin/ssh/sshd.c b/usr.bin/ssh/sshd.c index b2288f3795e..cb9689daced 100644 --- a/usr.bin/ssh/sshd.c +++ b/usr.bin/ssh/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.431 2015/01/07 18:15:07 tedu Exp $ */ +/* $OpenBSD: sshd.c,v 1.432 2015/01/14 20:05:27 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -105,6 +105,7 @@ #include "roaming.h" #include "ssh-sandbox.h" #include "version.h" +#include "ssherr.h" #ifndef O_NOCTTY #define O_NOCTTY 0 @@ -172,7 +173,7 @@ char *server_version_string = NULL; Kex *xxx_kex; /* Daemon's agent connection */ -AuthenticationConnection *auth_conn = NULL; +int auth_sock = -1; int have_agent = 0; /* @@ -631,7 +632,7 @@ privsep_preauth_child(void) static int privsep_preauth(Authctxt *authctxt) { - int status; + int status, r; pid_t pid; struct ssh_sandbox *box = NULL; @@ -649,8 +650,14 @@ privsep_preauth(Authctxt *authctxt) debug2("Network child is on pid %ld", (long)pid); pmonitor->m_pid = pid; - if (have_agent) - auth_conn = ssh_get_authentication_connection(); + if (have_agent) { + r = ssh_get_authentication_socket(&auth_sock); + if (r != 0) { + error("Could not get agent socket: %s", + ssh_err(r)); + have_agent = 0; + } + } if (box != NULL) ssh_sandbox_parent_preauth(box, pid); monitor_child_preauth(authctxt, pmonitor); @@ -1331,7 +1338,7 @@ main(int ac, char **av) { extern char *optarg; extern int optind; - int opt, i, j, on = 1; + int r, opt, i, j, on = 1; int sock_in = -1, sock_out = -1, newsock = -1; const char *remote_ip; int remote_port; @@ -1592,7 +1599,7 @@ main(int ac, char **av) if (strcmp(options.host_key_agent, SSH_AUTHSOCKET_ENV_NAME)) setenv(SSH_AUTHSOCKET_ENV_NAME, options.host_key_agent, 1); - have_agent = ssh_agent_present(); + have_agent = ssh_get_authentication_socket(NULL); } for (i = 0; i < options.num_host_key_files; i++) { @@ -1957,8 +1964,12 @@ main(int ac, char **av) if (use_privsep) { if (privsep_preauth(authctxt) == 1) goto authenticated; - } else if (compat20 && have_agent) - auth_conn = ssh_get_authentication_connection(); + } else if (compat20 && have_agent) { + if ((r = ssh_get_authentication_socket(&auth_sock)) != 0) { + error("Unable to get agent socket: %s", ssh_err(r)); + have_agent = -1; + } + } /* perform the key exchange */ /* authenticate user and start session */ @@ -2251,6 +2262,8 @@ void sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, u_int *slen, u_char *data, u_int dlen) { + int r; + if (privkey) { if (PRIVSEP(key_sign(privkey, signature, slen, data, dlen) < 0)) fatal("%s: key_sign failed", __func__); @@ -2258,9 +2271,15 @@ sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, u_int *slen, if (mm_key_sign(pubkey, signature, slen, data, dlen) < 0) fatal("%s: pubkey_sign failed", __func__); } else { - if (ssh_agent_sign(auth_conn, pubkey, signature, slen, data, - dlen)) - fatal("%s: ssh_agent_sign failed", __func__); + size_t xxx_slen; + + if ((r = ssh_agent_sign(auth_sock, pubkey, signature, &xxx_slen, + data, dlen, datafellows)) != 0) + fatal("%s: ssh_agent_sign failed: %s", + __func__, ssh_err(r)); + /* XXX: Old API is u_int; new size_t */ + if (slen != NULL) + *slen = xxx_slen; } }