From 7650bc68420a227212ba0ff5cd4a0d133471b872 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Tue, 30 Jan 2001 09:27:26 +1100 Subject: - (djm) OpenBSD CVS Sync: - markus@cvs.openbsd.org 2001/01/29 12:47:32 [rsa.c rsa.h ssh-agent.c sshconnect1.c sshd.c] handle rsa_private_decrypt failures; helps against the Bleichenbacher pkcs#1 attack --- ChangeLog | 4 ++++ rsa.c | 15 ++++++++------- rsa.h | 4 ++-- ssh-agent.c | 7 ++++--- sshconnect1.c | 11 +++++++---- sshd.c | 57 ++++++++++++++++++++++++++++++++++++++------------------- 6 files changed, 63 insertions(+), 35 deletions(-) diff --git a/ChangeLog b/ChangeLog index 250ab58af..9c97a1287 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,10 @@ - markus@cvs.openbsd.org 2001/01/29 12:42:35 [canohost.c canohost.h channels.c clientloop.c] add get_peer_ipaddr(socket), x11-fwd in ssh2 requires ipaddr, not DNS + - markus@cvs.openbsd.org 2001/01/29 12:47:32 + [rsa.c rsa.h ssh-agent.c sshconnect1.c sshd.c] + handle rsa_private_decrypt failures; helps against the Bleichenbacher + pkcs#1 attack 20000129 - (stevesk) sftp-server.c: use %lld vs. %qd diff --git a/rsa.c b/rsa.c index 04bb239e5..100524607 100644 --- a/rsa.c +++ b/rsa.c @@ -60,7 +60,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: rsa.c,v 1.19 2001/01/21 19:05:54 markus Exp $"); +RCSID("$OpenBSD: rsa.c,v 1.20 2001/01/29 19:47:30 markus Exp $"); #include "rsa.h" #include "log.h" @@ -94,7 +94,7 @@ rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key) xfree(inbuf); } -void +int rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key) { u_char *inbuf, *outbuf; @@ -108,13 +108,14 @@ rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key) BN_bn2bin(in, inbuf); if ((len = RSA_private_decrypt(ilen, inbuf, outbuf, key, - RSA_PKCS1_PADDING)) <= 0) - fatal("rsa_private_decrypt() failed"); - - BN_bin2bn(outbuf, len, out); - + RSA_PKCS1_PADDING)) <= 0) { + error("rsa_private_decrypt() failed"); + } else { + BN_bin2bn(outbuf, len, out); + } memset(outbuf, 0, olen); memset(inbuf, 0, ilen); xfree(outbuf); xfree(inbuf); + return len; } diff --git a/rsa.h b/rsa.h index 57d72cc78..713d31281 100644 --- a/rsa.h +++ b/rsa.h @@ -11,7 +11,7 @@ * called by a name other than "ssh" or "Secure Shell". */ -/* RCSID("$OpenBSD: rsa.h,v 1.9 2000/11/12 19:50:38 markus Exp $"); */ +/* RCSID("$OpenBSD: rsa.h,v 1.10 2001/01/29 19:47:30 markus Exp $"); */ #ifndef RSA_H #define RSA_H @@ -20,6 +20,6 @@ #include void rsa_public_encrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv)); -void rsa_private_decrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv)); +int rsa_private_decrypt __P((BIGNUM * out, BIGNUM * in, RSA * prv)); #endif /* RSA_H */ diff --git a/ssh-agent.c b/ssh-agent.c index 539f8ce7d..deed3ecae 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.48 2001/01/25 08:06:33 deraadt Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.49 2001/01/29 19:47:31 markus Exp $ */ /* * Author: Tatu Ylonen @@ -37,7 +37,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh-agent.c,v 1.48 2001/01/25 08:06:33 deraadt Exp $"); +RCSID("$OpenBSD: ssh-agent.c,v 1.49 2001/01/29 19:47:31 markus Exp $"); #include #include @@ -198,7 +198,8 @@ process_authentication_challenge1(SocketEntry *e) private = lookup_private_key(key, NULL, 1); if (private != NULL) { /* Decrypt the challenge using the private key. */ - rsa_private_decrypt(challenge, challenge, private->rsa); + if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0) + goto failure; /* The response is MD5 of decrypted challenge plus session id. */ len = BN_num_bytes(challenge); diff --git a/sshconnect1.c b/sshconnect1.c index 5a5a22227..e732806f3 100644 --- a/sshconnect1.c +++ b/sshconnect1.c @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect1.c,v 1.20 2001/01/22 23:06:40 markus Exp $"); +RCSID("$OpenBSD: sshconnect1.c,v 1.21 2001/01/29 19:47:31 markus Exp $"); #include #include @@ -163,14 +163,17 @@ respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv) int i, len; /* Decrypt the challenge using the private key. */ - rsa_private_decrypt(challenge, challenge, prv); + /* XXX think about Bleichenbacher, too */ + if (rsa_private_decrypt(challenge, challenge, prv) <= 0) + packet_disconnect( + "respond_to_rsa_challenge: rsa_private_decrypt failed"); /* Compute the response. */ /* The response is MD5 of decrypted challenge plus session id. */ len = BN_num_bytes(challenge); if (len <= 0 || len > sizeof(buf)) - packet_disconnect("respond_to_rsa_challenge: bad challenge length %d", - len); + packet_disconnect( + "respond_to_rsa_challenge: bad challenge length %d", len); memset(buf, 0, sizeof(buf)); BN_bn2bin(challenge, buf + sizeof(buf) - len); diff --git a/sshd.c b/sshd.c index d46e4aa8b..02fe2ec42 100644 --- a/sshd.c +++ b/sshd.c @@ -40,7 +40,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.158 2001/01/28 10:37:26 markus Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.159 2001/01/29 19:47:31 markus Exp $"); #include #include @@ -1186,6 +1186,7 @@ do_ssh1_kex(void) { int i, len; int plen, slen; + int rsafail = 0; BIGNUM *session_key_int; u_char session_key[SSH_SESSION_KEY_LENGTH]; u_char cookie[8]; @@ -1296,7 +1297,7 @@ do_ssh1_kex(void) * with larger modulus first). */ if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) { - /* Private key has bigger modulus. */ + /* Server key has bigger modulus. */ if (BN_num_bits(sensitive_data.server_key->rsa->n) < BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { fatal("do_connection: %s: server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", @@ -1305,10 +1306,12 @@ do_ssh1_kex(void) BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), SSH_KEY_BITS_RESERVED); } - rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.server_key->rsa); - rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.ssh1_host_key->rsa); + if (rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.server_key->rsa) <= 0) + rsafail++; + if (rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.ssh1_host_key->rsa) <= 0) + rsafail++; } else { /* Host key has bigger modulus (or they are equal). */ if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) < @@ -1319,10 +1322,12 @@ do_ssh1_kex(void) BN_num_bits(sensitive_data.server_key->rsa->n), SSH_KEY_BITS_RESERVED); } - rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.ssh1_host_key->rsa); - rsa_private_decrypt(session_key_int, session_key_int, - sensitive_data.server_key->rsa); + if (rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.ssh1_host_key->rsa) < 0) + rsafail++; + if (rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.server_key->rsa) < 0) + rsafail++; } compute_session_id(session_id, cookie, @@ -1337,15 +1342,29 @@ do_ssh1_kex(void) * least significant 256 bits of the integer; the first byte of the * key is in the highest bits. */ - BN_mask_bits(session_key_int, sizeof(session_key) * 8); - len = BN_num_bytes(session_key_int); - if (len < 0 || len > sizeof(session_key)) - fatal("do_connection: bad len from %s: session_key_int %d > sizeof(session_key) %d", - get_remote_ipaddr(), - len, sizeof(session_key)); - memset(session_key, 0, sizeof(session_key)); - BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len); - + 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) %d", + get_remote_ipaddr(), len, sizeof(session_key)); + rsafail++; + } else { + memset(session_key, 0, sizeof(session_key)); + BN_bn2bin(session_key_int, + session_key + sizeof(session_key) - len); + } + } + if (rsafail) { + log("do_connection: generating a fake encryption key"); + for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) { + if (i % 4 == 0) + rand = arc4random(); + session_key[i] = rand & 0xff; + rand >>= 8; + } + } /* Destroy the decrypted integer. It is no longer needed. */ BN_clear_free(session_key_int); -- cgit v1.2.3