diff --git a/LICENSE b/LICENSE index be3f7b28..b5c24884 100644 --- a/LICENSE +++ b/LICENSE @@ -659,3 +659,14 @@ specific requirements. if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . + +REDISTRIBUTION NOTE: + +A few files listed below are released under different licenses (that are +compatible with AGPL3), as specified in the files themselves, and are +redistributed alongside this software: + +- crypto-curve25519.c/h: public domain +- siphash24.c/h: public domain +- crypto-rfc6234.c/h: simplified BSD license +- crypto-aes256.c/h: MIT license diff --git a/README.md b/README.md index ed61e2f1..f59edad3 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ Masscan supports banner checking on the following protocols: * POP3 * SMTP * SSH - * SSL + * SSL/TLS * SMBv1 * SMBv2 * Telnet diff --git a/src/crypto-aes256.c b/src/crypto-aes256.c new file mode 100644 index 00000000..f5b8d125 --- /dev/null +++ b/src/crypto-aes256.c @@ -0,0 +1,485 @@ +// https://github.com/ilvn/aes256 + +// A compact byte-oriented AES-256 implementation. +// All lookup tables replaced with 'on the fly' calculations. +// +// Copyright (c) 2007-2011 Literatecode, http://www.literatecode.com +// Copyright (c) 2022 Ilia Levin (ilia@levin.sg) +// +// Other contributors: Hal Finney. +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include "crypto-aes256.h" +#ifndef NULL +#define NULL ((void *)0) +#endif + +// We use the compact version with runtime calculations by default. You may +// want to define BACK_TO_TABLES for a pre-calculated faster version. + +#define BACK_TO_TABLES + +#ifdef _MSC_VER +#define __attribute__(...) +#endif +#define GFC_FN_ static uint8_t __attribute__((const)) +#define AES_CORE_FN_ static void __attribute__((nonnull)) + +// ----------------------------------------------------------------------------- +GFC_FN_ +rj_xtime(uint8_t x) +{ + uint8_t y = 0xff & (x << 1); + return (x & 0x80) ? (y ^ 0x1b) : y; +} // rj_xtime + +#ifdef BACK_TO_TABLES // use pre-calculated tables + +static const uint8_t sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; +static const uint8_t sboxinv[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, + 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, + 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, + 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, + 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, + 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, + 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, + 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, + 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, + 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, + 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, + 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, + 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, + 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, + 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +}; + +#define rj_sbox(x) sbox[(x)] +#define rj_sbox_inv(x) sboxinv[(x)] + +#else // use tableless subroutines + +#define SHL8(x, n) ((0xff & ((x) << (n))) | ((x) >> (8 - (n)))) + +// ----------------------------------------------------------------------------- +GFC_FN_ +gf_alog(uint8_t x) // calculate anti-logarithm gen 3 +{ + uint8_t y = 1; + + for (uint8_t i = 0; (x < 0xff) && (i < x); i++) { + y ^= rj_xtime(y); + } + + return y; +} // gf_alog + +// ----------------------------------------------------------------------------- +GFC_FN_ +gf_log(uint8_t x) // calculate logarithm gen 3 +{ + uint8_t y = 1, i = 0; + + if (0 != x) { + do { + y ^= rj_xtime(y); + } while ((++i != 0xff) && (y != x)); + } + + return i; +} // gf_log + +// ----------------------------------------------------------------------------- +GFC_FN_ +gf_mulinv(uint8_t x) // calculate multiplicative inverse +{ + return ((x) ? gf_alog(255 - gf_log(x)) : 0); +} // gf_mulinv + +// ----------------------------------------------------------------------------- +GFC_FN_ +rj_sbox(uint8_t x) +{ + uint8_t y = gf_mulinv(x), sb = y; + + sb ^= y = SHL8(y, 1); + sb ^= y = SHL8(y, 1); + sb ^= y = SHL8(y, 1); + + return (sb ^ SHL8(y, 1) ^ 0x63); +} // rj_sbox + +// ----------------------------------------------------------------------------- +GFC_FN_ +rj_sbox_inv(uint8_t x) +{ + uint8_t y = (x ^ 0x63), sb = y = SHL8(y, 1); + + sb ^= y = SHL8(y, 2); + + return gf_mulinv(sb ^ SHL8(y, 3)); +} // rj_sbox_inv + +#endif // BACK_TO_TABLES + + +// ----------------------------------------------------------------------------- +AES_CORE_FN_ +subBytes(uint8_t *buf) +{ + for (uint8_t i = 0; i < 16; i++) { + buf[i] = rj_sbox(buf[i]); + } +} // subBytes + +// ----------------------------------------------------------------------------- +AES_CORE_FN_ +subBytes_inv(uint8_t *buf) +{ + for (uint8_t i = 0; i < 16; i++) { + buf[i] = rj_sbox_inv(buf[i]); + } +} // subBytes_inv + +// ----------------------------------------------------------------------------- +AES_CORE_FN_ +addRoundKey(uint8_t *buf, uint8_t *key) +{ + for (uint8_t i = 0; i < 16; i++) { + buf[i] ^= key[i]; + } +} // addRoundKey + +// ----------------------------------------------------------------------------- +AES_CORE_FN_ +addRoundKey_cpy(uint8_t *buf, uint8_t *key, uint8_t *cpk) +{ + for (uint8_t i = 0; i < 16; i++) { + buf[i] ^= (cpk[i] = key[i]); + cpk[16 + i] = key[16 + i]; + } +} // addRoundKey_cpy + +// ----------------------------------------------------------------------------- +AES_CORE_FN_ +shiftRows(uint8_t *buf) +{ + register uint8_t i, j; // to make it potentially parallelable :) + + i = buf[1]; + buf[1] = buf[5]; + buf[5] = buf[9]; + buf[9] = buf[13]; + buf[13] = i; + + i = buf[10]; + buf[10] = buf[2]; + buf[2] = i; + + j = buf[3]; + buf[3] = buf[15]; + buf[15] = buf[11]; + buf[11] = buf[7]; + buf[7] = j; + + j = buf[14]; + buf[14] = buf[6]; + buf[6] = j; +} // shiftRows + +// ----------------------------------------------------------------------------- +AES_CORE_FN_ +shiftRows_inv(uint8_t *buf) +{ + register uint8_t i, j; // similar to shiftRows :) + + i = buf[1]; + buf[1] = buf[13]; + buf[13] = buf[9]; + buf[9] = buf[5]; + buf[5] = i; + + i = buf[2]; + buf[2] = buf[10]; + buf[10] = i; + + j = buf[3]; + buf[3] = buf[7]; + buf[7] = buf[11]; + buf[11] = buf[15]; + buf[15] = j; + + j = buf[6]; + buf[6] = buf[14]; + buf[14] = j; +} // shiftRows_inv + +// ----------------------------------------------------------------------------- +AES_CORE_FN_ +mixColumns(uint8_t *buf) +{ + register uint8_t a, b, c, d, e; + + for (uint8_t i = 0; i < 16; i += 4) { + a = buf[i]; + b = buf[i + 1]; + c = buf[i + 2]; + d = buf[i + 3]; + e = a ^ b ^ c ^ d; + buf[i] ^= e ^ rj_xtime(a ^ b); + buf[i + 1] ^= e ^ rj_xtime(b ^ c); + buf[i + 2] ^= e ^ rj_xtime(c ^ d); + buf[i + 3] ^= e ^ rj_xtime(d ^ a); + } +} // mixColumns + +// ----------------------------------------------------------------------------- +AES_CORE_FN_ +mixColumns_inv(uint8_t *buf) +{ + register uint8_t a, b, c, d, e, x, y, z; + + for (uint8_t i = 0; i < 16; i += 4) { + a = buf[i]; + b = buf[i + 1]; + c = buf[i + 2]; + d = buf[i + 3]; + e = a ^ b ^ c ^ d; + z = rj_xtime(e); + x = e ^ rj_xtime(rj_xtime(z ^ a ^ c)); + y = e ^ rj_xtime(rj_xtime(z ^ b ^ d)); + buf[i] ^= x ^ rj_xtime(a ^ b); + buf[i + 1] ^= y ^ rj_xtime(b ^ c); + buf[i + 2] ^= x ^ rj_xtime(c ^ d); + buf[i + 3] ^= y ^ rj_xtime(d ^ a); + } +} // mixColumns_inv + +// ----------------------------------------------------------------------------- +AES_CORE_FN_ +expandEncKey(uint8_t *k, uint8_t *rc) +{ + k[0] ^= rj_sbox(k[29]) ^ (*rc); + k[1] ^= rj_sbox(k[30]); + k[2] ^= rj_sbox(k[31]); + k[3] ^= rj_sbox(k[28]); + *rc = rj_xtime(*rc); + + for (uint8_t i = 4; i < 16; i += 4) { + k[i] ^= k[i - 4]; + k[i + 1] ^= k[i - 3]; + k[i + 2] ^= k[i - 2]; + k[i + 3] ^= k[i - 1]; + } + + k[16] ^= rj_sbox(k[12]); + k[17] ^= rj_sbox(k[13]); + k[18] ^= rj_sbox(k[14]); + k[19] ^= rj_sbox(k[15]); + + for (uint8_t i = 20; i < 32; i += 4) { + k[i] ^= k[i - 4]; + k[i + 1] ^= k[i - 3]; + k[i + 2] ^= k[i - 2]; + k[i + 3] ^= k[i - 1]; + } +} // expandEncKey + +// ----------------------------------------------------------------------------- +AES_CORE_FN_ +expandDecKey(uint8_t *k, uint8_t *rc) +{ + for (uint8_t i = 28; i > 16; i -= 4) { + k[i + 0] ^= k[i - 4]; + k[i + 1] ^= k[i - 3]; + k[i + 2] ^= k[i - 2]; + k[i + 3] ^= k[i - 1]; + } + + k[16] ^= rj_sbox(k[12]); + k[17] ^= rj_sbox(k[13]); + k[18] ^= rj_sbox(k[14]); + k[19] ^= rj_sbox(k[15]); + + for (uint8_t i = 12; i > 0; i -= 4) { + k[i + 0] ^= k[i - 4]; + k[i + 1] ^= k[i - 3]; + k[i + 2] ^= k[i - 2]; + k[i + 3] ^= k[i - 1]; + } + + *rc = (((*rc) >> 1) ^ (((*rc) & 1) ? 0x8d : 0)); + k[0] ^= rj_sbox(k[29]) ^ (*rc); + k[1] ^= rj_sbox(k[30]); + k[2] ^= rj_sbox(k[31]); + k[3] ^= rj_sbox(k[28]); +} // expandDecKey + +// ----------------------------------------------------------------------------- +uint8_t +aes256_init(aes256_context_t *ctx, aes256_key_t *key) +{ + if ((NULL == ctx) || (NULL == key)) { + return AES_ERROR; + } + + ctx->enckey = ctx->deckey = *key; + + for (uint8_t i = 0, rcon = 1; i < 7; i++) { + expandEncKey(ctx->deckey.raw, &rcon); + } + + return AES_SUCCESS; +} // aes256_init + + +// ----------------------------------------------------------------------------- +uint8_t +aes256_done(aes256_context_t *ctx) +{ + const aes256_key_t zero = {0}; + + if (NULL != ctx) { + ctx->key = ctx->enckey = ctx->deckey = zero; + return AES_SUCCESS; + } + + return AES_ERROR; +} // aes256_done + + +// ----------------------------------------------------------------------------- +uint8_t +aes256_encrypt_ecb(aes256_context_t *ctx, aes256_blk_t *buf) +{ + if ((NULL == ctx) || (NULL == buf)) { + return AES_ERROR; + } + + uint8_t rcon = 1; + addRoundKey_cpy(buf->raw, ctx->enckey.raw, ctx->key.raw); + + for (uint8_t i = 1; i < 14; ++i) { + subBytes(buf->raw); + shiftRows(buf->raw); + mixColumns(buf->raw); + if (1 == (i & 1)) { + addRoundKey(buf->raw, &ctx->key.raw[16]); + } else { + expandEncKey(ctx->key.raw, &rcon); + addRoundKey(buf->raw, ctx->key.raw); + } + } + + subBytes(buf->raw); + shiftRows(buf->raw); + expandEncKey(ctx->key.raw, &rcon); + addRoundKey(buf->raw, ctx->key.raw); + + return AES_SUCCESS; +} // aes256_encrypt + +// ----------------------------------------------------------------------------- +uint8_t +aes256_decrypt_ecb(aes256_context_t *ctx, aes256_blk_t *buf) +{ + if ((NULL == ctx) || (NULL == buf)) { + return AES_ERROR; + } + + addRoundKey_cpy(buf->raw, ctx->deckey.raw, ctx->key.raw); + shiftRows_inv(buf->raw); + subBytes_inv(buf->raw); + + for (uint8_t i = 14, rcon = 0x80; --i;) { + if (1 == (i & 1)) { + expandDecKey(ctx->key.raw, &rcon); + addRoundKey(buf->raw, &ctx->key.raw[16]); + } else { + addRoundKey(buf->raw, ctx->key.raw); + } + mixColumns_inv(buf->raw); + shiftRows_inv(buf->raw); + subBytes_inv(buf->raw); + } + + addRoundKey(buf->raw, ctx->key.raw); + + return AES_SUCCESS; +} // aes256_decrypt + +// ----------------------------------------------------------------------------- +uint8_t +aes256_ctr_inc(uint8_t *p) +{ + p += 12; + uint32_t val = (uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 | (uint32_t)p[2] << 8 | (uint32_t)p[3]; + val++; + p[0] = (val >> 24) & 0xFF; + p[1] = (val >> 16) & 0xFF; + p[2] = (val >> 8) & 0xFF; + p[3] = val & 0xFF; + + return AES_SUCCESS; +} // aes256_ctr_inc \ No newline at end of file diff --git a/src/crypto-aes256.h b/src/crypto-aes256.h new file mode 100644 index 00000000..79e17e76 --- /dev/null +++ b/src/crypto-aes256.h @@ -0,0 +1,105 @@ +// https://github.com/ilvn/aes256 + +// A compact byte-oriented AES-256 implementation. +// All lookup tables replaced with 'on the fly' calculations. +// +// Copyright (c) 2007-2011 Literatecode, http://www.literatecode.com +// Copyright (c) 2022 Ilia Levin (ilia@levin.sg) +// +// Other contributors: Hal Finney. +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#ifndef AES256_H__ +#define AES256_H__ 1 + +#ifndef uint8_t +#define uint8_t unsigned char +#endif + +#ifndef uint32_t +#define uint32_t unsigned int +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define AES_SUCCESS (0) +#define AES_ERROR (1) + +typedef struct aes256_key_t { uint8_t raw[32]; } aes256_key_t; +typedef struct aes256_blk_t { uint8_t raw[16]; } aes256_blk_t; + +typedef struct aes256_context_t { + aes256_key_t key; + aes256_key_t enckey; + aes256_key_t deckey; +} aes256_context_t; + + +/// @function aes256_init +/// @brief Initialize a context structure. +/// @param[in,out] ctx Pointer to a pre-allocated context structure. +/// @param[in] key Pointer to a key initialized buffer. +/// @return AES_SUCCESS on success, AES_ERROR on failure. +/// +uint8_t aes256_init( + aes256_context_t *ctx, + aes256_key_t *key +); + +/// @brief Clear the context structure. +/// @param[in,out] ctx Pointer to a context structure. +/// @return AES_SUCCESS on success, AES_ERROR on failure. +/// +uint8_t aes256_done( + aes256_context_t *ctx +); + +/// @brief Encrypt a single data block in place. +/// @param[in] ctx Pointer to an initialized context structure. +/// @param[in,out] buf Plaintext in, ciphertext out. +/// @return AES_SUCCESS on success, AES_ERROR on failure. +/// +uint8_t aes256_encrypt_ecb( + aes256_context_t *ctx, + aes256_blk_t *buf +); + +/// @brief Decrypt a single data block in place. +/// @param[in] ctx Pointer to an initialized context structure. +/// @param[in,out] buf Ciphertext in, plaintext out. +/// @return AES_SUCCESS on success, AES_ERROR on failure. +/// +uint8_t aes256_decrypt_ecb( + aes256_context_t *ctx, + aes256_blk_t *buf +); + +// added by us (masscan): + +/// @brief Increment the CTR pointer by 1 in-place. +/// @param[in,out] p Pointer to the CTR pointer. +/// @return AES_SUCCESS on success, AES_ERROR on failure. +/// +uint8_t aes256_ctr_inc( + uint8_t *p +); + +#ifdef __cplusplus +} +#endif + +#endif // AES256_H__ + diff --git a/src/crypto-curve25519.c b/src/crypto-curve25519.c new file mode 100644 index 00000000..bbd61d1e --- /dev/null +++ b/src/crypto-curve25519.c @@ -0,0 +1,452 @@ +// https://github.com/agl/curve25519-donna/blob/master/curve25519-donna-c64.c + +/* Copyright 2008, Google Inc. + * All rights reserved. + * + * Code released into the public domain. + * + * curve25519-donna: Curve25519 elliptic curve, public key function + * + * http://code.google.com/p/curve25519-donna/ + * + * Adam Langley + * + * Derived from public domain C code by Daniel J. Bernstein + * + * More information about curve25519 can be found here + * http://cr.yp.to/ecdh.html + * + * djb's sample implementation of curve25519 is written in a special assembly + * language called qhasm and uses the floating point registers. + * + * This is, almost, a clean room reimplementation from the curve25519 paper. It + * uses many of the tricks described therein. Only the crecip function is taken + * from the sample implementation. + */ + +#include "crypto-curve25519.h" +#include +#include + +typedef uint8_t u8; +typedef uint64_t limb; +typedef limb felem[5]; +// This is a special gcc mode for 128-bit integers. It's implemented on 64-bit +// platforms only as far as I know. +typedef unsigned uint128_t __attribute__((mode(TI))); + +#undef force_inline +#define force_inline __attribute__((always_inline)) + +/* Sum two numbers: output += in */ +static inline void force_inline +fsum(limb *output, const limb *in) { + output[0] += in[0]; + output[1] += in[1]; + output[2] += in[2]; + output[3] += in[3]; + output[4] += in[4]; +} + +/* Find the difference of two numbers: output = in - output + * (note the order of the arguments!) + * + * Assumes that out[i] < 2**52 + * On return, out[i] < 2**55 + */ +static inline void force_inline +fdifference_backwards(felem out, const felem in) { + /* 152 is 19 << 3 */ + static const limb two54m152 = (((limb)1) << 54) - 152; + static const limb two54m8 = (((limb)1) << 54) - 8; + + out[0] = in[0] + two54m152 - out[0]; + out[1] = in[1] + two54m8 - out[1]; + out[2] = in[2] + two54m8 - out[2]; + out[3] = in[3] + two54m8 - out[3]; + out[4] = in[4] + two54m8 - out[4]; +} + +/* Multiply a number by a scalar: output = in * scalar */ +static inline void force_inline +fscalar_product(felem output, const felem in, const limb scalar) { + uint128_t a; + + a = ((uint128_t) in[0]) * scalar; + output[0] = ((limb)a) & 0x7ffffffffffff; + + a = ((uint128_t) in[1]) * scalar + ((limb) (a >> 51)); + output[1] = ((limb)a) & 0x7ffffffffffff; + + a = ((uint128_t) in[2]) * scalar + ((limb) (a >> 51)); + output[2] = ((limb)a) & 0x7ffffffffffff; + + a = ((uint128_t) in[3]) * scalar + ((limb) (a >> 51)); + output[3] = ((limb)a) & 0x7ffffffffffff; + + a = ((uint128_t) in[4]) * scalar + ((limb) (a >> 51)); + output[4] = ((limb)a) & 0x7ffffffffffff; + + output[0] += (a >> 51) * 19; +} + +/* Multiply two numbers: output = in2 * in + * + * output must be distinct to both inputs. The inputs are reduced coefficient + * form, the output is not. + * + * Assumes that in[i] < 2**55 and likewise for in2. + * On return, output[i] < 2**52 + */ +static inline void force_inline +fmul(felem output, const felem in2, const felem in) { + uint128_t t[5]; + limb r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + + s0 = in2[0]; + s1 = in2[1]; + s2 = in2[2]; + s3 = in2[3]; + s4 = in2[4]; + + t[0] = ((uint128_t) r0) * s0; + t[1] = ((uint128_t) r0) * s1 + ((uint128_t) r1) * s0; + t[2] = ((uint128_t) r0) * s2 + ((uint128_t) r2) * s0 + ((uint128_t) r1) * s1; + t[3] = ((uint128_t) r0) * s3 + ((uint128_t) r3) * s0 + ((uint128_t) r1) * s2 + ((uint128_t) r2) * s1; + t[4] = ((uint128_t) r0) * s4 + ((uint128_t) r4) * s0 + ((uint128_t) r3) * s1 + ((uint128_t) r1) * s3 + ((uint128_t) r2) * s2; + + r4 *= 19; + r1 *= 19; + r2 *= 19; + r3 *= 19; + + t[0] += ((uint128_t) r4) * s1 + ((uint128_t) r1) * s4 + ((uint128_t) r2) * s3 + ((uint128_t) r3) * s2; + t[1] += ((uint128_t) r4) * s2 + ((uint128_t) r2) * s4 + ((uint128_t) r3) * s3; + t[2] += ((uint128_t) r4) * s3 + ((uint128_t) r3) * s4; + t[3] += ((uint128_t) r4) * s4; + + r0 = (limb)t[0] & 0x7ffffffffffff; c = (limb)(t[0] >> 51); + t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffff; c = (limb)(t[1] >> 51); + t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffff; c = (limb)(t[2] >> 51); + t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffff; c = (limb)(t[3] >> 51); + t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffff; c = (limb)(t[4] >> 51); + r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff; + r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff; + r2 += c; + + output[0] = r0; + output[1] = r1; + output[2] = r2; + output[3] = r3; + output[4] = r4; +} + +static inline void force_inline +fsquare_times(felem output, const felem in, limb count) { + uint128_t t[5]; + limb r0,r1,r2,r3,r4,c; + limb d0,d1,d2,d4,d419; + + r0 = in[0]; + r1 = in[1]; + r2 = in[2]; + r3 = in[3]; + r4 = in[4]; + + do { + d0 = r0 * 2; + d1 = r1 * 2; + d2 = r2 * 2 * 19; + d419 = r4 * 19; + d4 = d419 * 2; + + t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 )); + t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19)); + t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 )); + t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 )); + t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 )); + + r0 = (limb)t[0] & 0x7ffffffffffff; c = (limb)(t[0] >> 51); + t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffff; c = (limb)(t[1] >> 51); + t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffff; c = (limb)(t[2] >> 51); + t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffff; c = (limb)(t[3] >> 51); + t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffff; c = (limb)(t[4] >> 51); + r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffff; + r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffff; + r2 += c; + } while(--count); + + output[0] = r0; + output[1] = r1; + output[2] = r2; + output[3] = r3; + output[4] = r4; +} + +/* Load a little-endian 64-bit number */ +static limb +load_limb(const u8 *in) { + return + ((limb)in[0]) | + (((limb)in[1]) << 8) | + (((limb)in[2]) << 16) | + (((limb)in[3]) << 24) | + (((limb)in[4]) << 32) | + (((limb)in[5]) << 40) | + (((limb)in[6]) << 48) | + (((limb)in[7]) << 56); +} + +static void +store_limb(u8 *out, limb in) { + out[0] = in & 0xff; + out[1] = (in >> 8) & 0xff; + out[2] = (in >> 16) & 0xff; + out[3] = (in >> 24) & 0xff; + out[4] = (in >> 32) & 0xff; + out[5] = (in >> 40) & 0xff; + out[6] = (in >> 48) & 0xff; + out[7] = (in >> 56) & 0xff; +} + +/* Take a little-endian, 32-byte number and expand it into polynomial form */ +static void +fexpand(limb *output, const u8 *in) { + output[0] = load_limb(in) & 0x7ffffffffffff; + output[1] = (load_limb(in+6) >> 3) & 0x7ffffffffffff; + output[2] = (load_limb(in+12) >> 6) & 0x7ffffffffffff; + output[3] = (load_limb(in+19) >> 1) & 0x7ffffffffffff; + output[4] = (load_limb(in+24) >> 12) & 0x7ffffffffffff; +} + +/* Take a fully reduced polynomial form number and contract it into a + * little-endian, 32-byte array + */ +static void +fcontract(u8 *output, const felem input) { + uint128_t t[5]; + + t[0] = input[0]; + t[1] = input[1]; + t[2] = input[2]; + t[3] = input[3]; + t[4] = input[4]; + + t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff; + t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff; + t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff; + t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff; + t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff; + + t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff; + t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff; + t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff; + t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff; + t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff; + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + + t[0] += 19; + + t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff; + t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff; + t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff; + t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff; + t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffff; + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + + t[0] += 0x8000000000000 - 19; + t[1] += 0x8000000000000 - 1; + t[2] += 0x8000000000000 - 1; + t[3] += 0x8000000000000 - 1; + t[4] += 0x8000000000000 - 1; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + + t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffff; + t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffff; + t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffff; + t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffff; + t[4] &= 0x7ffffffffffff; + + store_limb(output, t[0] | (t[1] << 51)); + store_limb(output+8, (t[1] >> 13) | (t[2] << 38)); + store_limb(output+16, (t[2] >> 26) | (t[3] << 25)); + store_limb(output+24, (t[3] >> 39) | (t[4] << 12)); +} + +/* Input: Q, Q', Q-Q' + * Output: 2Q, Q+Q' + * + * x2 z3: long form + * x3 z3: long form + * x z: short form, destroyed + * xprime zprime: short form, destroyed + * qmqp: short form, preserved + */ +static void +fmonty(limb *x2, limb *z2, /* output 2Q */ + limb *x3, limb *z3, /* output Q + Q' */ + limb *x, limb *z, /* input Q */ + limb *xprime, limb *zprime, /* input Q' */ + const limb *qmqp /* input Q - Q' */) { + limb origx[5], origxprime[5], zzz[5], xx[5], zz[5], xxprime[5], + zzprime[5], zzzprime[5]; + + memcpy(origx, x, 5 * sizeof(limb)); + fsum(x, z); + fdifference_backwards(z, origx); // does x - z + + memcpy(origxprime, xprime, sizeof(limb) * 5); + fsum(xprime, zprime); + fdifference_backwards(zprime, origxprime); + fmul(xxprime, xprime, z); + fmul(zzprime, x, zprime); + memcpy(origxprime, xxprime, sizeof(limb) * 5); + fsum(xxprime, zzprime); + fdifference_backwards(zzprime, origxprime); + fsquare_times(x3, xxprime, 1); + fsquare_times(zzzprime, zzprime, 1); + fmul(z3, zzzprime, qmqp); + + fsquare_times(xx, x, 1); + fsquare_times(zz, z, 1); + fmul(x2, xx, zz); + fdifference_backwards(zz, xx); // does zz = xx - zz + fscalar_product(zzz, zz, 121665); + fsum(zzz, xx); + fmul(z2, zz, zzz); +} + +// ----------------------------------------------------------------------------- +// Maybe swap the contents of two limb arrays (@a and @b), each @len elements +// long. Perform the swap iff @swap is non-zero. +// +// This function performs the swap without leaking any side-channel +// information. +// ----------------------------------------------------------------------------- +static void +swap_conditional(limb a[5], limb b[5], limb iswap) { + unsigned i; + const limb swap = -iswap; + + for (i = 0; i < 5; ++i) { + const limb x = swap & (a[i] ^ b[i]); + a[i] ^= x; + b[i] ^= x; + } +} + +/* Calculates nQ where Q is the x-coordinate of a point on the curve + * + * resultx/resultz: the x coordinate of the resulting curve point (short form) + * n: a little endian, 32-byte number + * q: a point of the curve (short form) + */ +static void +cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) { + limb a[5] = {0}, b[5] = {1}, c[5] = {1}, d[5] = {0}; + limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; + limb e[5] = {0}, f[5] = {1}, g[5] = {0}, h[5] = {1}; + limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; + + unsigned i, j; + + memcpy(nqpqx, q, sizeof(limb) * 5); + + for (i = 0; i < 32; ++i) { + u8 byte = n[31 - i]; + for (j = 0; j < 8; ++j) { + const limb bit = byte >> 7; + + swap_conditional(nqx, nqpqx, bit); + swap_conditional(nqz, nqpqz, bit); + fmonty(nqx2, nqz2, + nqpqx2, nqpqz2, + nqx, nqz, + nqpqx, nqpqz, + q); + swap_conditional(nqx2, nqpqx2, bit); + swap_conditional(nqz2, nqpqz2, bit); + + t = nqx; + nqx = nqx2; + nqx2 = t; + t = nqz; + nqz = nqz2; + nqz2 = t; + t = nqpqx; + nqpqx = nqpqx2; + nqpqx2 = t; + t = nqpqz; + nqpqz = nqpqz2; + nqpqz2 = t; + + byte <<= 1; + } + } + + memcpy(resultx, nqx, sizeof(limb) * 5); + memcpy(resultz, nqz, sizeof(limb) * 5); +} + + +// ----------------------------------------------------------------------------- +// Shamelessly copied from djb's code, tightened a little +// ----------------------------------------------------------------------------- +static void +crecip(felem out, const felem z) { + felem a,t0,b,c; + + /* 2 */ fsquare_times(a, z, 1); // a = 2 + /* 8 */ fsquare_times(t0, a, 2); + /* 9 */ fmul(b, t0, z); // b = 9 + /* 11 */ fmul(a, b, a); // a = 11 + /* 22 */ fsquare_times(t0, a, 1); + /* 2^5 - 2^0 = 31 */ fmul(b, t0, b); + /* 2^10 - 2^5 */ fsquare_times(t0, b, 5); + /* 2^10 - 2^0 */ fmul(b, t0, b); + /* 2^20 - 2^10 */ fsquare_times(t0, b, 10); + /* 2^20 - 2^0 */ fmul(c, t0, b); + /* 2^40 - 2^20 */ fsquare_times(t0, c, 20); + /* 2^40 - 2^0 */ fmul(t0, t0, c); + /* 2^50 - 2^10 */ fsquare_times(t0, t0, 10); + /* 2^50 - 2^0 */ fmul(b, t0, b); + /* 2^100 - 2^50 */ fsquare_times(t0, b, 50); + /* 2^100 - 2^0 */ fmul(c, t0, b); + /* 2^200 - 2^100 */ fsquare_times(t0, c, 100); + /* 2^200 - 2^0 */ fmul(t0, t0, c); + /* 2^250 - 2^50 */ fsquare_times(t0, t0, 50); + /* 2^250 - 2^0 */ fmul(t0, t0, b); + /* 2^255 - 2^5 */ fsquare_times(t0, t0, 5); + /* 2^255 - 21 */ fmul(out, t0, a); +} + +int curve25519_donna(u8 *, const u8 *, const u8 *); + +int +curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) { + limb bp[5], x[5], z[5], zmone[5]; + uint8_t e[32]; + int i; + + for (i = 0;i < 32;++i) e[i] = secret[i]; + e[0] &= 248; + e[31] &= 127; + e[31] |= 64; + + fexpand(bp, basepoint); + cmult(x, z, e, bp); + crecip(zmone, z); + fmul(z, x, zmone); + fcontract(mypublic, z); + return 0; +} diff --git a/src/crypto-curve25519.h b/src/crypto-curve25519.h new file mode 100644 index 00000000..7f72b8a6 --- /dev/null +++ b/src/crypto-curve25519.h @@ -0,0 +1,7 @@ +#ifndef CRYPTO_X25519_H +#define CRYPTO_X25519_H +#include + +int curve25519_donna(unsigned char *mypublic, const unsigned char *secret, const unsigned char *basepoint); + +#endif diff --git a/src/crypto-rfc6234.c b/src/crypto-rfc6234.c new file mode 100644 index 00000000..cff046f8 --- /dev/null +++ b/src/crypto-rfc6234.c @@ -0,0 +1,2775 @@ +/***************** See RFC 6234 for details. *******************/ +/* Copyright (c) 2011 IETF Trust and the persons identified as */ +/* authors of the code. All rights reserved. */ +/* See crypto-rfc2634.h for terms of use and redistribution. */ + +/* + * This is a concatenation of all the .c files included in + * RFC6234: https://www.rfc-editor.org/rfc/rfc6234 + * + * This implements most of the crypto required to compute the + * various keys in TLS: + * - TLS 1.1: SHA-1 + * - TLS 1.2: SHA-256/SHA-384 + * - TLS 1.3: SHA-384 + HKDF + */ + +#include "crypto-rfc6234.h" +#include +#include + +/*****************************************************************/ +/*****************************************************************/ +/*****************************************************************/ + +#ifdef USE_32BIT_ONLY +/* + * Define 64-bit arithmetic in terms of 32-bit arithmetic. + * Each 64-bit number is represented in a 2-word array. + * All macros are defined such that the result is the last parameter. + */ + +/* + * Define shift, rotate left, and rotate right functions + */ +#define SHA512_SHR(bits, word, ret) ( \ + /* (((uint64_t)((word))) >> (bits)) */ \ + (ret)[0] = (((bits) < 32) && ((bits) >= 0)) ? \ + ((word)[0] >> (bits)) : 0, \ + (ret)[1] = ((bits) > 32) ? ((word)[0] >> ((bits) - 32)) : \ + ((bits) == 32) ? (word)[0] : \ + ((bits) >= 0) ? \ + (((word)[0] << (32 - (bits))) | \ + ((word)[1] >> (bits))) : 0 ) + +#define SHA512_SHL(bits, word, ret) ( \ + /* (((uint64_t)(word)) << (bits)) */ \ + (ret)[0] = ((bits) > 32) ? ((word)[1] << ((bits) - 32)) : \ + ((bits) == 32) ? (word)[1] : \ + ((bits) >= 0) ? \ + (((word)[0] << (bits)) | \ + ((word)[1] >> (32 - (bits)))) : \ + 0, \ + (ret)[1] = (((bits) < 32) && ((bits) >= 0)) ? \ + ((word)[1] << (bits)) : 0 ) + +/* + * Define 64-bit OR + */ +#define SHA512_OR(word1, word2, ret) ( \ + (ret)[0] = (word1)[0] | (word2)[0], \ + (ret)[1] = (word1)[1] | (word2)[1] ) + +/* + * Define 64-bit XOR + */ +#define SHA512_XOR(word1, word2, ret) ( \ + (ret)[0] = (word1)[0] ^ (word2)[0], \ + (ret)[1] = (word1)[1] ^ (word2)[1] ) + +/* + * Define 64-bit AND + */ +#define SHA512_AND(word1, word2, ret) ( \ + (ret)[0] = (word1)[0] & (word2)[0], \ + (ret)[1] = (word1)[1] & (word2)[1] ) + +/* + * Define 64-bit TILDA + */ +#define SHA512_TILDA(word, ret) \ + ( (ret)[0] = ~(word)[0], (ret)[1] = ~(word)[1] ) + +/* + * Define 64-bit ADD + */ +#define SHA512_ADD(word1, word2, ret) ( \ + (ret)[1] = (word1)[1], (ret)[1] += (word2)[1], \ + (ret)[0] = (word1)[0] + (word2)[0] + ((ret)[1] < (word1)[1]) ) + +/* + * Add the 4word value in word2 to word1. + */ +static uint32_t ADDTO4_temp, ADDTO4_temp2; +#define SHA512_ADDTO4(word1, word2) ( \ + ADDTO4_temp = (word1)[3], \ + (word1)[3] += (word2)[3], \ + ADDTO4_temp2 = (word1)[2], \ + (word1)[2] += (word2)[2] + ((word1)[3] < ADDTO4_temp), \ + ADDTO4_temp = (word1)[1], \ + (word1)[1] += (word2)[1] + ((word1)[2] < ADDTO4_temp2), \ + (word1)[0] += (word2)[0] + ((word1)[1] < ADDTO4_temp) ) + +/* + * Add the 2word value in word2 to word1. + */ +static uint32_t ADDTO2_temp; +#define SHA512_ADDTO2(word1, word2) ( \ + ADDTO2_temp = (word1)[1], \ + (word1)[1] += (word2)[1], \ + (word1)[0] += (word2)[0] + ((word1)[1] < ADDTO2_temp) ) + +/* + * SHA rotate ((word >> bits) | (word << (64-bits))) + */ +static uint32_t ROTR_temp1[2], ROTR_temp2[2]; +#define SHA512_ROTR(bits, word, ret) ( \ + SHA512_SHR((bits), (word), ROTR_temp1), \ + SHA512_SHL(64-(bits), (word), ROTR_temp2), \ + SHA512_OR(ROTR_temp1, ROTR_temp2, (ret)) ) + +/* + * Define the SHA SIGMA and sigma macros + * + * SHA512_ROTR(28,word) ^ SHA512_ROTR(34,word) ^ SHA512_ROTR(39,word) + */ +static uint32_t SIGMA0_temp1[2], SIGMA0_temp2[2], + SIGMA0_temp3[2], SIGMA0_temp4[2]; +#define SHA512_SIGMA0(word, ret) ( \ + SHA512_ROTR(28, (word), SIGMA0_temp1), \ + SHA512_ROTR(34, (word), SIGMA0_temp2), \ + SHA512_ROTR(39, (word), SIGMA0_temp3), \ + SHA512_XOR(SIGMA0_temp2, SIGMA0_temp3, SIGMA0_temp4), \ + SHA512_XOR(SIGMA0_temp1, SIGMA0_temp4, (ret)) ) + +/* + * SHA512_ROTR(14,word) ^ SHA512_ROTR(18,word) ^ SHA512_ROTR(41,word) + */ +static uint32_t SIGMA1_temp1[2], SIGMA1_temp2[2], + SIGMA1_temp3[2], SIGMA1_temp4[2]; +#define SHA512_SIGMA1(word, ret) ( \ + SHA512_ROTR(14, (word), SIGMA1_temp1), \ + SHA512_ROTR(18, (word), SIGMA1_temp2), \ + SHA512_ROTR(41, (word), SIGMA1_temp3), \ + SHA512_XOR(SIGMA1_temp2, SIGMA1_temp3, SIGMA1_temp4), \ + SHA512_XOR(SIGMA1_temp1, SIGMA1_temp4, (ret)) ) + +/* + * (SHA512_ROTR( 1,word) ^ SHA512_ROTR( 8,word) ^ SHA512_SHR( 7,word)) + */ +static uint32_t sigma0_temp1[2], sigma0_temp2[2], + sigma0_temp3[2], sigma0_temp4[2]; +#define SHA512_sigma0(word, ret) ( \ + SHA512_ROTR( 1, (word), sigma0_temp1), \ + SHA512_ROTR( 8, (word), sigma0_temp2), \ + SHA512_SHR( 7, (word), sigma0_temp3), \ + SHA512_XOR(sigma0_temp2, sigma0_temp3, sigma0_temp4), \ + SHA512_XOR(sigma0_temp1, sigma0_temp4, (ret)) ) + +/* + * (SHA512_ROTR(19,word) ^ SHA512_ROTR(61,word) ^ SHA512_SHR( 6,word)) + */ +static uint32_t sigma1_temp1[2], sigma1_temp2[2], + sigma1_temp3[2], sigma1_temp4[2]; +#define SHA512_sigma1(word, ret) ( \ + SHA512_ROTR(19, (word), sigma1_temp1), \ + SHA512_ROTR(61, (word), sigma1_temp2), \ + SHA512_SHR( 6, (word), sigma1_temp3), \ + SHA512_XOR(sigma1_temp2, sigma1_temp3, sigma1_temp4), \ + SHA512_XOR(sigma1_temp1, sigma1_temp4, (ret)) ) + +#ifndef USE_MODIFIED_MACROS +/* + * These definitions are the ones used in FIPS 180-3, section 4.1.3 + * Ch(x,y,z) ((x & y) ^ (~x & z)) + */ +static uint32_t Ch_temp1[2], Ch_temp2[2], Ch_temp3[2]; +#define SHA_Ch(x, y, z, ret) ( \ + SHA512_AND(x, y, Ch_temp1), \ + SHA512_TILDA(x, Ch_temp2), \ + SHA512_AND(Ch_temp2, z, Ch_temp3), \ + SHA512_XOR(Ch_temp1, Ch_temp3, (ret)) ) + +/* + * Maj(x,y,z) (((x)&(y)) ^ ((x)&(z)) ^ ((y)&(z))) + */ +static uint32_t Maj_temp1[2], Maj_temp2[2], + Maj_temp3[2], Maj_temp4[2]; +#define SHA_Maj(x, y, z, ret) ( \ + SHA512_AND(x, y, Maj_temp1), \ + SHA512_AND(x, z, Maj_temp2), \ + SHA512_AND(y, z, Maj_temp3), \ + SHA512_XOR(Maj_temp2, Maj_temp3, Maj_temp4), \ + SHA512_XOR(Maj_temp1, Maj_temp4, (ret)) ) +#else /* !USE_MODIFIED_MACROS */ +/* + * These definitions are potentially faster equivalents for the ones + * used in FIPS 180-3, section 4.1.3. + * ((x & y) ^ (~x & z)) becomes + * ((x & (y ^ z)) ^ z) + */ +#define SHA_Ch(x, y, z, ret) ( \ + (ret)[0] = (((x)[0] & ((y)[0] ^ (z)[0])) ^ (z)[0]), \ + (ret)[1] = (((x)[1] & ((y)[1] ^ (z)[1])) ^ (z)[1]) ) + +/* + * ((x & y) ^ (x & z) ^ (y & z)) becomes + * ((x & (y | z)) | (y & z)) + */ +#define SHA_Maj(x, y, z, ret) ( \ + ret[0] = (((x)[0] & ((y)[0] | (z)[0])) | ((y)[0] & (z)[0])), \ + ret[1] = (((x)[1] & ((y)[1] | (z)[1])) | ((y)[1] & (z)[1])) ) +#endif /* USE_MODIFIED_MACROS */ + +/* + * Add "length" to the length. + * Set Corrupted when overflow has occurred. + */ +static uint32_t addTemp[4] = { 0, 0, 0, 0 }; +#define SHA384_512AddLength(context, length) ( \ + addTemp[3] = (length), SHA512_ADDTO4((context)->Length, addTemp), \ + (context)->Corrupted = (((context)->Length[3] < (length)) && \ + ((context)->Length[2] == 0) && ((context)->Length[1] == 0) && \ + ((context)->Length[0] == 0)) ? shaInputTooLong : \ + (context)->Corrupted ) + +/* Local Function Prototypes */ +static int SHA384_512Reset(SHA512Context *context, + uint32_t H0[SHA512HashSize/4]); +static void SHA384_512ProcessMessageBlock(SHA512Context *context); +static void SHA384_512Finalize(SHA512Context *context, + uint8_t Pad_Byte); +static void SHA384_512PadMessage(SHA512Context *context, + uint8_t Pad_Byte); +static int SHA384_512ResultN( SHA512Context *context, + uint8_t Message_Digest[ ], int HashSize); + +/* Initial Hash Values: FIPS 180-3 sections 5.3.4 and 5.3.5 */ +static uint32_t SHA384_H0[SHA512HashSize/4] = { + 0xCBBB9D5D, 0xC1059ED8, 0x629A292A, 0x367CD507, 0x9159015A, + 0x3070DD17, 0x152FECD8, 0xF70E5939, 0x67332667, 0xFFC00B31, + 0x8EB44A87, 0x68581511, 0xDB0C2E0D, 0x64F98FA7, 0x47B5481D, + 0xBEFA4FA4 +}; +static uint32_t SHA512_H0[SHA512HashSize/4] = { + 0x6A09E667, 0xF3BCC908, 0xBB67AE85, 0x84CAA73B, 0x3C6EF372, + 0xFE94F82B, 0xA54FF53A, 0x5F1D36F1, 0x510E527F, 0xADE682D1, + 0x9B05688C, 0x2B3E6C1F, 0x1F83D9AB, 0xFB41BD6B, 0x5BE0CD19, + 0x137E2179 +}; + +#else /* !USE_32BIT_ONLY */ + +/* + * These definitions are defined in FIPS 180-3, section 4.1. + * Ch() and Maj() are defined identically in sections 4.1.1, + * 4.1.2, and 4.1.3. + * + * The definitions used in FIPS 180-3 are as follows: + */ + +#ifndef USE_MODIFIED_MACROS +#define SHA_Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define SHA_Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#else /* USE_MODIFIED_MACROS */ +/* + * The following definitions are equivalent and potentially faster. + */ + +#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z)) +#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) + +#endif /* USE_MODIFIED_MACROS */ + +#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z)) + +/* Define the SHA shift, rotate left and rotate right macros */ +#define SHA512_SHR(bits,word) (((uint64_t)(word)) >> (bits)) +#define SHA512_ROTR(bits,word) ((((uint64_t)(word)) >> (bits)) | \ + (((uint64_t)(word)) << (64-(bits)))) + +/* + * Define the SHA SIGMA and sigma macros + * + * SHA512_ROTR(28,word) ^ SHA512_ROTR(34,word) ^ SHA512_ROTR(39,word) + */ +#define SHA512_SIGMA0(word) \ + (SHA512_ROTR(28,word) ^ SHA512_ROTR(34,word) ^ SHA512_ROTR(39,word)) +#define SHA512_SIGMA1(word) \ + (SHA512_ROTR(14,word) ^ SHA512_ROTR(18,word) ^ SHA512_ROTR(41,word)) +#define SHA512_sigma0(word) \ + (SHA512_ROTR( 1,word) ^ SHA512_ROTR( 8,word) ^ SHA512_SHR( 7,word)) +#define SHA512_sigma1(word) \ + (SHA512_ROTR(19,word) ^ SHA512_ROTR(61,word) ^ SHA512_SHR( 6,word)) + +/* + * Add "length" to the length. + * Set Corrupted when overflow has occurred. + */ +static unsigned int addTemp; +#define SHA384_512AddLength(context, length) \ + (addTemp = context->Length_Low, context->Corrupted = \ + ((context->Length_Low += length) < addTemp) && \ + (++context->Length_High == 0) ? shaInputTooLong : \ + (context)->Corrupted) + +/* Local Function Prototypes */ +static int SHA384_512Reset(SHA512Context *context, + uint64_t H0[SHA512HashSize/8]); +static void SHA384_512ProcessMessageBlock(SHA512Context *context); +static void SHA384_512Finalize(SHA512Context *context, + uint8_t Pad_Byte); +static void SHA384_512PadMessage(SHA512Context *context, + uint8_t Pad_Byte); +static int SHA384_512ResultN(SHA512Context *context, + uint8_t Message_Digest[ ], int HashSize); + +/* Initial Hash Values: FIPS 180-3 sections 5.3.4 and 5.3.5 */ +static uint64_t SHA384_H0[ ] = { + 0xCBBB9D5DC1059ED8ll, 0x629A292A367CD507ll, 0x9159015A3070DD17ll, + 0x152FECD8F70E5939ll, 0x67332667FFC00B31ll, 0x8EB44A8768581511ll, + 0xDB0C2E0D64F98FA7ll, 0x47B5481DBEFA4FA4ll +}; +static uint64_t SHA512_H0[ ] = { + 0x6A09E667F3BCC908ll, 0xBB67AE8584CAA73Bll, 0x3C6EF372FE94F82Bll, + 0xA54FF53A5F1D36F1ll, 0x510E527FADE682D1ll, 0x9B05688C2B3E6C1Fll, + 0x1F83D9ABFB41BD6Bll, 0x5BE0CD19137E2179ll +}; + +#endif /* USE_32BIT_ONLY */ + +/* + * SHA384Reset + * + * Description: + * This function will initialize the SHA384Context in preparation + * for computing a new SHA384 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int SHA384Reset(SHA384Context *context) +{ + return SHA384_512Reset(context, SHA384_H0); +} + +/* + * SHA384Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_array[ ]: [in] + * An array of octets representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array. + * + * Returns: + * sha Error Code. + * + */ +int SHA384Input(SHA384Context *context, + const uint8_t *message_array, unsigned int length) +{ + return SHA512Input(context, message_array, length); +} + +/* + * SHA384FinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + * + */ +int SHA384FinalBits(SHA384Context *context, + uint8_t message_bits, unsigned int length) +{ + return SHA512FinalBits(context, message_bits, length); +} + +/* + * SHA384Result + * + * Description: + * This function will return the 384-bit message digest + * into the Message_Digest array provided by the caller. + * NOTE: + * The first octet of hash is stored in the element with index 0, + * the last octet of hash in the element with index 47. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA hash. + * Message_Digest[ ]: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int SHA384Result(SHA384Context *context, + uint8_t Message_Digest[SHA384HashSize]) +{ + return SHA384_512ResultN(context, Message_Digest, SHA384HashSize); +} + +/* + * SHA512Reset + * + * Description: + * This function will initialize the SHA512Context in preparation + * for computing a new SHA512 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int SHA512Reset(SHA512Context *context) +{ + return SHA384_512Reset(context, SHA512_H0); +} + +/* + * SHA512Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_array[ ]: [in] + * An array of octets representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array. + * + * Returns: + * sha Error Code. + * + */ +int SHA512Input(SHA512Context *context, + const uint8_t *message_array, + unsigned int length) +{ + if (!context) return shaNull; + if (!length) return shaSuccess; + if (!message_array) return shaNull; + if (context->Computed) return context->Corrupted = shaStateError; + if (context->Corrupted) return context->Corrupted; + + while (length--) { + context->Message_Block[context->Message_Block_Index++] = + *message_array; + + if ((SHA384_512AddLength(context, 8) == shaSuccess) && + (context->Message_Block_Index == SHA512_Message_Block_Size)) + SHA384_512ProcessMessageBlock(context); + + message_array++; + } + + return context->Corrupted; +} + +/* + * SHA512FinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + * + */ +int SHA512FinalBits(SHA512Context *context, + uint8_t message_bits, unsigned int length) +{ + static uint8_t masks[8] = { + /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, + /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, + /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, + /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE + }; + static uint8_t markbit[8] = { + /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, + /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, + /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, + /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 + }; + + if (!context) return shaNull; + if (!length) return shaSuccess; + if (context->Corrupted) return context->Corrupted; + if (context->Computed) return context->Corrupted = shaStateError; + if (length >= 8) return context->Corrupted = shaBadParam; + + SHA384_512AddLength(context, length); + SHA384_512Finalize(context, (uint8_t) + ((message_bits & masks[length]) | markbit[length])); + + return context->Corrupted; +} + +/* + * SHA512Result + * + * Description: + * This function will return the 512-bit message digest + * into the Message_Digest array provided by the caller. + * NOTE: + * The first octet of hash is stored in the element with index 0, + * the last octet of hash in the element with index 63. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA hash. + * Message_Digest[ ]: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int SHA512Result(SHA512Context *context, + uint8_t Message_Digest[SHA512HashSize]) +{ + return SHA384_512ResultN(context, Message_Digest, SHA512HashSize); +} + +/* + * SHA384_512Reset + * + * Description: + * This helper function will initialize the SHA512Context in + * preparation for computing a new SHA384 or SHA512 message + * digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * H0[ ]: [in] + * The initial hash value array to use. + * + * Returns: + * sha Error Code. + * + */ +#ifdef USE_32BIT_ONLY +static int SHA384_512Reset(SHA512Context *context, + uint32_t H0[SHA512HashSize/4]) +#else /* !USE_32BIT_ONLY */ +static int SHA384_512Reset(SHA512Context *context, + uint64_t H0[SHA512HashSize/8]) +#endif /* USE_32BIT_ONLY */ +{ + int i; + if (!context) return shaNull; + context->Message_Block_Index = 0; + +#ifdef USE_32BIT_ONLY + context->Length[0] = context->Length[1] = + context->Length[2] = context->Length[3] = 0; + + for (i = 0; i < SHA512HashSize/4; i++) + context->Intermediate_Hash[i] = H0[i]; +#else /* !USE_32BIT_ONLY */ + context->Length_High = context->Length_Low = 0; + + for (i = 0; i < SHA512HashSize/8; i++) + context->Intermediate_Hash[i] = H0[i]; +#endif /* USE_32BIT_ONLY */ + + context->Computed = 0; + context->Corrupted = shaSuccess; + + return shaSuccess; +} + +/* + * SHA384_512ProcessMessageBlock + * + * Description: + * This helper function will process the next 1024 bits of the + * message stored in the Message_Block array. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * + * Returns: + * Nothing. + * + * Comments: + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the Secure Hash Standard. + * + * + */ +static void SHA384_512ProcessMessageBlock(SHA512Context *context) +{ +#ifdef USE_32BIT_ONLY + /* Constants defined in FIPS 180-3, section 4.2.3 */ + static const uint32_t K[80*2] = { + 0x428A2F98, 0xD728AE22, 0x71374491, 0x23EF65CD, 0xB5C0FBCF, + 0xEC4D3B2F, 0xE9B5DBA5, 0x8189DBBC, 0x3956C25B, 0xF348B538, + 0x59F111F1, 0xB605D019, 0x923F82A4, 0xAF194F9B, 0xAB1C5ED5, + 0xDA6D8118, 0xD807AA98, 0xA3030242, 0x12835B01, 0x45706FBE, + 0x243185BE, 0x4EE4B28C, 0x550C7DC3, 0xD5FFB4E2, 0x72BE5D74, + 0xF27B896F, 0x80DEB1FE, 0x3B1696B1, 0x9BDC06A7, 0x25C71235, + 0xC19BF174, 0xCF692694, 0xE49B69C1, 0x9EF14AD2, 0xEFBE4786, + 0x384F25E3, 0x0FC19DC6, 0x8B8CD5B5, 0x240CA1CC, 0x77AC9C65, + 0x2DE92C6F, 0x592B0275, 0x4A7484AA, 0x6EA6E483, 0x5CB0A9DC, + 0xBD41FBD4, 0x76F988DA, 0x831153B5, 0x983E5152, 0xEE66DFAB, + 0xA831C66D, 0x2DB43210, 0xB00327C8, 0x98FB213F, 0xBF597FC7, + 0xBEEF0EE4, 0xC6E00BF3, 0x3DA88FC2, 0xD5A79147, 0x930AA725, + 0x06CA6351, 0xE003826F, 0x14292967, 0x0A0E6E70, 0x27B70A85, + 0x46D22FFC, 0x2E1B2138, 0x5C26C926, 0x4D2C6DFC, 0x5AC42AED, + 0x53380D13, 0x9D95B3DF, 0x650A7354, 0x8BAF63DE, 0x766A0ABB, + 0x3C77B2A8, 0x81C2C92E, 0x47EDAEE6, 0x92722C85, 0x1482353B, + 0xA2BFE8A1, 0x4CF10364, 0xA81A664B, 0xBC423001, 0xC24B8B70, + 0xD0F89791, 0xC76C51A3, 0x0654BE30, 0xD192E819, 0xD6EF5218, + 0xD6990624, 0x5565A910, 0xF40E3585, 0x5771202A, 0x106AA070, + 0x32BBD1B8, 0x19A4C116, 0xB8D2D0C8, 0x1E376C08, 0x5141AB53, + 0x2748774C, 0xDF8EEB99, 0x34B0BCB5, 0xE19B48A8, 0x391C0CB3, + 0xC5C95A63, 0x4ED8AA4A, 0xE3418ACB, 0x5B9CCA4F, 0x7763E373, + 0x682E6FF3, 0xD6B2B8A3, 0x748F82EE, 0x5DEFB2FC, 0x78A5636F, + 0x43172F60, 0x84C87814, 0xA1F0AB72, 0x8CC70208, 0x1A6439EC, + 0x90BEFFFA, 0x23631E28, 0xA4506CEB, 0xDE82BDE9, 0xBEF9A3F7, + 0xB2C67915, 0xC67178F2, 0xE372532B, 0xCA273ECE, 0xEA26619C, + 0xD186B8C7, 0x21C0C207, 0xEADA7DD6, 0xCDE0EB1E, 0xF57D4F7F, + 0xEE6ED178, 0x06F067AA, 0x72176FBA, 0x0A637DC5, 0xA2C898A6, + 0x113F9804, 0xBEF90DAE, 0x1B710B35, 0x131C471B, 0x28DB77F5, + 0x23047D84, 0x32CAAB7B, 0x40C72493, 0x3C9EBE0A, 0x15C9BEBC, + 0x431D67C4, 0x9C100D4C, 0x4CC5D4BE, 0xCB3E42B6, 0x597F299C, + 0xFC657E2A, 0x5FCB6FAB, 0x3AD6FAEC, 0x6C44198C, 0x4A475817 + }; + int t, t2, t8; /* Loop counter */ + uint32_t temp1[2], temp2[2], /* Temporary word values */ + temp3[2], temp4[2], temp5[2]; + uint32_t W[2*80]; /* Word sequence */ + uint32_t A[2], B[2], C[2], D[2], /* Word buffers */ + E[2], F[2], G[2], H[2]; + + /* Initialize the first 16 words in the array W */ + for (t = t2 = t8 = 0; t < 16; t++, t8 += 8) { + W[t2++] = ((((uint32_t)context->Message_Block[t8 ])) << 24) | + ((((uint32_t)context->Message_Block[t8 + 1])) << 16) | + ((((uint32_t)context->Message_Block[t8 + 2])) << 8) | + ((((uint32_t)context->Message_Block[t8 + 3]))); + W[t2++] = ((((uint32_t)context->Message_Block[t8 + 4])) << 24) | + ((((uint32_t)context->Message_Block[t8 + 5])) << 16) | + ((((uint32_t)context->Message_Block[t8 + 6])) << 8) | + ((((uint32_t)context->Message_Block[t8 + 7]))); + } + + for (t = 16; t < 80; t++, t2 += 2) { + /* W[t] = SHA512_sigma1(W[t-2]) + W[t-7] + + SHA512_sigma0(W[t-15]) + W[t-16]; */ + uint32_t *Wt2 = &W[t2-2*2]; + uint32_t *Wt7 = &W[t2-7*2]; + uint32_t *Wt15 = &W[t2-15*2]; + uint32_t *Wt16 = &W[t2-16*2]; + SHA512_sigma1(Wt2, temp1); + SHA512_ADD(temp1, Wt7, temp2); + SHA512_sigma0(Wt15, temp1); + SHA512_ADD(temp1, Wt16, temp3); + SHA512_ADD(temp2, temp3, &W[t2]); + } + + A[0] = context->Intermediate_Hash[0]; + A[1] = context->Intermediate_Hash[1]; + B[0] = context->Intermediate_Hash[2]; + B[1] = context->Intermediate_Hash[3]; + C[0] = context->Intermediate_Hash[4]; + C[1] = context->Intermediate_Hash[5]; + D[0] = context->Intermediate_Hash[6]; + D[1] = context->Intermediate_Hash[7]; + E[0] = context->Intermediate_Hash[8]; + E[1] = context->Intermediate_Hash[9]; + F[0] = context->Intermediate_Hash[10]; + F[1] = context->Intermediate_Hash[11]; + G[0] = context->Intermediate_Hash[12]; + G[1] = context->Intermediate_Hash[13]; + H[0] = context->Intermediate_Hash[14]; + H[1] = context->Intermediate_Hash[15]; + + for (t = t2 = 0; t < 80; t++, t2 += 2) { + /* + * temp1 = H + SHA512_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t]; + */ + SHA512_SIGMA1(E,temp1); + SHA512_ADD(H, temp1, temp2); + SHA_Ch(E,F,G,temp3); + SHA512_ADD(temp2, temp3, temp4); + SHA512_ADD(&K[t2], &W[t2], temp5); + SHA512_ADD(temp4, temp5, temp1); + /* + * temp2 = SHA512_SIGMA0(A) + SHA_Maj(A,B,C); + */ + SHA512_SIGMA0(A,temp3); + SHA_Maj(A,B,C,temp4); + SHA512_ADD(temp3, temp4, temp2); + H[0] = G[0]; H[1] = G[1]; + G[0] = F[0]; G[1] = F[1]; + F[0] = E[0]; F[1] = E[1]; + SHA512_ADD(D, temp1, E); + D[0] = C[0]; D[1] = C[1]; + C[0] = B[0]; C[1] = B[1]; + B[0] = A[0]; B[1] = A[1]; + SHA512_ADD(temp1, temp2, A); + } + + SHA512_ADDTO2(&context->Intermediate_Hash[0], A); + SHA512_ADDTO2(&context->Intermediate_Hash[2], B); + SHA512_ADDTO2(&context->Intermediate_Hash[4], C); + SHA512_ADDTO2(&context->Intermediate_Hash[6], D); + SHA512_ADDTO2(&context->Intermediate_Hash[8], E); + SHA512_ADDTO2(&context->Intermediate_Hash[10], F); + SHA512_ADDTO2(&context->Intermediate_Hash[12], G); + SHA512_ADDTO2(&context->Intermediate_Hash[14], H); + +#else /* !USE_32BIT_ONLY */ + /* Constants defined in FIPS 180-3, section 4.2.3 */ + static const uint64_t K[80] = { + 0x428A2F98D728AE22ll, 0x7137449123EF65CDll, 0xB5C0FBCFEC4D3B2Fll, + 0xE9B5DBA58189DBBCll, 0x3956C25BF348B538ll, 0x59F111F1B605D019ll, + 0x923F82A4AF194F9Bll, 0xAB1C5ED5DA6D8118ll, 0xD807AA98A3030242ll, + 0x12835B0145706FBEll, 0x243185BE4EE4B28Cll, 0x550C7DC3D5FFB4E2ll, + 0x72BE5D74F27B896Fll, 0x80DEB1FE3B1696B1ll, 0x9BDC06A725C71235ll, + 0xC19BF174CF692694ll, 0xE49B69C19EF14AD2ll, 0xEFBE4786384F25E3ll, + 0x0FC19DC68B8CD5B5ll, 0x240CA1CC77AC9C65ll, 0x2DE92C6F592B0275ll, + 0x4A7484AA6EA6E483ll, 0x5CB0A9DCBD41FBD4ll, 0x76F988DA831153B5ll, + 0x983E5152EE66DFABll, 0xA831C66D2DB43210ll, 0xB00327C898FB213Fll, + 0xBF597FC7BEEF0EE4ll, 0xC6E00BF33DA88FC2ll, 0xD5A79147930AA725ll, + 0x06CA6351E003826Fll, 0x142929670A0E6E70ll, 0x27B70A8546D22FFCll, + 0x2E1B21385C26C926ll, 0x4D2C6DFC5AC42AEDll, 0x53380D139D95B3DFll, + 0x650A73548BAF63DEll, 0x766A0ABB3C77B2A8ll, 0x81C2C92E47EDAEE6ll, + 0x92722C851482353Bll, 0xA2BFE8A14CF10364ll, 0xA81A664BBC423001ll, + 0xC24B8B70D0F89791ll, 0xC76C51A30654BE30ll, 0xD192E819D6EF5218ll, + 0xD69906245565A910ll, 0xF40E35855771202All, 0x106AA07032BBD1B8ll, + 0x19A4C116B8D2D0C8ll, 0x1E376C085141AB53ll, 0x2748774CDF8EEB99ll, + 0x34B0BCB5E19B48A8ll, 0x391C0CB3C5C95A63ll, 0x4ED8AA4AE3418ACBll, + 0x5B9CCA4F7763E373ll, 0x682E6FF3D6B2B8A3ll, 0x748F82EE5DEFB2FCll, + 0x78A5636F43172F60ll, 0x84C87814A1F0AB72ll, 0x8CC702081A6439ECll, + 0x90BEFFFA23631E28ll, 0xA4506CEBDE82BDE9ll, 0xBEF9A3F7B2C67915ll, + 0xC67178F2E372532Bll, 0xCA273ECEEA26619Cll, 0xD186B8C721C0C207ll, + 0xEADA7DD6CDE0EB1Ell, 0xF57D4F7FEE6ED178ll, 0x06F067AA72176FBAll, + 0x0A637DC5A2C898A6ll, 0x113F9804BEF90DAEll, 0x1B710B35131C471Bll, + 0x28DB77F523047D84ll, 0x32CAAB7B40C72493ll, 0x3C9EBE0A15C9BEBCll, + 0x431D67C49C100D4Cll, 0x4CC5D4BECB3E42B6ll, 0x597F299CFC657E2All, + 0x5FCB6FAB3AD6FAECll, 0x6C44198C4A475817ll + }; + int t, t8; /* Loop counter */ + uint64_t temp1, temp2; /* Temporary word value */ + uint64_t W[80]; /* Word sequence */ + uint64_t A, B, C, D, E, F, G, H; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for (t = t8 = 0; t < 16; t++, t8 += 8) + W[t] = ((uint64_t)(context->Message_Block[t8 ]) << 56) | + ((uint64_t)(context->Message_Block[t8 + 1]) << 48) | + ((uint64_t)(context->Message_Block[t8 + 2]) << 40) | + ((uint64_t)(context->Message_Block[t8 + 3]) << 32) | + ((uint64_t)(context->Message_Block[t8 + 4]) << 24) | + ((uint64_t)(context->Message_Block[t8 + 5]) << 16) | + ((uint64_t)(context->Message_Block[t8 + 6]) << 8) | + ((uint64_t)(context->Message_Block[t8 + 7])); + + for (t = 16; t < 80; t++) + W[t] = SHA512_sigma1(W[t-2]) + W[t-7] + + SHA512_sigma0(W[t-15]) + W[t-16]; + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + F = context->Intermediate_Hash[5]; + G = context->Intermediate_Hash[6]; + H = context->Intermediate_Hash[7]; + + for (t = 0; t < 80; t++) { + temp1 = H + SHA512_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t]; + temp2 = SHA512_SIGMA0(A) + SHA_Maj(A,B,C); + H = G; + G = F; + F = E; + E = D + temp1; + D = C; + C = B; + B = A; + A = temp1 + temp2; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + context->Intermediate_Hash[5] += F; + context->Intermediate_Hash[6] += G; + context->Intermediate_Hash[7] += H; +#endif /* USE_32BIT_ONLY */ + + context->Message_Block_Index = 0; +} + +/* + * SHA384_512Finalize + * + * Description: + * This helper function finishes off the digest calculations. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * Pad_Byte: [in] + * The last byte to add to the message block before the 0-padding + * and length. This will contain the last bits of the message + * followed by another single bit. If the message was an + * exact multiple of 8-bits long, Pad_Byte will be 0x80. + * + * Returns: + * sha Error Code. + * + */ +static void SHA384_512Finalize(SHA512Context *context, + uint8_t Pad_Byte) +{ + int_least16_t i; + SHA384_512PadMessage(context, Pad_Byte); + /* message may be sensitive, clear it out */ + for (i = 0; i < SHA512_Message_Block_Size; ++i) + context->Message_Block[i] = 0; +#ifdef USE_32BIT_ONLY /* and clear length */ + context->Length[0] = context->Length[1] = 0; + context->Length[2] = context->Length[3] = 0; +#else /* !USE_32BIT_ONLY */ + context->Length_High = context->Length_Low = 0; +#endif /* USE_32BIT_ONLY */ + context->Computed = 1; +} + +/* + * SHA384_512PadMessage + * + * Description: + * According to the standard, the message must be padded to the next + * even multiple of 1024 bits. The first padding bit must be a '1'. + * The last 128 bits represent the length of the original message. + * All bits in between should be 0. This helper function will + * pad the message according to those rules by filling the + * Message_Block array accordingly. When it returns, it can be + * assumed that the message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad. + * Pad_Byte: [in] + * The last byte to add to the message block before the 0-padding + * and length. This will contain the last bits of the message + * followed by another single bit. If the message was an + * exact multiple of 8-bits long, Pad_Byte will be 0x80. + * + * Returns: + * Nothing. + * + */ +static void SHA384_512PadMessage(SHA512Context *context, + uint8_t Pad_Byte) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index >= (SHA512_Message_Block_Size-16)) { + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + while (context->Message_Block_Index < SHA512_Message_Block_Size) + context->Message_Block[context->Message_Block_Index++] = 0; + + SHA384_512ProcessMessageBlock(context); + } else + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + + while (context->Message_Block_Index < (SHA512_Message_Block_Size-16)) + context->Message_Block[context->Message_Block_Index++] = 0; + + /* + * Store the message length as the last 16 octets + */ +#ifdef USE_32BIT_ONLY + context->Message_Block[112] = (uint8_t)(context->Length[0] >> 24); + context->Message_Block[113] = (uint8_t)(context->Length[0] >> 16); + context->Message_Block[114] = (uint8_t)(context->Length[0] >> 8); + context->Message_Block[115] = (uint8_t)(context->Length[0]); + context->Message_Block[116] = (uint8_t)(context->Length[1] >> 24); + context->Message_Block[117] = (uint8_t)(context->Length[1] >> 16); + context->Message_Block[118] = (uint8_t)(context->Length[1] >> 8); + context->Message_Block[119] = (uint8_t)(context->Length[1]); + + context->Message_Block[120] = (uint8_t)(context->Length[2] >> 24); + context->Message_Block[121] = (uint8_t)(context->Length[2] >> 16); + context->Message_Block[122] = (uint8_t)(context->Length[2] >> 8); + context->Message_Block[123] = (uint8_t)(context->Length[2]); + context->Message_Block[124] = (uint8_t)(context->Length[3] >> 24); + context->Message_Block[125] = (uint8_t)(context->Length[3] >> 16); + context->Message_Block[126] = (uint8_t)(context->Length[3] >> 8); + context->Message_Block[127] = (uint8_t)(context->Length[3]); +#else /* !USE_32BIT_ONLY */ + context->Message_Block[112] = (uint8_t)(context->Length_High >> 56); + context->Message_Block[113] = (uint8_t)(context->Length_High >> 48); + context->Message_Block[114] = (uint8_t)(context->Length_High >> 40); + context->Message_Block[115] = (uint8_t)(context->Length_High >> 32); + context->Message_Block[116] = (uint8_t)(context->Length_High >> 24); + context->Message_Block[117] = (uint8_t)(context->Length_High >> 16); + context->Message_Block[118] = (uint8_t)(context->Length_High >> 8); + context->Message_Block[119] = (uint8_t)(context->Length_High); + + context->Message_Block[120] = (uint8_t)(context->Length_Low >> 56); + context->Message_Block[121] = (uint8_t)(context->Length_Low >> 48); + context->Message_Block[122] = (uint8_t)(context->Length_Low >> 40); + context->Message_Block[123] = (uint8_t)(context->Length_Low >> 32); + context->Message_Block[124] = (uint8_t)(context->Length_Low >> 24); + context->Message_Block[125] = (uint8_t)(context->Length_Low >> 16); + context->Message_Block[126] = (uint8_t)(context->Length_Low >> 8); + context->Message_Block[127] = (uint8_t)(context->Length_Low); +#endif /* USE_32BIT_ONLY */ + + SHA384_512ProcessMessageBlock(context); +} + +/* + * SHA384_512ResultN + * + * Description: + * This helper function will return the 384-bit or 512-bit message + * digest into the Message_Digest array provided by the caller. + * NOTE: + * The first octet of hash is stored in the element with index 0, + * the last octet of hash in the element with index 47/63. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA hash. + * Message_Digest[ ]: [out] + * Where the digest is returned. + * HashSize: [in] + * The size of the hash, either 48 or 64. + * + * Returns: + * sha Error Code. + * + */ +static int SHA384_512ResultN(SHA512Context *context, + uint8_t Message_Digest[ ], int HashSize) +{ + int i; +#ifdef USE_32BIT_ONLY + int i2; +#endif /* USE_32BIT_ONLY */ + + if (!context) return shaNull; + if (!Message_Digest) return shaNull; + if (context->Corrupted) return context->Corrupted; + + if (!context->Computed) + SHA384_512Finalize(context, 0x80); + +#ifdef USE_32BIT_ONLY + for (i = i2 = 0; i < HashSize; ) { + Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>24); + Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>16); + Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>8); + Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2++]); + Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>24); + Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>16); + Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>8); + Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2++]); + } +#else /* !USE_32BIT_ONLY */ + for (i = 0; i < HashSize; ++i) + Message_Digest[i] = (uint8_t) + (context->Intermediate_Hash[i>>3] >> 8 * ( 7 - ( i % 8 ) )); +#endif /* USE_32BIT_ONLY */ + + return shaSuccess; +} + +/*****************************************************************/ +/*****************************************************************/ +/*****************************************************************/ + +/* Define the SHA shift, rotate left, and rotate right macros */ +#define SHA256_SHR(bits,word) ((word) >> (bits)) +#define SHA256_ROTL(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) +#define SHA256_ROTR(bits,word) \ + (((word) >> (bits)) | ((word) << (32-(bits)))) + +/* Define the SHA SIGMA and sigma macros */ +#define SHA256_SIGMA0(word) \ + (SHA256_ROTR( 2,word) ^ SHA256_ROTR(13,word) ^ SHA256_ROTR(22,word)) +#define SHA256_SIGMA1(word) \ + (SHA256_ROTR( 6,word) ^ SHA256_ROTR(11,word) ^ SHA256_ROTR(25,word)) +#define SHA256_sigma0(word) \ + (SHA256_ROTR( 7,word) ^ SHA256_ROTR(18,word) ^ SHA256_SHR( 3,word)) +#define SHA256_sigma1(word) \ + (SHA256_ROTR(17,word) ^ SHA256_ROTR(19,word) ^ SHA256_SHR(10,word)) + +/* + * Add "length" to the length. + * Set Corrupted when overflow has occurred. + */ +static unsigned int addTemp; +#define SHA224_256AddLength(context, length) \ + (addTemp = (context)->Length_Low, (context)->Corrupted = \ + (((context)->Length_Low += (length)) < addTemp) && \ + (++(context)->Length_High == 0) ? shaInputTooLong : \ + (context)->Corrupted ) + +/* Local Function Prototypes */ +static int SHA224_256Reset(SHA256Context *context, uint32_t *H0); +static void SHA224_256ProcessMessageBlock(SHA256Context *context); +static void SHA224_256Finalize(SHA256Context *context, + uint8_t Pad_Byte); +static void SHA224_256PadMessage(SHA256Context *context, + uint8_t Pad_Byte); +static int SHA224_256ResultN(SHA256Context *context, + uint8_t Message_Digest[ ], int HashSize); + +/* Initial Hash Values: FIPS 180-3 section 5.3.2 */ +static uint32_t SHA224_H0[SHA256HashSize/4] = { + 0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939, + 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4 +}; + +/* Initial Hash Values: FIPS 180-3 section 5.3.3 */ +static uint32_t SHA256_H0[SHA256HashSize/4] = { + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 +}; + +/* + * SHA224Reset + * + * Description: + * This function will initialize the SHA224Context in preparation + * for computing a new SHA224 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + */ +int SHA224Reset(SHA224Context *context) +{ + return SHA224_256Reset(context, SHA224_H0); +} + +/* + * SHA224Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_array[ ]: [in] + * An array of octets representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array. + * + * Returns: + * sha Error Code. + * + */ +int SHA224Input(SHA224Context *context, const uint8_t *message_array, + unsigned int length) +{ + return SHA256Input(context, message_array, length); +} + +/* + * SHA224FinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + */ +int SHA224FinalBits(SHA224Context *context, + uint8_t message_bits, unsigned int length) +{ + return SHA256FinalBits(context, message_bits, length); +} + +/* + * SHA224Result + * + * Description: + * This function will return the 224-bit message digest + * into the Message_Digest array provided by the caller. + * NOTE: + * The first octet of hash is stored in the element with index 0, + * the last octet of hash in the element with index 27. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA hash. + * Message_Digest[ ]: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + */ +int SHA224Result(SHA224Context *context, + uint8_t Message_Digest[SHA224HashSize]) +{ + return SHA224_256ResultN(context, Message_Digest, SHA224HashSize); +} + +/* + * SHA256Reset + * + * Description: + * This function will initialize the SHA256Context in preparation + * for computing a new SHA256 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + */ +int SHA256Reset(SHA256Context *context) +{ + return SHA224_256Reset(context, SHA256_H0); +} + +/* + * SHA256Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_array[ ]: [in] + * An array of octets representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array. + * + * Returns: + * sha Error Code. + */ +int SHA256Input(SHA256Context *context, const uint8_t *message_array, + unsigned int length) +{ + if (!context) return shaNull; + if (!length) return shaSuccess; + if (!message_array) return shaNull; + if (context->Computed) return context->Corrupted = shaStateError; + if (context->Corrupted) return context->Corrupted; + + while (length--) { + context->Message_Block[context->Message_Block_Index++] = + *message_array; + + if ((SHA224_256AddLength(context, 8) == shaSuccess) && + (context->Message_Block_Index == SHA256_Message_Block_Size)) + SHA224_256ProcessMessageBlock(context); + + message_array++; + } + + return context->Corrupted; + +} + +/* + * SHA256FinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + */ +int SHA256FinalBits(SHA256Context *context, + uint8_t message_bits, unsigned int length) +{ + static uint8_t masks[8] = { + /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, + /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, + /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, + /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE + }; + static uint8_t markbit[8] = { + /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, + /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, + /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, + /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 + }; + + if (!context) return shaNull; + if (!length) return shaSuccess; + if (context->Corrupted) return context->Corrupted; + if (context->Computed) return context->Corrupted = shaStateError; + if (length >= 8) return context->Corrupted = shaBadParam; + + SHA224_256AddLength(context, length); + SHA224_256Finalize(context, (uint8_t) + ((message_bits & masks[length]) | markbit[length])); + + return context->Corrupted; +} + +/* + * SHA256Result + * + * Description: + * This function will return the 256-bit message digest + * into the Message_Digest array provided by the caller. + * NOTE: + * The first octet of hash is stored in the element with index 0, + * the last octet of hash in the element with index 31. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA hash. + * Message_Digest[ ]: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + */ +int SHA256Result(SHA256Context *context, + uint8_t Message_Digest[SHA256HashSize]) +{ + return SHA224_256ResultN(context, Message_Digest, SHA256HashSize); +} + +/* + * SHA224_256Reset + * + * Description: + * This helper function will initialize the SHA256Context in + * preparation for computing a new SHA-224 or SHA-256 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * H0[ ]: [in] + * The initial hash value array to use. + * + * Returns: + * sha Error Code. + */ +static int SHA224_256Reset(SHA256Context *context, uint32_t *H0) +{ + if (!context) return shaNull; + + context->Length_High = context->Length_Low = 0; + context->Message_Block_Index = 0; + + context->Intermediate_Hash[0] = H0[0]; + context->Intermediate_Hash[1] = H0[1]; + context->Intermediate_Hash[2] = H0[2]; + context->Intermediate_Hash[3] = H0[3]; + context->Intermediate_Hash[4] = H0[4]; + context->Intermediate_Hash[5] = H0[5]; + context->Intermediate_Hash[6] = H0[6]; + context->Intermediate_Hash[7] = H0[7]; + + context->Computed = 0; + context->Corrupted = shaSuccess; + + return shaSuccess; +} + +/* + * SHA224_256ProcessMessageBlock + * + * Description: + * This helper function will process the next 512 bits of the + * message stored in the Message_Block array. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * + * Returns: + * Nothing. + * + * Comments: + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the Secure Hash Standard. + */ +static void SHA224_256ProcessMessageBlock(SHA256Context *context) +{ + /* Constants defined in FIPS 180-3, section 4.2.2 */ + static const uint32_t K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, + 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, + 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, + 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, + 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, + 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, + 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, + 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, + 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + int t, t4; /* Loop counter */ + uint32_t temp1, temp2; /* Temporary word value */ + uint32_t W[64]; /* Word sequence */ + uint32_t A, B, C, D, E, F, G, H; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for (t = t4 = 0; t < 16; t++, t4 += 4) + W[t] = (((uint32_t)context->Message_Block[t4]) << 24) | + (((uint32_t)context->Message_Block[t4 + 1]) << 16) | + (((uint32_t)context->Message_Block[t4 + 2]) << 8) | + (((uint32_t)context->Message_Block[t4 + 3])); + for (t = 16; t < 64; t++) + W[t] = SHA256_sigma1(W[t-2]) + W[t-7] + + SHA256_sigma0(W[t-15]) + W[t-16]; + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + F = context->Intermediate_Hash[5]; + G = context->Intermediate_Hash[6]; + H = context->Intermediate_Hash[7]; + + for (t = 0; t < 64; t++) { + temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t]; + temp2 = SHA256_SIGMA0(A) + SHA_Maj(A,B,C); + H = G; + G = F; + F = E; + E = D + temp1; + D = C; + C = B; + B = A; + A = temp1 + temp2; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + context->Intermediate_Hash[5] += F; + context->Intermediate_Hash[6] += G; + context->Intermediate_Hash[7] += H; + + context->Message_Block_Index = 0; +} + +/* + * SHA224_256Finalize + * + * Description: + * This helper function finishes off the digest calculations. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * Pad_Byte: [in] + * The last byte to add to the message block before the 0-padding + * and length. This will contain the last bits of the message + * followed by another single bit. If the message was an + * exact multiple of 8-bits long, Pad_Byte will be 0x80. + * + * Returns: + * sha Error Code. + */ +static void SHA224_256Finalize(SHA256Context *context, + uint8_t Pad_Byte) +{ + int i; + SHA224_256PadMessage(context, Pad_Byte); + /* message may be sensitive, so clear it out */ + for (i = 0; i < SHA256_Message_Block_Size; ++i) + context->Message_Block[i] = 0; + context->Length_High = 0; /* and clear length */ + context->Length_Low = 0; + context->Computed = 1; +} + +/* + * SHA224_256PadMessage + * + * Description: + * According to the standard, the message must be padded to the next + * even multiple of 512 bits. The first padding bit must be a '1'. + * The last 64 bits represent the length of the original message. + * All bits in between should be 0. This helper function will pad + * the message according to those rules by filling the + * Message_Block array accordingly. When it returns, it can be + * assumed that the message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad. + * Pad_Byte: [in] + * The last byte to add to the message block before the 0-padding + * and length. This will contain the last bits of the message + * followed by another single bit. If the message was an + * exact multiple of 8-bits long, Pad_Byte will be 0x80. + * + * Returns: + * Nothing. + */ +static void SHA224_256PadMessage(SHA256Context *context, + uint8_t Pad_Byte) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index >= (SHA256_Message_Block_Size-8)) { + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + while (context->Message_Block_Index < SHA256_Message_Block_Size) + context->Message_Block[context->Message_Block_Index++] = 0; + SHA224_256ProcessMessageBlock(context); + } else + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + + while (context->Message_Block_Index < (SHA256_Message_Block_Size-8)) + context->Message_Block[context->Message_Block_Index++] = 0; + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = (uint8_t)(context->Length_High >> 24); + context->Message_Block[57] = (uint8_t)(context->Length_High >> 16); + context->Message_Block[58] = (uint8_t)(context->Length_High >> 8); + context->Message_Block[59] = (uint8_t)(context->Length_High); + context->Message_Block[60] = (uint8_t)(context->Length_Low >> 24); + context->Message_Block[61] = (uint8_t)(context->Length_Low >> 16); + context->Message_Block[62] = (uint8_t)(context->Length_Low >> 8); + context->Message_Block[63] = (uint8_t)(context->Length_Low); + + SHA224_256ProcessMessageBlock(context); +} + +/* + * SHA224_256ResultN + * + * Description: + * This helper function will return the 224-bit or 256-bit message + * digest into the Message_Digest array provided by the caller. + * NOTE: + * The first octet of hash is stored in the element with index 0, + * the last octet of hash in the element with index 27/31. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA hash. + * Message_Digest[ ]: [out] + * Where the digest is returned. + * HashSize: [in] + * The size of the hash, either 28 or 32. + * + * Returns: + * sha Error Code. + */ +static int SHA224_256ResultN(SHA256Context *context, + uint8_t Message_Digest[ ], int HashSize) +{ + int i; + + if (!context) return shaNull; + if (!Message_Digest) return shaNull; + if (context->Corrupted) return context->Corrupted; + + if (!context->Computed) + SHA224_256Finalize(context, 0x80); + + for (i = 0; i < HashSize; ++i) + Message_Digest[i] = (uint8_t) + (context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) )); + + return shaSuccess; +} + +/*****************************************************************/ +/*****************************************************************/ +/*****************************************************************/ + +/* + * Define the SHA1 circular left shift macro + */ +#define SHA1_ROTL(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) + +/* + * Add "length" to the length. + * Set Corrupted when overflow has occurred. + */ +static unsigned int addTemp; +#define SHA1AddLength(context, length) \ + (addTemp = (context)->Length_Low, \ + (context)->Corrupted = \ + (((context)->Length_Low += (length)) < addTemp) && \ + (++(context)->Length_High == 0) ? shaInputTooLong \ + : (context)->Corrupted ) + +/* Local Function Prototypes */ +static void SHA1ProcessMessageBlock(SHA1Context *context); +static void SHA1Finalize(SHA1Context *context, uint8_t Pad_Byte); +static void SHA1PadMessage(SHA1Context *context, uint8_t Pad_Byte); + +/* + * SHA1Reset + * + * Description: + * This function will initialize the SHA1Context in preparation + * for computing a new SHA1 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Reset(SHA1Context *context) +{ + if (!context) return shaNull; + + context->Length_High = context->Length_Low = 0; + context->Message_Block_Index = 0; + + /* Initial Hash Values: FIPS 180-3 section 5.3.1 */ + context->Intermediate_Hash[0] = 0x67452301; + context->Intermediate_Hash[1] = 0xEFCDAB89; + context->Intermediate_Hash[2] = 0x98BADCFE; + context->Intermediate_Hash[3] = 0x10325476; + context->Intermediate_Hash[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = shaSuccess; + + return shaSuccess; +} + +/* + * SHA1Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_array[ ]: [in] + * An array of octets representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Input(SHA1Context *context, + const uint8_t *message_array, unsigned length) +{ + if (!context) return shaNull; + if (!length) return shaSuccess; + if (!message_array) return shaNull; + if (context->Computed) return context->Corrupted = shaStateError; + if (context->Corrupted) return context->Corrupted; + + while (length--) { + context->Message_Block[context->Message_Block_Index++] = + *message_array; + + if ((SHA1AddLength(context, 8) == shaSuccess) && + (context->Message_Block_Index == SHA1_Message_Block_Size)) + SHA1ProcessMessageBlock(context); + + message_array++; + } + + return context->Corrupted; +} + +/* + * SHA1FinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + */ +int SHA1FinalBits(SHA1Context *context, uint8_t message_bits, + unsigned int length) +{ + static uint8_t masks[8] = { + /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, + /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, + /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, + /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE + }; + + static uint8_t markbit[8] = { + /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, + /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, + /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, + /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 + }; + + if (!context) return shaNull; + if (!length) return shaSuccess; + if (context->Corrupted) return context->Corrupted; + if (context->Computed) return context->Corrupted = shaStateError; + if (length >= 8) return context->Corrupted = shaBadParam; + + SHA1AddLength(context, length); + SHA1Finalize(context, + (uint8_t) ((message_bits & masks[length]) | markbit[length])); + + return context->Corrupted; +} + +/* + * SHA1Result + * + * Description: + * This function will return the 160-bit message digest + * into the Message_Digest array provided by the caller. + * NOTE: + * The first octet of hash is stored in the element with index 0, + * the last octet of hash in the element with index 19. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * Message_Digest[ ]: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Result(SHA1Context *context, + uint8_t Message_Digest[SHA1HashSize]) +{ + int i; + + if (!context) return shaNull; + if (!Message_Digest) return shaNull; + if (context->Corrupted) return context->Corrupted; + + if (!context->Computed) + SHA1Finalize(context, 0x80); + + for (i = 0; i < SHA1HashSize; ++i) + Message_Digest[i] = (uint8_t) (context->Intermediate_Hash[i>>2] + >> (8 * ( 3 - ( i & 0x03 ) ))); + + return shaSuccess; +} + +/* + * SHA1ProcessMessageBlock + * + * Description: + * This helper function will process the next 512 bits of the + * message stored in the Message_Block array. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * + * Returns: + * Nothing. + * + * Comments: + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the Secure Hash Standard. + */ +static void SHA1ProcessMessageBlock(SHA1Context *context) +{ + /* Constants defined in FIPS 180-3, section 4.2.1 */ + const uint32_t K[4] = { + 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 + }; + + int t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ + uint32_t W[80]; /* Word sequence */ + uint32_t A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for (t = 0; t < 16; t++) { + W[t] = ((uint32_t)context->Message_Block[t * 4]) << 24; + W[t] |= ((uint32_t)context->Message_Block[t * 4 + 1]) << 16; + W[t] |= ((uint32_t)context->Message_Block[t * 4 + 2]) << 8; + W[t] |= ((uint32_t)context->Message_Block[t * 4 + 3]); + } + + for (t = 16; t < 80; t++) + W[t] = SHA1_ROTL(1, W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + + for (t = 0; t < 20; t++) { + temp = SHA1_ROTL(5,A) + SHA_Ch(B, C, D) + E + W[t] + K[0]; + E = D; + D = C; + C = SHA1_ROTL(30,B); + B = A; + A = temp; + } + + for (t = 20; t < 40; t++) { + temp = SHA1_ROTL(5,A) + SHA_Parity(B, C, D) + E + W[t] + K[1]; + E = D; + D = C; + C = SHA1_ROTL(30,B); + B = A; + A = temp; + } + + for (t = 40; t < 60; t++) { + temp = SHA1_ROTL(5,A) + SHA_Maj(B, C, D) + E + W[t] + K[2]; + E = D; + D = C; + C = SHA1_ROTL(30,B); + B = A; + A = temp; + } + + for (t = 60; t < 80; t++) { + temp = SHA1_ROTL(5,A) + SHA_Parity(B, C, D) + E + W[t] + K[3]; + E = D; + D = C; + C = SHA1_ROTL(30,B); + B = A; + A = temp; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + context->Message_Block_Index = 0; +} + +/* + * SHA1Finalize + * + * Description: + * This helper function finishes off the digest calculations. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * Pad_Byte: [in] + * The last byte to add to the message block before the 0-padding + * and length. This will contain the last bits of the message + * followed by another single bit. If the message was an + * exact multiple of 8-bits long, Pad_Byte will be 0x80. + * + * Returns: + * sha Error Code. + * + */ +static void SHA1Finalize(SHA1Context *context, uint8_t Pad_Byte) +{ + int i; + SHA1PadMessage(context, Pad_Byte); + /* message may be sensitive, clear it out */ + for (i = 0; i < SHA1_Message_Block_Size; ++i) + context->Message_Block[i] = 0; + context->Length_High = 0; /* and clear length */ + context->Length_Low = 0; + context->Computed = 1; +} + +/* + * SHA1PadMessage + * + * Description: + * According to the standard, the message must be padded to the next + * even multiple of 512 bits. The first padding bit must be a '1'. + * The last 64 bits represent the length of the original message. + * All bits in between should be 0. This helper function will pad + * the message according to those rules by filling the Message_Block + * array accordingly. When it returns, it can be assumed that the + * message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad. + * Pad_Byte: [in] + * The last byte to add to the message block before the 0-padding + * and length. This will contain the last bits of the message + * followed by another single bit. If the message was an + * exact multiple of 8-bits long, Pad_Byte will be 0x80. + * + * Returns: + * Nothing. + */ +static void SHA1PadMessage(SHA1Context *context, uint8_t Pad_Byte) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index >= (SHA1_Message_Block_Size - 8)) { + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + while (context->Message_Block_Index < SHA1_Message_Block_Size) + context->Message_Block[context->Message_Block_Index++] = 0; + + SHA1ProcessMessageBlock(context); + } else + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + + while (context->Message_Block_Index < (SHA1_Message_Block_Size - 8)) + context->Message_Block[context->Message_Block_Index++] = 0; + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = (uint8_t) (context->Length_High >> 24); + context->Message_Block[57] = (uint8_t) (context->Length_High >> 16); + context->Message_Block[58] = (uint8_t) (context->Length_High >> 8); + context->Message_Block[59] = (uint8_t) (context->Length_High); + context->Message_Block[60] = (uint8_t) (context->Length_Low >> 24); + context->Message_Block[61] = (uint8_t) (context->Length_Low >> 16); + context->Message_Block[62] = (uint8_t) (context->Length_Low >> 8); + context->Message_Block[63] = (uint8_t) (context->Length_Low); + + SHA1ProcessMessageBlock(context); +} + +/*****************************************************************/ +/*****************************************************************/ +/*****************************************************************/ + +/* + * USHAReset + * + * Description: + * This function will initialize the SHA Context in preparation + * for computing a new SHA message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * whichSha: [in] + * Selects which SHA reset to call + * + * Returns: + * sha Error Code. + * + */ +int USHAReset(USHAContext *context, enum SHAversion whichSha) +{ + if (!context) return shaNull; + context->whichSha = whichSha; + switch (whichSha) { + case SHA1: return SHA1Reset((SHA1Context*)&context->ctx); + case SHA224: return SHA224Reset((SHA224Context*)&context->ctx); + case SHA256: return SHA256Reset((SHA256Context*)&context->ctx); + case SHA384: return SHA384Reset((SHA384Context*)&context->ctx); + case SHA512: return SHA512Reset((SHA512Context*)&context->ctx); + default: return shaBadParam; + } +} + +/* + * USHAInput + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_array: [in] + * An array of octets representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array. + * + * Returns: + * sha Error Code. + * + */ +int USHAInput(USHAContext *context, + const uint8_t *bytes, unsigned int bytecount) +{ + if (!context) return shaNull; + switch (context->whichSha) { + case SHA1: + return SHA1Input((SHA1Context*)&context->ctx, bytes, + bytecount); + case SHA224: + return SHA224Input((SHA224Context*)&context->ctx, bytes, + bytecount); + case SHA256: + return SHA256Input((SHA256Context*)&context->ctx, bytes, + bytecount); + case SHA384: + return SHA384Input((SHA384Context*)&context->ctx, bytes, + bytecount); + case SHA512: + return SHA512Input((SHA512Context*)&context->ctx, bytes, + bytecount); + default: return shaBadParam; + } +} + +/* + * USHAFinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update. + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + */ +int USHAFinalBits(USHAContext *context, + uint8_t bits, unsigned int bit_count) +{ + if (!context) return shaNull; + switch (context->whichSha) { + case SHA1: + return SHA1FinalBits((SHA1Context*)&context->ctx, bits, + bit_count); + case SHA224: + return SHA224FinalBits((SHA224Context*)&context->ctx, bits, + bit_count); + case SHA256: + return SHA256FinalBits((SHA256Context*)&context->ctx, bits, + bit_count); + case SHA384: + return SHA384FinalBits((SHA384Context*)&context->ctx, bits, + bit_count); + case SHA512: + return SHA512FinalBits((SHA512Context*)&context->ctx, bits, + bit_count); + default: return shaBadParam; + } +} + +/* + * USHAResult + * + * Description: + * This function will return the message digest of the appropriate + * bit size, as returned by USHAHashSizeBits(whichSHA) for the + * 'whichSHA' value used in the preceeding call to USHAReset, + * into the Message_Digest array provided by the caller. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int USHAResult(USHAContext *context, + uint8_t Message_Digest[USHAMaxHashSize]) +{ + if (!context) return shaNull; + switch (context->whichSha) { + case SHA1: + return SHA1Result((SHA1Context*)&context->ctx, Message_Digest); + case SHA224: + return SHA224Result((SHA224Context*)&context->ctx, + Message_Digest); + case SHA256: + return SHA256Result((SHA256Context*)&context->ctx, + Message_Digest); + case SHA384: + return SHA384Result((SHA384Context*)&context->ctx, + Message_Digest); + case SHA512: + return SHA512Result((SHA512Context*)&context->ctx, + Message_Digest); + default: return shaBadParam; + } +} + +/* + * USHABlockSize + * + * Description: + * This function will return the blocksize for the given SHA + * algorithm. + * + * Parameters: + * whichSha: + * which SHA algorithm to query + * + * Returns: + * block size + * + */ +int USHABlockSize(enum SHAversion whichSha) +{ + switch (whichSha) { + case SHA1: return SHA1_Message_Block_Size; + case SHA224: return SHA224_Message_Block_Size; + case SHA256: return SHA256_Message_Block_Size; + case SHA384: return SHA384_Message_Block_Size; + default: + case SHA512: return SHA512_Message_Block_Size; + } +} + +/* + * USHAHashSize + * + * Description: + * This function will return the hashsize for the given SHA + * algorithm. + * + * Parameters: + * whichSha: + * which SHA algorithm to query + * + * Returns: + * hash size + * + */ +int USHAHashSize(enum SHAversion whichSha) +{ + switch (whichSha) { + case SHA1: return SHA1HashSize; + case SHA224: return SHA224HashSize; + case SHA256: return SHA256HashSize; + case SHA384: return SHA384HashSize; + default: + case SHA512: return SHA512HashSize; + } +} + +/* + * USHAHashSizeBits + * + * Description: + * This function will return the hashsize for the given SHA + * algorithm, expressed in bits. + * + * Parameters: + * whichSha: + * which SHA algorithm to query + * + * Returns: + * hash size in bits + * + */ +int USHAHashSizeBits(enum SHAversion whichSha) +{ + switch (whichSha) { + case SHA1: return SHA1HashSizeBits; + case SHA224: return SHA224HashSizeBits; + case SHA256: return SHA256HashSizeBits; + case SHA384: return SHA384HashSizeBits; + default: + case SHA512: return SHA512HashSizeBits; + } +} + +/* + * USHAHashName + * + * Description: + * This function will return the name of the given SHA algorithm + * as a string. + * + * Parameters: + * whichSha: + * which SHA algorithm to query + * + * Returns: + * character string with the name in it + * + */ +const char *USHAHashName(enum SHAversion whichSha) +{ + switch (whichSha) { + case SHA1: return "SHA1"; + case SHA224: return "SHA224"; + case SHA256: return "SHA256"; + case SHA384: return "SHA384"; + default: + case SHA512: return "SHA512"; + } +} + +/*****************************************************************/ +/*****************************************************************/ +/*****************************************************************/ + +/* + * hmac + * + * Description: + * This function will compute an HMAC message digest. + * + * Parameters: + * whichSha: [in] + * One of SHA1, SHA224, SHA256, SHA384, SHA512 + * message_array[ ]: [in] + * An array of octets representing the message. + * Note: in RFC 2104, this parameter is known + * as 'text'. + * length: [in] + * The length of the message in message_array. + * key[ ]: [in] + * The secret shared key. + * key_len: [in] + * The length of the secret shared key. + * digest[ ]: [out] + * Where the digest is to be returned. + * NOTE: The length of the digest is determined by + * the value of whichSha. + * + * Returns: + * sha Error Code. + * + */ + +int hmac(SHAversion whichSha, + const unsigned char *message_array, int length, + const unsigned char *key, int key_len, + uint8_t digest[USHAMaxHashSize]) +{ + HMACContext context; + return hmacReset(&context, whichSha, key, key_len) || + hmacInput(&context, message_array, length) || + hmacResult(&context, digest); +} + +/* + * hmacReset + * + * Description: + * This function will initialize the hmacContext in preparation + * for computing a new HMAC message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * whichSha: [in] + * One of SHA1, SHA224, SHA256, SHA384, SHA512 + * key[ ]: [in] + * The secret shared key. + * key_len: [in] + * The length of the secret shared key. + * + * Returns: + * sha Error Code. + * + */ +int hmacReset(HMACContext *context, enum SHAversion whichSha, + const unsigned char *key, int key_len) +{ + int i, blocksize, hashsize, ret; + + /* inner padding - key XORd with ipad */ + unsigned char k_ipad[USHA_Max_Message_Block_Size]; + + /* temporary buffer when keylen > blocksize */ + unsigned char tempkey[USHAMaxHashSize]; + + if (!context) return shaNull; + context->Computed = 0; + context->Corrupted = shaSuccess; + + blocksize = context->blockSize = USHABlockSize(whichSha); + hashsize = context->hashSize = USHAHashSize(whichSha); + context->whichSha = whichSha; + + /* + * If key is longer than the hash blocksize, + * reset it to key = HASH(key). + */ + if (key_len > blocksize) { + USHAContext tcontext; + int err = USHAReset(&tcontext, whichSha) || + USHAInput(&tcontext, key, key_len) || + USHAResult(&tcontext, tempkey); + if (err != shaSuccess) return err; + + key = tempkey; + key_len = hashsize; + } + + /* + * The HMAC transform looks like: + * + * SHA(K XOR opad, SHA(K XOR ipad, text)) + * + * where K is an n byte key, 0-padded to a total of blocksize bytes, + * ipad is the byte 0x36 repeated blocksize times, + * opad is the byte 0x5c repeated blocksize times, + * and text is the data being protected. + */ + + /* store key into the pads, XOR'd with ipad and opad values */ + for (i = 0; i < key_len; i++) { + k_ipad[i] = key[i] ^ 0x36; + context->k_opad[i] = key[i] ^ 0x5c; + } + /* remaining pad bytes are '\0' XOR'd with ipad and opad values */ + for ( ; i < blocksize; i++) { + k_ipad[i] = 0x36; + context->k_opad[i] = 0x5c; + } + + /* perform inner hash */ + /* init context for 1st pass */ + ret = USHAReset(&context->shaContext, whichSha) || + /* and start with inner pad */ + USHAInput(&context->shaContext, k_ipad, blocksize); + return context->Corrupted = ret; +} + +/* + * hmacInput + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. It may be called multiple times. + * + * Parameters: + * context: [in/out] + * The HMAC context to update. + * text[ ]: [in] + * An array of octets representing the next portion of + * the message. + * text_len: [in] + * The length of the message in text. + * + * Returns: + * sha Error Code. + * + */ +int hmacInput(HMACContext *context, const unsigned char *text, + int text_len) +{ + if (!context) return shaNull; + if (context->Corrupted) return context->Corrupted; + if (context->Computed) return context->Corrupted = shaStateError; + /* then text of datagram */ + return context->Corrupted = + USHAInput(&context->shaContext, text, text_len); +} + +/* + * hmacFinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The HMAC context to update. + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + */ +int hmacFinalBits(HMACContext *context, + uint8_t bits, unsigned int bit_count) +{ + if (!context) return shaNull; + if (context->Corrupted) return context->Corrupted; + if (context->Computed) return context->Corrupted = shaStateError; + /* then final bits of datagram */ + return context->Corrupted = + USHAFinalBits(&context->shaContext, bits, bit_count); +} + +/* + * hmacResult + * + * Description: + * This function will return the N-byte message digest into the + * Message_Digest array provided by the caller. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the HMAC hash. + * digest[ ]: [out] + * Where the digest is returned. + * NOTE 2: The length of the hash is determined by the value of + * whichSha that was passed to hmacReset(). + * + * Returns: + * sha Error Code. + * + */ +int hmacResult(HMACContext *context, uint8_t digest[USHAMaxHashSize]) +{ + int ret; + if (!context) return shaNull; + if (context->Corrupted) return context->Corrupted; + if (context->Computed) return context->Corrupted = shaStateError; + + /* finish up 1st pass */ + /* (Use digest here as a temporary buffer.) */ + ret = + USHAResult(&context->shaContext, digest) || + + /* perform outer SHA */ + /* init context for 2nd pass */ + USHAReset(&context->shaContext, context->whichSha) || + + /* start with outer pad */ + USHAInput(&context->shaContext, context->k_opad, + context->blockSize) || + + /* then results of 1st hash */ + USHAInput(&context->shaContext, digest, context->hashSize) || + /* finish up 2nd pass */ + USHAResult(&context->shaContext, digest); + + context->Computed = 1; + return context->Corrupted = ret; +} + +/* + * hkdf + * + * Description: + * This function will generate keying material using HKDF. + * + * Parameters: + * whichSha: [in] + * One of SHA1, SHA224, SHA256, SHA384, SHA512 + * salt[ ]: [in] + * The optional salt value (a non-secret random value); + * if not provided (salt == NULL), it is set internally + * to a string of HashLen(whichSha) zeros. + * salt_len: [in] + * The length of the salt value. (Ignored if salt == NULL.) + * ikm[ ]: [in] + * Input keying material. + * ikm_len: [in] + * The length of the input keying material. + * info[ ]: [in] + * The optional context and application specific information. + * If info == NULL or a zero-length string, it is ignored. + * info_len: [in] + * The length of the optional context and application specific + * information. (Ignored if info == NULL.) + * okm[ ]: [out] + * Where the HKDF is to be stored. + * okm_len: [in] + * The length of the buffer to hold okm. + * okm_len must be <= 255 * USHABlockSize(whichSha) + * + * Notes: + * Calls hkdfExtract() and hkdfExpand(). + * + * Returns: + * sha Error Code. + * + */ +int hkdf(SHAversion whichSha, + const unsigned char *salt, int salt_len, + const unsigned char *ikm, int ikm_len, + const unsigned char *info, int info_len, + uint8_t okm[ ], int okm_len) +{ + uint8_t prk[USHAMaxHashSize]; + return hkdfExtract(whichSha, salt, salt_len, ikm, ikm_len, prk) || + hkdfExpand(whichSha, prk, USHAHashSize(whichSha), info, + info_len, okm, okm_len); +} + +/* + * hkdfExtract + * + * Description: + * This function will perform HKDF extraction. + * + * Parameters: + * whichSha: [in] + * One of SHA1, SHA224, SHA256, SHA384, SHA512 + * salt[ ]: [in] + * The optional salt value (a non-secret random value); + * if not provided (salt == NULL), it is set internally + * to a string of HashLen(whichSha) zeros. + * salt_len: [in] + * The length of the salt value. (Ignored if salt == NULL.) + * ikm[ ]: [in] + * Input keying material. + * ikm_len: [in] + * The length of the input keying material. + * prk[ ]: [out] + * Array where the HKDF extraction is to be stored. + * Must be larger than USHAHashSize(whichSha); + * + * Returns: + * sha Error Code. + * + */ +int hkdfExtract(SHAversion whichSha, + const unsigned char *salt, int salt_len, + const unsigned char *ikm, int ikm_len, + uint8_t prk[USHAMaxHashSize]) +{ + unsigned char nullSalt[USHAMaxHashSize]; + if (salt == 0) { + salt = nullSalt; + salt_len = USHAHashSize(whichSha); + memset(nullSalt, '\0', salt_len); + } else if (salt_len < 0) { + return shaBadParam; + } + return hmac(whichSha, ikm, ikm_len, salt, salt_len, prk); +} + +/* + * hkdfExpand + * + * Description: + * This function will perform HKDF expansion. + * + * Parameters: + * whichSha: [in] + * One of SHA1, SHA224, SHA256, SHA384, SHA512 + * prk[ ]: [in] + * The pseudo-random key to be expanded; either obtained + * directly from a cryptographically strong, uniformly + * distributed pseudo-random number generator, or as the + * output from hkdfExtract(). + * prk_len: [in] + * The length of the pseudo-random key in prk; + * should at least be equal to USHAHashSize(whichSHA). + * info[ ]: [in] + * The optional context and application specific information. + * If info == NULL or a zero-length string, it is ignored. + * info_len: [in] + * The length of the optional context and application specific + * information. (Ignored if info == NULL.) + * okm[ ]: [out] + * Where the HKDF is to be stored. + * okm_len: [in] + * The length of the buffer to hold okm. + * okm_len must be <= 255 * USHABlockSize(whichSha) + * + * Returns: + * sha Error Code. + * + */ +int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ], int prk_len, + const unsigned char *info, int info_len, + uint8_t okm[ ], int okm_len) +{ + int hash_len, N; + unsigned char T[USHAMaxHashSize]; + int Tlen, where, i; + + if (info == 0) { + info = (const unsigned char *)""; + info_len = 0; + } else if (info_len < 0) { + return shaBadParam; + } + if (okm_len <= 0) return shaBadParam; + if (!okm) return shaBadParam; + + hash_len = USHAHashSize(whichSha); + if (prk_len < hash_len) return shaBadParam; + N = okm_len / hash_len; + if ((okm_len % hash_len) != 0) N++; + if (N > 255) return shaBadParam; + + Tlen = 0; + where = 0; + for (i = 1; i <= N; i++) { + HMACContext context; + unsigned char c = i; + int ret = hmacReset(&context, whichSha, prk, prk_len) || + hmacInput(&context, T, Tlen) || + hmacInput(&context, info, info_len) || + hmacInput(&context, &c, 1) || + hmacResult(&context, T); + if (ret != shaSuccess) return ret; + memcpy(okm + where, T, + (i != N) ? hash_len : (okm_len - where)); + where += hash_len; + Tlen = hash_len; + } + return shaSuccess; +} + +/* + * hkdfReset + * + * Description: + * This function will initialize the hkdfContext in preparation + * for key derivation using the modular HKDF interface for + * arbitrary length inputs. + * + * Parameters: + * context: [in/out] + * The context to reset. + * whichSha: [in] + * One of SHA1, SHA224, SHA256, SHA384, SHA512 + * salt[ ]: [in] + * The optional salt value (a non-secret random value); + * if not provided (salt == NULL), it is set internally + * to a string of HashLen(whichSha) zeros. + * salt_len: [in] + * The length of the salt value. (Ignored if salt == NULL.) + * + * Returns: + * sha Error Code. + * + */ +int hkdfReset(HKDFContext *context, enum SHAversion whichSha, + const unsigned char *salt, int salt_len) +{ + unsigned char nullSalt[USHAMaxHashSize]; + if (!context) return shaNull; + + context->whichSha = whichSha; + context->hashSize = USHAHashSize(whichSha); + if (salt == 0) { + salt = nullSalt; + salt_len = context->hashSize; + memset(nullSalt, '\0', salt_len); + } + + return hmacReset(&context->hmacContext, whichSha, salt, salt_len); +} + +/* + * hkdfInput + * + * Description: + * This function accepts an array of octets as the next portion + * of the input keying material. It may be called multiple times. + * + * Parameters: + * context: [in/out] + * The HKDF context to update. + * ikm[ ]: [in] + * An array of octets representing the next portion of + * the input keying material. + * ikm_len: [in] + * The length of ikm. + * + * Returns: + * sha Error Code. + * + */ +int hkdfInput(HKDFContext *context, const unsigned char *ikm, + int ikm_len) +{ + if (!context) return shaNull; + if (context->Corrupted) return context->Corrupted; + if (context->Computed) return context->Corrupted = shaStateError; + return hmacInput(&context->hmacContext, ikm, ikm_len); +} + +/* + * hkdfFinalBits + * + * Description: + * This function will add in any final bits of the + * input keying material. + * + * Parameters: + * context: [in/out] + * The HKDF context to update + * ikm_bits: [in] + * The final bits of the input keying material, in the upper + * portion of the byte. (Use 0b###00000 instead of 0b00000### + * to input the three bits ###.) + * ikm_bit_count: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + */ +int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits, + unsigned int ikm_bit_count) +{ + if (!context) return shaNull; + if (context->Corrupted) return context->Corrupted; + if (context->Computed) return context->Corrupted = shaStateError; + return hmacFinalBits(&context->hmacContext, ikm_bits, ikm_bit_count); +} + +/* + * hkdfResult + * + * Description: + * This function will finish the HKDF extraction and perform the + * final HKDF expansion. + * + * Parameters: + * context: [in/out] + * The HKDF context to use to calculate the HKDF hash. + * prk[ ]: [out] + * An optional location to store the HKDF extraction. + * Either NULL, or pointer to a buffer that must be + * larger than USHAHashSize(whichSha); + * info[ ]: [in] + * The optional context and application specific information. + * If info == NULL or a zero-length string, it is ignored. + * info_len: [in] + * The length of the optional context and application specific + * information. (Ignored if info == NULL.) + * okm[ ]: [out] + * Where the HKDF is to be stored. + * okm_len: [in] + * The length of the buffer to hold okm. + * okm_len must be <= 255 * USHABlockSize(whichSha) + * + * Returns: + * sha Error Code. + * + */ +int hkdfResult(HKDFContext *context, + uint8_t prk[USHAMaxHashSize], + const unsigned char *info, int info_len, + uint8_t okm[USHAMaxHashSize], int okm_len) +{ + uint8_t prkbuf[USHAMaxHashSize]; + int ret; + + if (!context) return shaNull; + if (context->Corrupted) return context->Corrupted; + if (context->Computed) return context->Corrupted = shaStateError; + if (!okm) return context->Corrupted = shaBadParam; + if (!prk) prk = prkbuf; + + ret = hmacResult(&context->hmacContext, prk) || + hkdfExpand(context->whichSha, prk, context->hashSize, info, + info_len, okm, okm_len); + context->Computed = 1; + return context->Corrupted = ret; +} + diff --git a/src/crypto-rfc6234.h b/src/crypto-rfc6234.h new file mode 100644 index 00000000..777bb00d --- /dev/null +++ b/src/crypto-rfc6234.h @@ -0,0 +1,357 @@ +/***************** See RFC 6234 for details. *******************/ +/* + Copyright (c) 2011 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, are permitted provided that the following + conditions are met: + + - Redistributions of source code must retain the above + copyright notice, this list of conditions and + the following disclaimer. + + - Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + - Neither the name of Internet Society, IETF or IETF Trust, nor + the names of specific contributors, may be used to endorse or + promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef _SHA_H_ +#define _SHA_H_ + +/* + * Description: + * This file implements the Secure Hash Algorithms + * as defined in the U.S. National Institute of Standards + * and Technology Federal Information Processing Standards + * Publication (FIPS PUB) 180-3 published in October 2008 + * and formerly defined in its predecessors, FIPS PUB 180-1 + * and FIP PUB 180-2. + * + * A combined document showing all algorithms is available at + * http://csrc.nist.gov/publications/fips/ + * fips180-3/fips180-3_final.pdf + * + * The five hashes are defined in these sizes: + * SHA-1 20 byte / 160 bit + * SHA-224 28 byte / 224 bit + * SHA-256 32 byte / 256 bit + * SHA-384 48 byte / 384 bit + * SHA-512 64 byte / 512 bit + * + * Compilation Note: + * These files may be compiled with two options: + * USE_32BIT_ONLY - use 32-bit arithmetic only, for systems + * without 64-bit integers + * + * USE_MODIFIED_MACROS - use alternate form of the SHA_Ch() + * and SHA_Maj() macros that are equivalent + * and potentially faster on many systems + * + */ + +#include +/* + * If you do not have the ISO standard stdint.h header file, then you + * must typedef the following: + * name meaning + * uint64_t unsigned 64-bit integer + * uint32_t unsigned 32-bit integer + * uint8_t unsigned 8-bit integer (i.e., unsigned char) + * int_least16_t integer of >= 16 bits + * + * See stdint-example.h + */ + +#ifndef _SHA_enum_ +#define _SHA_enum_ +/* + * All SHA functions return one of these values. + */ +enum { + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError, /* called Input after FinalBits or Result */ + shaBadParam /* passed a bad parameter */ +}; +#endif /* _SHA_enum_ */ + +/* + * These constants hold size information for each of the SHA + * hashing operations + */ +enum { + SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64, + SHA256_Message_Block_Size = 64, SHA384_Message_Block_Size = 128, + SHA512_Message_Block_Size = 128, + USHA_Max_Message_Block_Size = SHA512_Message_Block_Size, + + SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32, + SHA384HashSize = 48, SHA512HashSize = 64, + USHAMaxHashSize = SHA512HashSize, + + SHA1HashSizeBits = 160, SHA224HashSizeBits = 224, + SHA256HashSizeBits = 256, SHA384HashSizeBits = 384, + SHA512HashSizeBits = 512, USHAMaxHashSizeBits = SHA512HashSizeBits +}; + +/* + * These constants are used in the USHA (Unified SHA) functions. + */ +typedef enum SHAversion { + SHA1, SHA224, SHA256, SHA384, SHA512 +} SHAversion; + +/* + * This structure will hold context information for the SHA-1 + * hashing operation. + */ +typedef struct SHA1Context { + uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ + + uint32_t Length_High; /* Message length in bits */ + uint32_t Length_Low; /* Message length in bits */ + + int_least16_t Message_Block_Index; /* Message_Block array index */ + /* 512-bit message blocks */ + uint8_t Message_Block[SHA1_Message_Block_Size]; + + int Computed; /* Is the hash computed? */ + int Corrupted; /* Cumulative corruption code */ +} SHA1Context; + +/* + * This structure will hold context information for the SHA-256 + * hashing operation. + */ +typedef struct SHA256Context { + uint32_t Intermediate_Hash[SHA256HashSize/4]; /* Message Digest */ + + uint32_t Length_High; /* Message length in bits */ + uint32_t Length_Low; /* Message length in bits */ + + int_least16_t Message_Block_Index; /* Message_Block array index */ + /* 512-bit message blocks */ + uint8_t Message_Block[SHA256_Message_Block_Size]; + + int Computed; /* Is the hash computed? */ + int Corrupted; /* Cumulative corruption code */ +} SHA256Context; + +/* + * This structure will hold context information for the SHA-512 + * hashing operation. + */ +typedef struct SHA512Context { +#ifdef USE_32BIT_ONLY + uint32_t Intermediate_Hash[SHA512HashSize/4]; /* Message Digest */ + uint32_t Length[4]; /* Message length in bits */ +#else /* !USE_32BIT_ONLY */ + uint64_t Intermediate_Hash[SHA512HashSize/8]; /* Message Digest */ + uint64_t Length_High, Length_Low; /* Message length in bits */ +#endif /* USE_32BIT_ONLY */ + + int_least16_t Message_Block_Index; /* Message_Block array index */ + /* 1024-bit message blocks */ + uint8_t Message_Block[SHA512_Message_Block_Size]; + + int Computed; /* Is the hash computed?*/ + int Corrupted; /* Cumulative corruption code */ +} SHA512Context; + +/* + * This structure will hold context information for the SHA-224 + * hashing operation. It uses the SHA-256 structure for computation. + */ +typedef struct SHA256Context SHA224Context; + +/* + * This structure will hold context information for the SHA-384 + * hashing operation. It uses the SHA-512 structure for computation. + */ +typedef struct SHA512Context SHA384Context; + +/* + * This structure holds context information for all SHA + * hashing operations. + */ +typedef struct USHAContext { + int whichSha; /* which SHA is being used */ + union { + SHA1Context sha1Context; + SHA224Context sha224Context; SHA256Context sha256Context; + SHA384Context sha384Context; SHA512Context sha512Context; + } ctx; + +} USHAContext; + +/* + * This structure will hold context information for the HMAC + * keyed-hashing operation. + */ +typedef struct HMACContext { + int whichSha; /* which SHA is being used */ + int hashSize; /* hash size of SHA being used */ + int blockSize; /* block size of SHA being used */ + USHAContext shaContext; /* SHA context */ + unsigned char k_opad[USHA_Max_Message_Block_Size]; + /* outer padding - key XORd with opad */ + int Computed; /* Is the MAC computed? */ + int Corrupted; /* Cumulative corruption code */ + +} HMACContext; + +/* + * This structure will hold context information for the HKDF + * extract-and-expand Key Derivation Functions. + */ +typedef struct HKDFContext { + int whichSha; /* which SHA is being used */ + HMACContext hmacContext; + int hashSize; /* hash size of SHA being used */ + unsigned char prk[USHAMaxHashSize]; + /* pseudo-random key - output of hkdfInput */ + int Computed; /* Is the key material computed? */ + int Corrupted; /* Cumulative corruption code */ +} HKDFContext; + +/* + * Function Prototypes + */ + +/* SHA-1 */ +extern int SHA1Reset(SHA1Context *); +extern int SHA1Input(SHA1Context *, const uint8_t *bytes, + unsigned int bytecount); +extern int SHA1FinalBits(SHA1Context *, uint8_t bits, + unsigned int bit_count); +extern int SHA1Result(SHA1Context *, + uint8_t Message_Digest[SHA1HashSize]); + +/* SHA-224 */ +extern int SHA224Reset(SHA224Context *); +extern int SHA224Input(SHA224Context *, const uint8_t *bytes, + unsigned int bytecount); +extern int SHA224FinalBits(SHA224Context *, uint8_t bits, + unsigned int bit_count); +extern int SHA224Result(SHA224Context *, + uint8_t Message_Digest[SHA224HashSize]); + +/* SHA-256 */ +extern int SHA256Reset(SHA256Context *); +extern int SHA256Input(SHA256Context *, const uint8_t *bytes, + unsigned int bytecount); +extern int SHA256FinalBits(SHA256Context *, uint8_t bits, + unsigned int bit_count); +extern int SHA256Result(SHA256Context *, + uint8_t Message_Digest[SHA256HashSize]); + +/* SHA-384 */ +extern int SHA384Reset(SHA384Context *); +extern int SHA384Input(SHA384Context *, const uint8_t *bytes, + unsigned int bytecount); +extern int SHA384FinalBits(SHA384Context *, uint8_t bits, + unsigned int bit_count); +extern int SHA384Result(SHA384Context *, + uint8_t Message_Digest[SHA384HashSize]); + +/* SHA-512 */ +extern int SHA512Reset(SHA512Context *); +extern int SHA512Input(SHA512Context *, const uint8_t *bytes, + unsigned int bytecount); +extern int SHA512FinalBits(SHA512Context *, uint8_t bits, + unsigned int bit_count); +extern int SHA512Result(SHA512Context *, + uint8_t Message_Digest[SHA512HashSize]); + +/* Unified SHA functions, chosen by whichSha */ +extern int USHAReset(USHAContext *context, SHAversion whichSha); +extern int USHAInput(USHAContext *context, + const uint8_t *bytes, unsigned int bytecount); +extern int USHAFinalBits(USHAContext *context, + uint8_t bits, unsigned int bit_count); +extern int USHAResult(USHAContext *context, + uint8_t Message_Digest[USHAMaxHashSize]); +extern int USHABlockSize(enum SHAversion whichSha); +extern int USHAHashSize(enum SHAversion whichSha); +extern int USHAHashSizeBits(enum SHAversion whichSha); +extern const char *USHAHashName(enum SHAversion whichSha); + +/* + * HMAC Keyed-Hashing for Message Authentication, RFC 2104, + * for all SHAs. + * This interface allows a fixed-length text input to be used. + */ +extern int hmac(SHAversion whichSha, /* which SHA algorithm to use */ + const unsigned char *text, /* pointer to data stream */ + int text_len, /* length of data stream */ + const unsigned char *key, /* pointer to authentication key */ + int key_len, /* length of authentication key */ + uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */ + +/* + * HMAC Keyed-Hashing for Message Authentication, RFC 2104, + * for all SHAs. + * This interface allows any length of text input to be used. + */ +extern int hmacReset(HMACContext *context, enum SHAversion whichSha, + const unsigned char *key, int key_len); +extern int hmacInput(HMACContext *context, const unsigned char *text, + int text_len); +extern int hmacFinalBits(HMACContext *context, uint8_t bits, + unsigned int bit_count); +extern int hmacResult(HMACContext *context, + uint8_t digest[USHAMaxHashSize]); + +/* + * HKDF HMAC-based Extract-and-Expand Key Derivation Function, + * RFC 5869, for all SHAs. + */ +extern int hkdf(SHAversion whichSha, const unsigned char *salt, + int salt_len, const unsigned char *ikm, int ikm_len, + const unsigned char *info, int info_len, + uint8_t okm[ ], int okm_len); +extern int hkdfExtract(SHAversion whichSha, const unsigned char *salt, + int salt_len, const unsigned char *ikm, + int ikm_len, uint8_t prk[USHAMaxHashSize]); +extern int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ], + int prk_len, const unsigned char *info, + int info_len, uint8_t okm[ ], int okm_len); + +/* + * HKDF HMAC-based Extract-and-Expand Key Derivation Function, + * RFC 5869, for all SHAs. + * This interface allows any length of text input to be used. + */ +extern int hkdfReset(HKDFContext *context, enum SHAversion whichSha, + const unsigned char *salt, int salt_len); +extern int hkdfInput(HKDFContext *context, const unsigned char *ikm, + int ikm_len); +extern int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits, + unsigned int ikm_bit_count); +extern int hkdfResult(HKDFContext *context, + uint8_t prk[USHAMaxHashSize], + const unsigned char *info, int info_len, + uint8_t okm[USHAMaxHashSize], int okm_len); +#endif /* _SHA_H_ */ + diff --git a/src/proto-banner1.c b/src/proto-banner1.c index ddcd5ae4..d5fe1dfd 100644 --- a/src/proto-banner1.c +++ b/src/proto-banner1.c @@ -256,7 +256,16 @@ banner1_parse( socket); break; case PROTO_SSL3: - banner_ssl.parse( + if (tcb_state->is_sent_tls13) + banner_tls_13.parse( + banner1, + banner1->http_fields, + tcb_state, + px, length, + banout, + socket); + else + banner_ssl.parse( banner1, banner1->http_fields, tcb_state, @@ -619,7 +628,7 @@ banner1_create(void) banner_smtp.init(b); banner_ssh.init(b); banner_ssl.init(b); - banner_ssl_12.init(b); + banner_tls_13.init(b); banner_smb0.init(b); banner_smb1.init(b); banner_telnet.init(b); @@ -797,12 +806,6 @@ banner1_selftest() return 1; } - x = banner_ssl_12.selftest(); - if (x) { - fprintf(stderr, "SSL banner: selftest failed\n"); - return 1; - } - x = banner_smb1.selftest(); if (x) { fprintf(stderr, "SMB banner: selftest failed\n"); diff --git a/src/proto-banner1.h b/src/proto-banner1.h index 5056532b..ae96ae0e 100644 --- a/src/proto-banner1.h +++ b/src/proto-banner1.h @@ -8,6 +8,9 @@ #include "proto-x509.h" #include "proto-spnego.h" +#include "crypto-aes256.h" +#include "crypto-rfc6234.h" + struct stack_handle_t; struct Banner1; struct StreamState; @@ -50,16 +53,27 @@ struct BannerBase64 unsigned temp:24; }; +struct AES_CTR_STATE { + unsigned char counter[16]; // 128 bits + struct aes256_context_t key; + unsigned char buf[16]; + unsigned char offset; // how much the buf is filled +}; + struct SSL_SERVER_HELLO { unsigned state; unsigned remaining; unsigned timestamp; unsigned short cipher_suite; - unsigned short ext_tag; - unsigned short ext_remaining; + struct { + unsigned short tag; + unsigned short len; + unsigned short i; + } ext; unsigned char compression_method; unsigned char version_major; unsigned char version_minor; + unsigned char kx_data[32]; // x25519 server pubkey }; struct SSL_SERVER_CERT { unsigned state; @@ -73,18 +87,34 @@ struct SSL_SERVER_ALERT { unsigned char level; unsigned char description; }; +struct SSL_APPLICATION_DATA { + unsigned state; + struct AES_CTR_STATE aes; +}; struct SSLRECORD { unsigned char type; unsigned char version_major; unsigned char version_minor; + /* "sequence number is set to zero at the beginning of a + * connection and whenever the key is changed" */ + unsigned long seqnum; struct { unsigned state; unsigned char type; unsigned remaining; + unsigned negotiation_state; + // For TLS 1.3, one must do the SHA384 of clienthello + serverhello + SHA384Context sha384ctx; + aes256_key_t client_handshake_key; + aes256_key_t server_handshake_key; + unsigned char client_handshake_iv[12]; + unsigned char server_handshake_iv[12]; } handshake; + struct SSL_APPLICATION_DATA application_data; + union { struct { /* all these structs should start with state */ @@ -247,6 +277,7 @@ struct StreamState { unsigned short port; unsigned short app_proto; unsigned is_sent_sslhello:1; + unsigned is_sent_tls13:1; struct BannerBase64 base64; union { diff --git a/src/proto-banout.c b/src/proto-banout.c index 88c1eda3..1a1fb43c 100644 --- a/src/proto-banout.c +++ b/src/proto-banout.c @@ -135,7 +135,7 @@ banout_is_contains(const struct BannerOutput *banout, unsigned proto, unsigned banout_string_length(const struct BannerOutput *banout, unsigned proto) { - while (banout && banout->protocol != proto) + while (banout && (banout->protocol&0xFFFF) != proto) banout = banout->next; if (banout) @@ -359,6 +359,69 @@ banout_append(struct BannerOutput *banout, unsigned proto, } +/*************************************************************************** + ***************************************************************************/ +unsigned +banout_replacefirst(struct BannerOutput *banout, unsigned proto, + const char *string, const char *replace) +{ + struct BannerOutput *p; + + char* first_instance; + size_t string_length; + size_t replace_length; + + if (string == NULL) + return 0; + + string_length = strlen(string); + + if (replace == NULL) + return 0; + + replace_length = strlen(replace); + + /* + * Get the matching record for the protocol (e.g. HTML, SSL, etc.). + */ + p = banout_find_proto(banout, proto); + if (p == NULL) { + return 0; + } + + /* + * Find the string in the banout. + */ + first_instance = strstr((char*) p->banner, string); + size_t offset = ((unsigned) (first_instance - (char*) p->banner)); + if (first_instance == NULL) { + return 0; + } + + /* + * If the current object isn't big enough, expand it + */ + while (p->length + replace_length - string_length >= p->max_length) { + p = banout_expand(banout, p); + } + + /* + * Now that we are assured there is enough space, do the replacement + */ + p->length = (unsigned)(p->length + replace_length - string_length); // can't be <0 because strstr != NULL + memcpy( + first_instance + replace_length, + first_instance + string_length, + p->length - offset - string_length + ); + memcpy( + first_instance, + replace, + replace_length + ); + return 1; +} + /***************************************************************************** *****************************************************************************/ static const char *b64 = diff --git a/src/proto-banout.h b/src/proto-banout.h index 6c5361c2..d694fe34 100644 --- a/src/proto-banout.h +++ b/src/proto-banout.h @@ -78,6 +78,14 @@ banout_append_hexint(struct BannerOutput *banout, unsigned proto, unsigned long void banout_append_unicode(struct BannerOutput *banout, unsigned proto, unsigned c); +/* + * Replace first occurence of string with another string inside the banner. + * This function should only be used when banout represents a string, + * and not a X.509 certificate. + */ +unsigned +banout_replacefirst(struct BannerOutput *banout, unsigned proto, const char *string, const char *replace); + /** * Select a specific string (of the specified protocol). * The "banner output" can have multiple protocol objects associated diff --git a/src/proto-ssl-test.c b/src/proto-ssl-test.c index 89e03a2f..ad423ce8 100644 --- a/src/proto-ssl-test.c +++ b/src/proto-ssl-test.c @@ -2430,3 +2430,494 @@ const char yahoo_cert[] = "\xbe\xbd\x25\x4f\x24\x9b\x26\x98\x2c\x04\x1c\x51\x2b"; size_t yahoo_cert_size = sizeof(yahoo_cert) - 1; +const char tls13_test_case_1_clienthello[] = +"\x16\x03\x01\x00\xf8\x01\x00\x00\xf4\x03\x03\x00\x01\x02\x03\x04" +"\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14" +"\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\xe0\xe1\xe2\xe3" +"\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3" +"\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\x00\x08\x13\x02" +"\x13\x03\x13\x01\x00\xff\x01\x00\x00\xa3\x00\x00\x00\x18\x00\x16" +"\x00\x00\x13\x65\x78\x61\x6d\x70\x6c\x65\x2e\x75\x6c\x66\x68\x65" +"\x69\x6d\x2e\x6e\x65\x74\x00\x0b\x00\x04\x03\x00\x01\x02\x00\x0a" +"\x00\x16\x00\x14\x00\x1d\x00\x17\x00\x1e\x00\x19\x00\x18\x01\x00" +"\x01\x01\x01\x02\x01\x03\x01\x04\x00\x23\x00\x00\x00\x16\x00\x00" +"\x00\x17\x00\x00\x00\x0d\x00\x1e\x00\x1c\x04\x03\x05\x03\x06\x03" +"\x08\x07\x08\x08\x08\x09\x08\x0a\x08\x0b\x08\x04\x08\x05\x08\x06" +"\x04\x01\x05\x01\x06\x01\x00\x2b\x00\x03\x02\x03\x04\x00\x2d\x00" +"\x02\x01\x01\x00\x33\x00\x26\x00\x24\x00\x1d\x00\x20\x35\x80\x72" +"\xd6\x36\x58\x80\xd1\xae\xea\x32\x9a\xdf\x91\x21\x38\x38\x51\xed" +"\x21\xa2\x8e\x3b\x75\xe9\x65\xd0\xd2\xcd\x16\x62\x54"; +size_t tls13_test_case_1_clienthello_size = sizeof(tls13_test_case_1_clienthello) - 1; + +const char tls13_test_case_1_kxdata[32] = +"\x9f\xd7\xad\x6d\xcf\xf4\x29\x8d\xd3\xf9\x6d\x5b\x1b\x2a\xf9\x10" +"\xa0\x53\x5b\x14\x88\xd7\xf8\xfa\xbb\x34\x9a\x98\x28\x80\xb6\x15"; + +const char tls13_test_case_1_serverhello[] = +"\x16\x03\x03\x00\x7a\x02\x00\x00\x76\x03\x03\x70\x71\x72\x73\x74" +"\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84" +"\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x20\xe0\xe1\xe2\xe3" +"\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3" +"\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\x13\x02\x00\x00" +"\x2e\x00\x2b\x00\x02\x03\x04\x00\x33\x00\x24\x00\x1d\x00\x20\x9f" +"\xd7\xad\x6d\xcf\xf4\x29\x8d\xd3\xf9\x6d\x5b\x1b\x2a\xf9\x10\xa0" +"\x53\x5b\x14\x88\xd7\xf8\xfa\xbb\x34\x9a\x98\x28\x80\xb6\x15\x14" +"\x03\x03\x00\x01\x01\x17\x03\x03\x00\x17\x6b\xe0\x2f\x9d\xa7\xc2" +"\xdc\x9d\xde\xf5\x6f\x24\x68\xb9\x0a\xdf\xa2\x51\x01\xab\x03\x44" +"\xae\x17\x03\x03\x03\x43\xba\xf0\x0a\x9b\xe5\x0f\x3f\x23\x07\xe7" +"\x26\xed\xcb\xda\xcb\xe4\xb1\x86\x16\x44\x9d\x46\xc6\x20\x7a\xf6" +"\xe9\x95\x3e\xe5\xd2\x41\x1b\xa6\x5d\x31\xfe\xaf\x4f\x78\x76\x4f" +"\x2d\x69\x39\x87\x18\x6c\xc0\x13\x29\xc1\x87\xa5\xe4\x60\x8e\x8d" +"\x27\xb3\x18\xe9\x8d\xd9\x47\x69\xf7\x73\x9c\xe6\x76\x83\x92\xca" +"\xca\x8d\xcc\x59\x7d\x77\xec\x0d\x12\x72\x23\x37\x85\xf6\xe6\x9d" +"\x6f\x43\xef\xfa\x8e\x79\x05\xed\xfd\xc4\x03\x7e\xee\x59\x33\xe9" +"\x90\xa7\x97\x2f\x20\x69\x13\xa3\x1e\x8d\x04\x93\x13\x66\xd3\xd8" +"\xbc\xd6\xa4\xa4\xd6\x47\xdd\x4b\xd8\x0b\x0f\xf8\x63\xce\x35\x54" +"\x83\x3d\x74\x4c\xf0\xe0\xb9\xc0\x7c\xae\x72\x6d\xd2\x3f\x99\x53" +"\xdf\x1f\x1c\xe3\xac\xeb\x3b\x72\x30\x87\x1e\x92\x31\x0c\xfb\x2b" +"\x09\x84\x86\xf4\x35\x38\xf8\xe8\x2d\x84\x04\xe5\xc6\xc2\x5f\x66" +"\xa6\x2e\xbe\x3c\x5f\x26\x23\x26\x40\xe2\x0a\x76\x91\x75\xef\x83" +"\x48\x3c\xd8\x1e\x6c\xb1\x6e\x78\xdf\xad\x4c\x1b\x71\x4b\x04\xb4" +"\x5f\x6a\xc8\xd1\x06\x5a\xd1\x8c\x13\x45\x1c\x90\x55\xc4\x7d\xa3" +"\x00\xf9\x35\x36\xea\x56\xf5\x31\x98\x6d\x64\x92\x77\x53\x93\xc4" +"\xcc\xb0\x95\x46\x70\x92\xa0\xec\x0b\x43\xed\x7a\x06\x87\xcb\x47" +"\x0c\xe3\x50\x91\x7b\x0a\xc3\x0c\x6e\x5c\x24\x72\x5a\x78\xc4\x5f" +"\x9f\x5f\x29\xb6\x62\x68\x67\xf6\xf7\x9c\xe0\x54\x27\x35\x47\xb3" +"\x6d\xf0\x30\xbd\x24\xaf\x10\xd6\x32\xdb\xa5\x4f\xc4\xe8\x90\xbd" +"\x05\x86\x92\x8c\x02\x06\xca\x2e\x28\xe4\x4e\x22\x7a\x2d\x50\x63" +"\x19\x59\x35\xdf\x38\xda\x89\x36\x09\x2e\xef\x01\xe8\x4c\xad\x2e" +"\x49\xd6\x2e\x47\x0a\x6c\x77\x45\xf6\x25\xec\x39\xe4\xfc\x23\x32" +"\x9c\x79\xd1\x17\x28\x76\x80\x7c\x36\xd7\x36\xba\x42\xbb\x69\xb0" +"\x04\xff\x55\xf9\x38\x50\xdc\x33\xc1\xf9\x8a\xbb\x92\x85\x83\x24" +"\xc7\x6f\xf1\xeb\x08\x5d\xb3\xc1\xfc\x50\xf7\x4e\xc0\x44\x42\xe6" +"\x22\x97\x3e\xa7\x07\x43\x41\x87\x94\xc3\x88\x14\x0b\xb4\x92\xd6" +"\x29\x4a\x05\x40\xe5\xa5\x9c\xfa\xe6\x0b\xa0\xf1\x48\x99\xfc\xa7" +"\x13\x33\x31\x5e\xa0\x83\xa6\x8e\x1d\x7c\x1e\x4c\xdc\x2f\x56\xbc" +"\xd6\x11\x96\x81\xa4\xad\xbc\x1b\xbf\x42\xaf\xd8\x06\xc3\xcb\xd4" +"\x2a\x07\x6f\x54\x5d\xee\x4e\x11\x8d\x0b\x39\x67\x54\xbe\x2b\x04" +"\x2a\x68\x5d\xd4\x72\x7e\x89\xc0\x38\x6a\x94\xd3\xcd\x6e\xcb\x98" +"\x20\xe9\xd4\x9a\xfe\xed\x66\xc4\x7e\x6f\xc2\x43\xea\xbe\xbb\xcb" +"\x0b\x02\x45\x38\x77\xf5\xac\x5d\xbf\xbd\xf8\xdb\x10\x52\xa3\xc9" +"\x94\xb2\x24\xcd\x9a\xaa\xf5\x6b\x02\x6b\xb9\xef\xa2\xe0\x13\x02" +"\xb3\x64\x01\xab\x64\x94\xe7\x01\x8d\x6e\x5b\x57\x3b\xd3\x8b\xce" +"\xf0\x23\xb1\xfc\x92\x94\x6b\xbc\xa0\x20\x9c\xa5\xfa\x92\x6b\x49" +"\x70\xb1\x00\x91\x03\x64\x5c\xb1\xfc\xfe\x55\x23\x11\xff\x73\x05" +"\x58\x98\x43\x70\x03\x8f\xd2\xcc\xe2\xa9\x1f\xc7\x4d\x6f\x3e\x3e" +"\xa9\xf8\x43\xee\xd3\x56\xf6\xf8\x2d\x35\xd0\x3b\xc2\x4b\x81\xb5" +"\x8c\xeb\x1a\x43\xec\x94\x37\xe6\xf1\xe5\x0e\xb6\xf5\x55\xe3\x21" +"\xfd\x67\xc8\x33\x2e\xb1\xb8\x32\xaa\x8d\x79\x5a\x27\xd4\x79\xc6" +"\xe2\x7d\x5a\x61\x03\x46\x83\x89\x19\x03\xf6\x64\x21\xd0\x94\xe1" +"\xb0\x0a\x9a\x13\x8d\x86\x1e\x6f\x78\xa2\x0a\xd3\xe1\x58\x00\x54" +"\xd2\xe3\x05\x25\x3c\x71\x3a\x02\xfe\x1e\x28\xde\xee\x73\x36\x24" +"\x6f\x6a\xe3\x43\x31\x80\x6b\x46\xb4\x7b\x83\x3c\x39\xb9\xd3\x1c" +"\xd3\x00\xc2\xa6\xed\x83\x13\x99\x77\x6d\x07\xf5\x70\xea\xf0\x05" +"\x9a\x2c\x68\xa5\xf3\xae\x16\xb6\x17\x40\x4a\xf7\xb7\x23\x1a\x4d" +"\x94\x27\x58\xfc\x02\x0b\x3f\x23\xee\x8c\x15\xe3\x60\x44\xcf\xd6" +"\x7c\xd6\x40\x99\x3b\x16\x20\x75\x97\xfb\xf3\x85\xea\x7a\x4d\x99" +"\xe8\xd4\x56\xff\x83\xd4\x1f\x7b\x8b\x4f\x06\x9b\x02\x8a\x2a\x63" +"\xa9\x19\xa7\x0e\x3a\x10\xe3\x08\x41\x58\xfa\xa5\xba\xfa\x30\x18" +"\x6c\x6b\x2f\x23\x8e\xb5\x30\xc7\x3e\x17\x03\x03\x01\x19\x73\x71" +"\x9f\xce\x07\xec\x2f\x6d\x3b\xba\x02\x92\xa0\xd4\x0b\x27\x70\xc0" +"\x6a\x27\x17\x99\xa5\x33\x14\xf6\xf7\x7f\xc9\x5c\x5f\xe7\xb9\xa4" +"\x32\x9f\xd9\x54\x8c\x67\x0e\xbe\xea\x2f\x2d\x5c\x35\x1d\xd9\x35" +"\x6e\xf2\xdc\xd5\x2e\xb1\x37\xbd\x3a\x67\x65\x22\xf8\xcd\x0f\xb7" +"\x56\x07\x89\xad\x7b\x0e\x3c\xab\xa2\xe3\x7e\x6b\x41\x99\xc6\x79" +"\x3b\x33\x46\xed\x46\xcf\x74\x0a\x9f\xa1\xfe\xc4\x14\xdc\x71\x5c" +"\x41\x5c\x60\xe5\x75\x70\x3c\xe6\xa3\x4b\x70\xb5\x19\x1a\xa6\xa6" +"\x1a\x18\xfa\xff\x21\x6c\x68\x7a\xd8\xd1\x7e\x12\xa7\xe9\x99\x15" +"\xa6\x11\xbf\xc1\xa2\xbe\xfc\x15\xe6\xe9\x4d\x78\x46\x42\xe6\x82" +"\xfd\x17\x38\x2a\x34\x8c\x30\x10\x56\xb9\x40\xc9\x84\x72\x00\x40" +"\x8b\xec\x56\xc8\x1e\xa3\xd7\x21\x7a\xb8\xe8\x5a\x88\x71\x53\x95" +"\x89\x9c\x90\x58\x7f\x72\xe8\xdd\xd7\x4b\x26\xd8\xed\xc1\xc7\xc8" +"\x37\xd9\xf2\xeb\xbc\x26\x09\x62\x21\x90\x38\xb0\x56\x54\xa6\x3a" +"\x0b\x12\x99\x9b\x4a\x83\x06\xa3\xdd\xcc\x0e\x17\xc5\x3b\xa8\xf9" +"\xc8\x03\x63\xf7\x84\x13\x54\xd2\x91\xb4\xac\xe0\xc0\xf3\x30\xc0" +"\xfc\xd5\xaa\x9d\xee\xf9\x69\xae\x8a\xb2\xd9\x8d\xa8\x8e\xbb\x6e" +"\xa8\x0a\x3a\x11\xf0\x0e\xa2\x96\xa3\x23\x23\x67\xff\x07\x5e\x1c" +"\x66\xdd\x9c\xbe\xdc\x47\x13\x17\x03\x03\x00\x45\x10\x61\xde\x27" +"\xe5\x1c\x2c\x9f\x34\x29\x11\x80\x6f\x28\x2b\x71\x0c\x10\x63\x2c" +"\xa5\x00\x67\x55\x88\x0d\xbf\x70\x06\x00\x2d\x0e\x84\xfe\xd9\xad" +"\xf2\x7a\x43\xb5\x19\x23\x03\xe4\xdf\x5c\x28\x5d\x58\xe3\xc7\x62" +"\x24\x07\x84\x40\xc0\x74\x23\x74\x74\x4a\xec\xf2\x8c\xf3\x18\x2f" +"\xd0"; +size_t tls13_test_case_1_serverhello_size = sizeof(tls13_test_case_1_serverhello) - 1; + +const char tls13_test_case_1_server_handshake_key[] = +"\x9f\x13\x57\x5c\xe3\xf8\xcf\xc1\xdf\x64\xa7\x7c\xea\xff\xe8\x97" +"\x00\xb4\x92\xad\x31\xb4\xfa\xb0\x1c\x47\x92\xbe\x1b\x26\x6b\x7f"; + +const char tls13_test_case_1_client_handshake_key[] = +"\x11\x35\xb4\x82\x6a\x9a\x70\x25\x7e\x5a\x39\x1a\xd9\x30\x93\xdf" +"\xd7\xc4\x21\x48\x12\xf4\x93\xb3\xe3\xda\xae\x1e\xb2\xb1\xac\x69"; + +const char tls13_test_case_1_server_handshake_iv[] = +"\x95\x63\xbc\x8b\x59\x0f\x67\x1f\x48\x8d\x2d\xa3"; + +const char tls13_test_case_1_client_handshake_iv[] = +"\x42\x56\xd2\xe0\xe8\x8b\xab\xdd\x05\xeb\x2f\x27"; + +/* TLS 1.3 certificates have a slightly different format. Parse that */ +const char tls13_test_case_2_certs[] = +"\x00\x00\x10\x95\x00\x04\x73\x30\x82\x04\x6f\x30\x82\x03\x57\xa0" +"\x03\x02\x01\x02\x02\x12\x04\xd8\x3f\xac\xd5\xe2\x1c\x8a\x0c\xbd" +"\x60\xab\x5f\x2f\xd1\x8a\x0d\xbd\x30\x0d\x06\x09\x2a\x86\x48\x86" +"\xf7\x0d\x01\x01\x0b\x05\x00\x30\x32\x31\x0b\x30\x09\x06\x03\x55" +"\x04\x06\x13\x02\x55\x53\x31\x16\x30\x14\x06\x03\x55\x04\x0a\x13" +"\x0d\x4c\x65\x74\x27\x73\x20\x45\x6e\x63\x72\x79\x70\x74\x31\x0b" +"\x30\x09\x06\x03\x55\x04\x03\x13\x02\x52\x33\x30\x1e\x17\x0d\x32" +"\x33\x30\x32\x32\x37\x31\x31\x30\x31\x32\x38\x5a\x17\x0d\x32\x33" +"\x30\x35\x32\x38\x31\x31\x30\x31\x32\x37\x5a\x30\x16\x31\x14\x30" +"\x12\x06\x03\x55\x04\x03\x13\x0b\x74\x6c\x73\x31\x33\x2e\x31\x64" +"\x2e\x70\x77\x30\x76\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01" +"\x06\x05\x2b\x81\x04\x00\x22\x03\x62\x00\x04\xde\xad\xc0\xde\xd7" +"\xcb\xfb\x7e\xa3\xba\x63\x37\x18\x06\x53\x37\xf9\xd0\xf7\x4e\x33" +"\x32\x17\x65\xbc\xdf\xa9\x0d\xe7\x28\x42\x80\xf2\x18\x60\x61\xce" +"\x79\x26\x8c\x6d\x8f\xaa\xbe\xf5\x33\xe2\xaf\x93\xc1\x46\x0d\xc9" +"\xc0\x2d\xca\x87\x30\x7d\xa8\x7d\xd4\x42\x2d\xec\x34\xa8\xdc\xd1" +"\xdb\x9f\x94\x1d\x54\x44\xc9\xa4\x07\x5e\x77\xfb\xfd\x51\x6d\x26" +"\x80\x35\xcd\xd1\xe7\x7e\x4d\x6b\xbf\x16\x8f\xa3\x82\x02\x47\x30" +"\x82\x02\x43\x30\x0e\x06\x03\x55\x1d\x0f\x01\x01\xff\x04\x04\x03" +"\x02\x07\x80\x30\x1d\x06\x03\x55\x1d\x25\x04\x16\x30\x14\x06\x08" +"\x2b\x06\x01\x05\x05\x07\x03\x01\x06\x08\x2b\x06\x01\x05\x05\x07" +"\x03\x02\x30\x0c\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x02\x30\x00" +"\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x71\x6c\x38\x7d\x80" +"\x4a\x13\x78\x0c\x59\x4a\x3c\x4a\x04\xd9\xaf\x68\xde\xef\x08\x30" +"\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x14\x2e\xb3\x17" +"\xb7\x58\x56\xcb\xae\x50\x09\x40\xe6\x1f\xaf\x9d\x8b\x14\xc2\xc6" +"\x30\x55\x06\x08\x2b\x06\x01\x05\x05\x07\x01\x01\x04\x49\x30\x47" +"\x30\x21\x06\x08\x2b\x06\x01\x05\x05\x07\x30\x01\x86\x15\x68\x74" +"\x74\x70\x3a\x2f\x2f\x72\x33\x2e\x6f\x2e\x6c\x65\x6e\x63\x72\x2e" +"\x6f\x72\x67\x30\x22\x06\x08\x2b\x06\x01\x05\x05\x07\x30\x02\x86" +"\x16\x68\x74\x74\x70\x3a\x2f\x2f\x72\x33\x2e\x69\x2e\x6c\x65\x6e" +"\x63\x72\x2e\x6f\x72\x67\x2f\x30\x16\x06\x03\x55\x1d\x11\x04\x0f" +"\x30\x0d\x82\x0b\x74\x6c\x73\x31\x33\x2e\x31\x64\x2e\x70\x77\x30" +"\x4c\x06\x03\x55\x1d\x20\x04\x45\x30\x43\x30\x08\x06\x06\x67\x81" +"\x0c\x01\x02\x01\x30\x37\x06\x0b\x2b\x06\x01\x04\x01\x82\xdf\x13" +"\x01\x01\x01\x30\x28\x30\x26\x06\x08\x2b\x06\x01\x05\x05\x07\x02" +"\x01\x16\x1a\x68\x74\x74\x70\x3a\x2f\x2f\x63\x70\x73\x2e\x6c\x65" +"\x74\x73\x65\x6e\x63\x72\x79\x70\x74\x2e\x6f\x72\x67\x30\x82\x01" +"\x05\x06\x0a\x2b\x06\x01\x04\x01\xd6\x79\x02\x04\x02\x04\x81\xf6" +"\x04\x81\xf3\x00\xf1\x00\x77\x00\x7a\x32\x8c\x54\xd8\xb7\x2d\xb6" +"\x20\xea\x38\xe0\x52\x1e\xe9\x84\x16\x70\x32\x13\x85\x4d\x3b\xd2" +"\x2b\xc1\x3a\x57\xa3\x52\xeb\x52\x00\x00\x01\x86\x92\xbf\xca\x80" +"\x00\x00\x04\x03\x00\x48\x30\x46\x02\x21\x00\xe5\x4b\x5e\x6d\xa3" +"\xdc\x1d\xc4\xe4\x4e\x6a\xb9\xfc\x03\x85\x9c\xa8\x3b\x71\x2f\x6d" +"\x99\x6e\x5f\x07\xee\x19\x04\x39\x2d\x75\x10\x02\x21\x00\xa4\x41" +"\xa3\x0b\x5a\xca\x69\xf2\xbd\xb5\x7e\x81\xbf\xec\xbc\xf3\x48\x09" +"\x2f\x23\x2c\xe6\xe6\x84\x32\x34\x7b\xd8\x27\xe7\xa4\x76\x00\x76" +"\x00\xe8\x3e\xd0\xda\x3e\xf5\x06\x35\x32\xe7\x57\x28\xbc\x89\x6b" +"\xc9\x03\xd3\xcb\xd1\x11\x6b\xec\xeb\x69\xe1\x77\x7d\x6d\x06\xbd" +"\x6e\x00\x00\x01\x86\x92\xbf\xca\x6c\x00\x00\x04\x03\x00\x47\x30" +"\x45\x02\x21\x00\xdb\x6d\xcb\xb1\x7f\x79\xaa\x05\xce\xbd\x8f\x0e" +"\xc6\x51\xf6\x73\xe0\x6a\x37\x43\x25\xa0\x72\x35\x99\x6b\x3b\x3b" +"\xbb\x41\x3a\x62\x02\x20\x3c\x59\x85\x99\x9b\xda\x63\x13\xe5\x3e" +"\x5d\x89\x6f\x51\xc8\x9c\x43\x6d\x78\xe0\xdc\x2b\x09\x74\xb5\x30" +"\x75\x53\x97\xa8\x69\xbc\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d" +"\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\x3f\x58\xc2\xed\x47\xec" +"\x81\x28\xc4\xfd\x9e\xf1\xbe\x7f\xa2\x55\xf8\x0b\xff\xaa\x2f\x3b" +"\xfc\x4a\x8b\xd8\x26\x35\x88\x8f\xcd\x62\xb4\x87\xb3\xd6\xac\x97" +"\xc3\x7b\x26\x62\x0a\xc1\x23\x5f\x2c\xd2\x8c\xbb\xde\x95\x9f\x39" +"\xa3\x34\xbc\xb8\xe7\x73\x30\x5b\x0d\x43\x06\xcc\x3e\xf2\x7e\xe4" +"\x17\xcf\xe4\x0f\xf1\xf5\x96\xa9\x44\x5c\x67\xd0\xba\x2b\xdd\xa1" +"\x44\xf4\xda\x95\xfa\x73\xec\x4a\x06\xa8\x14\xa0\xa7\xa8\xdf\xec" +"\x95\x28\x8a\x57\x73\x87\x2f\x4b\xae\x73\x02\x0a\x35\x65\x32\x83" +"\x6e\x1c\x55\x58\xcd\x95\x67\x73\xdf\x66\x61\xd9\xd5\xfd\xec\xdf" +"\xde\x86\x3a\xc1\xb5\x7a\xce\xef\xfd\x8f\x5a\xb6\x0f\x18\xbc\x91" +"\x36\x0f\xe9\xea\xa6\xf9\xfc\x03\xd0\x01\xb0\x7e\x8b\x3b\xee\xe7" +"\x25\xd7\xce\xd6\x35\xd8\xf4\x61\x17\x15\x31\x82\xdc\x85\x66\x70" +"\x9d\x3d\x8a\xc3\x49\x59\xdb\xd5\xb4\x54\xf8\xac\x79\x51\xc6\xcf" +"\xec\x98\xfe\x69\xef\x0e\xa5\xb2\x7b\x9b\x25\x9e\x8c\xfc\x3f\xaa" +"\xe4\x33\xff\xbe\xa2\xc3\x23\x4a\xf7\x51\x35\x1f\x95\xe9\xe3\x10" +"\x3d\xbd\x1d\x9b\x93\x37\x41\x10\x9b\x99\x5e\xd3\xb7\xba\x3b\x4f" +"\xc5\x3b\x18\xd9\x80\x82\x79\x85\xb9\x32\x00\x00\x00\x05\x1a\x30" +"\x82\x05\x16\x30\x82\x02\xfe\xa0\x03\x02\x01\x02\x02\x11\x00\x91" +"\x2b\x08\x4a\xcf\x0c\x18\xa7\x53\xf6\xd6\x2e\x25\xa7\x5f\x5a\x30" +"\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x30\x4f" +"\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x29\x30" +"\x27\x06\x03\x55\x04\x0a\x13\x20\x49\x6e\x74\x65\x72\x6e\x65\x74" +"\x20\x53\x65\x63\x75\x72\x69\x74\x79\x20\x52\x65\x73\x65\x61\x72" +"\x63\x68\x20\x47\x72\x6f\x75\x70\x31\x15\x30\x13\x06\x03\x55\x04" +"\x03\x13\x0c\x49\x53\x52\x47\x20\x52\x6f\x6f\x74\x20\x58\x31\x30" +"\x1e\x17\x0d\x32\x30\x30\x39\x30\x34\x30\x30\x30\x30\x30\x30\x5a" +"\x17\x0d\x32\x35\x30\x39\x31\x35\x31\x36\x30\x30\x30\x30\x5a\x30" +"\x32\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x16" +"\x30\x14\x06\x03\x55\x04\x0a\x13\x0d\x4c\x65\x74\x27\x73\x20\x45" +"\x6e\x63\x72\x79\x70\x74\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x13" +"\x02\x52\x33\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7" +"\x0d\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02" +"\x82\x01\x01\x00\xbb\x02\x15\x28\xcc\xf6\xa0\x94\xd3\x0f\x12\xec" +"\x8d\x55\x92\xc3\xf8\x82\xf1\x99\xa6\x7a\x42\x88\xa7\x5d\x26\xaa" +"\xb5\x2b\xb9\xc5\x4c\xb1\xaf\x8e\x6b\xf9\x75\xc8\xa3\xd7\x0f\x47" +"\x94\x14\x55\x35\x57\x8c\x9e\xa8\xa2\x39\x19\xf5\x82\x3c\x42\xa9" +"\x4e\x6e\xf5\x3b\xc3\x2e\xdb\x8d\xc0\xb0\x5c\xf3\x59\x38\xe7\xed" +"\xcf\x69\xf0\x5a\x0b\x1b\xbe\xc0\x94\x24\x25\x87\xfa\x37\x71\xb3" +"\x13\xe7\x1c\xac\xe1\x9b\xef\xdb\xe4\x3b\x45\x52\x45\x96\xa9\xc1" +"\x53\xce\x34\xc8\x52\xee\xb5\xae\xed\x8f\xde\x60\x70\xe2\xa5\x54" +"\xab\xb6\x6d\x0e\x97\xa5\x40\x34\x6b\x2b\xd3\xbc\x66\xeb\x66\x34" +"\x7c\xfa\x6b\x8b\x8f\x57\x29\x99\xf8\x30\x17\x5d\xba\x72\x6f\xfb" +"\x81\xc5\xad\xd2\x86\x58\x3d\x17\xc7\xe7\x09\xbb\xf1\x2b\xf7\x86" +"\xdc\xc1\xda\x71\x5d\xd4\x46\xe3\xcc\xad\x25\xc1\x88\xbc\x60\x67" +"\x75\x66\xb3\xf1\x18\xf7\xa2\x5c\xe6\x53\xff\x3a\x88\xb6\x47\xa5" +"\xff\x13\x18\xea\x98\x09\x77\x3f\x9d\x53\xf9\xcf\x01\xe5\xf5\xa6" +"\x70\x17\x14\xaf\x63\xa4\xff\x99\xb3\x93\x9d\xdc\x53\xa7\x06\xfe" +"\x48\x85\x1d\xa1\x69\xae\x25\x75\xbb\x13\xcc\x52\x03\xf5\xed\x51" +"\xa1\x8b\xdb\x15\x02\x03\x01\x00\x01\xa3\x82\x01\x08\x30\x82\x01" +"\x04\x30\x0e\x06\x03\x55\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x01" +"\x86\x30\x1d\x06\x03\x55\x1d\x25\x04\x16\x30\x14\x06\x08\x2b\x06" +"\x01\x05\x05\x07\x03\x02\x06\x08\x2b\x06\x01\x05\x05\x07\x03\x01" +"\x30\x12\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x08\x30\x06\x01\x01" +"\xff\x02\x01\x00\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x14" +"\x2e\xb3\x17\xb7\x58\x56\xcb\xae\x50\x09\x40\xe6\x1f\xaf\x9d\x8b" +"\x14\xc2\xc6\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14" +"\x79\xb4\x59\xe6\x7b\xb6\xe5\xe4\x01\x73\x80\x08\x88\xc8\x1a\x58" +"\xf6\xe9\x9b\x6e\x30\x32\x06\x08\x2b\x06\x01\x05\x05\x07\x01\x01" +"\x04\x26\x30\x24\x30\x22\x06\x08\x2b\x06\x01\x05\x05\x07\x30\x02" +"\x86\x16\x68\x74\x74\x70\x3a\x2f\x2f\x78\x31\x2e\x69\x2e\x6c\x65" +"\x6e\x63\x72\x2e\x6f\x72\x67\x2f\x30\x27\x06\x03\x55\x1d\x1f\x04" +"\x20\x30\x1e\x30\x1c\xa0\x1a\xa0\x18\x86\x16\x68\x74\x74\x70\x3a" +"\x2f\x2f\x78\x31\x2e\x63\x2e\x6c\x65\x6e\x63\x72\x2e\x6f\x72\x67" +"\x2f\x30\x22\x06\x03\x55\x1d\x20\x04\x1b\x30\x19\x30\x08\x06\x06" +"\x67\x81\x0c\x01\x02\x01\x30\x0d\x06\x0b\x2b\x06\x01\x04\x01\x82" +"\xdf\x13\x01\x01\x01\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01" +"\x01\x0b\x05\x00\x03\x82\x02\x01\x00\x85\xca\x4e\x47\x3e\xa3\xf7" +"\x85\x44\x85\xbc\xd5\x67\x78\xb2\x98\x63\xad\x75\x4d\x1e\x96\x3d" +"\x33\x65\x72\x54\x2d\x81\xa0\xea\xc3\xed\xf8\x20\xbf\x5f\xcc\xb7" +"\x70\x00\xb7\x6e\x3b\xf6\x5e\x94\xde\xe4\x20\x9f\xa6\xef\x8b\xb2" +"\x03\xe7\xa2\xb5\x16\x3c\x91\xce\xb4\xed\x39\x02\xe7\x7c\x25\x8a" +"\x47\xe6\x65\x6e\x3f\x46\xf4\xd9\xf0\xce\x94\x2b\xee\x54\xce\x12" +"\xbc\x8c\x27\x4b\xb8\xc1\x98\x2f\xa2\xaf\xcd\x71\x91\x4a\x08\xb7" +"\xc8\xb8\x23\x7b\x04\x2d\x08\xf9\x08\x57\x3e\x83\xd9\x04\x33\x0a" +"\x47\x21\x78\x09\x82\x27\xc3\x2a\xc8\x9b\xb9\xce\x5c\xf2\x64\xc8" +"\xc0\xbe\x79\xc0\x4f\x8e\x6d\x44\x0c\x5e\x92\xbb\x2e\xf7\x8b\x10" +"\xe1\xe8\x1d\x44\x29\xdb\x59\x20\xed\x63\xb9\x21\xf8\x12\x26\x94" +"\x93\x57\xa0\x1d\x65\x04\xc1\x0a\x22\xae\x10\x0d\x43\x97\xa1\x18" +"\x1f\x7e\xe0\xe0\x86\x37\xb5\x5a\xb1\xbd\x30\xbf\x87\x6e\x2b\x2a" +"\xff\x21\x4e\x1b\x05\xc3\xf5\x18\x97\xf0\x5e\xac\xc3\xa5\xb8\x6a" +"\xf0\x2e\xbc\x3b\x33\xb9\xee\x4b\xde\xcc\xfc\xe4\xaf\x84\x0b\x86" +"\x3f\xc0\x55\x43\x36\xf6\x68\xe1\x36\x17\x6a\x8e\x99\xd1\xff\xa5" +"\x40\xa7\x34\xb7\xc0\xd0\x63\x39\x35\x39\x75\x6e\xf2\xba\x76\xc8" +"\x93\x02\xe9\xa9\x4b\x6c\x17\xce\x0c\x02\xd9\xbd\x81\xfb\x9f\xb7" +"\x68\xd4\x06\x65\xb3\x82\x3d\x77\x53\xf8\x8e\x79\x03\xad\x0a\x31" +"\x07\x75\x2a\x43\xd8\x55\x97\x72\xc4\x29\x0e\xf7\xc4\x5d\x4e\xc8" +"\xae\x46\x84\x30\xd7\xf2\x85\x5f\x18\xa1\x79\xbb\xe7\x5e\x70\x8b" +"\x07\xe1\x86\x93\xc3\xb9\x8f\xdc\x61\x71\x25\x2a\xaf\xdf\xed\x25" +"\x50\x52\x68\x8b\x92\xdc\xe5\xd6\xb5\xe3\xda\x7d\xd0\x87\x6c\x84" +"\x21\x31\xae\x82\xf5\xfb\xb9\xab\xc8\x89\x17\x3d\xe1\x4c\xe5\x38" +"\x0e\xf6\xbd\x2b\xbd\x96\x81\x14\xeb\xd5\xdb\x3d\x20\xa7\x7e\x59" +"\xd3\xe2\xf8\x58\xf9\x5b\xb8\x48\xcd\xfe\x5c\x4f\x16\x29\xfe\x1e" +"\x55\x23\xaf\xc8\x11\xb0\x8d\xea\x7c\x93\x90\x17\x2f\xfd\xac\xa2" +"\x09\x47\x46\x3f\xf0\xe9\xb0\xb7\xff\x28\x4d\x68\x32\xd6\x67\x5e" +"\x1e\x69\xa3\x93\xb8\xf5\x9d\x8b\x2f\x0b\xd2\x52\x43\xa6\x6f\x32" +"\x57\x65\x4d\x32\x81\xdf\x38\x53\x85\x5d\x7e\x5d\x66\x29\xea\xb8" +"\xdd\xe4\x95\xb5\xcd\xb5\x56\x12\x42\xcd\xc4\x4e\xc6\x25\x38\x44" +"\x50\x6d\xec\xce\x00\x55\x18\xfe\xe9\x49\x64\xd4\x4e\xca\x97\x9c" +"\xb4\x5b\xc0\x73\xa8\xab\xb8\x47\xc2\x00\x00\x00\x05\x64\x30\x82" +"\x05\x60\x30\x82\x04\x48\xa0\x03\x02\x01\x02\x02\x10\x40\x01\x77" +"\x21\x37\xd4\xe9\x42\xb8\xee\x76\xaa\x3c\x64\x0a\xb7\x30\x0d\x06" +"\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x30\x3f\x31\x24" +"\x30\x22\x06\x03\x55\x04\x0a\x13\x1b\x44\x69\x67\x69\x74\x61\x6c" +"\x20\x53\x69\x67\x6e\x61\x74\x75\x72\x65\x20\x54\x72\x75\x73\x74" +"\x20\x43\x6f\x2e\x31\x17\x30\x15\x06\x03\x55\x04\x03\x13\x0e\x44" +"\x53\x54\x20\x52\x6f\x6f\x74\x20\x43\x41\x20\x58\x33\x30\x1e\x17" +"\x0d\x32\x31\x30\x31\x32\x30\x31\x39\x31\x34\x30\x33\x5a\x17\x0d" +"\x32\x34\x30\x39\x33\x30\x31\x38\x31\x34\x30\x33\x5a\x30\x4f\x31" +"\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x29\x30\x27" +"\x06\x03\x55\x04\x0a\x13\x20\x49\x6e\x74\x65\x72\x6e\x65\x74\x20" +"\x53\x65\x63\x75\x72\x69\x74\x79\x20\x52\x65\x73\x65\x61\x72\x63" +"\x68\x20\x47\x72\x6f\x75\x70\x31\x15\x30\x13\x06\x03\x55\x04\x03" +"\x13\x0c\x49\x53\x52\x47\x20\x52\x6f\x6f\x74\x20\x58\x31\x30\x82" +"\x02\x22\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05" +"\x00\x03\x82\x02\x0f\x00\x30\x82\x02\x0a\x02\x82\x02\x01\x00\xad" +"\xe8\x24\x73\xf4\x14\x37\xf3\x9b\x9e\x2b\x57\x28\x1c\x87\xbe\xdc" +"\xb7\xdf\x38\x90\x8c\x6e\x3c\xe6\x57\xa0\x78\xf7\x75\xc2\xa2\xfe" +"\xf5\x6a\x6e\xf6\x00\x4f\x28\xdb\xde\x68\x86\x6c\x44\x93\xb6\xb1" +"\x63\xfd\x14\x12\x6b\xbf\x1f\xd2\xea\x31\x9b\x21\x7e\xd1\x33\x3c" +"\xba\x48\xf5\xdd\x79\xdf\xb3\xb8\xff\x12\xf1\x21\x9a\x4b\xc1\x8a" +"\x86\x71\x69\x4a\x66\x66\x6c\x8f\x7e\x3c\x70\xbf\xad\x29\x22\x06" +"\xf3\xe4\xc0\xe6\x80\xae\xe2\x4b\x8f\xb7\x99\x7e\x94\x03\x9f\xd3" +"\x47\x97\x7c\x99\x48\x23\x53\xe8\x38\xae\x4f\x0a\x6f\x83\x2e\xd1" +"\x49\x57\x8c\x80\x74\xb6\xda\x2f\xd0\x38\x8d\x7b\x03\x70\x21\x1b" +"\x75\xf2\x30\x3c\xfa\x8f\xae\xdd\xda\x63\xab\xeb\x16\x4f\xc2\x8e" +"\x11\x4b\x7e\xcf\x0b\xe8\xff\xb5\x77\x2e\xf4\xb2\x7b\x4a\xe0\x4c" +"\x12\x25\x0c\x70\x8d\x03\x29\xa0\xe1\x53\x24\xec\x13\xd9\xee\x19" +"\xbf\x10\xb3\x4a\x8c\x3f\x89\xa3\x61\x51\xde\xac\x87\x07\x94\xf4" +"\x63\x71\xec\x2e\xe2\x6f\x5b\x98\x81\xe1\x89\x5c\x34\x79\x6c\x76" +"\xef\x3b\x90\x62\x79\xe6\xdb\xa4\x9a\x2f\x26\xc5\xd0\x10\xe1\x0e" +"\xde\xd9\x10\x8e\x16\xfb\xb7\xf7\xa8\xf7\xc7\xe5\x02\x07\x98\x8f" +"\x36\x08\x95\xe7\xe2\x37\x96\x0d\x36\x75\x9e\xfb\x0e\x72\xb1\x1d" +"\x9b\xbc\x03\xf9\x49\x05\xd8\x81\xdd\x05\xb4\x2a\xd6\x41\xe9\xac" +"\x01\x76\x95\x0a\x0f\xd8\xdf\xd5\xbd\x12\x1f\x35\x2f\x28\x17\x6c" +"\xd2\x98\xc1\xa8\x09\x64\x77\x6e\x47\x37\xba\xce\xac\x59\x5e\x68" +"\x9d\x7f\x72\xd6\x89\xc5\x06\x41\x29\x3e\x59\x3e\xdd\x26\xf5\x24" +"\xc9\x11\xa7\x5a\xa3\x4c\x40\x1f\x46\xa1\x99\xb5\xa7\x3a\x51\x6e" +"\x86\x3b\x9e\x7d\x72\xa7\x12\x05\x78\x59\xed\x3e\x51\x78\x15\x0b" +"\x03\x8f\x8d\xd0\x2f\x05\xb2\x3e\x7b\x4a\x1c\x4b\x73\x05\x12\xfc" +"\xc6\xea\xe0\x50\x13\x7c\x43\x93\x74\xb3\xca\x74\xe7\x8e\x1f\x01" +"\x08\xd0\x30\xd4\x5b\x71\x36\xb4\x07\xba\xc1\x30\x30\x5c\x48\xb7" +"\x82\x3b\x98\xa6\x7d\x60\x8a\xa2\xa3\x29\x82\xcc\xba\xbd\x83\x04" +"\x1b\xa2\x83\x03\x41\xa1\xd6\x05\xf1\x1b\xc2\xb6\xf0\xa8\x7c\x86" +"\x3b\x46\xa8\x48\x2a\x88\xdc\x76\x9a\x76\xbf\x1f\x6a\xa5\x3d\x19" +"\x8f\xeb\x38\xf3\x64\xde\xc8\x2b\x0d\x0a\x28\xff\xf7\xdb\xe2\x15" +"\x42\xd4\x22\xd0\x27\x5d\xe1\x79\xfe\x18\xe7\x70\x88\xad\x4e\xe6" +"\xd9\x8b\x3a\xc6\xdd\x27\x51\x6e\xff\xbc\x64\xf5\x33\x43\x4f\x02" +"\x03\x01\x00\x01\xa3\x82\x01\x46\x30\x82\x01\x42\x30\x0f\x06\x03" +"\x55\x1d\x13\x01\x01\xff\x04\x05\x30\x03\x01\x01\xff\x30\x0e\x06" +"\x03\x55\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x01\x06\x30\x4b\x06" +"\x08\x2b\x06\x01\x05\x05\x07\x01\x01\x04\x3f\x30\x3d\x30\x3b\x06" +"\x08\x2b\x06\x01\x05\x05\x07\x30\x02\x86\x2f\x68\x74\x74\x70\x3a" +"\x2f\x2f\x61\x70\x70\x73\x2e\x69\x64\x65\x6e\x74\x72\x75\x73\x74" +"\x2e\x63\x6f\x6d\x2f\x72\x6f\x6f\x74\x73\x2f\x64\x73\x74\x72\x6f" +"\x6f\x74\x63\x61\x78\x33\x2e\x70\x37\x63\x30\x1f\x06\x03\x55\x1d" +"\x23\x04\x18\x30\x16\x80\x14\xc4\xa7\xb1\xa4\x7b\x2c\x71\xfa\xdb" +"\xe1\x4b\x90\x75\xff\xc4\x15\x60\x85\x89\x10\x30\x54\x06\x03\x55" +"\x1d\x20\x04\x4d\x30\x4b\x30\x08\x06\x06\x67\x81\x0c\x01\x02\x01" +"\x30\x3f\x06\x0b\x2b\x06\x01\x04\x01\x82\xdf\x13\x01\x01\x01\x30" +"\x30\x30\x2e\x06\x08\x2b\x06\x01\x05\x05\x07\x02\x01\x16\x22\x68" +"\x74\x74\x70\x3a\x2f\x2f\x63\x70\x73\x2e\x72\x6f\x6f\x74\x2d\x78" +"\x31\x2e\x6c\x65\x74\x73\x65\x6e\x63\x72\x79\x70\x74\x2e\x6f\x72" +"\x67\x30\x3c\x06\x03\x55\x1d\x1f\x04\x35\x30\x33\x30\x31\xa0\x2f" +"\xa0\x2d\x86\x2b\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\x6c\x2e\x69" +"\x64\x65\x6e\x74\x72\x75\x73\x74\x2e\x63\x6f\x6d\x2f\x44\x53\x54" +"\x52\x4f\x4f\x54\x43\x41\x58\x33\x43\x52\x4c\x2e\x63\x72\x6c\x30" +"\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x79\xb4\x59\xe6\x7b\xb6" +"\xe5\xe4\x01\x73\x80\x08\x88\xc8\x1a\x58\xf6\xe9\x9b\x6e\x30\x0d" +"\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x03\x82\x01" +"\x01\x00\x0a\x73\x00\x6c\x96\x6e\xff\x0e\x52\xd0\xae\xdd\x8c\xe7" +"\x5a\x06\xad\x2f\xa8\xe3\x8f\xbf\xc9\x0a\x03\x15\x50\xc2\xe5\x6c" +"\x42\xbb\x6f\x9b\xf4\xb4\x4f\xc2\x44\x88\x08\x75\xcc\xeb\x07\x9b" +"\x14\x62\x6e\x78\xde\xec\x27\xba\x39\x5c\xf5\xa2\xa1\x6e\x56\x94" +"\x70\x10\x53\xb1\xbb\xe4\xaf\xd0\xa2\xc3\x2b\x01\xd4\x96\xf4\xc5" +"\x20\x35\x33\xf9\xd8\x61\x36\xe0\x71\x8d\xb4\xb8\xb5\xaa\x82\x45" +"\x95\xc0\xf2\xa9\x23\x28\xe7\xd6\xa1\xcb\x67\x08\xda\xa0\x43\x2c" +"\xaa\x1b\x93\x1f\xc9\xde\xf5\xab\x69\x5d\x13\xf5\x5b\x86\x58\x22" +"\xca\x4d\x55\xe4\x70\x67\x6d\xc2\x57\xc5\x46\x39\x41\xcf\x8a\x58" +"\x83\x58\x6d\x99\xfe\x57\xe8\x36\x0e\xf0\x0e\x23\xaa\xfd\x88\x97" +"\xd0\xe3\x5c\x0e\x94\x49\xb5\xb5\x17\x35\xd2\x2e\xbf\x4e\x85\xef" +"\x18\xe0\x85\x92\xeb\x06\x3b\x6c\x29\x23\x09\x60\xdc\x45\x02\x4c" +"\x12\x18\x3b\xe9\xfb\x0e\xde\xdc\x44\xf8\x58\x98\xae\xea\xbd\x45" +"\x45\xa1\x88\x5d\x66\xca\xfe\x10\xe9\x6f\x82\xc8\x11\x42\x0d\xfb" +"\xe9\xec\xe3\x86\x00\xde\x9d\x10\xe3\x38\xfa\xa4\x7d\xb1\xd8\xe8" +"\x49\x82\x84\x06\x9b\x2b\xe8\x6b\x4f\x01\x0c\x38\x77\x2e\xf9\xdd" +"\xe7\x39\x00\x00\x00\x01\x90\x30\x82\x01\x8c\x30\x82\x01\x32\xa0" +"\x03\x02\x01\x02\x02\x08\x79\xe4\xdb\x53\x53\xee\x6a\x34\x30\x0a" +"\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x02\x30\x18\x31\x16\x30\x14" +"\x06\x03\x55\x04\x03\x0c\x0d\x48\x53\x20\x44\x48\x3a\x20\x58\x32" +"\x35\x35\x31\x39\x30\x1e\x17\x0d\x32\x33\x30\x34\x31\x36\x30\x30" +"\x33\x33\x35\x32\x5a\x17\x0d\x32\x33\x30\x35\x31\x36\x31\x32\x33" +"\x33\x35\x32\x5a\x30\x27\x31\x25\x30\x23\x06\x03\x55\x04\x03\x0c" +"\x1c\x49\x50\x2c\x20\x70\x6f\x72\x74\x3a\x20\x38\x32\x2e\x36\x34" +"\x2e\x37\x35\x2e\x31\x38\x32\x3a\x35\x32\x37\x38\x37\x30\x59\x30" +"\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce" +"\x3d\x03\x01\x07\x03\x42\x00\x04\x25\x98\xdb\x7b\x19\xfd\x4d\x11" +"\x76\x2d\x65\x75\xa5\xb0\x62\xf0\xad\x69\x80\xf8\xb8\x99\xe4\x3a" +"\xd3\x12\x67\xa4\xe5\xe2\x3a\xb6\xbd\xcc\x4b\x29\x96\x91\xba\x07" +"\xc5\x35\x9e\xef\xff\xe9\x59\xd0\x80\xad\x99\xb6\x1b\xf0\xd3\xea" +"\xcb\x1a\x87\xac\xa8\x7c\xaa\x48\xa3\x57\x30\x55\x30\x0e\x06\x03" +"\x55\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x07\x80\x30\x0c\x06\x03" +"\x55\x1d\x13\x01\x01\xff\x04\x02\x30\x00\x30\x1d\x06\x03\x55\x1d" +"\x25\x04\x16\x30\x14\x06\x08\x2b\x06\x01\x05\x05\x07\x03\x01\x06" +"\x08\x2b\x06\x01\x05\x05\x07\x03\x02\x30\x16\x06\x03\x55\x1d\x11" +"\x04\x0f\x30\x0d\x82\x0b\x74\x6c\x73\x31\x33\x2e\x31\x64\x2e\x70" +"\x77\x30\x0a\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x02\x03\x48\x00" +"\x30\x45\x02\x20\x0d\xc4\xa3\xb6\xe4\x83\x07\x32\x3b\x74\x99\xc6" +"\xa4\x6a\x41\x19\x8c\xdc\x1a\xaa\x4f\x49\x41\x00\x05\x0d\x04\x32" +"\x36\xbd\x4d\x3e\x02\x21\x00\xf8\x3d\xa3\xcb\xdd\x51\x8c\xd8\xc6" +"\x42\x7e\x3b\x1a\x57\x92\xde\x14\x5f\x79\xdc\xe5\x1a\x48\x66\x6d" +"\x52\x9f\xad\x68\x59\x6a\xf2\x00\x00"; +size_t tls13_test_case_2_certs_size = sizeof(tls13_test_case_2_certs) - 1; + +/* The results are banners as base64 */ +const char tls13_test_case_2_result_cert1[] = +"MIIBjDCCATKgAwIBAgIIeeTbU1PuajQwCgYIKoZIzj0EAwIwGDEWMBQGA1UEAwwN" +"SFMgREg6IFgyNTUxOTAeFw0yMzA0MTYwMDMzNTJaFw0yMzA1MTYxMjMzNTJaMCcx" +"JTAjBgNVBAMMHElQLCBwb3J0OiA4Mi42NC43NS4xODI6NTI3ODcwWTATBgcqhkjO" +"PQIBBggqhkjOPQMBBwNCAAQlmNt7Gf1NEXYtZXWlsGLwrWmA+LiZ5DrTEmek5eI6" +"tr3MSymWkboHxTWe7//pWdCArZm2G/DT6ssah6yofKpIo1cwVTAOBgNVHQ8BAf8E" +"BAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH" +"AwIwFgYDVR0RBA8wDYILdGxzMTMuMWQucHcwCgYIKoZIzj0EAwIDSAAwRQIgDcSj" +"tuSDBzI7dJnGpGpBGYzcGqpPSUEABQ0EMja9TT4CIQD4PaPL3VGM2MZCfjsaV5Le" +"FF953OUaSGZtUp+taFlq8g=="; +const char tls13_test_case_2_result_cert2[] = +"MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/" +"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT" +"DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow" +"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh" +"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB" +"AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC" +"ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL" +"wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D" +"LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK" +"4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5" +"bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y" +"sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ" +"Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4" +"FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc" +"SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql" +"PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND" +"TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw" +"SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1" +"c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx" +"+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB" +"ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu" +"b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E" +"U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu" +"MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC" +"5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW" +"9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG" +"WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O" +"he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC" +"Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5"; +const char tls13_test_case_2_result_cert3[] = +"MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw" +"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh" +"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw" +"WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg" +"RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK" +"AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP" +"R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx" +"sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm" +"NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg" +"Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG" +"/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC" +"AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB" +"Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA" +"FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw" +"AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw" +"Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB" +"gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W" +"PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl" +"ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz" +"CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm" +"lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4" +"avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2" +"yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O" +"yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids" +"hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+" +"HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv" +"MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX" +"nLRbwHOoq7hHwg=="; +const char tls13_test_case_2_result_cert4[] = +"MIIEbzCCA1egAwIBAgISBNg/rNXiHIoMvWCrXy/Rig29MA0GCSqGSIb3DQEBCwUA" +"MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD" +"EwJSMzAeFw0yMzAyMjcxMTAxMjhaFw0yMzA1MjgxMTAxMjdaMBYxFDASBgNVBAMT" +"C3RsczEzLjFkLnB3MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3q3A3tfL+36jumM3" +"GAZTN/nQ904zMhdlvN+pDecoQoDyGGBhznkmjG2Pqr71M+Kvk8FGDcnALcqHMH2o" +"fdRCLew0qNzR25+UHVREyaQHXnf7/VFtJoA1zdHnfk1rvxaPo4ICRzCCAkMwDgYD" +"VR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV" +"HRMBAf8EAjAAMB0GA1UdDgQWBBRxbDh9gEoTeAxZSjxKBNmvaN7vCDAfBgNVHSME" +"GDAWgBQULrMXt1hWy65QCUDmH6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYB" +"BQUHMAGGFWh0dHA6Ly9yMy5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDov" +"L3IzLmkubGVuY3Iub3JnLzAWBgNVHREEDzANggt0bHMxMy4xZC5wdzBMBgNVHSAE" +"RTBDMAgGBmeBDAECATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRw" +"Oi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB3" +"AHoyjFTYty22IOo44FIe6YQWcDIThU070ivBOlejUutSAAABhpK/yoAAAAQDAEgw" +"RgIhAOVLXm2j3B3E5E5qufwDhZyoO3EvbZluXwfuGQQ5LXUQAiEApEGjC1rKafK9" +"tX6Bv+y880gJLyMs5uaEMjR72CfnpHYAdgDoPtDaPvUGNTLnVyi8iWvJA9PL0RFr" +"7Otp4Xd9bQa9bgAAAYaSv8psAAAEAwBHMEUCIQDbbcuxf3mqBc69jw7GUfZz4Go3" +"QyWgcjWZazs7u0E6YgIgPFmFmZvaYxPlPl2Jb1HInENteODcKwl0tTB1U5eoabww" +"DQYJKoZIhvcNAQELBQADggEBAD9Ywu1H7IEoxP2e8b5/olX4C/+qLzv8SovYJjWI" +"j81itIez1qyXw3smYgrBI18s0oy73pWfOaM0vLjnczBbDUMGzD7yfuQXz+QP8fWW" +"qURcZ9C6K92hRPTalfpz7EoGqBSgp6jf7JUoildzhy9LrnMCCjVlMoNuHFVYzZVn" +"c99mYdnV/ezf3oY6wbV6zu/9j1q2Dxi8kTYP6eqm+fwD0AGwfos77ucl187WNdj0" +"YRcVMYLchWZwnT2Kw0lZ29W0VPiseVHGz+yY/mnvDqWye5slnoz8P6rkM/++osMj" +"SvdRNR+V6eMQPb0dm5M3QRCbmV7Tt7o7T8U7GNmAgnmFuTI="; \ No newline at end of file diff --git a/src/proto-ssl.c b/src/proto-ssl.c index 5e392c2c..16a8b92c 100644 --- a/src/proto-ssl.c +++ b/src/proto-ssl.c @@ -52,12 +52,16 @@ #include "crypto-siphash24.h" #include "util-safefunc.h" #include "util-malloc.h" + +#include "crypto-aes256.h" +#include "crypto-curve25519.h" +#include "crypto-rfc6234.h" + +#include #include #include #include - - /** * Fugly macro for doing state-machine parsing. I know it's bad, but * it makes stepping through the code in a debugger so much easier. @@ -117,6 +121,115 @@ BANNER_VERSION(struct BannerOutput *banout, unsigned version_major, } } +/***************************************************************************** + *****************************************************************************/ +/* + * This key is the private key hardcoded for all X25519 exchanges + */ +static const unsigned char +tls_x25519_privkey[] = +"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" +"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"; + +#define iv_length 12 + +/* + * HKDF-Expand-Label as per RFC 8446 sect 7.1. + * This is made to be compatible with crypto-rfc6234 + */ +int hkdfExpandLabel(SHAversion whichSha, const uint8_t prk[ ], int prk_len, + const char *label, uint8_t label_len, + const unsigned char *ctx, uint8_t ctx_len, + uint8_t okm[ ], uint16_t okm_len) +{ + if (label_len > 0xf9) { + // too big + return shaBadParam; + } + uint16_t info_len = label_len + ctx_len + 10; + if (info_len > 514) { + // impossible + return shaBadParam; + } + unsigned char info[514]; + memset(info, 0, 514); + info[0] = (okm_len) >> 8; + info[1] = (okm_len) & 0xff; + info[2] = 6 + label_len; + memcpy(info + 3, "tls13 ", 6); + memcpy(info + 9, label, label_len); + info[9 + label_len] = ctx_len; + if (ctx != NULL) { + memcpy(info + 10 + label_len, ctx, ctx_len); + } + return hkdfExpand(whichSha, + prk, prk_len, + info, info_len, + okm, okm_len); +} + +/* + * This computes the TLS 1.3 keys, using x25519 + TLS_AES_256_GCM_SHA384. + * The ciphers used and the client keys are all hardcoded. + */ + +unsigned char derived_secret[48] = +"\x15\x91\xda\xc5\xcb\xbf\x03\x30\xa4\xa8\x4d\xe9\xc7\x53\x33\x0e" +"\x92\xd0\x1f\x0a\x88\x21\x4b\x44\x64\x97\x2f\xd6\x68\x04\x9e\x93" +"\xe5\x2f\x2b\x16\xfa\xd9\x22\xfd\xc0\x58\x44\x78\x42\x8f\x28\x2b"; + +enum { + NEGO_NONE, + NEGO_HANDSHAKE_KEYS, + NEGO_APPLICATION_KEYS, +}; + +static void +compute_tls_handshake_keys( + struct StreamState *pstate +) +{ + unsigned char pre_master_secret[32]; + unsigned char hello_hash[48]; + unsigned char handhake_secret[64]; // usable size: 48 bytes + unsigned char client_secret[48]; + unsigned char server_secret[48]; + + // Compute the PreMasterKey + curve25519_donna(pre_master_secret, + tls_x25519_privkey, + pstate->sub.ssl.x.server_hello.kx_data); + + // Finalize the SHA-384 hash + SHA384Result(&pstate->sub.ssl.handshake.sha384ctx, + hello_hash); + + // Compute the derived secret: HARDCODED for speed + + // static const unsigned char _zerokey[48] = {0}; + // unsigned char early_secret[48]; + // hkdfExtract(SHA384, NULL, 0, _zerokey, 48, early_secret); + // unsigned char empty_hash[48]; + // SHA384Context empty_hashctx; + // SHA384Reset(&empty_hashctx); + // SHA384Result(&empty_hashctx, empty_hash); + // hkdfExpandLabel(SHA384, early_secret, 48, "derived", 7, empty_hash, 48, derived_secret, 48); + + // Compute the handshake secret + hkdfExtract(SHA384, derived_secret, 48, pre_master_secret, 32, handhake_secret); + + // compute client and server secret + hkdfExpandLabel(SHA384, handhake_secret, 48, "c hs traffic", 12, hello_hash, 48, client_secret, 48); + hkdfExpandLabel(SHA384, handhake_secret, 48, "s hs traffic", 12, hello_hash, 48, server_secret, 48); + + // compute handshake keys + hkdfExpandLabel(SHA384, client_secret, 48, "key", 3, NULL, 0, pstate->sub.ssl.handshake.client_handshake_key.raw, 32); + hkdfExpandLabel(SHA384, server_secret, 48, "key", 3, NULL, 0, pstate->sub.ssl.handshake.server_handshake_key.raw, 32); + hkdfExpandLabel(SHA384, client_secret, 48, "iv", 2, NULL, 0, pstate->sub.ssl.handshake.client_handshake_iv, 12); + hkdfExpandLabel(SHA384, server_secret, 48, "iv", 2, NULL, 0, pstate->sub.ssl.handshake.server_handshake_iv, 12); + + pstate->sub.ssl.handshake.negotiation_state = NEGO_HANDSHAKE_KEYS; +} /***************************************************************************** * This parses the "Server Hello" packet, the response to our "ClientHello" @@ -149,6 +262,8 @@ parse_server_hello( EXT_LEN0, EXT_LEN1, EXT_DATA, EXT_DATA_HEARTBEAT, + EXT_DATA_SUPPORTED_VERSIONS, + EXT_DATA_KEY_SHARE, UNKNOWN, }; @@ -268,50 +383,50 @@ parse_server_hello( remaining |= px[i]; DROPDOWN(i,length,state); + /* Handling of the various TLS extensions */ + case EXT_TAG0: ext_tag: if (remaining < 4) { state = UNKNOWN; continue; } - hello->ext_tag = px[i]<<8; + hello->ext.i = 0; + hello->ext.tag = px[i]<<8; remaining--; DROPDOWN(i,length,state); case EXT_TAG1: - hello->ext_tag |= px[i]; + hello->ext.tag |= px[i]; remaining--; DROPDOWN(i,length,state); case EXT_LEN0: - hello->ext_remaining = px[i]<<8; + hello->ext.len = px[i]<<8; remaining--; DROPDOWN(i,length,state); case EXT_LEN1: - hello->ext_remaining |= px[i]; + hello->ext.len |= px[i]; remaining--; - switch (hello->ext_tag) { + // Next step depends on the tag + switch (hello->ext.tag) { case 0x000f: /* heartbeat */ state = EXT_DATA_HEARTBEAT; continue; + case 0x002b: /* supported_versions */ + state = EXT_DATA_SUPPORTED_VERSIONS; + continue; + case 0x0033: /* key_share */ + state = EXT_DATA_KEY_SHARE; + continue; } DROPDOWN(i,length,state); - - case EXT_DATA: - if (hello->ext_remaining == 0) { - state = EXT_TAG0; - goto ext_tag; - } - if (remaining == 0) { - state = UNKNOWN; - continue; - } - remaining--; - hello->ext_remaining--; - continue; + case EXT_DATA: case EXT_DATA_HEARTBEAT: - if (hello->ext_remaining == 0) { + case EXT_DATA_SUPPORTED_VERSIONS: + case EXT_DATA_KEY_SHARE: + if (hello->ext.i >= hello->ext.len) { state = EXT_TAG0; goto ext_tag; } @@ -320,20 +435,50 @@ parse_server_hello( continue; } remaining--; - hello->ext_remaining--; - if (px[i]) { - banout_append( banout, PROTO_VULN, "SSL[heartbeat] ", 15); + hello->ext.i++; + + switch (state) { + case EXT_DATA_HEARTBEAT: + if (px[i]) { + banout_append( banout, PROTO_VULN, "SSL[heartbeat] ", 15); + } + state = EXT_DATA; + continue; + case EXT_DATA_SUPPORTED_VERSIONS: + if (hello->ext.i == 1) { + hello->version_major = px[i]; + } else if (hello->ext.i == 2) { + hello->version_minor = px[i]; + if ((hello->version_major<<8 | hello->version_minor) == 0x0304) { // TLS 1.3 + banout_replacefirst(banout, PROTO_SSL3, "TLS/1.2", "TLS/1.3"); + } + } + continue; + case EXT_DATA_KEY_SHARE: + // This is a TLS 1.3 only extension + // get the 32bytes (x25519) of the server public key + if (hello->ext.i > 4 && hello->ext.i <= 36) { + hello->kx_data[hello->ext.i - 5] = px[i]; + } + continue; + default: + // skip unknown extension + hello->ext.i = hello->ext.len; + i += hello->ext.len; + remaining -= (hello->ext.len - 1); } - state = EXT_DATA; continue; - - case UNKNOWN: default: i = (unsigned)length; } + if (remaining == 0) { + /* end of the serverhello */ + state = 0; + } + hello->state = state; hello->remaining = remaining; } @@ -374,7 +519,8 @@ parse_server_cert( struct StreamState *pstate, const unsigned char *px, size_t length, struct BannerOutput *banout, - struct stack_handle_t *socket) + struct stack_handle_t *socket, + bool tls_13) { struct SSL_SERVER_CERT *data = &pstate->sub.ssl.x.server_cert; unsigned state = data->state; @@ -382,11 +528,13 @@ parse_server_cert( unsigned cert_remaining = data->sub.remaining; unsigned i; enum { + CTXTLEN, CTXT, // TLS 1.3 cert only LEN0, LEN1, LEN2, CLEN0, CLEN1, CLEN2, CERT, CALEN0, CALEN1, CALEN2, CACERT, + EXTLEN1, EXTLEN2, EXT, // TLS 1.3 cert only UNKNOWN, }; @@ -394,8 +542,30 @@ parse_server_cert( UNUSEDPARM(banner1_private); UNUSEDPARM(socket); + if (state == CTXTLEN && !tls_13) { + // If not on TLS 1.3, skip to LEN0 directly + state = LEN0; + } + for (i=0; i remaining) + len = remaining; + + // skip + remaining -= len; + i += len-1; + if (remaining != 0) + break; + } + DROPDOWN(i,length,state); case LEN0: remaining = px[i]; DROPDOWN(i,length,state); @@ -441,7 +611,7 @@ parse_server_cert( case CACERT: { unsigned len = (unsigned)length-i; - unsigned proto = (state == CERT ? PROTO_X509_CERT : PROTO_X509_CACERT); + unsigned proto = (state == CERT ? PROTO_X509_CERT : PROTO_X509_CACERT); if (len > remaining) len = remaining; if (len > cert_remaining) @@ -471,18 +641,49 @@ parse_server_cert( &pstate->base64); banout_end(banout, proto); } - state = CALEN0; - if (remaining == 0) { - /* FIXME: reduce this logic, it should only flush the - * FIXME: ertificate, not close the connection*/ - if (!banner1->is_heartbleed) { - ; //tcpapi_close(socket); + if (tls_13) { + // TLS 1.3 has a 2 extra fields + state = EXTLEN1; + } else { + state = CALEN0; + if (remaining == 0) { + /* FIXME: reduce this logic, it should only flush the + * FIXME: ertificate, not close the connection*/ + if (!banner1->is_heartbleed) { + ; //tcpapi_close(socket); + } } } } } break; + /* TLS 1.3 only */ + case EXTLEN1: + // we use cert_remaining to store extlen + cert_remaining = px[i] << 8; + remaining--; + DROPDOWN(i,length,state); + case EXTLEN2: + cert_remaining |= px[i]; + remaining--; + DROPDOWN(i,length,state); + case EXT: + { + unsigned len = (unsigned)length-i; + if (len > remaining) + len = remaining; + if (len > cert_remaining) + len = cert_remaining; + // skip + remaining -= len; + cert_remaining -= len; + i += len-1; + if (!cert_remaining || !remaining) { + state = CALEN0; + break; + } + } case UNKNOWN: default: @@ -526,7 +727,9 @@ parse_handshake( struct StreamState *pstate, const unsigned char *px, size_t length, struct BannerOutput *banout, - struct stack_handle_t *socket) + struct stack_handle_t *socket, + const unsigned char *client_hello, size_t client_hello_length, + bool tls_13) { struct SSLRECORD *ssl = &pstate->sub.ssl; unsigned state = ssl->handshake.state; @@ -539,6 +742,23 @@ parse_handshake( UNKNOWN, }; + /* + * TLS 1.3 needs to SHA384 the client hello + server hello + */ + if (tls_13) { + if (state == START && client_hello != NULL) { + SHA384Reset(&ssl->handshake.sha384ctx); + // dump client hello (skip record) + SHA384Input(&ssl->handshake.sha384ctx, + client_hello + 5, + client_hello_length - 5); + } + // dump server hello as it comes + SHA384Input(&ssl->handshake.sha384ctx, + px, + length); + } + /* * `for all bytes in the segment` * `do a state transition for that byte ` @@ -617,7 +837,7 @@ parse_handshake( break; case 2: /* server hello */ - parse_server_hello( banner1, + parse_server_hello(banner1, banner1_private, pstate, px+i, len, @@ -630,15 +850,25 @@ parse_handshake( pstate, px+i, len, banout, - socket); + socket, + tls_13); break; } remaining -= len; i += len-1; - if (remaining == 0) + if (remaining == 0) { + /* end of handshake record */ state = START; + /* reset the sequence number */ + ssl->seqnum = 0; + if (tls_13 && ssl->handshake.type == 2) { + // we should have everything to compute the + // TLS 1.3 keys by now. + compute_tls_handshake_keys(pstate); + } + } } break; @@ -726,7 +956,6 @@ parse_heartbeat( /* if we've been configured to "capture" the heartbleed contents, * then initialize the BASE64 encoder */ if (banner1->is_capture_heartbleed) { - banout_init_base64(&pstate->base64); banout_append(banout, PROTO_HEARTBLEED, "", 0); } } @@ -866,6 +1095,134 @@ parse_alert( ssl->handshake.remaining = remaining; } +/***************************************************************************** + * Called to decrypt encrypted application_data. + * + * This is mainly used to retrieve the server certificate, which is encrypted + * in the case of TLS 1.3. Note that to stick to masscan's paradigm, the TLS + * fragments are not reassembled: instead only the minimum 128 bits of data are + * aggregated in the AES state, which is decrypted and sent to banout directly. + * Unlike normal AES this requires an additional offset that allows to handle + * cross-packet skips. + * + *****************************************************************************/ +static void +parse_application_data( + const struct Banner1 *banner1, + void *banner1_private, + struct StreamState *pstate, + const unsigned char *px, size_t length, + struct BannerOutput *banout, + struct stack_handle_t *socket, + bool record_end, + bool tls_13) +{ + struct SSLRECORD *ssl = &pstate->sub.ssl; + unsigned state = ssl->application_data.state; + struct AES_CTR_STATE *aes = &ssl->application_data.aes; + unsigned i,j; + enum { + START, + DATA, + UNKNOWN, + }; + + if (ssl->handshake.negotiation_state != NEGO_HANDSHAKE_KEYS) { + /* We don't have the handshake keys */ + return; + } + + if (tls_13 && state == START) { + /* We perform AES decryption bloc by bloc, so that we don't + * ever aggregate more than 128 bits at a time. However when + * fragmented, we must remember what's left in the current + * AES buffer. This is what 'offset' is for. + */ + aes->offset = 0; + /* Initialize aes key */ + aes256_init(&aes->key, &ssl->handshake.server_handshake_key); + /* Calculate the ICB: last 64 bits are seqnum as big endian */ + memset(aes->counter, 0, 16); + for (i=0; i<8; i++) + aes->counter[iv_length-1-i] = (ssl->seqnum >> (8*i)) & 0xFF; + /* XOR with iv */ + for (i = 0; i < iv_length; i++) + aes->counter[i] ^= ssl->handshake.server_handshake_iv[i]; + /* HERE aes->counter is the ICB */ + /* Increment the counter once (as the counter 0 is only for Auth tag) */ + aes256_ctr_inc(aes->counter); + state = DATA; + } + + switch(state) { + case DATA: + { + /* This is a TLS 1.3 encrypted certificate */ + unsigned remaining = length; + aes256_blk_t temp; + uint8_t len; + i = 0; + do { + /* Fill the 128 bits buffer: len is how much we want */ + len = 16 - aes->offset; + if (len > remaining) { + if (!record_end) { + /* Not the end of the record + remaining */ + memcpy(aes->buf+aes->offset, px+i, remaining); + aes->offset += (uint8_t) remaining; + break; + } else { + /* End of record: pad and continue */ + memset(aes->buf+aes->offset+remaining, 0, len - remaining); + len = remaining; + } + } + memcpy(aes->buf+aes->offset, px+i, len); + + // Reminder of how GCM works (but we ignore the authTag part. yolo) + // https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Galois/counter_(GCM) + + /* Increment the counter */ + aes256_ctr_inc(aes->counter); + + /* Perform encryption of the counter */ + memcpy(temp.raw, aes->counter, 16); + aes256_encrypt_ecb(&aes->key, &temp); + + /* XOR the result with the ciphertext */ + for (j = 0; j < 16; j++) + temp.raw[j] ^= aes->buf[j]; + + /* Parse the decrypted data */ + parse_handshake(banner1, + banner1_private, + pstate, + temp.raw, len+aes->offset, + banout, + socket, + NULL, + 0, + tls_13); + + i += len; + remaining -= len; + aes->offset = 0; + } while(remaining); + } + break; + } + + /* End of current application_data record */ + if(record_end) { + state = START; + ssl->seqnum += 1; + } + + /* Any data we don't handle is discarded by ssl_parse_record */ + + ssl->application_data.state = state; +} + /***************************************************************************** * This is the main SSL parsing function. @@ -896,7 +1253,9 @@ ssl_parse_record( struct StreamState *pstate, const unsigned char *px, size_t length, struct BannerOutput *banout, - struct stack_handle_t *socket) + struct stack_handle_t *socket, + const unsigned char *client_hello, size_t client_hello_length, + bool tls_13) { unsigned state = pstate->state; unsigned remaining = pstate->remaining; @@ -1011,10 +1370,33 @@ ssl_parse_record( pstate, px+i, len, banout, - socket); + socket, + client_hello, + client_hello_length, + tls_13); break; case 23: /* application data */ - /* encrypted, always*/ + /* encrypted, always */ + + /* IMPORTANT ! + * We are using an AEAD cipher. + * Therefore the last 16 bytes are the Auth tag, which + * we currently simply IGNORE. This is obviously crytographically + * broken, but faster to compute, and we just 'trust' the server. */ + if (remaining <= 16) + break; + unsigned data_len = len; + if (data_len > remaining - 16) + data_len = remaining - 16; + + parse_application_data(banner1, + banner1_private, + pstate, + px+i, data_len, + banout, + socket, + (data_len == remaining - 16), + tls_13); break; case 24: /* heartbeat */ /* encrypted, in theory, but not practice */ @@ -1073,7 +1455,13 @@ ssl_init(struct Banner1 *banner1) * TODO: we need to make this dynamically generated, so that users can * select various options. *****************************************************************************/ -static const char + +/* + * By setting the TLS record version to 1.0, and the ClientHello version to 1.2, + * this packet support for TLS 1.0, 1.1 and 1.2. + */ + +static const unsigned char ssl_hello_template[] = "\x16\x03\x01\x00\xc1" /* TLSv1.0 record layer */ "\x01" /* type = client-hello */ @@ -1103,21 +1491,82 @@ ssl_hello_template[] = "\x04\x01\x05\x01\x06\x01\x03\x03\x02\x03\x03\x01\x02\x01\x03\x02" "\x02\x02\x04\x02\x05\x02\x06\x02" ; +static const size_t ssl_hello_template_length = sizeof(ssl_hello_template) - 1; + + +/* + * If the previous packet didn't work, the server is most likely TLS 1.3 only. + * + * The following is: + * - ciphers supported: [TLS_AES_256_GCM_SHA384] + * - ec_point_formats: [uncompressed] + * - supported_groups: [x25519] + * - key_share: x25519 + * + * Client x25519: + * - privkey: 202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f + * - pubkey: 358072d6365880d1aeea329adf9121383851ed21a28e3b75e965d0d2cd166254 + * + * (why x25519 and not a simpler FFDHE? Because openssl<3.0 doesn't support it) + * + * to debug this string: + * $ scapy + * >>> load_layer("tls") + * >>> TLS(b"\x16\x03\x01.....").show() + */ +static const unsigned char +tls_13_hello_template[] = +"\x16\x03\x01\x00\xd4" +"\x01" +"\x00\x00\xd0" +"\x03\x03\x02\x58\x33\x79\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\x00\x02\x13\x02\x01\x00\x00\x85\x00\x0b\x00\x02\x01\x00\x00\x0a\x00\x04\x00\x02\x00\x1d\x00\x23\x00\x00\x00\x16\x00\x00\x00\x17\x00\x00\x00\x0d\x00\x2a\x00\x28\x04\x03\x05\x03\x06\x03\x08\x07\x08\x08\x08\x09\x08\x0a\x08\x0b\x08\x04\x08\x05\x08\x06\x04\x01\x05\x01\x06\x01\x03\x03\x03\x01\x03\x02\x04\x02\x05\x02\x06\x02\x00\x2b\x00\x09\x08\x03\x04\x03\x03\x03\x02\x03\x01\x00\x2d\x00\x02\x01\x01\x00\x33\x00\x26\x00\x24\x00\x1d\x00\x20\x35\x80\x72\xd6\x36\x58\x80\xd1\xae\xea\x32\x9a\xdf\x91\x21\x38\x38\x51\xed\x21\xa2\x8e\x3b\x75\xe9\x65\xd0\xd2\xcd\x16\x62\x54"; +static const size_t tls_13_hello_template_length = sizeof(tls_13_hello_template) - 1; /***************************************************************************** - * This is the template "Client Hello" packet that is sent to the server - * to initiate the SSL connection. Right now, it's statically just transmitted - * on to the wire. - * TODO: we need to make this dynamically generated, so that users can - * select various options. + * Those functions are stubs that call ssl_parse_record slightly differently + * depending on whether the client hello sent was for TLS1.3 or not. *****************************************************************************/ -static const char -ssl_12_hello_template[] = -"\x16\x03\x01\x01\x1a" -"\x01" -"\x00\x01\x16" -"\x03\x03\x02\x58\x33\x79\x5f\x71\x03\xef\x07\xfe\x36\x61\xb0\x32\x81\xaa\x99\x10\x87\x6a\x8e\x5b\xf9\x03\x93\x44\x58\x4b\x19\xff\x42\x6a\x20\x64\x84\xcd\x28\x9c\xe9\xb1\x9d\xcd\x8a\x11\x4c\x3b\x40\x1c\x90\x02\xf2\xb5\x1a\xf1\x7e\x5d\xb8\x42\xc2\x1e\x17\x1e\x59\xa4\xac\x00\x3e\x13\x02\x13\x03\x13\x01\xc0\x2c\xc0\x30\x00\x9f\xcc\xa9\xcc\xa8\xcc\xaa\xc0\x2b\xc0\x2f\x00\x9e\xc0\x24\xc0\x28\x00\x6b\xc0\x23\xc0\x27\x00\x67\xc0\x0a\xc0\x14\x00\x39\xc0\x09\xc0\x13\x00\x33\x00\x9d\x00\x9c\x00\x3d\x00\x3c\x00\x35\x00\x2f\x00\xff\x01\x00\x00\x8f\x00\x0b\x00\x04\x03\x00\x01\x02\x00\x0a\x00\x0c\x00\x0a\x00\x1d\x00\x17\x00\x1e\x00\x19\x00\x18\x00\x23\x00\x00\x00\x16\x00\x00\x00\x17\x00\x00\x00\x0d\x00\x2a\x00\x28\x04\x03\x05\x03\x06\x03\x08\x07\x08\x08\x08\x09\x08\x0a\x08\x0b\x08\x04\x08\x05\x08\x06\x04\x01\x05\x01\x06\x01\x03\x03\x03\x01\x03\x02\x04\x02\x05\x02\x06\x02\x00\x2b\x00\x09\x08\x03\x04\x03\x03\x03\x02\x03\x01\x00\x2d\x00\x02\x01\x01\x00\x33\x00\x26\x00\x24\x00\x1d\x00\x20\xb6\x87\xb7\x72\xb9\xcb\x07\xe0\x14\x0a\x14\x81\x3f\x3f\x0a\xcc\xc4\x7d\x80\xf7\xe8\xaa\x1e\x73\xb0\xa9\xad\xb8\x3a\xa7\x3c\x64"; -; + +static void +ssl_parse_record_tls13( + const struct Banner1 *banner1, + void *banner1_private, + struct StreamState *pstate, + const unsigned char *px, size_t length, + struct BannerOutput *banout, + struct stack_handle_t *socket) +{ + ssl_parse_record(banner1, + banner1_private, + pstate, + px, length, + banout, + socket, + tls_13_hello_template, + tls_13_hello_template_length, + true); +} + +static void +ssl_parse_record_tls1( + const struct Banner1 *banner1, + void *banner1_private, + struct StreamState *pstate, + const unsigned char *px, size_t length, + struct BannerOutput *banout, + struct stack_handle_t *socket) +{ + ssl_parse_record(banner1, + banner1_private, + pstate, + px, length, + banout, + socket, + ssl_hello_template, + ssl_hello_template_length, + false); +} + /***************************************************************************** *****************************************************************************/ static char * @@ -1262,7 +1711,21 @@ extern unsigned char google_cert[]; extern size_t google_cert_size; extern unsigned char yahoo_cert[]; extern size_t yahoo_cert_size; - +extern unsigned char tls13_test_case_1_clienthello[]; +extern size_t tls13_test_case_1_clienthello_size; +extern unsigned char tls13_test_case_1_kxdata[32]; +extern unsigned char tls13_test_case_1_serverhello[]; +extern size_t tls13_test_case_1_serverhello_size; +extern unsigned char tls13_test_case_1_server_handshake_key[32]; +extern unsigned char tls13_test_case_1_client_handshake_key[32]; +extern unsigned char tls13_test_case_1_server_handshake_iv[12]; +extern unsigned char tls13_test_case_1_client_handshake_iv[12]; +extern unsigned char tls13_test_case_2_certs[]; +extern size_t tls13_test_case_2_certs_size; +extern char tls13_test_case_2_result_cert1[]; +extern char tls13_test_case_2_result_cert2[]; +extern char tls13_test_case_2_result_cert3[]; +extern char tls13_test_case_2_result_cert4[]; /***************************************************************************** *****************************************************************************/ @@ -1296,7 +1759,7 @@ ssl_selftest(void) x = banout_is_contains(banout1, PROTO_SSL3, ", fr.yahoo.com, "); if (!x) { - printf("x.509 parser failure: google.com\n"); + printf("x.509 parser failure: fr.yahoo.com\n"); return 1; } @@ -1332,7 +1795,6 @@ ssl_selftest(void) banout_release(banout1); } - /* * Do the normal parse */ @@ -1343,14 +1805,14 @@ ssl_selftest(void) { size_t i; for (i=0; iis_capture_cert = 1; + memset(state, 0, sizeof(state)); + banout_init(banout1); + // set the private key + memcpy(state->sub.ssl.x.server_hello.kx_data, tls13_test_case_1_kxdata, 32); + // parse the handshake + size_t i; + for (i=0; isub.ssl.handshake.server_handshake_key.raw, + tls13_test_case_1_server_handshake_key, + 32) != 0) + { + printf("Error: server handshake key is wrong !\n"); + return 1; + } + if(memcmp(state->sub.ssl.handshake.client_handshake_key.raw, + tls13_test_case_1_client_handshake_key, + 32) != 0) + { + printf("Error: client handshake key is wrong !\n"); + return 1; + } + if(memcmp(state->sub.ssl.handshake.server_handshake_iv, + tls13_test_case_1_server_handshake_iv, + 12) != 0) + { + printf("Error: server handshake iv is wrong !\n"); + return 1; + } + if(memcmp(state->sub.ssl.handshake.client_handshake_iv, + tls13_test_case_1_client_handshake_iv, + 12) != 0) + { + printf("Error: client handshake iv is wrong !\n"); + return 1; + } + banner1_destroy(banner1); + banout_release(banout1); + } + /* TLS 1.3 certificates parsing. + * This test payload contains 4 different certs */ + { + banner1 = banner1_create(); + banner1->is_capture_cert = 1; + memset(state, 0, sizeof(state)); + banout_init(banout1); + size_t i; + for (i=0; inext->banner; + strsize = banout1->next->length; + if(memcmp(str, tls13_test_case_2_result_cert1, strsize) != 0) + { + printf("TLS 1.3 certificate n°1 is wrong !\n"); + return 1; + } + str = banout1->next->next->banner; + strsize = banout1->next->next->length; + if(memcmp(str, tls13_test_case_2_result_cert2, strsize) != 0) + { + printf("TLS 1.3 certificate n°2 is wrong !\n"); + return 1; + } + str = banout1->next->next->next->banner; + strsize = banout1->next->next->next->length; + if(memcmp(str, tls13_test_case_2_result_cert3, strsize) != 0) + { + printf("TLS 1.3 certificate n°3 is wrong !\n"); + return 1; + } + str = banout1->next->next->next->next->banner; + strsize = banout1->next->next->next->next->length; + if(memcmp(str, tls13_test_case_2_result_cert4, strsize) != 0) + { + printf("TLS 1.3 certificate n°4 is wrong !\n"); + return 1; + } + banner1_destroy(banner1); + banout_release(banout1); + } return 0; } @@ -1432,20 +2006,23 @@ ssl_selftest(void) * This is the 'plugin' structure that registers callbacks for this parser in * the main system. *****************************************************************************/ -struct ProtocolParserStream banner_ssl_12 = { - "ssl", 443, ssl_12_hello_template, sizeof(ssl_12_hello_template)-1, 0, + +// if TLS 1.0-1.2 didn't work, try TLS 1.3 +struct ProtocolParserStream banner_tls_13 = { + "ssl", 443, tls_13_hello_template, tls_13_hello_template_length, 0, ssl_selftest, ssl_init, - ssl_parse_record, + ssl_parse_record_tls13, }; +// this will be tried first: try TLS 1.0-TLS 1.2 struct ProtocolParserStream banner_ssl = { - "ssl", 443, ssl_hello_template, sizeof(ssl_hello_template)-1, + "ssl", 443, ssl_hello_template, ssl_hello_template_length, SF__close, /* send FIN after the hello */ ssl_selftest, ssl_init, - ssl_parse_record, + ssl_parse_record_tls1, 0, 0, - &banner_ssl_12, + &banner_tls_13, }; diff --git a/src/proto-ssl.h b/src/proto-ssl.h index 9d726a54..a6f8bdc0 100644 --- a/src/proto-ssl.h +++ b/src/proto-ssl.h @@ -3,7 +3,7 @@ #include "proto-banner1.h" extern struct ProtocolParserStream banner_ssl; -extern struct ProtocolParserStream banner_ssl_12; +extern struct ProtocolParserStream banner_tls_13; extern const char *ssl_hello_heartbeat_template; extern const char *ssl_hello_ticketbleed_template; diff --git a/src/stack-tcp-app.c b/src/stack-tcp-app.c index 4694619a..327d5259 100644 --- a/src/stack-tcp-app.c +++ b/src/stack-tcp-app.c @@ -154,12 +154,13 @@ application_event(struct stack_handle_t *socket, case App_SendFirst: /* This isn't called from the outside, but from one of the * states internally whhen we transmit for the first time */ - if (stream == &banner_ssl || stream == &banner_ssl_12) { + if (stream == &banner_ssl || stream == &banner_tls_13) { /* * Kludge, extreme kludge * I don't even know what this does any longer */ banner_set_sslhello(socket, true); + banner_set_ssltls13(socket, stream == &banner_tls_13); } if (banner_is_heartbleed(socket)) { diff --git a/src/stack-tcp-app.h b/src/stack-tcp-app.h index e33ddef6..43bbdee8 100644 --- a/src/stack-tcp-app.h +++ b/src/stack-tcp-app.h @@ -31,6 +31,9 @@ application_event( struct stack_handle_t *socket, void banner_set_sslhello(struct stack_handle_t *socket, bool is_true); +void +banner_set_ssltls13(struct stack_handle_t *socket, bool is_true); + void banner_set_small_window(struct stack_handle_t *socket, bool is_true); diff --git a/src/stack-tcp-core.c b/src/stack-tcp-core.c index 911056de..eac81c5c 100644 --- a/src/stack-tcp-core.c +++ b/src/stack-tcp-core.c @@ -1556,6 +1556,12 @@ banner_set_sslhello(struct stack_handle_t *socket, bool is_true) { tcb->banner1_state.is_sent_sslhello = is_true; } +void +banner_set_ssltls13(struct stack_handle_t *socket, bool is_true) { + struct TCP_Control_Block *tcb = socket->tcb; + tcb->banner1_state.is_sent_tls13 = is_true; +} + void banner_set_small_window(struct stack_handle_t *socket, bool is_true) { struct TCP_Control_Block *tcb = socket->tcb;