Add and use a constant-time memcmp.
authorBen Laurie <ben@links.org>
Mon, 28 Jan 2013 17:30:38 +0000 (17:30 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 6 Feb 2013 13:56:12 +0000 (13:56 +0000)
This change adds CRYPTO_memcmp, which compares two vectors of bytes in
an amount of time that's independent of their contents. It also changes
several MAC compares in the code to use this over the standard memcmp,
which may leak information about the size of a matching prefix.
(cherry picked from commit 2ee798880a246d648ecddadc5b91367bee4a5d98)

crypto/cryptlib.c
crypto/crypto.h
crypto/rsa/rsa_oaep.c
ssl/d1_pkt.c
ssl/s2_clnt.c
ssl/s2_pkt.c
ssl/s3_both.c
ssl/s3_pkt.c
ssl/t1_lib.c

index a7cb4202e863530efa38e66c3a3f887471cc2eac..304c6b70627b2aeb88abe71a6863cfef2302bd6f 100644 (file)
@@ -925,3 +925,16 @@ void OpenSSLDie(const char *file,int line,const char *assertion)
        }
 
 void *OPENSSL_stderr(void)     { return stderr; }
+
+int CRYPTO_memcmp(const void *in_a, const void *in_b, size_t len)
+       {
+       size_t i;
+       const unsigned char *a = in_a;
+       const unsigned char *b = in_b;
+       unsigned char x = 0;
+
+       for (i = 0; i < len; i++)
+               x |= a[i] ^ b[i];
+
+       return x;
+       }
index 61605769bb2b3d2016d156ee5f39f27aed832d24..f92fc5182d9e92f6488997db45d117f0cc1a40b2 100644 (file)
@@ -574,6 +574,13 @@ void OPENSSL_init(void);
 #define fips_cipher_abort(alg) while(0)
 #endif
 
+/* CRYPTO_memcmp returns zero iff the |len| bytes at |a| and |b| are equal. It
+ * takes an amount of time dependent on |len|, but independent of the contents
+ * of |a| and |b|. Unlike memcmp, it cannot be used to put elements into a
+ * defined order as the return value when a != b is undefined, other than to be
+ * non-zero. */
+int CRYPTO_memcmp(const void *a, const void *b, size_t len);
+
 /* BEGIN ERROR CODES */
 /* The following lines are auto generated by the script mkerr.pl. Any changes
  * made after this point may be overwritten when the script is next run.
index 553d212ebe9c7cdacde646a92ac0250185793df2..af4d24a56ef5918def4e19e914901f5163ad48d5 100644 (file)
@@ -149,7 +149,7 @@ int RSA_padding_check_PKCS1_OAEP(unsigned char *to, int tlen,
        if (!EVP_Digest((void *)param, plen, phash, NULL, EVP_sha1(), NULL))
                return -1;
 
-       if (memcmp(db, phash, SHA_DIGEST_LENGTH) != 0 || bad)
+       if (CRYPTO_memcmp(db, phash, SHA_DIGEST_LENGTH) != 0 || bad)
                goto decoding_err;
        else
                {
index 987af608358d914a72fa8a4620d7faf8188d22f0..5e2c56c9833ddcb85c0286de0e2cb89c9cbf9578 100644 (file)
@@ -463,7 +463,7 @@ printf("\n");
                else
                        rr->length = 0;
                i=s->method->ssl3_enc->mac(s,md,0);
-               if (i < 0 || mac == NULL || memcmp(md, mac, mac_size) != 0)
+               if (i < 0 || mac == NULL || CRYPTO_memcmp(md,mac,mac_size) != 0)
                        {
                        decryption_failed_or_bad_record_mac = 1;
                        }
index 76b690ea1340f04bad5c9eeb25e3cc9dc43ed9cb..03b6cf9673809a7582c4c176c30a75b7e0e1b6a4 100644 (file)
@@ -939,7 +939,7 @@ static int get_server_verify(SSL *s)
                s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* SERVER-VERIFY */
        p += 1;
 
-       if (memcmp(p,s->s2->challenge,s->s2->challenge_length) != 0)
+       if (CRYPTO_memcmp(p,s->s2->challenge,s->s2->challenge_length) != 0)
                {
                ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR);
                SSLerr(SSL_F_GET_SERVER_VERIFY,SSL_R_CHALLENGE_IS_DIFFERENT);
index ac963b2d47d6e369adc012ffac5c8df4ddc7f4bb..8bb6ab8baa33501dcd6f0991d53ad80b3d9361aa 100644 (file)
@@ -269,8 +269,7 @@ static int ssl2_read_internal(SSL *s, void *buf, int len, int peek)
                        s->s2->ract_data_length-=mac_size;
                        ssl2_mac(s,mac,0);
                        s->s2->ract_data_length-=s->s2->padding;
-                       if (    (memcmp(mac,s->s2->mac_data,
-                               (unsigned int)mac_size) != 0) ||
+                       if (    (CRYPTO_memcmp(mac,s->s2->mac_data,mac_size) != 0) ||
                                (s->s2->rlength%EVP_CIPHER_CTX_block_size(s->enc_read_ctx) != 0))
                                {
                                SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_BAD_MAC_DECODE);
index 349531460d39f54da0e9474d913ac70370df9d7f..a537738f4298971a61304ab130921f81ab6b652a 100644 (file)
@@ -265,7 +265,7 @@ int ssl3_get_finished(SSL *s, int a, int b)
                goto f_err;
                }
 
-       if (memcmp(p, s->s3->tmp.peer_finish_md, i) != 0)
+       if (CRYPTO_memcmp(p, s->s3->tmp.peer_finish_md, i) != 0)
                {
                al=SSL_AD_DECRYPT_ERROR;
                SSLerr(SSL_F_SSL3_GET_FINISHED,SSL_R_DIGEST_CHECK_FAILED);
index 4299af1e7cccf343d6ec8eb26f041514588306e1..9246ff2951e2db9185aa0680325dbe12b65971e5 100644 (file)
@@ -465,7 +465,7 @@ printf("\n");
 #endif
                        }
                i=s->method->ssl3_enc->mac(s,md,0);
-               if (i < 0 || mac == NULL || memcmp(md, mac, (size_t)mac_size) != 0)
+               if (i < 0 || mac == NULL || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
                        {
                        decryption_failed_or_bad_record_mac = 1;
                        }
index 512045f31e8e8bbf29c4b99a6998c528d1d4a020..88570201a1b1a2ec0ddc85ab78b2cb9f0c145a23 100644 (file)
@@ -3123,7 +3123,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
        HMAC_Update(&hctx, etick, eticklen);
        HMAC_Final(&hctx, tick_hmac, NULL);
        HMAC_CTX_cleanup(&hctx);
-       if (memcmp(tick_hmac, etick + eticklen, mlen))
+       if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen))
                return 2;
        /* Attempt to decrypt session data */
        /* Move p after IV to start of encrypted ticket, update length */