From 363239bfbe92bfe654c21f1b181531ebdd8fa8ad Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 18 Apr 2020 18:34:28 +0300 Subject: [PATCH 86/87] kdftree: add support for TLSTREE rekeying algorithm GOST CTR-OMAC ciphersuites use external rekeying names TLSTREE. Add support for this transformation. Sponsored by ROSA Linux Signed-off-by: Dmitry Baryshkov --- src/lib/libcrypto/kdftree/kdftree.c | 3 +- src/lib/libcrypto/kdftree/kdftree.h | 23 ++++ src/lib/libcrypto/kdftree/kdftree_locl.h | 31 +++++ src/lib/libcrypto/kdftree/tlstree.c | 154 +++++++++++++++++++++++ 4 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 src/lib/libcrypto/kdftree/kdftree_locl.h create mode 100644 src/lib/libcrypto/kdftree/tlstree.c diff --git a/src/lib/libcrypto/kdftree/kdftree.c b/src/lib/libcrypto/kdftree/kdftree.c index 4dc7b0096..957ca2875 100644 --- a/src/lib/libcrypto/kdftree/kdftree.c +++ b/src/lib/libcrypto/kdftree/kdftree.c @@ -18,6 +18,7 @@ #include #include +#include "kdftree_locl.h" #include @@ -26,7 +27,7 @@ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ *((c)++)=(unsigned char)(((l) )&0xff)) -static int +int kdf_tree_block(HMAC_CTX *ctx, const unsigned char *i, unsigned int i_length, const unsigned char *label, unsigned int label_length, diff --git a/src/lib/libcrypto/kdftree/kdftree.h b/src/lib/libcrypto/kdftree/kdftree.h index 132f70690..378b06b51 100644 --- a/src/lib/libcrypto/kdftree/kdftree.h +++ b/src/lib/libcrypto/kdftree/kdftree.h @@ -40,6 +40,29 @@ int KDF_TREE_SIMPLE(const EVP_MD *md, ENGINE *impl, const unsigned char *seed, unsigned int seed_length, unsigned char *out); +/* TLSTREE is an external re-keying function (see + * draft-smyshlyaev-tls12-gost-suites Section 8 for the definition, RFC 8645 + * Section 5.2.2 for the discussion of the approach. */ + +/* Opaque */ +typedef struct TLSTREE_CTX_st TLSTREE_CTX; + +typedef struct tlstree_const_st { + uint64_t c1, c2, c3; +} TLSTREE_CONST; + +TLSTREE_CTX *TLSTREE_CTX_new(void); +void TLSTREE_CTX_free(TLSTREE_CTX *ctx); + +int TLSTREE_Init(TLSTREE_CTX *ctx, + const TLSTREE_CONST *tlsconst, + const EVP_MD *md, ENGINE *impl, + const unsigned char *key, + int key_length); +int TLSTREE_GET(TLSTREE_CTX *ctx, + unsigned char *seq, + unsigned char *out); + #if defined(__cplusplus) } /* extern C */ #endif diff --git a/src/lib/libcrypto/kdftree/kdftree_locl.h b/src/lib/libcrypto/kdftree/kdftree_locl.h new file mode 100644 index 000000000..0eff3156d --- /dev/null +++ b/src/lib/libcrypto/kdftree/kdftree_locl.h @@ -0,0 +1,31 @@ +/* $OpenBSD: kdftree_locl.h,v 1.4 2019/11/21 20:02:20 tim Exp $ */ +/* Copyright (c) 2020, Dmitry Baryshkov + * + * Sponsored by ROSA Linux + * + * Permission to use, copy, modify, and/or 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 OPENSSL_HEADER_KDFTREE_LOCL_H +#define OPENSSL_HEADER_KDFTREE_LOCL_H + +#include + +int kdf_tree_block(HMAC_CTX *ctx, + const unsigned char *i, unsigned int i_length, + const unsigned char *label, unsigned int label_length, + const unsigned char *seed, unsigned int seed_length, + const unsigned char *l, unsigned int l_length, + unsigned char *out, unsigned int *length); + +#endif /* OPENSSL_HEADER_KDFTREE_LOCL_H */ diff --git a/src/lib/libcrypto/kdftree/tlstree.c b/src/lib/libcrypto/kdftree/tlstree.c new file mode 100644 index 000000000..5c3322675 --- /dev/null +++ b/src/lib/libcrypto/kdftree/tlstree.c @@ -0,0 +1,154 @@ +/* $OpenBSD: tlstree.h,v 1.4 2019/11/21 20:02:20 tim Exp $ */ +/* Copyright (c) 2020, Dmitry Baryshkov + * + * Sponsored by ROSA Linux + * + * Permission to use, copy, modify, and/or 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 +#include "kdftree_locl.h" +#include + +#define ll2c(l,c) (*((c)++)=(unsigned char)(((l)>>56)&0xff), \ + *((c)++)=(unsigned char)(((l)>>48)&0xff), \ + *((c)++)=(unsigned char)(((l)>>40)&0xff), \ + *((c)++)=(unsigned char)(((l)>>24)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16)&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ + *((c)++)=(unsigned char)(((l) )&0xff)) + +#define c2ll(c,l) (l =((uint64_t)(*((c)++))) , \ + l|=((uint64_t)(*((c)++)))<< 8, \ + l|=((uint64_t)(*((c)++)))<<16, \ + l|=((uint64_t)(*((c)++)))<<24, \ + l|=((uint64_t)(*((c)++)))<<32, \ + l|=((uint64_t)(*((c)++)))<<40, \ + l|=((uint64_t)(*((c)++)))<<48, \ + l|=((uint64_t)(*((c)++)))<<56) + +#define TLSTREE_L1 ((const unsigned char *)"level1") +#define TLSTREE_L2 ((const unsigned char *)"level2") +#define TLSTREE_L3 ((const unsigned char *)"level3") +#define TLSTREE_L_LENGTH 6 + +#define TLSTREE_KEY_LENGTH 32 + +struct TLSTREE_CTX_st { + uint64_t seq; + const TLSTREE_CONST *tlsconst; + HMAC_CTX ctx1, ctx2, ctx3; + unsigned char current[TLSTREE_KEY_LENGTH]; +}; + +TLSTREE_CTX * +TLSTREE_CTX_new(void) +{ + TLSTREE_CTX *ctx; + + ctx = malloc(sizeof(TLSTREE_CTX)); + if (!ctx) + return NULL; + + HMAC_CTX_init(&ctx->ctx1); + HMAC_CTX_init(&ctx->ctx2); + HMAC_CTX_init(&ctx->ctx3); + ctx->tlsconst = NULL; + + return ctx; +} + +void +TLSTREE_CTX_free(TLSTREE_CTX *ctx) +{ + if (ctx == NULL) + return; + + HMAC_CTX_cleanup(&ctx->ctx1); + HMAC_CTX_cleanup(&ctx->ctx2); + HMAC_CTX_cleanup(&ctx->ctx3); +} + +static int tlstree_one(HMAC_CTX *ctx, const unsigned char *label, uint64_t seq, unsigned char *out) +{ + unsigned char seed[8], *p = seed; + static const unsigned char data1[1] = { 0x01 }; + static const unsigned char data2[2] = { 0x01, 0x00 }; + int dummy = TLSTREE_KEY_LENGTH; + + ll2c(seq, p); + return kdf_tree_block(ctx, data1, 1, label, TLSTREE_L_LENGTH, seed, 8, data2, 2, out, &dummy); +} + +int +TLSTREE_Init(TLSTREE_CTX *ctx, + const TLSTREE_CONST *tlsconst, + const EVP_MD *md, ENGINE *impl, + const unsigned char *key, + int key_length) +{ + unsigned char tmp[TLSTREE_KEY_LENGTH]; + + /* Support only reasonable cases, which allow simplification of KDF_TREE calls */ + if (key_length != EVP_MD_size(md) || + key_length != TLSTREE_KEY_LENGTH) + return 0; + + if (!ctx || !tlsconst || !md || !key) + return 0; + + ctx->tlsconst = tlsconst; + ctx->seq = 0; + + if (!HMAC_Init_ex(&ctx->ctx1, key, TLSTREE_KEY_LENGTH, md, impl) || + !tlstree_one(&ctx->ctx1, TLSTREE_L1, 0, tmp) || + !HMAC_Init_ex(&ctx->ctx2, tmp, TLSTREE_KEY_LENGTH, md, impl) || + !tlstree_one(&ctx->ctx2, TLSTREE_L2, 0, tmp) || + !HMAC_Init_ex(&ctx->ctx3, tmp, TLSTREE_KEY_LENGTH, md, impl) || + !tlstree_one(&ctx->ctx3, TLSTREE_L3, 0, ctx->current)) + return 0; + + return 1; +} + +int +TLSTREE_GET(TLSTREE_CTX *ctx, + unsigned char *seq, + unsigned char *out) +{ + uint64_t s; + unsigned char *p = seq; + unsigned char tmp[TLSTREE_KEY_LENGTH]; + + c2ll(p, s); + + if ((s & ctx->tlsconst->c1) != (ctx->seq & ctx->tlsconst->c1)) { + if (!tlstree_one(&ctx->ctx1, TLSTREE_L1, 0, tmp) || + !HMAC_Init_ex(&ctx->ctx2, tmp, TLSTREE_KEY_LENGTH, NULL, NULL)) + return 0; + } + if ((s & ctx->tlsconst->c2) != (ctx->seq & ctx->tlsconst->c2)) { + if (!tlstree_one(&ctx->ctx2, TLSTREE_L2, 0, tmp) || + !HMAC_Init_ex(&ctx->ctx3, tmp, TLSTREE_KEY_LENGTH, NULL, NULL)) + return 0; + } + if ((s & ctx->tlsconst->c3) != (ctx->seq & ctx->tlsconst->c3)) { + if (!tlstree_one(&ctx->ctx3, TLSTREE_L3, 0, ctx->current)) + return 0; + } + + memcpy(out, ctx->current, TLSTREE_KEY_LENGTH); + + return 1; +} -- 2.17.1