Commit 28ba2541 authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

PRF and handshake hash revision.



Change handshake hash array into a single digest context simplifying the
handhake hash code. Use EVP_md5_sha1() if needed for handshake hashes in
TLS 1.1 and earlier.

Simplify PRF code to also use a single digest and treat EVP_md5_sha1()
as a special case.

Modify algorithm2 field of ciphers to use a single index value for handshake
hash and PRF instead of a bitmap.

Reviewed-by: default avatarMatt Caswell <matt@openssl.org>
parent 2a9b9654
Loading
Loading
Loading
Loading
+33 −111
Original line number Diff line number Diff line
@@ -140,26 +140,6 @@
#include <openssl/evp.h>
#include <openssl/md5.h>

static const unsigned char ssl3_pad_1[48] = {
    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
};

static const unsigned char ssl3_pad_2[48] = {
    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c
};

static int ssl3_handshake_mac(SSL *s, int md_nid,
                              const char *sender, int len, unsigned char *p);
static int ssl3_generate_key_block(SSL *s, unsigned char *km, int num)
{
    EVP_MD_CTX m5;
@@ -488,69 +468,48 @@ void ssl3_init_finished_mac(SSL *s)

void ssl3_free_digest_list(SSL *s)
{
    int i;
    BIO_free(s->s3->handshake_buffer);
    s->s3->handshake_buffer = NULL;
    if (!s->s3->handshake_dgst)
        return;
    for (i = 0; i < SSL_MAX_DIGEST; i++) {
        if (s->s3->handshake_dgst[i])
            EVP_MD_CTX_destroy(s->s3->handshake_dgst[i]);
    }
    OPENSSL_free(s->s3->handshake_dgst);
    EVP_MD_CTX_destroy(s->s3->handshake_dgst);
    s->s3->handshake_dgst = NULL;
}

void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len)
{
    if (s->s3->handshake_dgst == NULL) {
    if (s->s3->handshake_dgst == NULL)
        BIO_write(s->s3->handshake_buffer, (void *)buf, len);
    } else {
        int i;
        for (i = 0; i < SSL_MAX_DIGEST; i++) {
            if (s->s3->handshake_dgst[i] != NULL)
                EVP_DigestUpdate(s->s3->handshake_dgst[i], buf, len);
        }
    }
    else
        EVP_DigestUpdate(s->s3->handshake_dgst, buf, len);
}

int ssl3_digest_cached_records(SSL *s, int keep)
{
    int i;
    long mask;
    const EVP_MD *md;
    long hdatalen;
    void *hdata;

    if (s->s3->handshake_dgst == NULL) {
        /* Allocate handshake_dgst array */
        s->s3->handshake_dgst =
            OPENSSL_malloc(sizeof(*s->s3->handshake_dgst) * SSL_MAX_DIGEST);
        if (s->s3->handshake_dgst == NULL) {
            SSLerr(SSL_F_SSL3_DIGEST_CACHED_RECORDS, ERR_R_MALLOC_FAILURE);
            return 0;
        }
        hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
        if (hdatalen <= 0) {
            SSLerr(SSL_F_SSL3_DIGEST_CACHED_RECORDS, SSL_R_BAD_HANDSHAKE_LENGTH);
            return 0;
        }

        /* Loop through bits of algorithm2 field and create MD_CTX-es */
        for (i = 0; ssl_get_handshake_digest(i, &mask, &md); i++) {
            if ((mask & ssl_get_algorithm2(s)) && md) {
                s->s3->handshake_dgst[i] = EVP_MD_CTX_create();
                if (EVP_MD_nid(md) == NID_md5) {
                    EVP_MD_CTX_set_flags(s->s3->handshake_dgst[i],
                                         EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
                }
                EVP_DigestInit_ex(s->s3->handshake_dgst[i], md, NULL);
                EVP_DigestUpdate(s->s3->handshake_dgst[i], hdata, hdatalen);
            } else {
                s->s3->handshake_dgst[i] = NULL;
        s->s3->handshake_dgst = EVP_MD_CTX_create();
        if (s->s3->handshake_dgst == NULL) {
            SSLerr(SSL_F_SSL3_DIGEST_CACHED_RECORDS, ERR_R_MALLOC_FAILURE);
            return 0;
        }

        md = ssl_handshake_md(s);
        if (md == NULL) {
            SSLerr(SSL_F_SSL3_DIGEST_CACHED_RECORDS, ERR_R_INTERNAL_ERROR);
            return 0;
        }

        EVP_DigestInit_ex(s->s3->handshake_dgst, md, NULL);
        EVP_DigestUpdate(s->s3->handshake_dgst, hdata, hdatalen);

    }
    if (keep == 0) {
        BIO_free(s->s3->handshake_buffer);
@@ -560,77 +519,40 @@ int ssl3_digest_cached_records(SSL *s, int keep)
    return 1;
}

int ssl3_final_finish_mac(SSL *s,
                          const char *sender, int len, unsigned char *p)
int ssl3_final_finish_mac(SSL *s, const char *sender, int len, unsigned char *p)
{
    int ret, sha1len;
    ret = ssl3_handshake_mac(s, NID_md5, sender, len, p);
    if (ret == 0)
        return 0;

    p += ret;

    sha1len = ssl3_handshake_mac(s, NID_sha1, sender, len, p);
    if (sha1len == 0)
        return 0;

    ret += sha1len;
    return (ret);
}

static int ssl3_handshake_mac(SSL *s, int md_nid,
                              const char *sender, int len, unsigned char *p)
{
    unsigned int ret;
    int npad, n;
    unsigned int i;
    unsigned char md_buf[EVP_MAX_MD_SIZE];
    EVP_MD_CTX ctx, *d = NULL;
    int ret;
    EVP_MD_CTX ctx;

    if (!ssl3_digest_cached_records(s, 0))
        return 0;

    /*
     * Search for digest of specified type in the handshake_dgst array
     */
    for (i = 0; i < SSL_MAX_DIGEST; i++) {
        if (s->s3->handshake_dgst[i]
            && EVP_MD_CTX_type(s->s3->handshake_dgst[i]) == md_nid) {
            d = s->s3->handshake_dgst[i];
            break;
        }
    }
    if (!d) {
    if (EVP_MD_CTX_type(s->s3->handshake_dgst) != NID_md5_sha1) {
        SSLerr(SSL_F_SSL3_HANDSHAKE_MAC, SSL_R_NO_REQUIRED_DIGEST);
        return 0;
    }

    EVP_MD_CTX_init(&ctx);
    EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
    EVP_MD_CTX_copy_ex(&ctx, d);
    n = EVP_MD_CTX_size(&ctx);
    if (n < 0)
    EVP_MD_CTX_copy_ex(&ctx, s->s3->handshake_dgst);

    ret = EVP_MD_CTX_size(&ctx);
    if (ret < 0) {
        EVP_MD_CTX_cleanup(&ctx);
        return 0;
    }

    npad = (48 / n) * n;
    if ((sender != NULL && EVP_DigestUpdate(&ctx, sender, len) <= 0)
            || EVP_DigestUpdate(&ctx, s->session->master_key,
                                s->session->master_key_length) <= 0
            || EVP_DigestUpdate(&ctx, ssl3_pad_1, npad) <= 0
            || EVP_DigestFinal_ex(&ctx, md_buf, &i) <= 0

            || EVP_DigestInit_ex(&ctx, EVP_MD_CTX_md(&ctx), NULL) <= 0
            || EVP_DigestUpdate(&ctx, s->session->master_key,
                                s->session->master_key_length) <= 0
            || EVP_DigestUpdate(&ctx, ssl3_pad_2, npad) <= 0
            || EVP_DigestUpdate(&ctx, md_buf, i) <= 0
            || EVP_DigestFinal_ex(&ctx, p, &ret) <= 0) {
            || EVP_MD_CTX_ctrl(&ctx, EVP_CTRL_SSL3_MASTER_SECRET,
                               s->session->master_key_length,
                               s->session->master_key) <= 0
            || EVP_DigestFinal_ex(&ctx, p, NULL) <= 0) {
        SSLerr(SSL_F_SSL3_HANDSHAKE_MAC, ERR_R_INTERNAL_ERROR);
        ret = 0;
    }

    EVP_MD_CTX_cleanup(&ctx);

    return ((int)ret);
    return ret;
}

int ssl3_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
+3 −0
Original line number Diff line number Diff line
@@ -110,6 +110,9 @@ int SSL_library_init(void)
#ifndef OPENSSL_NO_MD5
    EVP_add_digest(EVP_md5());
    EVP_add_digest_alias(SN_md5, "ssl3-md5");
# ifndef OPENSSL_NO_SHA
    EVP_add_digest(EVP_md5_sha1());
# endif
#endif
    EVP_add_digest(EVP_sha1()); /* RSA with sha1 */
    EVP_add_digest_alias(SN_sha1, "ssl3-sha1");
+19 −29
Original line number Diff line number Diff line
@@ -212,15 +212,6 @@ static const EVP_CIPHER *ssl_cipher_methods[SSL_ENC_NUM_IDX] = {

static STACK_OF(SSL_COMP) *ssl_comp_methods = NULL;

#define SSL_MD_MD5_IDX  0
#define SSL_MD_SHA1_IDX 1
#define SSL_MD_GOST94_IDX 2
#define SSL_MD_GOST89MAC_IDX 3
#define SSL_MD_SHA256_IDX 4
#define SSL_MD_SHA384_IDX 5
#define SSL_MD_GOST12_256_IDX  6
#define SSL_MD_GOST89MAC12_IDX 7
#define SSL_MD_GOST12_512_IDX  8
/*
 * Constant SSL_MAX_DIGEST equal to size of digests array should be defined
 * in the ssl_locl.h
@@ -238,11 +229,12 @@ static const ssl_cipher_table ssl_cipher_table_mac[SSL_MD_NUM_IDX] = {
    {SSL_SHA384, NID_sha384},   /* SSL_MD_SHA384_IDX 5 */
    {SSL_GOST12_256, NID_id_GostR3411_2012_256},  /* SSL_MD_GOST12_256_IDX 6 */
    {SSL_GOST89MAC12, NID_gost_mac_12},           /* SSL_MD_GOST89MAC12_IDX 7 */
    {SSL_GOST12_512, NID_id_GostR3411_2012_512}   /* SSL_MD_GOST12_512_IDX 8 */
    {SSL_GOST12_512, NID_id_GostR3411_2012_512},  /* SSL_MD_GOST12_512_IDX 8 */
    {0, NID_md5_sha1}           /* SSL_MD_MD5_SHA1_IDX 9 */
};

static const EVP_MD *ssl_digest_methods[SSL_MD_NUM_IDX] = {
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};

/* Utility function for table lookup */
@@ -275,14 +267,7 @@ static int ssl_mac_pkey_id[SSL_MD_NUM_IDX] = {
};

static int ssl_mac_secret_size[SSL_MD_NUM_IDX] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0
};

static const int ssl_handshake_digest_flag[SSL_MD_NUM_IDX] = {
    SSL_HANDSHAKE_MAC_MD5, SSL_HANDSHAKE_MAC_SHA,
    SSL_HANDSHAKE_MAC_GOST94, 0, SSL_HANDSHAKE_MAC_SHA256,
    SSL_HANDSHAKE_MAC_SHA384, SSL_HANDSHAKE_MAC_GOST12_256, 0,
    SSL_HANDSHAKE_MAC_GOST12_512,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

#define CIPHER_ADD      1
@@ -727,17 +712,22 @@ int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc,
        return (0);
}

int ssl_get_handshake_digest(int idx, long *mask, const EVP_MD **md)
static const EVP_MD *ssl_cipher_table_idx(int idx)
{
    if (idx < 0 || idx >= SSL_MD_NUM_IDX) {
        return 0;
    idx &= SSL_HANDSHAKE_MAC_MASK;
    if (idx < 0 || idx >= SSL_MD_NUM_IDX)
        return NULL;
    return ssl_digest_methods[idx];
}
    *mask = ssl_handshake_digest_flag[idx];
    if (*mask)
        *md = ssl_digest_methods[idx];
    else
        *md = NULL;
    return 1;

const EVP_MD *ssl_handshake_md(SSL *s)
{
    return ssl_cipher_table_idx(ssl_get_algorithm2(s));
}

const EVP_MD *ssl_prf_md(SSL *s)
{
    return ssl_cipher_table_idx(ssl_get_algorithm2(s) >> TLS1_PRF_DGST_SHIFT);
}

#define ITEM_SEP(a) \
+8 −18
Original line number Diff line number Diff line
@@ -3335,27 +3335,17 @@ void ssl_clear_hash_ctx(EVP_MD_CTX **hash)
/* Retrieve handshake hashes */
int ssl_handshake_hash(SSL *s, unsigned char *out, int outlen)
{
    unsigned char *p = out;
    int idx, ret = 0;
    long mask;
    EVP_MD_CTX ctx;
    const EVP_MD *md;
    EVP_MD_CTX *hdgst = s->s3->handshake_dgst;
    int ret = EVP_MD_CTX_size(hdgst);
    EVP_MD_CTX_init(&ctx);
    for (idx = 0; ssl_get_handshake_digest(idx, &mask, &md); idx++) {
        if (mask & ssl_get_algorithm2(s)) {
            int hashsize = EVP_MD_size(md);
            EVP_MD_CTX *hdgst = s->s3->handshake_dgst[idx];
            if (!hdgst || hashsize < 0 || hashsize > outlen)
    if (ret < 0 || ret > outlen) {
        ret = 0;
        goto err;
            if (!EVP_MD_CTX_copy_ex(&ctx, hdgst))
                goto err;
            if (!EVP_DigestFinal_ex(&ctx, p, NULL))
                goto err;
            p += hashsize;
            outlen -= hashsize;
        }
    }
    ret = p - out;
    if (!EVP_MD_CTX_copy_ex(&ctx, hdgst)
        || EVP_DigestFinal_ex(&ctx, out, NULL) <= 0)
        ret = 0;
 err:
    EVP_MD_CTX_cleanup(&ctx);
    return ret;
+40 −27
Original line number Diff line number Diff line
@@ -391,38 +391,50 @@
# define SSL_TLSV1               0x00000004U
# define SSL_TLSV1_2             0x00000008U

/* Bits for algorithm2 (handshake digests and other extra flags) */

# define SSL_HANDSHAKE_MAC_MD5 0x10
# define SSL_HANDSHAKE_MAC_SHA 0x20
# define SSL_HANDSHAKE_MAC_GOST94 0x40
# define SSL_HANDSHAKE_MAC_SHA256 0x80
# define SSL_HANDSHAKE_MAC_SHA384 0x100
# define SSL_HANDSHAKE_MAC_GOST12_256 0x200
# define SSL_HANDSHAKE_MAC_GOST12_512 0x400
# define SSL_HANDSHAKE_MAC_DEFAULT (SSL_HANDSHAKE_MAC_MD5 | SSL_HANDSHAKE_MAC_SHA)

/*
 * When adding new digest in the ssl_ciph.c and increment SSL_MD_NUM_IDX make
 * sure to update this constant too
 */
# define SSL_MAX_DIGEST 9

# define TLS1_PRF_DGST_SHIFT 10
# define TLS1_PRF_MD5 (SSL_HANDSHAKE_MAC_MD5 << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF_SHA1 (SSL_HANDSHAKE_MAC_SHA << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF_SHA256 (SSL_HANDSHAKE_MAC_SHA256 << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF_SHA384 (SSL_HANDSHAKE_MAC_SHA384 << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF_GOST94 (SSL_HANDSHAKE_MAC_GOST94 << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF_GOST12_256 (SSL_HANDSHAKE_MAC_GOST12_256 << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF_GOST12_512 (SSL_HANDSHAKE_MAC_GOST12_512 << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF (TLS1_PRF_MD5 | TLS1_PRF_SHA1)
# define SSL_MD_MD5_IDX  0
# define SSL_MD_SHA1_IDX 1
# define SSL_MD_GOST94_IDX 2
# define SSL_MD_GOST89MAC_IDX 3
# define SSL_MD_SHA256_IDX 4
# define SSL_MD_SHA384_IDX 5
# define SSL_MD_GOST12_256_IDX  6
# define SSL_MD_GOST89MAC12_IDX 7
# define SSL_MD_GOST12_512_IDX  8
# define SSL_MD_MD5_SHA1_IDX 9
# define SSL_MAX_DIGEST 10

/* Bits for algorithm2 (handshake digests and other extra flags) */

/* Bits 0-7 are handshake MAC */
# define SSL_HANDSHAKE_MAC_MASK  0xFF
# define SSL_HANDSHAKE_MAC_MD5_SHA1 SSL_MD_MD5_SHA1_IDX
# define SSL_HANDSHAKE_MAC_SHA256   SSL_MD_SHA256_IDX
# define SSL_HANDSHAKE_MAC_SHA384   SSL_MD_SHA384_IDX
# define SSL_HANDSHAKE_MAC_GOST94 SSL_MD_GOST94_IDX
# define SSL_HANDSHAKE_MAC_GOST12_256 SSL_MD_GOST12_256_IDX
# define SSL_HANDSHAKE_MAC_GOST12_512 SSL_MD_GOST12_512_IDX
# define SSL_HANDSHAKE_MAC_DEFAULT  SSL_HANDSHAKE_MAC_MD5_SHA1

/* Bits 8-15 bits are PRF */
# define TLS1_PRF_DGST_SHIFT 8
# define TLS1_PRF_SHA1_MD5 (SSL_MD_MD5_SHA1_IDX << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF_SHA256 (SSL_MD_SHA256_IDX << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF_SHA384 (SSL_MD_SHA384_IDX << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF_GOST94 (SSL_MD_GOST94_IDX << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF_GOST12_256 (SSL_MD_GOST12_256_IDX << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF_GOST12_512 (SSL_MD_GOST12_512_IDX << TLS1_PRF_DGST_SHIFT)
# define TLS1_PRF            (SSL_MD_MD5_SHA1_IDX << TLS1_PRF_DGST_SHIFT)

/*
 * Stream MAC for GOST ciphersuites from cryptopro draft (currently this also
 * goes into algorithm2)
 */
# define TLS1_STREAM_MAC 0x04
# define TLS1_STREAM_MAC 0x10000

/*
 * Export and cipher strength information. For each cipher we have to decide
@@ -1239,10 +1251,10 @@ typedef struct ssl3_state_st {
    /* used during startup, digest all incoming/outgoing packets */
    BIO *handshake_buffer;
    /*
     * When set of handshake digests is determined, buffer is hashed and
     * freed and MD_CTX-es for all required digests are stored in this array
     * When handshake digest is determined, buffer is hashed and
     * freed and MD_CTX for the required digest is stored here.
     */
    EVP_MD_CTX **handshake_dgst;
    EVP_MD_CTX *handshake_dgst;
    /*
     * Set whenever an expected ChangeCipherSpec message is processed.
     * Unset when the peer's Finished message is received.
@@ -1890,7 +1902,6 @@ void ssl_update_cache(SSL *s, int mode);
__owur int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc,
                       const EVP_MD **md, int *mac_pkey_type,
                       int *mac_secret_size, SSL_COMP **comp, int use_etm);
__owur int ssl_get_handshake_digest(int i, long *mask, const EVP_MD **md);
__owur int ssl_cipher_get_cert_index(const SSL_CIPHER *c);
__owur const SSL_CIPHER *ssl_get_cipher_by_char(SSL *ssl, const unsigned char *ptr);
__owur int ssl_cert_set0_chain(SSL *s, SSL_CTX *ctx, STACK_OF(X509) *chain);
@@ -2128,6 +2139,8 @@ __owur int ssl_add_serverhello_use_srtp_ext(SSL *s, unsigned char *p, int *len,
__owur int ssl_parse_serverhello_use_srtp_ext(SSL *s, PACKET *pkt, int *al);

__owur int ssl_handshake_hash(SSL *s, unsigned char *out, int outlen);
__owur const EVP_MD *ssl_handshake_md(SSL *s);
__owur const EVP_MD *ssl_prf_md(SSL *s);

/* s3_cbc.c */
__owur char ssl3_cbc_record_digest_supported(const EVP_MD_CTX *ctx);
Loading