summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjsing <>2024-06-25 14:10:45 +0000
committerjsing <>2024-06-25 14:10:45 +0000
commite59a7b2ee59c295978f01e92bf5132ee2e8548b6 (patch)
tree63af5f2e95c5104b6713eeb3528306b47ecc203a /src
parent7e17989e1f3f79c8497ce57ca420783bb5efba53 (diff)
downloadopenbsd-e59a7b2ee59c295978f01e92bf5132ee2e8548b6.tar.gz
openbsd-e59a7b2ee59c295978f01e92bf5132ee2e8548b6.tar.bz2
openbsd-e59a7b2ee59c295978f01e92bf5132ee2e8548b6.zip
Implement RSA key exchange in constant time.
RSA key exchange is known to have multiple security weaknesses, including being potentially susceptible to padding oracle and timing attacks. The RSA key exchange code that we inherited from OpenSSL was riddled with timing leaks, many of which we fixed (or minimised) early on. However, a number of issues still remained, particularly those related to libcrypto's RSA decryption and padding checks. Rework the RSA key exchange code such that we decrypt with RSA_NO_PADDING and then check the padding ourselves in constant time. In this case, the pre-master secret is of a known length, hence the padding is also a known length based on the size of the RSA key. This makes it easy to implement a check that is much safer than having RSA_private_decrypt() depad for us. Regardless, we still strongly recommend disabling RSA key exchange and using other key exchange methods that provide perfect forward secrecy and do not depend on client generated keys. Thanks to Marcel Maehren, Nurullah Erinola, Robert Merget, Juraj Somorovsky, Joerg Schwenk and Hubert Kario for raising these issues with us at various points in time. ok tb@
Diffstat (limited to 'src')
-rw-r--r--src/lib/libssl/Makefile3
-rw-r--r--src/lib/libssl/ssl_local.h4
-rw-r--r--src/lib/libssl/ssl_srvr.c129
3 files changed, 73 insertions, 63 deletions
diff --git a/src/lib/libssl/Makefile b/src/lib/libssl/Makefile
index 38e5ba30e0..a2b710922d 100644
--- a/src/lib/libssl/Makefile
+++ b/src/lib/libssl/Makefile
@@ -1,4 +1,4 @@
1# $OpenBSD: Makefile,v 1.81 2023/11/22 15:55:28 tb Exp $ 1# $OpenBSD: Makefile,v 1.82 2024/06/25 14:10:45 jsing Exp $
2 2
3.include <bsd.own.mk> 3.include <bsd.own.mk>
4.ifndef NOMAN 4.ifndef NOMAN
@@ -23,6 +23,7 @@ CFLAGS+= -DLIBRESSL_NAMESPACE
23CFLAGS+= -DTLS13_DEBUG 23CFLAGS+= -DTLS13_DEBUG
24.endif 24.endif
25CFLAGS+= -I${.CURDIR} 25CFLAGS+= -I${.CURDIR}
26CFLAGS+= -I${.CURDIR}/../libcrypto
26CFLAGS+= -I${.CURDIR}/../libcrypto/hidden 27CFLAGS+= -I${.CURDIR}/../libcrypto/hidden
27CFLAGS+= -I${.CURDIR}/../libcrypto/bio 28CFLAGS+= -I${.CURDIR}/../libcrypto/bio
28CFLAGS+= -I${.CURDIR}/hidden 29CFLAGS+= -I${.CURDIR}/hidden
diff --git a/src/lib/libssl/ssl_local.h b/src/lib/libssl/ssl_local.h
index eeef569fa9..db102212a8 100644
--- a/src/lib/libssl/ssl_local.h
+++ b/src/lib/libssl/ssl_local.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssl_local.h,v 1.16 2024/05/19 07:12:50 jsg Exp $ */ 1/* $OpenBSD: ssl_local.h,v 1.17 2024/06/25 14:10:45 jsing Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -167,8 +167,10 @@
167 167
168__BEGIN_HIDDEN_DECLS 168__BEGIN_HIDDEN_DECLS
169 169
170#ifndef CTASSERT
170#define CTASSERT(x) extern char _ctassert[(x) ? 1 : -1 ] \ 171#define CTASSERT(x) extern char _ctassert[(x) ? 1 : -1 ] \
171 __attribute__((__unused__)) 172 __attribute__((__unused__))
173#endif
172 174
173#ifndef LIBRESSL_HAS_DTLS1_2 175#ifndef LIBRESSL_HAS_DTLS1_2
174#define LIBRESSL_HAS_DTLS1_2 176#define LIBRESSL_HAS_DTLS1_2
diff --git a/src/lib/libssl/ssl_srvr.c b/src/lib/libssl/ssl_srvr.c
index 6d61a4e4fa..e9f14dc610 100644
--- a/src/lib/libssl/ssl_srvr.c
+++ b/src/lib/libssl/ssl_srvr.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssl_srvr.c,v 1.160 2024/02/03 17:39:17 tb Exp $ */ 1/* $OpenBSD: ssl_srvr.c,v 1.161 2024/06/25 14:10:45 jsing Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -163,6 +163,7 @@
163#include <openssl/x509.h> 163#include <openssl/x509.h>
164 164
165#include "bytestring.h" 165#include "bytestring.h"
166#include "crypto_internal.h"
166#include "dtls_local.h" 167#include "dtls_local.h"
167#include "ssl_local.h" 168#include "ssl_local.h"
168#include "ssl_sigalgs.h" 169#include "ssl_sigalgs.h"
@@ -1621,98 +1622,104 @@ ssl3_send_certificate_request(SSL *s)
1621static int 1622static int
1622ssl3_get_client_kex_rsa(SSL *s, CBS *cbs) 1623ssl3_get_client_kex_rsa(SSL *s, CBS *cbs)
1623{ 1624{
1624 unsigned char fakekey[SSL_MAX_MASTER_KEY_LENGTH]; 1625 uint8_t fakepms[SSL_MAX_MASTER_KEY_LENGTH];
1625 unsigned char *pms = NULL; 1626 uint8_t *pms = NULL;
1626 unsigned char *p;
1627 size_t pms_len = 0; 1627 size_t pms_len = 0;
1628 size_t pad_len;
1628 EVP_PKEY *pkey = NULL; 1629 EVP_PKEY *pkey = NULL;
1629 RSA *rsa = NULL; 1630 RSA *rsa = NULL;
1630 CBS enc_pms; 1631 CBS enc_pms;
1631 int decrypt_len; 1632 int decrypt_len;
1632 int al = -1; 1633 uint8_t mask;
1634 size_t i;
1635 int valid = 1;
1636 int ret = 0;
1637
1638 /*
1639 * Handle key exchange in the form of an RSA-Encrypted Premaster Secret
1640 * Message. See RFC 5246, section 7.4.7.1.
1641 */
1633 1642
1634 arc4random_buf(fakekey, sizeof(fakekey)); 1643 arc4random_buf(fakepms, sizeof(fakepms));
1635 1644
1636 fakekey[0] = s->s3->hs.peer_legacy_version >> 8; 1645 fakepms[0] = s->s3->hs.peer_legacy_version >> 8;
1637 fakekey[1] = s->s3->hs.peer_legacy_version & 0xff; 1646 fakepms[1] = s->s3->hs.peer_legacy_version & 0xff;
1638 1647
1639 pkey = s->cert->pkeys[SSL_PKEY_RSA].privatekey; 1648 pkey = s->cert->pkeys[SSL_PKEY_RSA].privatekey;
1640 if (pkey == NULL || (rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) { 1649 if (pkey == NULL || (rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) {
1641 al = SSL_AD_HANDSHAKE_FAILURE;
1642 SSLerror(s, SSL_R_MISSING_RSA_CERTIFICATE); 1650 SSLerror(s, SSL_R_MISSING_RSA_CERTIFICATE);
1643 goto fatal_err; 1651 ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
1652 goto err;
1644 } 1653 }
1645 1654
1655 /*
1656 * The minimum size of an encrypted premaster secret is 11 bytes of
1657 * padding (00 02 <8 or more non-zero bytes> 00) (RFC 8017, section
1658 * 9.2) and 48 bytes of premaster secret (RFC 5246, section 7.4.7.1).
1659 * This means an RSA key size of at least 472 bits.
1660 */
1646 pms_len = RSA_size(rsa); 1661 pms_len = RSA_size(rsa);
1647 if (pms_len < SSL_MAX_MASTER_KEY_LENGTH) 1662 if (pms_len < 11 + SSL_MAX_MASTER_KEY_LENGTH) {
1648 goto err; 1663 SSLerror(s, SSL_R_DECRYPTION_FAILED);
1649 if ((pms = malloc(pms_len)) == NULL) 1664 ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
1650 goto err; 1665 goto err;
1651 p = pms; 1666 }
1667 pad_len = pms_len - SSL_MAX_MASTER_KEY_LENGTH;
1652 1668
1653 if (!CBS_get_u16_length_prefixed(cbs, &enc_pms)) 1669 if (!CBS_get_u16_length_prefixed(cbs, &enc_pms)) {
1654 goto decode_err; 1670 SSLerror(s, SSL_R_BAD_PACKET_LENGTH);
1655 if (CBS_len(cbs) != 0 || CBS_len(&enc_pms) != RSA_size(rsa)) { 1671 ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
1672 goto err;
1673 }
1674 if (CBS_len(&enc_pms) != pms_len || CBS_len(cbs) != 0) {
1656 SSLerror(s, SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG); 1675 SSLerror(s, SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG);
1676 ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
1657 goto err; 1677 goto err;
1658 } 1678 }
1659 1679
1660 decrypt_len = RSA_private_decrypt(CBS_len(&enc_pms), CBS_data(&enc_pms), 1680 if ((pms = calloc(1, pms_len)) == NULL)
1661 pms, rsa, RSA_PKCS1_PADDING); 1681 goto err;
1662 1682
1663 ERR_clear_error(); 1683 decrypt_len = RSA_private_decrypt(CBS_len(&enc_pms), CBS_data(&enc_pms),
1684 pms, rsa, RSA_NO_PADDING);
1664 1685
1665 if (decrypt_len != SSL_MAX_MASTER_KEY_LENGTH) { 1686 if (decrypt_len != pms_len) {
1666 al = SSL_AD_DECODE_ERROR; 1687 SSLerror(s, SSL_R_DECRYPTION_FAILED);
1667 /* SSLerror(s, SSL_R_BAD_RSA_DECRYPT); */ 1688 ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
1689 goto err;
1668 } 1690 }
1669 1691
1670 if ((al == -1) && !((pms[0] == (s->s3->hs.peer_legacy_version >> 8)) && 1692 /*
1671 (pms[1] == (s->s3->hs.peer_legacy_version & 0xff)))) { 1693 * All processing from here on needs to avoid leaking any information
1672 /* 1694 * about the decrypted content, in order to prevent oracle attacks and
1673 * The premaster secret must contain the same version number 1695 * minimise timing attacks.
1674 * as the ClientHello to detect version rollback attacks 1696 */
1675 * (strangely, the protocol does not offer such protection for
1676 * DH ciphersuites).
1677 *
1678 * The Klima-Pokorny-Rosa extension of Bleichenbacher's attack
1679 * (http://eprint.iacr.org/2003/052/) exploits the version
1680 * number check as a "bad version oracle" -- an alert would
1681 * reveal that the plaintext corresponding to some ciphertext
1682 * made up by the adversary is properly formatted except that
1683 * the version number is wrong. To avoid such attacks, we should
1684 * treat this just like any other decryption error.
1685 */
1686 al = SSL_AD_DECODE_ERROR;
1687 /* SSLerror(s, SSL_R_BAD_PROTOCOL_VERSION_NUMBER); */
1688 }
1689 1697
1690 if (al != -1) { 1698 /* Check padding - 00 02 <8 or more non-zero bytes> 00 */
1691 /* 1699 valid &= crypto_ct_eq_u8(pms[0], 0x00);
1692 * Some decryption failure -- use random value instead 1700 valid &= crypto_ct_eq_u8(pms[1], 0x02);
1693 * as countermeasure against Bleichenbacher's attack 1701 for (i = 2; i < pad_len - 1; i++)
1694 * on PKCS #1 v1.5 RSA padding (see RFC 2246, 1702 valid &= crypto_ct_ne_u8(pms[i], 0x00);
1695 * section 7.4.7.1). 1703 valid &= crypto_ct_eq_u8(pms[pad_len - 1], 0x00);
1696 */
1697 p = fakekey;
1698 }
1699 1704
1700 if (!tls12_derive_master_secret(s, p, SSL_MAX_MASTER_KEY_LENGTH)) 1705 /* Ensure client version in premaster secret matches ClientHello version. */
1701 goto err; 1706 valid &= crypto_ct_eq_u8(pms[pad_len + 0], s->s3->hs.peer_legacy_version >> 8);
1707 valid &= crypto_ct_eq_u8(pms[pad_len + 1], s->s3->hs.peer_legacy_version & 0xff);
1702 1708
1703 freezero(pms, pms_len); 1709 /* Use the premaster secret if padding is correct, if not use the fake. */
1710 mask = crypto_ct_eq_mask_u8(valid, 1);
1711 for (i = 0; i < SSL_MAX_MASTER_KEY_LENGTH; i++)
1712 pms[i] = (pms[pad_len + i] & mask) | (fakepms[i] & ~mask);
1704 1713
1705 return 1; 1714 if (!tls12_derive_master_secret(s, pms, SSL_MAX_MASTER_KEY_LENGTH))
1715 goto err;
1716
1717 ret = 1;
1706 1718
1707 decode_err:
1708 al = SSL_AD_DECODE_ERROR;
1709 SSLerror(s, SSL_R_BAD_PACKET_LENGTH);
1710 fatal_err:
1711 ssl3_send_alert(s, SSL3_AL_FATAL, al);
1712 err: 1719 err:
1713 freezero(pms, pms_len); 1720 freezero(pms, pms_len);
1714 1721
1715 return 0; 1722 return ret;
1716} 1723}
1717 1724
1718static int 1725static int