openssl/crypto/evp/e_aes_cbc_hmac_sha1.c
Matt Caswell 335d0a4646 Fix undefined behaviour in e_aes_cbc_hmac_sha256.c and e_aes_cbc_hmac_sha1.c
In TLS mode of operation the padding value "pad" is obtained along with the
maximum possible padding value "maxpad". If pad > maxpad then the data is
invalid. However we must continue anyway because this is constant time code.

We calculate the payload length like this:

    inp_len = len - (SHA_DIGEST_LENGTH + pad + 1);

However if pad is invalid then inp_len ends up -ve (actually large +ve
because it is a size_t).

Later we do this:

    /* verify HMAC */
    out += inp_len;
    len -= inp_len;

This ends up with "out" pointing before the buffer which is undefined
behaviour. Next we calculate "p" like this:

    unsigned char *p =
        out + len - 1 - maxpad - SHA256_DIGEST_LENGTH;

Because of the "out + len" term the -ve inp_len value is cancelled out
so "p" points to valid memory (although technically the pointer arithmetic
is undefined behaviour again).

We only ever then dereference "p" and never "out" directly so there is
never an invalid read based on the bad pointer - so there is no security
issue.

This commit fixes the undefined behaviour by ensuring we use maxpad in
place of pad, if the supplied pad is invalid.

With thanks to Brian Carpenter for reporting this issue.

Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3832)
2017-07-19 11:49:08 +01:00

967 lines
31 KiB
C

/*
* Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <openssl/opensslconf.h>
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/aes.h>
#include <openssl/sha.h>
#include <openssl/rand.h>
#include "modes_lcl.h"
#include "internal/evp_int.h"
#include "internal/constant_time_locl.h"
typedef struct {
AES_KEY ks;
SHA_CTX head, tail, md;
size_t payload_length; /* AAD length in decrypt case */
union {
unsigned int tls_ver;
unsigned char tls_aad[16]; /* 13 used */
} aux;
} EVP_AES_HMAC_SHA1;
#define NO_PAYLOAD_LENGTH ((size_t)-1)
#if defined(AES_ASM) && ( \
defined(__x86_64) || defined(__x86_64__) || \
defined(_M_AMD64) || defined(_M_X64) )
extern unsigned int OPENSSL_ia32cap_P[];
# define AESNI_CAPABLE (1<<(57-32))
int aesni_set_encrypt_key(const unsigned char *userKey, int bits,
AES_KEY *key);
int aesni_set_decrypt_key(const unsigned char *userKey, int bits,
AES_KEY *key);
void aesni_cbc_encrypt(const unsigned char *in,
unsigned char *out,
size_t length,
const AES_KEY *key, unsigned char *ivec, int enc);
void aesni_cbc_sha1_enc(const void *inp, void *out, size_t blocks,
const AES_KEY *key, unsigned char iv[16],
SHA_CTX *ctx, const void *in0);
void aesni256_cbc_sha1_dec(const void *inp, void *out, size_t blocks,
const AES_KEY *key, unsigned char iv[16],
SHA_CTX *ctx, const void *in0);
# define data(ctx) ((EVP_AES_HMAC_SHA1 *)EVP_CIPHER_CTX_get_cipher_data(ctx))
static int aesni_cbc_hmac_sha1_init_key(EVP_CIPHER_CTX *ctx,
const unsigned char *inkey,
const unsigned char *iv, int enc)
{
EVP_AES_HMAC_SHA1 *key = data(ctx);
int ret;
if (enc)
ret = aesni_set_encrypt_key(inkey,
EVP_CIPHER_CTX_key_length(ctx) * 8,
&key->ks);
else
ret = aesni_set_decrypt_key(inkey,
EVP_CIPHER_CTX_key_length(ctx) * 8,
&key->ks);
SHA1_Init(&key->head); /* handy when benchmarking */
key->tail = key->head;
key->md = key->head;
key->payload_length = NO_PAYLOAD_LENGTH;
return ret < 0 ? 0 : 1;
}
# define STITCHED_CALL
# undef STITCHED_DECRYPT_CALL
# if !defined(STITCHED_CALL)
# define aes_off 0
# endif
void sha1_block_data_order(void *c, const void *p, size_t len);
static void sha1_update(SHA_CTX *c, const void *data, size_t len)
{
const unsigned char *ptr = data;
size_t res;
if ((res = c->num)) {
res = SHA_CBLOCK - res;
if (len < res)
res = len;
SHA1_Update(c, ptr, res);
ptr += res;
len -= res;
}
res = len % SHA_CBLOCK;
len -= res;
if (len) {
sha1_block_data_order(c, ptr, len / SHA_CBLOCK);
ptr += len;
c->Nh += len >> 29;
c->Nl += len <<= 3;
if (c->Nl < (unsigned int)len)
c->Nh++;
}
if (res)
SHA1_Update(c, ptr, res);
}
# ifdef SHA1_Update
# undef SHA1_Update
# endif
# define SHA1_Update sha1_update
# if !defined(OPENSSL_NO_MULTIBLOCK)
typedef struct {
unsigned int A[8], B[8], C[8], D[8], E[8];
} SHA1_MB_CTX;
typedef struct {
const unsigned char *ptr;
int blocks;
} HASH_DESC;
void sha1_multi_block(SHA1_MB_CTX *, const HASH_DESC *, int);
typedef struct {
const unsigned char *inp;
unsigned char *out;
int blocks;
u64 iv[2];
} CIPH_DESC;
void aesni_multi_cbc_encrypt(CIPH_DESC *, void *, int);
static size_t tls1_1_multi_block_encrypt(EVP_AES_HMAC_SHA1 *key,
unsigned char *out,
const unsigned char *inp,
size_t inp_len, int n4x)
{ /* n4x is 1 or 2 */
HASH_DESC hash_d[8], edges[8];
CIPH_DESC ciph_d[8];
unsigned char storage[sizeof(SHA1_MB_CTX) + 32];
union {
u64 q[16];
u32 d[32];
u8 c[128];
} blocks[8];
SHA1_MB_CTX *ctx;
unsigned int frag, last, packlen, i, x4 = 4 * n4x, minblocks, processed =
0;
size_t ret = 0;
u8 *IVs;
# if defined(BSWAP8)
u64 seqnum;
# endif
/* ask for IVs in bulk */
if (RAND_bytes((IVs = blocks[0].c), 16 * x4) <= 0)
return 0;
ctx = (SHA1_MB_CTX *) (storage + 32 - ((size_t)storage % 32)); /* align */
frag = (unsigned int)inp_len >> (1 + n4x);
last = (unsigned int)inp_len + frag - (frag << (1 + n4x));
if (last > frag && ((last + 13 + 9) % 64) < (x4 - 1)) {
frag++;
last -= x4 - 1;
}
packlen = 5 + 16 + ((frag + 20 + 16) & -16);
/* populate descriptors with pointers and IVs */
hash_d[0].ptr = inp;
ciph_d[0].inp = inp;
/* 5+16 is place for header and explicit IV */
ciph_d[0].out = out + 5 + 16;
memcpy(ciph_d[0].out - 16, IVs, 16);
memcpy(ciph_d[0].iv, IVs, 16);
IVs += 16;
for (i = 1; i < x4; i++) {
ciph_d[i].inp = hash_d[i].ptr = hash_d[i - 1].ptr + frag;
ciph_d[i].out = ciph_d[i - 1].out + packlen;
memcpy(ciph_d[i].out - 16, IVs, 16);
memcpy(ciph_d[i].iv, IVs, 16);
IVs += 16;
}
# if defined(BSWAP8)
memcpy(blocks[0].c, key->md.data, 8);
seqnum = BSWAP8(blocks[0].q[0]);
# endif
for (i = 0; i < x4; i++) {
unsigned int len = (i == (x4 - 1) ? last : frag);
# if !defined(BSWAP8)
unsigned int carry, j;
# endif
ctx->A[i] = key->md.h0;
ctx->B[i] = key->md.h1;
ctx->C[i] = key->md.h2;
ctx->D[i] = key->md.h3;
ctx->E[i] = key->md.h4;
/* fix seqnum */
# if defined(BSWAP8)
blocks[i].q[0] = BSWAP8(seqnum + i);
# else
for (carry = i, j = 8; j--;) {
blocks[i].c[j] = ((u8 *)key->md.data)[j] + carry;
carry = (blocks[i].c[j] - carry) >> (sizeof(carry) * 8 - 1);
}
# endif
blocks[i].c[8] = ((u8 *)key->md.data)[8];
blocks[i].c[9] = ((u8 *)key->md.data)[9];
blocks[i].c[10] = ((u8 *)key->md.data)[10];
/* fix length */
blocks[i].c[11] = (u8)(len >> 8);
blocks[i].c[12] = (u8)(len);
memcpy(blocks[i].c + 13, hash_d[i].ptr, 64 - 13);
hash_d[i].ptr += 64 - 13;
hash_d[i].blocks = (len - (64 - 13)) / 64;
edges[i].ptr = blocks[i].c;
edges[i].blocks = 1;
}
/* hash 13-byte headers and first 64-13 bytes of inputs */
sha1_multi_block(ctx, edges, n4x);
/* hash bulk inputs */
# define MAXCHUNKSIZE 2048
# if MAXCHUNKSIZE%64
# error "MAXCHUNKSIZE is not divisible by 64"
# elif MAXCHUNKSIZE
/*
* goal is to minimize pressure on L1 cache by moving in shorter steps,
* so that hashed data is still in the cache by the time we encrypt it
*/
minblocks = ((frag <= last ? frag : last) - (64 - 13)) / 64;
if (minblocks > MAXCHUNKSIZE / 64) {
for (i = 0; i < x4; i++) {
edges[i].ptr = hash_d[i].ptr;
edges[i].blocks = MAXCHUNKSIZE / 64;
ciph_d[i].blocks = MAXCHUNKSIZE / 16;
}
do {
sha1_multi_block(ctx, edges, n4x);
aesni_multi_cbc_encrypt(ciph_d, &key->ks, n4x);
for (i = 0; i < x4; i++) {
edges[i].ptr = hash_d[i].ptr += MAXCHUNKSIZE;
hash_d[i].blocks -= MAXCHUNKSIZE / 64;
edges[i].blocks = MAXCHUNKSIZE / 64;
ciph_d[i].inp += MAXCHUNKSIZE;
ciph_d[i].out += MAXCHUNKSIZE;
ciph_d[i].blocks = MAXCHUNKSIZE / 16;
memcpy(ciph_d[i].iv, ciph_d[i].out - 16, 16);
}
processed += MAXCHUNKSIZE;
minblocks -= MAXCHUNKSIZE / 64;
} while (minblocks > MAXCHUNKSIZE / 64);
}
# endif
# undef MAXCHUNKSIZE
sha1_multi_block(ctx, hash_d, n4x);
memset(blocks, 0, sizeof(blocks));
for (i = 0; i < x4; i++) {
unsigned int len = (i == (x4 - 1) ? last : frag),
off = hash_d[i].blocks * 64;
const unsigned char *ptr = hash_d[i].ptr + off;
off = (len - processed) - (64 - 13) - off; /* remainder actually */
memcpy(blocks[i].c, ptr, off);
blocks[i].c[off] = 0x80;
len += 64 + 13; /* 64 is HMAC header */
len *= 8; /* convert to bits */
if (off < (64 - 8)) {
# ifdef BSWAP4
blocks[i].d[15] = BSWAP4(len);
# else
PUTU32(blocks[i].c + 60, len);
# endif
edges[i].blocks = 1;
} else {
# ifdef BSWAP4
blocks[i].d[31] = BSWAP4(len);
# else
PUTU32(blocks[i].c + 124, len);
# endif
edges[i].blocks = 2;
}
edges[i].ptr = blocks[i].c;
}
/* hash input tails and finalize */
sha1_multi_block(ctx, edges, n4x);
memset(blocks, 0, sizeof(blocks));
for (i = 0; i < x4; i++) {
# ifdef BSWAP4
blocks[i].d[0] = BSWAP4(ctx->A[i]);
ctx->A[i] = key->tail.h0;
blocks[i].d[1] = BSWAP4(ctx->B[i]);
ctx->B[i] = key->tail.h1;
blocks[i].d[2] = BSWAP4(ctx->C[i]);
ctx->C[i] = key->tail.h2;
blocks[i].d[3] = BSWAP4(ctx->D[i]);
ctx->D[i] = key->tail.h3;
blocks[i].d[4] = BSWAP4(ctx->E[i]);
ctx->E[i] = key->tail.h4;
blocks[i].c[20] = 0x80;
blocks[i].d[15] = BSWAP4((64 + 20) * 8);
# else
PUTU32(blocks[i].c + 0, ctx->A[i]);
ctx->A[i] = key->tail.h0;
PUTU32(blocks[i].c + 4, ctx->B[i]);
ctx->B[i] = key->tail.h1;
PUTU32(blocks[i].c + 8, ctx->C[i]);
ctx->C[i] = key->tail.h2;
PUTU32(blocks[i].c + 12, ctx->D[i]);
ctx->D[i] = key->tail.h3;
PUTU32(blocks[i].c + 16, ctx->E[i]);
ctx->E[i] = key->tail.h4;
blocks[i].c[20] = 0x80;
PUTU32(blocks[i].c + 60, (64 + 20) * 8);
# endif
edges[i].ptr = blocks[i].c;
edges[i].blocks = 1;
}
/* finalize MACs */
sha1_multi_block(ctx, edges, n4x);
for (i = 0; i < x4; i++) {
unsigned int len = (i == (x4 - 1) ? last : frag), pad, j;
unsigned char *out0 = out;
memcpy(ciph_d[i].out, ciph_d[i].inp, len - processed);
ciph_d[i].inp = ciph_d[i].out;
out += 5 + 16 + len;
/* write MAC */
PUTU32(out + 0, ctx->A[i]);
PUTU32(out + 4, ctx->B[i]);
PUTU32(out + 8, ctx->C[i]);
PUTU32(out + 12, ctx->D[i]);
PUTU32(out + 16, ctx->E[i]);
out += 20;
len += 20;
/* pad */
pad = 15 - len % 16;
for (j = 0; j <= pad; j++)
*(out++) = pad;
len += pad + 1;
ciph_d[i].blocks = (len - processed) / 16;
len += 16; /* account for explicit iv */
/* arrange header */
out0[0] = ((u8 *)key->md.data)[8];
out0[1] = ((u8 *)key->md.data)[9];
out0[2] = ((u8 *)key->md.data)[10];
out0[3] = (u8)(len >> 8);
out0[4] = (u8)(len);
ret += len + 5;
inp += frag;
}
aesni_multi_cbc_encrypt(ciph_d, &key->ks, n4x);
OPENSSL_cleanse(blocks, sizeof(blocks));
OPENSSL_cleanse(ctx, sizeof(*ctx));
return ret;
}
# endif
static int aesni_cbc_hmac_sha1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, size_t len)
{
EVP_AES_HMAC_SHA1 *key = data(ctx);
unsigned int l;
size_t plen = key->payload_length, iv = 0, /* explicit IV in TLS 1.1 and
* later */
sha_off = 0;
# if defined(STITCHED_CALL)
size_t aes_off = 0, blocks;
sha_off = SHA_CBLOCK - key->md.num;
# endif
key->payload_length = NO_PAYLOAD_LENGTH;
if (len % AES_BLOCK_SIZE)
return 0;
if (EVP_CIPHER_CTX_encrypting(ctx)) {
if (plen == NO_PAYLOAD_LENGTH)
plen = len;
else if (len !=
((plen + SHA_DIGEST_LENGTH +
AES_BLOCK_SIZE) & -AES_BLOCK_SIZE))
return 0;
else if (key->aux.tls_ver >= TLS1_1_VERSION)
iv = AES_BLOCK_SIZE;
# if defined(STITCHED_CALL)
if (plen > (sha_off + iv)
&& (blocks = (plen - (sha_off + iv)) / SHA_CBLOCK)) {
SHA1_Update(&key->md, in + iv, sha_off);
aesni_cbc_sha1_enc(in, out, blocks, &key->ks,
EVP_CIPHER_CTX_iv_noconst(ctx),
&key->md, in + iv + sha_off);
blocks *= SHA_CBLOCK;
aes_off += blocks;
sha_off += blocks;
key->md.Nh += blocks >> 29;
key->md.Nl += blocks <<= 3;
if (key->md.Nl < (unsigned int)blocks)
key->md.Nh++;
} else {
sha_off = 0;
}
# endif
sha_off += iv;
SHA1_Update(&key->md, in + sha_off, plen - sha_off);
if (plen != len) { /* "TLS" mode of operation */
if (in != out)
memcpy(out + aes_off, in + aes_off, plen - aes_off);
/* calculate HMAC and append it to payload */
SHA1_Final(out + plen, &key->md);
key->md = key->tail;
SHA1_Update(&key->md, out + plen, SHA_DIGEST_LENGTH);
SHA1_Final(out + plen, &key->md);
/* pad the payload|hmac */
plen += SHA_DIGEST_LENGTH;
for (l = len - plen - 1; plen < len; plen++)
out[plen] = l;
/* encrypt HMAC|padding at once */
aesni_cbc_encrypt(out + aes_off, out + aes_off, len - aes_off,
&key->ks, EVP_CIPHER_CTX_iv_noconst(ctx), 1);
} else {
aesni_cbc_encrypt(in + aes_off, out + aes_off, len - aes_off,
&key->ks, EVP_CIPHER_CTX_iv_noconst(ctx), 1);
}
} else {
union {
unsigned int u[SHA_DIGEST_LENGTH / sizeof(unsigned int)];
unsigned char c[32 + SHA_DIGEST_LENGTH];
} mac, *pmac;
/* arrange cache line alignment */
pmac = (void *)(((size_t)mac.c + 31) & ((size_t)0 - 32));
if (plen != NO_PAYLOAD_LENGTH) { /* "TLS" mode of operation */
size_t inp_len, mask, j, i;
unsigned int res, maxpad, pad, bitlen;
int ret = 1;
union {
unsigned int u[SHA_LBLOCK];
unsigned char c[SHA_CBLOCK];
} *data = (void *)key->md.data;
# if defined(STITCHED_DECRYPT_CALL)
unsigned char tail_iv[AES_BLOCK_SIZE];
int stitch = 0;
# endif
if ((key->aux.tls_aad[plen - 4] << 8 | key->aux.tls_aad[plen - 3])
>= TLS1_1_VERSION) {
if (len < (AES_BLOCK_SIZE + SHA_DIGEST_LENGTH + 1))
return 0;
/* omit explicit iv */
memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), in, AES_BLOCK_SIZE);
in += AES_BLOCK_SIZE;
out += AES_BLOCK_SIZE;
len -= AES_BLOCK_SIZE;
} else if (len < (SHA_DIGEST_LENGTH + 1))
return 0;
# if defined(STITCHED_DECRYPT_CALL)
if (len >= 1024 && ctx->key_len == 32) {
/* decrypt last block */
memcpy(tail_iv, in + len - 2 * AES_BLOCK_SIZE,
AES_BLOCK_SIZE);
aesni_cbc_encrypt(in + len - AES_BLOCK_SIZE,
out + len - AES_BLOCK_SIZE, AES_BLOCK_SIZE,
&key->ks, tail_iv, 0);
stitch = 1;
} else
# endif
/* decrypt HMAC|padding at once */
aesni_cbc_encrypt(in, out, len, &key->ks,
EVP_CIPHER_CTX_iv_noconst(ctx), 0);
/* figure out payload length */
pad = out[len - 1];
maxpad = len - (SHA_DIGEST_LENGTH + 1);
maxpad |= (255 - maxpad) >> (sizeof(maxpad) * 8 - 8);
maxpad &= 255;
mask = constant_time_ge(maxpad, pad);
ret &= mask;
/*
* If pad is invalid then we will fail the above test but we must
* continue anyway because we are in constant time code. However,
* we'll use the maxpad value instead of the supplied pad to make
* sure we perform well defined pointer arithmetic.
*/
pad = constant_time_select(mask, pad, maxpad);
inp_len = len - (SHA_DIGEST_LENGTH + pad + 1);
mask = (0 - ((inp_len - len) >> (sizeof(inp_len) * 8 - 1)));
inp_len &= mask;
ret &= (int)mask;
key->aux.tls_aad[plen - 2] = inp_len >> 8;
key->aux.tls_aad[plen - 1] = inp_len;
/* calculate HMAC */
key->md = key->head;
SHA1_Update(&key->md, key->aux.tls_aad, plen);
# if defined(STITCHED_DECRYPT_CALL)
if (stitch) {
blocks = (len - (256 + 32 + SHA_CBLOCK)) / SHA_CBLOCK;
aes_off = len - AES_BLOCK_SIZE - blocks * SHA_CBLOCK;
sha_off = SHA_CBLOCK - plen;
aesni_cbc_encrypt(in, out, aes_off, &key->ks, ctx->iv, 0);
SHA1_Update(&key->md, out, sha_off);
aesni256_cbc_sha1_dec(in + aes_off,
out + aes_off, blocks, &key->ks,
ctx->iv, &key->md, out + sha_off);
sha_off += blocks *= SHA_CBLOCK;
out += sha_off;
len -= sha_off;
inp_len -= sha_off;
key->md.Nl += (blocks << 3); /* at most 18 bits */
memcpy(ctx->iv, tail_iv, AES_BLOCK_SIZE);
}
# endif
# if 1 /* see original reference version in #else */
len -= SHA_DIGEST_LENGTH; /* amend mac */
if (len >= (256 + SHA_CBLOCK)) {
j = (len - (256 + SHA_CBLOCK)) & (0 - SHA_CBLOCK);
j += SHA_CBLOCK - key->md.num;
SHA1_Update(&key->md, out, j);
out += j;
len -= j;
inp_len -= j;
}
/* but pretend as if we hashed padded payload */
bitlen = key->md.Nl + (inp_len << 3); /* at most 18 bits */
# ifdef BSWAP4
bitlen = BSWAP4(bitlen);
# else
mac.c[0] = 0;
mac.c[1] = (unsigned char)(bitlen >> 16);
mac.c[2] = (unsigned char)(bitlen >> 8);
mac.c[3] = (unsigned char)bitlen;
bitlen = mac.u[0];
# endif
pmac->u[0] = 0;
pmac->u[1] = 0;
pmac->u[2] = 0;
pmac->u[3] = 0;
pmac->u[4] = 0;
for (res = key->md.num, j = 0; j < len; j++) {
size_t c = out[j];
mask = (j - inp_len) >> (sizeof(j) * 8 - 8);
c &= mask;
c |= 0x80 & ~mask & ~((inp_len - j) >> (sizeof(j) * 8 - 8));
data->c[res++] = (unsigned char)c;
if (res != SHA_CBLOCK)
continue;
/* j is not incremented yet */
mask = 0 - ((inp_len + 7 - j) >> (sizeof(j) * 8 - 1));
data->u[SHA_LBLOCK - 1] |= bitlen & mask;
sha1_block_data_order(&key->md, data, 1);
mask &= 0 - ((j - inp_len - 72) >> (sizeof(j) * 8 - 1));
pmac->u[0] |= key->md.h0 & mask;
pmac->u[1] |= key->md.h1 & mask;
pmac->u[2] |= key->md.h2 & mask;
pmac->u[3] |= key->md.h3 & mask;
pmac->u[4] |= key->md.h4 & mask;
res = 0;
}
for (i = res; i < SHA_CBLOCK; i++, j++)
data->c[i] = 0;
if (res > SHA_CBLOCK - 8) {
mask = 0 - ((inp_len + 8 - j) >> (sizeof(j) * 8 - 1));
data->u[SHA_LBLOCK - 1] |= bitlen & mask;
sha1_block_data_order(&key->md, data, 1);
mask &= 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1));
pmac->u[0] |= key->md.h0 & mask;
pmac->u[1] |= key->md.h1 & mask;
pmac->u[2] |= key->md.h2 & mask;
pmac->u[3] |= key->md.h3 & mask;
pmac->u[4] |= key->md.h4 & mask;
memset(data, 0, SHA_CBLOCK);
j += 64;
}
data->u[SHA_LBLOCK - 1] = bitlen;
sha1_block_data_order(&key->md, data, 1);
mask = 0 - ((j - inp_len - 73) >> (sizeof(j) * 8 - 1));
pmac->u[0] |= key->md.h0 & mask;
pmac->u[1] |= key->md.h1 & mask;
pmac->u[2] |= key->md.h2 & mask;
pmac->u[3] |= key->md.h3 & mask;
pmac->u[4] |= key->md.h4 & mask;
# ifdef BSWAP4
pmac->u[0] = BSWAP4(pmac->u[0]);
pmac->u[1] = BSWAP4(pmac->u[1]);
pmac->u[2] = BSWAP4(pmac->u[2]);
pmac->u[3] = BSWAP4(pmac->u[3]);
pmac->u[4] = BSWAP4(pmac->u[4]);
# else
for (i = 0; i < 5; i++) {
res = pmac->u[i];
pmac->c[4 * i + 0] = (unsigned char)(res >> 24);
pmac->c[4 * i + 1] = (unsigned char)(res >> 16);
pmac->c[4 * i + 2] = (unsigned char)(res >> 8);
pmac->c[4 * i + 3] = (unsigned char)res;
}
# endif
len += SHA_DIGEST_LENGTH;
# else /* pre-lucky-13 reference version of above */
SHA1_Update(&key->md, out, inp_len);
res = key->md.num;
SHA1_Final(pmac->c, &key->md);
{
unsigned int inp_blocks, pad_blocks;
/* but pretend as if we hashed padded payload */
inp_blocks =
1 + ((SHA_CBLOCK - 9 - res) >> (sizeof(res) * 8 - 1));
res += (unsigned int)(len - inp_len);
pad_blocks = res / SHA_CBLOCK;
res %= SHA_CBLOCK;
pad_blocks +=
1 + ((SHA_CBLOCK - 9 - res) >> (sizeof(res) * 8 - 1));
for (; inp_blocks < pad_blocks; inp_blocks++)
sha1_block_data_order(&key->md, data, 1);
}
# endif
key->md = key->tail;
SHA1_Update(&key->md, pmac->c, SHA_DIGEST_LENGTH);
SHA1_Final(pmac->c, &key->md);
/* verify HMAC */
out += inp_len;
len -= inp_len;
# if 1 /* see original reference version in #else */
{
unsigned char *p = out + len - 1 - maxpad - SHA_DIGEST_LENGTH;
size_t off = out - p;
unsigned int c, cmask;
maxpad += SHA_DIGEST_LENGTH;
for (res = 0, i = 0, j = 0; j < maxpad; j++) {
c = p[j];
cmask =
((int)(j - off - SHA_DIGEST_LENGTH)) >> (sizeof(int) *
8 - 1);
res |= (c ^ pad) & ~cmask; /* ... and padding */
cmask &= ((int)(off - 1 - j)) >> (sizeof(int) * 8 - 1);
res |= (c ^ pmac->c[i]) & cmask;
i += 1 & cmask;
}
maxpad -= SHA_DIGEST_LENGTH;
res = 0 - ((0 - res) >> (sizeof(res) * 8 - 1));
ret &= (int)~res;
}
# else /* pre-lucky-13 reference version of above */
for (res = 0, i = 0; i < SHA_DIGEST_LENGTH; i++)
res |= out[i] ^ pmac->c[i];
res = 0 - ((0 - res) >> (sizeof(res) * 8 - 1));
ret &= (int)~res;
/* verify padding */
pad = (pad & ~res) | (maxpad & res);
out = out + len - 1 - pad;
for (res = 0, i = 0; i < pad; i++)
res |= out[i] ^ pad;
res = (0 - res) >> (sizeof(res) * 8 - 1);
ret &= (int)~res;
# endif
return ret;
} else {
# if defined(STITCHED_DECRYPT_CALL)
if (len >= 1024 && ctx->key_len == 32) {
if (sha_off %= SHA_CBLOCK)
blocks = (len - 3 * SHA_CBLOCK) / SHA_CBLOCK;
else
blocks = (len - 2 * SHA_CBLOCK) / SHA_CBLOCK;
aes_off = len - blocks * SHA_CBLOCK;
aesni_cbc_encrypt(in, out, aes_off, &key->ks, ctx->iv, 0);
SHA1_Update(&key->md, out, sha_off);
aesni256_cbc_sha1_dec(in + aes_off,
out + aes_off, blocks, &key->ks,
ctx->iv, &key->md, out + sha_off);
sha_off += blocks *= SHA_CBLOCK;
out += sha_off;
len -= sha_off;
key->md.Nh += blocks >> 29;
key->md.Nl += blocks <<= 3;
if (key->md.Nl < (unsigned int)blocks)
key->md.Nh++;
} else
# endif
/* decrypt HMAC|padding at once */
aesni_cbc_encrypt(in, out, len, &key->ks,
EVP_CIPHER_CTX_iv_noconst(ctx), 0);
SHA1_Update(&key->md, out, len);
}
}
return 1;
}
static int aesni_cbc_hmac_sha1_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
void *ptr)
{
EVP_AES_HMAC_SHA1 *key = data(ctx);
switch (type) {
case EVP_CTRL_AEAD_SET_MAC_KEY:
{
unsigned int i;
unsigned char hmac_key[64];
memset(hmac_key, 0, sizeof(hmac_key));
if (arg > (int)sizeof(hmac_key)) {
SHA1_Init(&key->head);
SHA1_Update(&key->head, ptr, arg);
SHA1_Final(hmac_key, &key->head);
} else {
memcpy(hmac_key, ptr, arg);
}
for (i = 0; i < sizeof(hmac_key); i++)
hmac_key[i] ^= 0x36; /* ipad */
SHA1_Init(&key->head);
SHA1_Update(&key->head, hmac_key, sizeof(hmac_key));
for (i = 0; i < sizeof(hmac_key); i++)
hmac_key[i] ^= 0x36 ^ 0x5c; /* opad */
SHA1_Init(&key->tail);
SHA1_Update(&key->tail, hmac_key, sizeof(hmac_key));
OPENSSL_cleanse(hmac_key, sizeof(hmac_key));
return 1;
}
case EVP_CTRL_AEAD_TLS1_AAD:
{
unsigned char *p = ptr;
unsigned int len;
if (arg != EVP_AEAD_TLS1_AAD_LEN)
return -1;
len = p[arg - 2] << 8 | p[arg - 1];
if (EVP_CIPHER_CTX_encrypting(ctx)) {
key->payload_length = len;
if ((key->aux.tls_ver =
p[arg - 4] << 8 | p[arg - 3]) >= TLS1_1_VERSION) {
if (len < AES_BLOCK_SIZE)
return 0;
len -= AES_BLOCK_SIZE;
p[arg - 2] = len >> 8;
p[arg - 1] = len;
}
key->md = key->head;
SHA1_Update(&key->md, p, arg);
return (int)(((len + SHA_DIGEST_LENGTH +
AES_BLOCK_SIZE) & -AES_BLOCK_SIZE)
- len);
} else {
memcpy(key->aux.tls_aad, ptr, arg);
key->payload_length = arg;
return SHA_DIGEST_LENGTH;
}
}
# if !defined(OPENSSL_NO_MULTIBLOCK)
case EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE:
return (int)(5 + 16 + ((arg + 20 + 16) & -16));
case EVP_CTRL_TLS1_1_MULTIBLOCK_AAD:
{
EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param =
(EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *) ptr;
unsigned int n4x = 1, x4;
unsigned int frag, last, packlen, inp_len;
if (arg < (int)sizeof(EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM))
return -1;
inp_len = param->inp[11] << 8 | param->inp[12];
if (EVP_CIPHER_CTX_encrypting(ctx)) {
if ((param->inp[9] << 8 | param->inp[10]) < TLS1_1_VERSION)
return -1;
if (inp_len) {
if (inp_len < 4096)
return 0; /* too short */
if (inp_len >= 8192 && OPENSSL_ia32cap_P[2] & (1 << 5))
n4x = 2; /* AVX2 */
} else if ((n4x = param->interleave / 4) && n4x <= 2)
inp_len = param->len;
else
return -1;
key->md = key->head;
SHA1_Update(&key->md, param->inp, 13);
x4 = 4 * n4x;
n4x += 1;
frag = inp_len >> n4x;
last = inp_len + frag - (frag << n4x);
if (last > frag && ((last + 13 + 9) % 64 < (x4 - 1))) {
frag++;
last -= x4 - 1;
}
packlen = 5 + 16 + ((frag + 20 + 16) & -16);
packlen = (packlen << n4x) - packlen;
packlen += 5 + 16 + ((last + 20 + 16) & -16);
param->interleave = x4;
return (int)packlen;
} else
return -1; /* not yet */
}
case EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT:
{
EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *param =
(EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM *) ptr;
return (int)tls1_1_multi_block_encrypt(key, param->out,
param->inp, param->len,
param->interleave / 4);
}
case EVP_CTRL_TLS1_1_MULTIBLOCK_DECRYPT:
# endif
default:
return -1;
}
}
static EVP_CIPHER aesni_128_cbc_hmac_sha1_cipher = {
# ifdef NID_aes_128_cbc_hmac_sha1
NID_aes_128_cbc_hmac_sha1,
# else
NID_undef,
# endif
AES_BLOCK_SIZE, 16, AES_BLOCK_SIZE,
EVP_CIPH_CBC_MODE | EVP_CIPH_FLAG_DEFAULT_ASN1 |
EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK,
aesni_cbc_hmac_sha1_init_key,
aesni_cbc_hmac_sha1_cipher,
NULL,
sizeof(EVP_AES_HMAC_SHA1),
EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_set_asn1_iv,
EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_get_asn1_iv,
aesni_cbc_hmac_sha1_ctrl,
NULL
};
static EVP_CIPHER aesni_256_cbc_hmac_sha1_cipher = {
# ifdef NID_aes_256_cbc_hmac_sha1
NID_aes_256_cbc_hmac_sha1,
# else
NID_undef,
# endif
AES_BLOCK_SIZE, 32, AES_BLOCK_SIZE,
EVP_CIPH_CBC_MODE | EVP_CIPH_FLAG_DEFAULT_ASN1 |
EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK,
aesni_cbc_hmac_sha1_init_key,
aesni_cbc_hmac_sha1_cipher,
NULL,
sizeof(EVP_AES_HMAC_SHA1),
EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_set_asn1_iv,
EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_get_asn1_iv,
aesni_cbc_hmac_sha1_ctrl,
NULL
};
const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha1(void)
{
return (OPENSSL_ia32cap_P[1] & AESNI_CAPABLE ?
&aesni_128_cbc_hmac_sha1_cipher : NULL);
}
const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha1(void)
{
return (OPENSSL_ia32cap_P[1] & AESNI_CAPABLE ?
&aesni_256_cbc_hmac_sha1_cipher : NULL);
}
#else
const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha1(void)
{
return NULL;
}
const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha1(void)
{
return NULL;
}
#endif