int auth_rsa_challenge_dialog(Key *key) { BIGNUM *challenge, *encrypted_challenge; u_char response[16]; int i, success; if ((encrypted_challenge = BN_new()) == NULL) fatal("auth_rsa_challenge_dialog: BN_new() failed"); challenge = PRIVSEP(auth_rsa_generate_challenge(key)); /* Encrypt the challenge with the public key. */ rsa_public_encrypt(encrypted_challenge, challenge, key->rsa); /* Send the encrypted challenge to the client. */ packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE); packet_put_bignum(encrypted_challenge); packet_send(); BN_clear_free(encrypted_challenge); packet_write_wait(); /* Wait for a response. */ packet_read_expect(SSH_CMSG_AUTH_RSA_RESPONSE); for (i = 0; i < 16; i++) response[i] = packet_get_char(); packet_check_eom(); success = PRIVSEP(auth_rsa_verify_response(key, challenge, response)); BN_clear_free(challenge); return (success); }
/* * Checks if the user has an authentication agent, and if so, tries to * authenticate using the agent. */ static int try_agent_authentication(void) { int type; char *comment; AuthenticationConnection *auth; u_char response[16]; u_int i; Key *key; BIGNUM *challenge; /* Get connection to the agent. */ auth = ssh_get_authentication_connection(); if (!auth) 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)) { /* Try this identity. */ debug("Trying RSA authentication via agent with '%.100s'", comment); xfree(comment); /* 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_send(); packet_write_wait(); /* Wait for server's response. */ type = packet_read(); /* The server sends failure if it doesn\'t like our key or 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. */ if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) packet_disconnect("Protocol error during RSA authentication: %d", type); packet_get_bignum(challenge); packet_check_eom(); debug("Received RSA challenge from server."); /* Ask the agent to decrypt the challenge. */ if (!ssh_decrypt_challenge(auth, key, challenge, session_id, 1, response)) { /* * The agent failed to authenticate this identifier * although it advertised it supports this. Just * return a wrong value. */ log("Authentication agent failed to decrypt challenge."); memset(response, 0, sizeof(response)); } key_free(key); debug("Sending response to RSA challenge."); /* Send the decrypted challenge back to the server. */ packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); for (i = 0; i < 16; i++) packet_put_char(response[i]); packet_send(); packet_write_wait(); /* Wait for response from the server. */ type = packet_read(); /* 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); } ssh_close_authentication_connection(auth); BN_clear_free(challenge); debug("RSA authentication using agent refused."); return 0; }
/* * SSH1 key exchange */ void do_ssh1_kex(void) { int i, len; int rsafail = 0; BIGNUM *session_key_int; u_char session_key[SSH_SESSION_KEY_LENGTH]; u_char cookie[8]; u_int cipher_type, auth_mask, protocol_flags; u_int32_t rnd = 0; /* * Generate check bytes that the client must send back in the user * packet in order for it to be accepted; this is used to defy ip * spoofing attacks. Note that this only works against somebody * doing IP spoofing from a remote machine; any machine on the local * network can still see outgoing packets and catch the random * cookie. This only affects rhosts authentication, and this is one * of the reasons why it is inherently insecure. */ for (i = 0; i < 8; i++) { if (i % 4 == 0) rnd = arc4random(); cookie[i] = rnd & 0xff; rnd >>= 8; } /* * Send our public key. We include in the packet 64 bits of random * data that must be matched in the reply in order to prevent IP * spoofing. */ packet_start(SSH_SMSG_PUBLIC_KEY); for (i = 0; i < 8; i++) packet_put_char(cookie[i]); /* Store our public server RSA key. */ packet_put_int(BN_num_bits(sensitive_data.server_key->rsa->n)); packet_put_bignum(sensitive_data.server_key->rsa->e); packet_put_bignum(sensitive_data.server_key->rsa->n); /* Store our public host RSA key. */ packet_put_int(BN_num_bits(sensitive_data.ssh1_host_key->rsa->n)); packet_put_bignum(sensitive_data.ssh1_host_key->rsa->e); packet_put_bignum(sensitive_data.ssh1_host_key->rsa->n); /* Put protocol flags. */ packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN); /* Declare which ciphers we support. */ packet_put_int(cipher_mask_ssh1(0)); /* Declare supported authentication types. */ auth_mask = 0; if (options.rhosts_rsa_authentication) auth_mask |= 1 << SSH_AUTH_RHOSTS_RSA; if (options.rsa_authentication) auth_mask |= 1 << SSH_AUTH_RSA; if (options.challenge_response_authentication == 1) auth_mask |= 1 << SSH_AUTH_TIS; if (options.password_authentication) auth_mask |= 1 << SSH_AUTH_PASSWORD; packet_put_int(auth_mask); /* Send the packet and wait for it to be sent. */ packet_send(); packet_write_wait(); debug("Sent %d bit server key and %d bit host key.", BN_num_bits(sensitive_data.server_key->rsa->n), BN_num_bits(sensitive_data.ssh1_host_key->rsa->n)); /* Read clients reply (cipher type and session key). */ packet_read_expect(SSH_CMSG_SESSION_KEY); /* Get cipher type and check whether we accept this. */ cipher_type = packet_get_char(); if (!(cipher_mask_ssh1(0) & (1 << cipher_type))) packet_disconnect("Warning: client selects unsupported cipher."); /* Get check bytes from the packet. These must match those we sent earlier with the public key packet. */ for (i = 0; i < 8; i++) if (cookie[i] != packet_get_char()) packet_disconnect("IP Spoofing check bytes do not match."); debug("Encryption type: %.200s", cipher_name(cipher_type)); /* Get the encrypted integer. */ if ((session_key_int = BN_new()) == NULL) fatal("do_ssh1_kex: BN_new failed"); packet_get_bignum(session_key_int); protocol_flags = packet_get_int(); packet_set_protocol_flags(protocol_flags); packet_check_eom(); /* Decrypt session_key_int using host/server keys */ rsafail = PRIVSEP(ssh1_session_key(session_key_int)); /* * Extract session key from the decrypted integer. The key is in the * least significant 256 bits of the integer; the first byte of the * key is in the highest bits. */ if (!rsafail) { BN_mask_bits(session_key_int, sizeof(session_key) * 8); len = BN_num_bytes(session_key_int); if (len < 0 || len > sizeof(session_key)) { error("do_connection: bad session key len from %s: " "session_key_int %d > sizeof(session_key) %lu", get_remote_ipaddr(), len, (u_long)sizeof(session_key)); rsafail++; } else { memset(session_key, 0, sizeof(session_key)); BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len); derive_ssh1_session_id( sensitive_data.ssh1_host_key->rsa->n, sensitive_data.server_key->rsa->n, cookie, session_id); /* * Xor the first 16 bytes of the session key with the * session id. */ for (i = 0; i < 16; i++) session_key[i] ^= session_id[i]; } } if (rsafail) { int bytes = BN_num_bytes(session_key_int); u_char *buf = xmalloc(bytes); MD5_CTX md; logit("do_connection: generating a fake encryption key"); BN_bn2bin(session_key_int, buf); MD5_Init(&md); MD5_Update(&md, buf, bytes); MD5_Update(&md, sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH); MD5_Final(session_key, &md); MD5_Init(&md); MD5_Update(&md, session_key, 16); MD5_Update(&md, buf, bytes); MD5_Update(&md, sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH); MD5_Final(session_key + 16, &md); memset(buf, 0, bytes); xfree(buf); for (i = 0; i < 16; i++) session_id[i] = session_key[i] ^ session_key[i + 16]; } /* Destroy the private and public keys. No longer. */ destroy_sensitive_data(); if (use_privsep) mm_ssh1_session_id(session_id); /* Destroy the decrypted integer. It is no longer needed. */ BN_clear_free(session_key_int); /* Set the session key. From this on all communications will be encrypted. */ packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, cipher_type); /* Destroy our copy of the session key. It is no longer needed. */ memset(session_key, 0, sizeof(session_key)); debug("Received session key; encryption turned on."); /* Send an acknowledgment packet. Note that this packet is sent encrypted. */ packet_start(SSH_SMSG_SUCCESS); packet_send(); packet_write_wait(); }
/* * Checks if the user has an authentication agent, and if so, tries to * authenticate using the agent. */ static int try_agent_authentication(void) { int r, type, agent_fd, ret = 0; u_char response[16]; size_t i; BIGNUM *challenge; struct ssh_identitylist *idlist = NULL; /* Get connection to the agent. */ 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. */ 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'", idlist->comments[i]); /* Tell the server that we are willing to authenticate using this key. */ packet_start(SSH_CMSG_AUTH_RSA); packet_put_bignum(idlist->keys[i]->rsa->n); packet_send(); packet_write_wait(); /* Wait for server's response. */ type = packet_read(); /* The server sends failure if it doesn't like our key or does not support RSA authentication. */ if (type == SSH_SMSG_FAILURE) { debug("Server refused our key."); continue; } /* Otherwise it should have sent a challenge. */ if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) packet_disconnect("Protocol error during RSA authentication: %d", type); packet_get_bignum(challenge); packet_check_eom(); debug("Received RSA challenge from server."); /* Ask the agent to decrypt the challenge. */ 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: %s", ssh_err(r)); explicit_bzero(response, sizeof(response)); } debug("Sending response to RSA challenge."); /* Send the decrypted challenge back to the server. */ packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); for (i = 0; i < 16; i++) packet_put_char(response[i]); packet_send(); packet_write_wait(); /* Wait for response from the server. */ type = packet_read(); /* * The server returns success if it accepted the * authentication. */ if (type == SSH_SMSG_SUCCESS) { debug("RSA authentication accepted by server."); ret = 1; break; } else if (type != SSH_SMSG_FAILURE) packet_disconnect("Protocol error waiting RSA auth " "response: %d", type); } if (ret != 1) debug("RSA authentication using agent refused."); out: ssh_free_identitylist(idlist); ssh_close_authentication_socket(agent_fd); BN_clear_free(challenge); return ret; }