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;