[openssl] master update

Matt Caswell matt at openssl.org
Thu Dec 5 16:21:20 UTC 2019


The branch master has been updated
       via  350c92351705aa5916ffdf07fd7b81c1cbcb178b (commit)
       via  e7db9680db57e180c525bc57c3858d8dd5637940 (commit)
       via  d9a75107478380641b6862acac74d0bb870a5374 (commit)
      from  6df44cf65fbc7e150965149d7e681ac3e22d11d8 (commit)


- Log -----------------------------------------------------------------
commit 350c92351705aa5916ffdf07fd7b81c1cbcb178b
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Nov 11 16:33:24 2019 +0000

    Add documentation for the newly added RSA_PKCS1_WITH_TLS_PADDING
    
    Documentation for RSA_PKCS1_WITH_TLS_PADDING padding mode as per the
    previous commits, as well as the associated parameters for this mode.
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/10411)

commit e7db9680db57e180c525bc57c3858d8dd5637940
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Nov 11 15:54:33 2019 +0000

    Move constant time RSA code out of libssl
    
    Server side RSA key transport code in a Client Key Exchange message
    currently uses constant time code to check that the RSA decrypt is
    correctly formatted. The previous commit taught the underlying RSA
    implementation how to do this instead, so we use that implementation and
    remove this code from libssl.
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/10411)

commit d9a75107478380641b6862acac74d0bb870a5374
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Nov 11 14:37:02 2019 +0000

    Teach the RSA implementation about TLS RSA Key Transport
    
    In TLSv1.2 a pre-master secret value is passed from the client to the
    server encrypted using RSA PKCS1 type 2 padding in a ClientKeyExchange
    message. As well as the normal formatting rules for RSA PKCA1 type 2
    padding TLS imposes some additional rules about what constitutes a well
    formed key. Specifically it must be exactly the right length and
    encode the TLS version originally requested by the client (as opposed to
    the actual negotiated version) in its first two bytes.
    
    All of these checks need to be done in constant time and, if they fail,
    then the TLS implementation is supposed to continue anyway with a random
    key (and therefore the connection will fail later on). This avoids
    padding oracle type attacks.
    
    This commit implements this within the RSA padding code so that we keep
    all the constant time padding logic in one place. A later commit will
    remove it from libssl.
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/10411)

-----------------------------------------------------------------------

Summary of changes:
 crypto/err/openssl.txt                            |   2 +
 crypto/rsa/rsa_pk1.c                              | 125 ++++++++++++++++++-
 doc/man3/EVP_PKEY_CTX_ctrl.pod                    |  23 +++-
 doc/man7/provider-asymcipher.pod                  |  17 +++
 include/crypto/rsa.h                              |   4 +
 include/openssl/core_names.h                      |  16 +--
 include/openssl/rsa.h                             |  14 ++-
 providers/common/include/prov/providercommonerr.h |   2 +
 providers/common/provider_err.c                   |   3 +
 providers/implementations/asymciphers/rsa_enc.c   | 100 +++++++++++++---
 ssl/statem/statem_srvr.c                          | 140 ++++++++--------------
 11 files changed, 322 insertions(+), 124 deletions(-)

diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index e81c32fe4f..4baed5c48e 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -2684,9 +2684,11 @@ PROV_R_AES_KEY_SETUP_FAILED:101:aes key setup failed
 PROV_R_BAD_DECRYPT:100:bad decrypt
 PROV_R_BAD_ENCODING:141:bad encoding
 PROV_R_BAD_LENGTH:142:bad length
+PROV_R_BAD_TLS_CLIENT_VERSION:161:bad tls client version
 PROV_R_BN_ERROR:160:bn error
 PROV_R_BOTH_MODE_AND_MODE_INT:127:both mode and mode int
 PROV_R_CIPHER_OPERATION_FAILED:102:cipher operation failed
+PROV_R_FAILED_TO_DECRYPT:162:failed to decrypt
 PROV_R_FAILED_TO_GENERATE_KEY:121:failed to generate key
 PROV_R_FAILED_TO_GET_PARAMETER:103:failed to get parameter
 PROV_R_FAILED_TO_SET_PARAMETER:104:failed to set parameter
diff --git a/crypto/rsa/rsa_pk1.c b/crypto/rsa/rsa_pk1.c
index 0c77422404..007e9b8cd5 100644
--- a/crypto/rsa/rsa_pk1.c
+++ b/crypto/rsa/rsa_pk1.c
@@ -10,10 +10,13 @@
 #include "internal/constant_time.h"
 
 #include <stdio.h>
-#include "internal/cryptlib.h"
 #include <openssl/bn.h>
 #include <openssl/rsa.h>
 #include <openssl/rand.h>
+/* Just for the SSL_MAX_MASTER_KEY_LENGTH value */
+#include <openssl/ssl.h>
+#include "internal/cryptlib.h"
+#include "crypto/rsa.h"
 
 int RSA_padding_add_PKCS1_type_1(unsigned char *to, int tlen,
                                  const unsigned char *from, int flen)
@@ -253,3 +256,123 @@ int RSA_padding_check_PKCS1_type_2(unsigned char *to, int tlen,
 
     return constant_time_select_int(good, mlen, -1);
 }
+
+/*
+ * rsa_padding_check_PKCS1_type_2_TLS() checks and removes the PKCS1 type 2
+ * padding from a decrypted RSA message in a TLS signature. The result is stored
+ * in the buffer pointed to by |to| which should be |tlen| bytes long. |tlen|
+ * must be at least SSL_MAX_MASTER_KEY_LENGTH. The original decrypted message
+ * should be stored in |from| which must be |flen| bytes in length and padded
+ * such that |flen == RSA_size()|. The TLS protocol version that the client
+ * originally requested should be passed in |client_version|. Some buggy clients
+ * can exist which use the negotiated version instead of the originally
+ * requested protocol version. If it is necessary to work around this bug then
+ * the negotiated protocol version can be passed in |alt_version|, otherwise 0
+ * should be passed.
+ *
+ * If the passed message is publicly invalid or some other error that can be
+ * treated in non-constant time occurs then -1 is returned. On success the
+ * length of the decrypted data is returned. This will always be
+ * SSL_MAX_MASTER_KEY_LENGTH. If an error occurs that should be treated in
+ * constant time then this function will appear to return successfully, but the
+ * decrypted data will be randomly generated (as per
+ * https://tools.ietf.org/html/rfc5246#section-7.4.7.1).
+ */
+int rsa_padding_check_PKCS1_type_2_TLS(unsigned char *to, size_t tlen,
+                                       const unsigned char *from, size_t flen,
+                                       int client_version, int alt_version)
+{
+    unsigned int i, good, version_good;
+    unsigned char rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH];
+
+    /*
+     * If these checks fail then either the message in publicly invalid, or
+     * we've been called incorrectly. We can fail immediately.
+     */
+    if (flen < RSA_PKCS1_PADDING_SIZE + SSL_MAX_MASTER_KEY_LENGTH
+            || tlen < SSL_MAX_MASTER_KEY_LENGTH) {
+        ERR_raise(ERR_LIB_RSA, RSA_R_PKCS_DECODING_ERROR);
+        return -1;
+    }
+
+    /*
+     * Generate a random premaster secret to use in the event that we fail
+     * to decrypt.
+     */
+    if (RAND_priv_bytes(rand_premaster_secret,
+                      sizeof(rand_premaster_secret)) <= 0) {
+        ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR);
+        return -1;
+    }
+
+    good = constant_time_is_zero(from[0]);
+    good &= constant_time_eq(from[1], 2);
+
+    /* Check we have the expected padding data */
+    for (i = 2; i < flen - SSL_MAX_MASTER_KEY_LENGTH - 1; i++)
+        good &= ~constant_time_is_zero_8(from[i]);
+    good &= constant_time_is_zero_8(from[flen - SSL_MAX_MASTER_KEY_LENGTH - 1]);
+
+
+    /*
+     * If the version in the decrypted pre-master secret is correct then
+     * version_good will be 0xff, otherwise it'll be zero. The
+     * Klima-Pokorny-Rosa extension of Bleichenbacher's attack
+     * (http://eprint.iacr.org/2003/052/) exploits the version number
+     * check as a "bad version oracle". Thus version checks are done in
+     * constant time and are treated like any other decryption error.
+     */
+    version_good =
+        constant_time_eq(from[flen - SSL_MAX_MASTER_KEY_LENGTH],
+                         (client_version >> 8) & 0xff);
+    version_good &=
+        constant_time_eq(from[flen - SSL_MAX_MASTER_KEY_LENGTH + 1],
+                         client_version & 0xff);
+
+    /*
+     * The premaster secret must contain the same version number as the
+     * ClientHello to detect version rollback attacks (strangely, the
+     * protocol does not offer such protection for DH ciphersuites).
+     * However, buggy clients exist that send the negotiated protocol
+     * version instead if the server does not support the requested
+     * protocol version. If SSL_OP_TLS_ROLLBACK_BUG is set then we tolerate
+     * such clients. In that case alt_version will be non-zero and set to
+     * the negotiated version.
+     */
+    if (alt_version > 0) {
+        unsigned int workaround_good;
+
+        workaround_good =
+            constant_time_eq(from[flen - SSL_MAX_MASTER_KEY_LENGTH],
+                             (alt_version >> 8) & 0xff);
+        workaround_good &=
+            constant_time_eq(from[flen - SSL_MAX_MASTER_KEY_LENGTH + 1],
+                             alt_version & 0xff);
+        version_good |= workaround_good;
+    }
+
+    good &= version_good;
+
+
+    /*
+     * Now copy the result over to the to buffer if good, or random data if
+     * not good.
+     */
+    for (i = 0; i < SSL_MAX_MASTER_KEY_LENGTH; i++) {
+        to[i] =
+            constant_time_select_8(good,
+                                   from[flen - SSL_MAX_MASTER_KEY_LENGTH + i],
+                                   rand_premaster_secret[i]);
+    }
+
+    /*
+     * We must not leak whether a decryption failure occurs because of
+     * Bleichenbacher's attack on PKCS #1 v1.5 RSA padding (see RFC 2246,
+     * section 7.4.7.1). The code follows that advice of the TLS RFC and
+     * generates a random premaster secret for the case that the decrypt
+     * fails. See https://tools.ietf.org/html/rfc5246#section-7.4.7.1
+     * So, whether we actually succeeded or not, return success.
+     */
+
+    return SSL_MAX_MASTER_KEY_LENGTH;
+}
diff --git a/doc/man3/EVP_PKEY_CTX_ctrl.pod b/doc/man3/EVP_PKEY_CTX_ctrl.pod
index 06151d4a5c..306b20b603 100644
--- a/doc/man3/EVP_PKEY_CTX_ctrl.pod
+++ b/doc/man3/EVP_PKEY_CTX_ctrl.pod
@@ -258,7 +258,9 @@ The B<pad> parameter can take the value B<RSA_PKCS1_PADDING> for PKCS#1
 padding, B<RSA_SSLV23_PADDING> for SSLv23 padding, B<RSA_NO_PADDING> for
 no padding, B<RSA_PKCS1_OAEP_PADDING> for OAEP padding (encrypt and
 decrypt only), B<RSA_X931_PADDING> for X9.31 padding (signature operations
-only) and B<RSA_PKCS1_PSS_PADDING> (sign and verify only).
+only), B<RSA_PKCS1_PSS_PADDING> (sign and verify only) and
+B<RSA_PKCS1_WITH_TLS_PADDING> for TLS RSA ClientKeyExchange message padding
+(decryption only).
 
 Two RSA padding modes behave differently if EVP_PKEY_CTX_set_signature_md()
 is used. If this macro is called for PKCS#1 padding the plaintext buffer is
@@ -352,6 +354,25 @@ B<label>. The return value is the label length. The padding mode
 must have been set to B<RSA_PKCS1_OAEP_PADDING>. The resulting pointer is owned
 by the library and should not be freed by the caller.
 
+B<RSA_PKCS1_WITH_TLS_PADDING> is used when decrypting an RSA encrypted TLS
+pre-master secret in a TLS ClientKeyExchange message. It is the same as
+RSA_PKCS1_PADDING except that it additionally verifies that the result is the
+correct length and the first two bytes are the protocol version initially
+requested by the client. If the encrypted content is publicly invalid then the
+decryption will fail. However, if the padding checks fail then decryption will
+still appear to succeed but a random TLS premaster secret will be returned
+instead. This padding mode accepts two parameters which can be set using the
+L<EVP_PKEY_CTX_set_params(3)> function. These are
+OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION and
+OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION, both of which are expected to be
+unsigned integers. Normally only the first of these will be set and represents
+the TLS protocol version that was first requested by the client (e.g. 0x0303 for
+TLSv1.2, 0x0302 for TLSv1.1 etc). Historically some buggy clients would use the
+negotiated protocol version instead of the protocol version first requested. If
+this behaviour should be tolerated then
+OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION should be set to the actual
+negotiated protocol version. Otherwise it should be left unset.
+
 =head2 DSA parameters
 
 The EVP_PKEY_CTX_set_dsa_paramgen_bits() macro sets the number of bits used
diff --git a/doc/man7/provider-asymcipher.pod b/doc/man7/provider-asymcipher.pod
index d0effa89b1..de615c463f 100644
--- a/doc/man7/provider-asymcipher.pod
+++ b/doc/man7/provider-asymcipher.pod
@@ -181,6 +181,13 @@ algorithms:
 
 =item "pad-mode" (B<OSSL_ASYM_CIPHER_PARAM_PAD_MODE>) <integer>
 
+The type of padding to be used. The interpretation of this value will depend
+on the algorithm in use. The default provider understands these RSA padding
+modes: 1 (RSA_PKCS1_PADDING), 2 (RSA_SSLV23_PADDING), 3 (RSA_NO_PADDING),
+4 (RSA_PKCS1_OAEP_PADDING), 5 (RSA_X931_PADDING), 6 (RSA_PKCS1_PSS_PADDING) and
+7 (RSA_PKCS1_WITH_TLS_PADDING). See L<EVP_PKEY_CTX_set_rsa_padding(3)> for
+further details.
+
 =item "digest" (B<OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST>) <UTF8 string>
 
 Gets or sets the name of the OAEP digest algorithm used when OAEP padding is in
@@ -207,6 +214,16 @@ Gets or sets the OAEP label used when OAEP padding is in use.
 
 Gets the length of an OAEP label when OAEP padding is in use.
 
+=item "tls-client-version" (B<OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION>) <unsigned integer>
+
+The TLS protocol version first requested by the client. See
+B<RSA_PKCS1_WITH_TLS_PADDING> on the page L<EVP_PKEY_CTX_set_rsa_padding(3)>.
+
+=item "tls-negotiated-version" (B<OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION>) <unsigned integer>
+
+The negotiated TLS protocol version. See
+B<RSA_PKCS1_WITH_TLS_PADDING> on the page L<EVP_PKEY_CTX_set_rsa_padding(3)>.
+
 =back
 
 OP_asym_cipher_gettable_ctx_params() and OP_asym_cipher_settable_ctx_params()
diff --git a/include/crypto/rsa.h b/include/crypto/rsa.h
index 6d2e7ffb53..29256371f6 100644
--- a/include/crypto/rsa.h
+++ b/include/crypto/rsa.h
@@ -18,4 +18,8 @@ int rsa_set0_all_params(RSA *r, const STACK_OF(BIGNUM) *primes,
 int rsa_get0_all_params(RSA *r, STACK_OF(BIGNUM_const) *primes,
                         STACK_OF(BIGNUM_const) *exps,
                         STACK_OF(BIGNUM_const) *coeffs);
+
+int rsa_padding_check_PKCS1_type_2_TLS(unsigned char *to, size_t tlen,
+                                       const unsigned char *from, size_t flen,
+                                       int client_version, int alt_version);
 #endif
diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h
index 053432e0f0..e441ddf6c8 100644
--- a/include/openssl/core_names.h
+++ b/include/openssl/core_names.h
@@ -194,13 +194,15 @@ extern "C" {
 #define OSSL_SIGNATURE_PARAM_DIGEST_SIZE    "digest-size"
 
 /* Asym cipher parameters */
-#define OSSL_ASYM_CIPHER_PARAM_PAD_MODE             "pad-mode"
-#define OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST          OSSL_ALG_PARAM_DIGEST
-#define OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS    "digest-props"
-#define OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST          "mgf1-digest"
-#define OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS    "mgf1-digest-props"
-#define OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL           "oaep-label"
-#define OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL_LEN       "oaep-label-len"
+#define OSSL_ASYM_CIPHER_PARAM_PAD_MODE                 "pad-mode"
+#define OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST              OSSL_ALG_PARAM_DIGEST
+#define OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS        "digest-props"
+#define OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST              "mgf1-digest"
+#define OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS        "mgf1-digest-props"
+#define OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL               "oaep-label"
+#define OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL_LEN           "oaep-label-len"
+#define OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION       "tls-client-version"
+#define OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION   "tls-negotiated-version"
 
 /*
  * Serializer parameters
diff --git a/include/openssl/rsa.h b/include/openssl/rsa.h
index 02a02160b3..9753c22c2c 100644
--- a/include/openssl/rsa.h
+++ b/include/openssl/rsa.h
@@ -182,13 +182,15 @@ int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx, unsigned char **label);
 
 # define EVP_PKEY_CTRL_RSA_KEYGEN_PRIMES  (EVP_PKEY_ALG_CTRL + 13)
 
-# define RSA_PKCS1_PADDING       1
-# define RSA_SSLV23_PADDING      2
-# define RSA_NO_PADDING          3
-# define RSA_PKCS1_OAEP_PADDING  4
-# define RSA_X931_PADDING        5
+# define RSA_PKCS1_PADDING          1
+# define RSA_SSLV23_PADDING         2
+# define RSA_NO_PADDING             3
+# define RSA_PKCS1_OAEP_PADDING     4
+# define RSA_X931_PADDING           5
+
 /* EVP_PKEY_ only */
-# define RSA_PKCS1_PSS_PADDING   6
+# define RSA_PKCS1_PSS_PADDING      6
+# define RSA_PKCS1_WITH_TLS_PADDING 7
 
 # define RSA_PKCS1_PADDING_SIZE  11
 
diff --git a/providers/common/include/prov/providercommonerr.h b/providers/common/include/prov/providercommonerr.h
index 85e5856d30..d97b735ca9 100644
--- a/providers/common/include/prov/providercommonerr.h
+++ b/providers/common/include/prov/providercommonerr.h
@@ -53,9 +53,11 @@ int ERR_load_PROV_strings(void);
 # define PROV_R_BAD_DECRYPT                               100
 # define PROV_R_BAD_ENCODING                              141
 # define PROV_R_BAD_LENGTH                                142
+# define PROV_R_BAD_TLS_CLIENT_VERSION                    161
 # define PROV_R_BN_ERROR                                  160
 # define PROV_R_BOTH_MODE_AND_MODE_INT                    127
 # define PROV_R_CIPHER_OPERATION_FAILED                   102
+# define PROV_R_FAILED_TO_DECRYPT                         162
 # define PROV_R_FAILED_TO_GENERATE_KEY                    121
 # define PROV_R_FAILED_TO_GET_PARAMETER                   103
 # define PROV_R_FAILED_TO_SET_PARAMETER                   104
diff --git a/providers/common/provider_err.c b/providers/common/provider_err.c
index 7cae969c79..eba3dbef5f 100644
--- a/providers/common/provider_err.c
+++ b/providers/common/provider_err.c
@@ -19,11 +19,14 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_BAD_DECRYPT), "bad decrypt"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_BAD_ENCODING), "bad encoding"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_BAD_LENGTH), "bad length"},
+    {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_BAD_TLS_CLIENT_VERSION),
+    "bad tls client version"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_BN_ERROR), "bn error"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_BOTH_MODE_AND_MODE_INT),
     "both mode and mode int"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_CIPHER_OPERATION_FAILED),
     "cipher operation failed"},
+    {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_TO_DECRYPT), "failed to decrypt"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_TO_GENERATE_KEY),
     "failed to generate key"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_TO_GET_PARAMETER),
diff --git a/providers/implementations/asymciphers/rsa_enc.c b/providers/implementations/asymciphers/rsa_enc.c
index 9b17377783..53fc6de265 100644
--- a/providers/implementations/asymciphers/rsa_enc.c
+++ b/providers/implementations/asymciphers/rsa_enc.c
@@ -14,7 +14,10 @@
 #include <openssl/rsa.h>
 #include <openssl/params.h>
 #include <openssl/err.h>
+/* Just for SSL_MAX_MASTER_KEY_LENGTH */
+#include <openssl/ssl.h>
 #include "internal/constant_time.h"
+#include "crypto/rsa.h"
 #include "prov/providercommonerr.h"
 #include "prov/provider_ctx.h"
 #include "prov/implementations.h"
@@ -51,6 +54,9 @@ typedef struct {
     /* OAEP label */
     unsigned char *oaep_label;
     size_t oaep_labellen;
+    /* TLS padding */
+    unsigned int client_version;
+    unsigned int alt_version;
 } PROV_RSA_CTX;
 
 static void *rsa_newctx(void *provctx)
@@ -130,38 +136,70 @@ static int rsa_decrypt(void *vprsactx, unsigned char *out, size_t *outlen,
 {
     PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx;
     int ret;
+    size_t len = RSA_size(prsactx->rsa);
 
-    if (out == NULL) {
-        size_t len = RSA_size(prsactx->rsa);
+    if (prsactx->pad_mode == RSA_PKCS1_WITH_TLS_PADDING) {
+        if (out == NULL) {
+            *outlen = SSL_MAX_MASTER_KEY_LENGTH;
+            return 1;
+        }
+        if (outsize < SSL_MAX_MASTER_KEY_LENGTH) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH);
+            return 0;
+        }
+    } else {
+        if (out == NULL) {
+            if (len == 0) {
+                ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY);
+                return 0;
+            }
+            *outlen = len;
+            return 1;
+        }
 
-        if (len == 0) {
-            ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY);
+        if (outsize < len) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH);
             return 0;
         }
-        *outlen = len;
-        return 1;
     }
 
-    if (prsactx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
-        int rsasize = RSA_size(prsactx->rsa);
+    if (prsactx->pad_mode == RSA_PKCS1_OAEP_PADDING
+            || prsactx->pad_mode == RSA_PKCS1_WITH_TLS_PADDING) {
         unsigned char *tbuf;
 
-        if ((tbuf = OPENSSL_malloc(rsasize)) == NULL) {
+        if ((tbuf = OPENSSL_malloc(len)) == NULL) {
             PROVerr(0, ERR_R_MALLOC_FAILURE);
             return 0;
         }
         ret = RSA_private_decrypt(inlen, in, tbuf, prsactx->rsa,
                                   RSA_NO_PADDING);
-        if (ret <= 0) {
+        /*
+         * With no padding then, on success ret should be len, otherwise an
+         * error occurred (non-constant time)
+         */
+        if (ret != (int)len) {
             OPENSSL_free(tbuf);
+            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_DECRYPT);
             return 0;
         }
-        ret = RSA_padding_check_PKCS1_OAEP_mgf1(out, ret, tbuf,
-                                                ret, ret,
-                                                prsactx->oaep_label,
-                                                prsactx->oaep_labellen,
-                                                prsactx->oaep_md,
-                                                prsactx->mgf1_md);
+        if (prsactx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
+            ret = RSA_padding_check_PKCS1_OAEP_mgf1(out, outsize, tbuf,
+                                                    len, len,
+                                                    prsactx->oaep_label,
+                                                    prsactx->oaep_labellen,
+                                                    prsactx->oaep_md,
+                                                    prsactx->mgf1_md);
+        } else {
+            /* RSA_PKCS1_WITH_TLS_PADDING */
+            if (prsactx->client_version <= 0) {
+                ERR_raise(ERR_LIB_PROV, PROV_R_BAD_TLS_CLIENT_VERSION);
+                return 0;
+            }
+            ret = rsa_padding_check_PKCS1_type_2_TLS(out, outsize,
+                                                     tbuf, len,
+                                                     prsactx->client_version,
+                                                     prsactx->alt_version);
+        }
         OPENSSL_free(tbuf);
     } else {
         ret = RSA_private_decrypt(inlen, in, out, prsactx->rsa,
@@ -252,6 +290,14 @@ static int rsa_get_ctx_params(void *vprsactx, OSSL_PARAM *params)
     if (p != NULL && !OSSL_PARAM_set_size_t(p, prsactx->oaep_labellen))
         return 0;
 
+    p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION);
+    if (p != NULL && !OSSL_PARAM_set_uint(p, prsactx->client_version))
+        return 0;
+
+    p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION);
+    if (p != NULL && !OSSL_PARAM_set_uint(p, prsactx->alt_version))
+        return 0;
+
     return 1;
 }
 
@@ -262,6 +308,8 @@ static const OSSL_PARAM known_gettable_ctx_params[] = {
     OSSL_PARAM_DEFN(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, OSSL_PARAM_OCTET_PTR,
                     NULL, 0),
     OSSL_PARAM_size_t(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL_LEN, NULL),
+    OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, NULL),
+    OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION, NULL),
     OSSL_PARAM_END
 };
 
@@ -354,6 +402,24 @@ static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[])
         prsactx->oaep_labellen = tmp_labellen;
     }
 
+    p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION);
+    if (p != NULL) {
+        unsigned int client_version;
+
+        if (!OSSL_PARAM_get_uint(p, &client_version))
+            return 0;
+        prsactx->client_version = client_version;
+    }
+
+    p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION);
+    if (p != NULL) {
+        unsigned int alt_version;
+
+        if (!OSSL_PARAM_get_uint(p, &alt_version))
+            return 0;
+        prsactx->alt_version = alt_version;
+    }
+
     return 1;
 }
 
@@ -363,6 +429,8 @@ static const OSSL_PARAM known_settable_ctx_params[] = {
     OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST, NULL, 0),
     OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS, NULL, 0),
     OSSL_PARAM_octet_string(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, NULL, 0),
+    OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, NULL),
+    OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION, NULL),
     OSSL_PARAM_END
 };
 
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 5f709e5f99..29512d80b3 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -24,6 +24,7 @@
 #include <openssl/bn.h>
 #include <openssl/md5.h>
 #include <openssl/trace.h>
+#include <openssl/core_names.h>
 
 #define TICKET_NONCE_SIZE       8
 
@@ -2966,16 +2967,15 @@ static int tls_process_cke_psk_preamble(SSL *s, PACKET *pkt)
 static int tls_process_cke_rsa(SSL *s, PACKET *pkt)
 {
 #ifndef OPENSSL_NO_RSA
-    unsigned char rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH];
-    int decrypt_len;
-    unsigned char decrypt_good, version_good;
-    size_t j, padding_len;
+    size_t outlen;
     PACKET enc_premaster;
-    RSA *rsa = NULL;
+    EVP_PKEY *rsa = NULL;
     unsigned char *rsa_decrypt = NULL;
     int ret = 0;
+    EVP_PKEY_CTX *ctx = NULL;
+    OSSL_PARAM params[3], *p = params;
 
-    rsa = EVP_PKEY_get0_RSA(s->cert->pkeys[SSL_PKEY_RSA].privatekey);
+    rsa = s->cert->pkeys[SSL_PKEY_RSA].privatekey;
     if (rsa == NULL) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
                  SSL_R_MISSING_RSA_CERTIFICATE);
@@ -3000,124 +3000,77 @@ static int tls_process_cke_rsa(SSL *s, PACKET *pkt)
      * (SSL_MAX_MASTER_KEY_LENGTH). Reject overly short RSA keys because
      * their ciphertext cannot accommodate a premaster secret anyway.
      */
-    if (RSA_size(rsa) < SSL_MAX_MASTER_KEY_LENGTH) {
+    if (EVP_PKEY_size(rsa) < RSA_PKCS1_PADDING_SIZE
+                             + SSL_MAX_MASTER_KEY_LENGTH) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
                  RSA_R_KEY_SIZE_TOO_SMALL);
         return 0;
     }
 
-    rsa_decrypt = OPENSSL_malloc(RSA_size(rsa));
+    outlen = SSL_MAX_MASTER_KEY_LENGTH;
+    rsa_decrypt = OPENSSL_malloc(outlen);
     if (rsa_decrypt == NULL) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
                  ERR_R_MALLOC_FAILURE);
         return 0;
     }
 
-    /*
-     * We must not leak whether a decryption failure occurs because of
-     * Bleichenbacher's attack on PKCS #1 v1.5 RSA padding (see RFC 2246,
-     * section 7.4.7.1). The code follows that advice of the TLS RFC and
-     * generates a random premaster secret for the case that the decrypt
-     * fails. See https://tools.ietf.org/html/rfc5246#section-7.4.7.1
-     */
-
-    if (RAND_priv_bytes(rand_premaster_secret,
-                      sizeof(rand_premaster_secret)) <= 0) {
+    ctx = EVP_PKEY_CTX_new(rsa, NULL);
+    if (ctx == NULL) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
-                 ERR_R_INTERNAL_ERROR);
+                 ERR_R_MALLOC_FAILURE);
         goto err;
     }
 
     /*
-     * Decrypt with no padding. PKCS#1 padding will be removed as part of
-     * the timing-sensitive code below.
+     * We must not leak whether a decryption failure occurs because of
+     * Bleichenbacher's attack on PKCS #1 v1.5 RSA padding (see RFC 2246,
+     * section 7.4.7.1). We use the special padding type
+     * RSA_PKCS1_WITH_TLS_PADDING to do that. It will automaticaly decrypt the
+     * RSA, check the padding and check that the client version is as expected
+     * in the premaster secret. If any of that fails then the function appears
+     * to return successfully but with a random result. The call below could
+     * still fail if the input is publicly invalid.
+     * See https://tools.ietf.org/html/rfc5246#section-7.4.7.1
      */
-     /* TODO(size_t): Convert this function */
-    decrypt_len = (int)RSA_private_decrypt((int)PACKET_remaining(&enc_premaster),
-                                           PACKET_data(&enc_premaster),
-                                           rsa_decrypt, rsa, RSA_NO_PADDING);
-    if (decrypt_len < 0) {
+    if (EVP_PKEY_decrypt_init(ctx) <= 0
+            || EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_WITH_TLS_PADDING) <= 0) {
         SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
-                 ERR_R_INTERNAL_ERROR);
+                 SSL_R_DECRYPTION_FAILED);
         goto err;
     }
 
-    /* Check the padding. See RFC 3447, section 7.2.2. */
+    *p++ = OSSL_PARAM_construct_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION,
+                                     (unsigned int *)&s->client_version);
+   if ((s->options & SSL_OP_TLS_ROLLBACK_BUG) != 0)
+        *p++ = OSSL_PARAM_construct_uint(
+            OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION,
+            (unsigned int *)&s->version);
+    *p++ = OSSL_PARAM_construct_end();
 
-    /*
-     * The smallest padded premaster is 11 bytes of overhead. Small keys
-     * are publicly invalid, so this may return immediately. This ensures
-     * PS is at least 8 bytes.
-     */
-    if (decrypt_len < 11 + SSL_MAX_MASTER_KEY_LENGTH) {
+    if (!EVP_PKEY_CTX_set_params(ctx, params)
+            || EVP_PKEY_decrypt(ctx, rsa_decrypt, &outlen,
+                                PACKET_data(&enc_premaster),
+                                PACKET_remaining(&enc_premaster)) <= 0) {
         SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
                  SSL_R_DECRYPTION_FAILED);
         goto err;
     }
 
-    padding_len = decrypt_len - SSL_MAX_MASTER_KEY_LENGTH;
-    decrypt_good = constant_time_eq_int_8(rsa_decrypt[0], 0) &
-        constant_time_eq_int_8(rsa_decrypt[1], 2);
-    for (j = 2; j < padding_len - 1; j++) {
-        decrypt_good &= ~constant_time_is_zero_8(rsa_decrypt[j]);
-    }
-    decrypt_good &= constant_time_is_zero_8(rsa_decrypt[padding_len - 1]);
-
-    /*
-     * If the version in the decrypted pre-master secret is correct then
-     * version_good will be 0xff, otherwise it'll be zero. The
-     * Klima-Pokorny-Rosa extension of Bleichenbacher's attack
-     * (http://eprint.iacr.org/2003/052/) exploits the version number
-     * check as a "bad version oracle". Thus version checks are done in
-     * constant time and are treated like any other decryption error.
-     */
-    version_good =
-        constant_time_eq_8(rsa_decrypt[padding_len],
-                           (unsigned)(s->client_version >> 8));
-    version_good &=
-        constant_time_eq_8(rsa_decrypt[padding_len + 1],
-                           (unsigned)(s->client_version & 0xff));
-
-    /*
-     * The premaster secret must contain the same version number as the
-     * ClientHello to detect version rollback attacks (strangely, the
-     * protocol does not offer such protection for DH ciphersuites).
-     * However, buggy clients exist that send the negotiated protocol
-     * version instead if the server does not support the requested
-     * protocol version. If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such
-     * clients.
-     */
-    if (s->options & SSL_OP_TLS_ROLLBACK_BUG) {
-        unsigned char workaround_good;
-        workaround_good = constant_time_eq_8(rsa_decrypt[padding_len],
-                                             (unsigned)(s->version >> 8));
-        workaround_good &=
-            constant_time_eq_8(rsa_decrypt[padding_len + 1],
-                               (unsigned)(s->version & 0xff));
-        version_good |= workaround_good;
-    }
-
-    /*
-     * Both decryption and version must be good for decrypt_good to
-     * remain non-zero (0xff).
-     */
-    decrypt_good &= version_good;
-
     /*
-     * Now copy rand_premaster_secret over from p using
-     * decrypt_good_mask. If decryption failed, then p does not
-     * contain valid plaintext, however, a check above guarantees
-     * it is still sufficiently large to read from.
+     * This test should never fail (otherwise we should have failed above) but
+     * we double check anyway.
      */
-    for (j = 0; j < sizeof(rand_premaster_secret); j++) {
-        rsa_decrypt[padding_len + j] =
-            constant_time_select_8(decrypt_good,
-                                   rsa_decrypt[padding_len + j],
-                                   rand_premaster_secret[j]);
+    if (outlen != SSL_MAX_MASTER_KEY_LENGTH) {
+        OPENSSL_cleanse(rsa_decrypt, SSL_MAX_MASTER_KEY_LENGTH);
+        SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_F_TLS_PROCESS_CKE_RSA,
+                 SSL_R_DECRYPTION_FAILED);
+        goto err;
     }
 
-    if (!ssl_generate_master_secret(s, rsa_decrypt + padding_len,
-                                    sizeof(rand_premaster_secret), 0)) {
+    /* Also cleanses rsa_decrypt (on success or failure) */
+    if (!ssl_generate_master_secret(s, rsa_decrypt,
+                                    SSL_MAX_MASTER_KEY_LENGTH, 0)) {
         /* SSLfatal() already called */
         goto err;
     }
@@ -3125,6 +3078,7 @@ static int tls_process_cke_rsa(SSL *s, PACKET *pkt)
     ret = 1;
  err:
     OPENSSL_free(rsa_decrypt);
+    EVP_PKEY_CTX_free(ctx);
     return ret;
 #else
     /* Should never happen */


More information about the openssl-commits mailing list