[openssl] master update
tmraz at fedoraproject.org
tmraz at fedoraproject.org
Wed Oct 23 06:33:35 UTC 2019
The branch master has been updated
via 33f54da3dda8ef95c2a8d8580fde312c6fe4d3fb (commit)
from eb2ff0408ac6e934e05db7ed4006855c018584f1 (commit)
- Log -----------------------------------------------------------------
commit 33f54da3dda8ef95c2a8d8580fde312c6fe4d3fb
Author: Simo Sorce <simo at redhat.com>
Date: Tue Sep 17 16:35:23 2019 -0400
Add KRB5KDF from RFC 3961
Signed-off-by: Simo Sorce <simo at redhat.com>
Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
Reviewed-by: Richard Levitte <levitte at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9949)
-----------------------------------------------------------------------
Summary of changes:
crypto/err/openssl.txt | 3 +
doc/man3/EVP_KDF.pod | 6 +-
doc/man7/EVP_KDF-KRB5KDF.pod | 119 ++++++
include/openssl/core_names.h | 3 +
providers/common/include/prov/providercommonerr.h | 3 +
providers/common/provider_err.c | 4 +
providers/defltprov.c | 1 +
.../implementations/include/prov/implementations.h | 1 +
providers/implementations/kdfs/build.info | 3 +
providers/implementations/kdfs/krb5kdf.c | 432 +++++++++++++++++++++
test/evp_kdf_test.c | 38 ++
test/evp_test.c | 9 +
test/recipes/30-test_evp_data/evpkdf.txt | 120 ++++++
13 files changed, 740 insertions(+), 2 deletions(-)
create mode 100644 doc/man7/EVP_KDF-KRB5KDF.pod
create mode 100644 providers/implementations/kdfs/krb5kdf.c
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 46d2eaa2eb..9f405018c4 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -2681,6 +2681,7 @@ PROV_R_FAILED_TO_GET_PARAMETER:103:failed to get parameter
PROV_R_FAILED_TO_SET_PARAMETER:104:failed to set parameter
PROV_R_INAVLID_UKM_LENGTH:146:inavlid ukm length
PROV_R_INVALID_AAD:108:invalid aad
+PROV_R_INVALID_CONSTANT_LENGTH:157:invalid constant length
PROV_R_INVALID_CUSTOM_LENGTH:111:invalid custom length
PROV_R_INVALID_DATA:115:invalid data
PROV_R_INVALID_DIGEST:122:invalid digest
@@ -2698,6 +2699,8 @@ PROV_R_INVALID_SEED_LENGTH:154:invalid seed length
PROV_R_INVALID_TAG:110:invalid tag
PROV_R_INVALID_TAGLEN:118:invalid taglen
PROV_R_MISSING_CEK_ALG:144:missing cek alg
+PROV_R_MISSING_CIPHER:155:missing cipher
+PROV_R_MISSING_CONSTANT:156:missing constant
PROV_R_MISSING_KEY:128:missing key
PROV_R_MISSING_MAC:150:missing mac
PROV_R_MISSING_MESSAGE_DIGEST:129:missing message digest
diff --git a/doc/man3/EVP_KDF.pod b/doc/man3/EVP_KDF.pod
index 339129a943..9bb360d8b8 100644
--- a/doc/man3/EVP_KDF.pod
+++ b/doc/man3/EVP_KDF.pod
@@ -183,8 +183,10 @@ The default value, if any, is implementation dependent.
=item "digest" (B<OSSL_KDF_PARAM_DIGEST>) <UTF8 string>
-For KDF implementations that use an underlying computation MAC or
-digest, these parameters set what the algorithm should be.
+=item "cipher" (B<OSSL_KDF_PARAM_CIPHER>) <UTF8 string>
+
+For KDF implementations that use an underlying computation MAC, digest or
+cipher, these parameters set what the algorithm should be.
The value is always the name of the intended algorithm,
or the properties.
diff --git a/doc/man7/EVP_KDF-KRB5KDF.pod b/doc/man7/EVP_KDF-KRB5KDF.pod
new file mode 100644
index 0000000000..08f50d1c05
--- /dev/null
+++ b/doc/man7/EVP_KDF-KRB5KDF.pod
@@ -0,0 +1,119 @@
+=pod
+
+=head1 NAME
+
+EVP_KDF-KRB5KDF - The RFC3961 Krb5 KDF EVP_KDF implementation
+
+=head1 DESCRIPTION
+
+Support for computing the B<KRB5KDF> KDF through the B<EVP_KDF> API.
+
+The EVP_KDF-KRB5KDF algorithm implements the key derivation function defined
+in RFC 3961, section 5.1 and is used by Krb5 to derive session keys.
+Three inputs are required to perform key derivation: a cipher, (for example
+AES-128-CBC), the initial key, and a constant.
+
+=head2 Identity
+
+"KRB5KDF" is the name for this implementation;
+it can be used with the EVP_KDF_fetch() function.
+
+=head2 Supported parameters
+
+The supported parameters are:
+
+=over 4
+
+=item "properies" (B<OSSL_KDF_PARAM_PROPERTIES>) <UTF8 string>
+
+=item "cipher" (B<OSSL_KDF_PARAM_CIPHER>) <UTF8 string>
+
+=item "key" (B<OSSL_KDF_PARAM_KEY>) <octet string>
+
+These parameters work as described in L<EVP_KDF(3)/PARAMETERS>.
+
+=item "constant" (B<OSSL_KDF_PARAM_CONSTANT>) <octet string>
+
+This parameter sets the constant value for the KDF.
+If a value is already set, the contents are replaced.
+
+=back
+
+=head1 NOTES
+
+A context for KRB5KDF can be obtained by calling:
+
+ EVP_KDF *kdf = EVP_KDF_fetch(NULL, "KRB5KDF", NULL);
+ EVP_KDF_CTX *kctx = EVP_KDF_CTX_new(kdf);
+
+The output length of the KRB5KDF derivation is specified via the I<keylen>
+parameter to the L<EVP_KDF_derive(3)> function, and MUST match the key
+length for the chosen cipher or an error is returned. Moreover the
+constant's length must not exceed the block size of the cipher.
+Since the KRB5KDF output length depends on the chosen cipher, calling
+L<EVP_KDF_size()> to obtain the requisite length returns the correct length
+only after the cipher is set. Prior to that B<EVP_MAX_KEY_LENGTH> is returned.
+The caller must allocate a buffer of the correct length for the chosen
+cipher, and pass that buffer to the L<EVP_KDF_derive(3)> function along
+with that length.
+
+=head1 EXAMPLES
+
+This example derives a key using the AES-128-CBC cipher:
+
+ EVP_KDF *kdf;
+ EVP_KDF_CTX *kctx;
+ unsigned char key[16] = "01234...";
+ unsigned char constant[] = "I'm a constant";
+ unsigned char out[16];
+ size_t outlen = sizeof(out);
+ OSSL_PARAM params[4], *p = params;
+
+ kdf = EVP_KDF_fetch(NULL, "KRB5KDF", NULL);
+ kctx = EVP_KDF_CTX_new(kdf);
+ EVP_KDF_free(kdf);
+
+ *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_CIPHER,
+ SN_aes_128_cbc,
+ strlen(SN_aes_128_cbc));
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
+ key, (size_t)16);
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_CONSTANT,
+ constant, strlen(constant));
+ *p = OSSL_PARAM_construct_end();
+ if (EVP_KDF_set_params(kctx, params) <= 0)
+ /* Error */
+
+ if (EVP_KDF_derive(kctx, out, &outlen) <= 0)
+ /* Error */
+
+
+=head1 CONFORMING TO
+
+RFC 3961
+
+=head1 SEE ALSO
+
+L<EVP_KDF>,
+L<EVP_KDF_CTX_new_id(3)>,
+L<EVP_KDF_CTX_free(3)>,
+L<EVP_KDF_ctrl(3)>,
+L<EVP_KDF_size(3)>,
+L<EVP_KDF_derive(3)>,
+L<EVP_KDF(3)/PARAMETERS>
+
+=head1 HISTORY
+
+This functionality was added to OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (the "License"). You may not use
+this file except in compliance with the License. You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
+
diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h
index e7e5ea060e..4cbcf0cc71 100644
--- a/include/openssl/core_names.h
+++ b/include/openssl/core_names.h
@@ -133,6 +133,8 @@ extern "C" {
#define OSSL_KDF_PARAM_SSHKDF_SESSION_ID "session_id" /* octet string */
#define OSSL_KDF_PARAM_SSHKDF_TYPE "type" /* int */
#define OSSL_KDF_PARAM_SIZE "size" /* size_t */
+#define OSSL_KDF_PARAM_CIPHER OSSL_ALG_PARAM_CIPHER /* utf8 string */
+#define OSSL_KDF_PARAM_CONSTANT "constant" /* octet string */
/* Known KDF names */
#define OSSL_KDF_NAME_HKDF "HKDF"
@@ -144,6 +146,7 @@ extern "C" {
#define OSSL_KDF_NAME_X942KDF "X942KDF"
#define OSSL_KDF_NAME_X963KDF "X963KDF"
#define OSSL_KDF_NAME_KBKDF "KBKDF"
+#define OSSL_KDF_NAME_KRB5KDF "KRB5KDF"
/* PKEY parameters */
/* Diffie-Hellman/DSA Parameters */
diff --git a/providers/common/include/prov/providercommonerr.h b/providers/common/include/prov/providercommonerr.h
index d35789e832..c726a1ec29 100644
--- a/providers/common/include/prov/providercommonerr.h
+++ b/providers/common/include/prov/providercommonerr.h
@@ -60,6 +60,7 @@ int ERR_load_PROV_strings(void);
# define PROV_R_FAILED_TO_SET_PARAMETER 104
# define PROV_R_INAVLID_UKM_LENGTH 146
# define PROV_R_INVALID_AAD 108
+# define PROV_R_INVALID_CONSTANT_LENGTH 157
# define PROV_R_INVALID_CUSTOM_LENGTH 111
# define PROV_R_INVALID_DATA 115
# define PROV_R_INVALID_DIGEST 122
@@ -77,6 +78,8 @@ int ERR_load_PROV_strings(void);
# define PROV_R_INVALID_TAG 110
# define PROV_R_INVALID_TAGLEN 118
# define PROV_R_MISSING_CEK_ALG 144
+# define PROV_R_MISSING_CIPHER 155
+# define PROV_R_MISSING_CONSTANT 156
# define PROV_R_MISSING_KEY 128
# define PROV_R_MISSING_MAC 150
# define PROV_R_MISSING_MESSAGE_DIGEST 129
diff --git a/providers/common/provider_err.c b/providers/common/provider_err.c
index 20060b0b35..589f37be70 100644
--- a/providers/common/provider_err.c
+++ b/providers/common/provider_err.c
@@ -32,6 +32,8 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INAVLID_UKM_LENGTH),
"inavlid ukm length"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_AAD), "invalid aad"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_CONSTANT_LENGTH),
+ "invalid constant length"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_CUSTOM_LENGTH),
"invalid custom length"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_DATA), "invalid data"},
@@ -54,6 +56,8 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_TAG), "invalid tag"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_TAGLEN), "invalid taglen"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_MISSING_CEK_ALG), "missing cek alg"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_MISSING_CIPHER), "missing cipher"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_MISSING_CONSTANT), "missing constant"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_MISSING_KEY), "missing key"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_MISSING_MAC), "missing mac"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_MISSING_MESSAGE_DIGEST),
diff --git a/providers/defltprov.c b/providers/defltprov.c
index 8104227fff..cf0a1755da 100644
--- a/providers/defltprov.c
+++ b/providers/defltprov.c
@@ -339,6 +339,7 @@ static const OSSL_ALGORITHM deflt_kdfs[] = {
#ifndef OPENSSL_NO_SCRYPT
{ "SCRYPT:id-scrypt", "default=yes", kdf_scrypt_functions },
#endif
+ { OSSL_KDF_NAME_KRB5KDF, "default=yes", kdf_krb5kdf_functions },
{ NULL, NULL, NULL }
};
diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h
index 16f2129115..ded3ef97f7 100644
--- a/providers/implementations/include/prov/implementations.h
+++ b/providers/implementations/include/prov/implementations.h
@@ -236,6 +236,7 @@ extern const OSSL_DISPATCH kdf_kbkdf_functions[];
#ifndef OPENSSL_NO_CMS
extern const OSSL_DISPATCH kdf_x942_kdf_functions[];
#endif
+extern const OSSL_DISPATCH kdf_krb5kdf_functions[];
/* Key management */
diff --git a/providers/implementations/kdfs/build.info b/providers/implementations/kdfs/build.info
index dee8f532fa..2c6b2ce1c8 100644
--- a/providers/implementations/kdfs/build.info
+++ b/providers/implementations/kdfs/build.info
@@ -4,6 +4,7 @@
$TLS1_PRF_GOAL=../../libimplementations.a
$HKDF_GOAL=../../libimplementations.a
$KBKDF_GOAL=../../libimplementations.a
+$KRB5KDF_GOAL=../../libimplementations.a
$PBKDF2_GOAL=../../libimplementations.a
$SSKDF_GOAL=../../libimplementations.a
$SCRYPT_GOAL=../../libimplementations.a
@@ -16,6 +17,8 @@ SOURCE[$HKDF_GOAL]=hkdf.c
SOURCE[$KBKDF_GOAL]=kbkdf.c
+SOURCE[$KRB5KDF_GOAL]=krb5kdf.c
+
SOURCE[$PBKDF2_GOAL]=pbkdf2.c
# Extra code to satisfy the FIPS and non-FIPS separation.
# When the PBKDF2 moves to legacy, this can be removed.
diff --git a/providers/implementations/kdfs/krb5kdf.c b/providers/implementations/kdfs/krb5kdf.c
new file mode 100644
index 0000000000..83dfa9c2dc
--- /dev/null
+++ b/providers/implementations/kdfs/krb5kdf.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright 2018-2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <openssl/core_names.h>
+#include <openssl/des.h>
+#include <openssl/evp.h>
+#include <openssl/kdf.h>
+
+#include "internal/cryptlib.h"
+#include "crypto/evp.h"
+#include "internal/numbers.h"
+#include "prov/implementations.h"
+#include "prov/provider_ctx.h"
+#include "prov/provider_util.h"
+#include "prov/providercommonerr.h"
+
+/* KRB5 KDF defined in RFC 3961, Section 5.1 */
+
+static OSSL_OP_kdf_newctx_fn krb5kdf_new;
+static OSSL_OP_kdf_freectx_fn krb5kdf_free;
+static OSSL_OP_kdf_reset_fn krb5kdf_reset;
+static OSSL_OP_kdf_derive_fn krb5kdf_derive;
+static OSSL_OP_kdf_settable_ctx_params_fn krb5kdf_settable_ctx_params;
+static OSSL_OP_kdf_set_ctx_params_fn krb5kdf_set_ctx_params;
+static OSSL_OP_kdf_gettable_ctx_params_fn krb5kdf_gettable_ctx_params;
+static OSSL_OP_kdf_get_ctx_params_fn krb5kdf_get_ctx_params;
+
+static int KRB5KDF(const EVP_CIPHER *cipher, ENGINE *engine,
+ const unsigned char *key, size_t key_len,
+ const unsigned char *constant, size_t constant_len,
+ unsigned char *okey, size_t okey_len);
+
+typedef struct {
+ void *provctx;
+ PROV_CIPHER cipher;
+ unsigned char *key;
+ size_t key_len;
+ unsigned char *constant;
+ size_t constant_len;
+} KRB5KDF_CTX;
+
+static void *krb5kdf_new(void *provctx)
+{
+ KRB5KDF_CTX *ctx;
+
+ if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+ ctx->provctx = provctx;
+ return ctx;
+}
+
+static void krb5kdf_free(void *vctx)
+{
+ KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx;
+
+ krb5kdf_reset(ctx);
+ OPENSSL_free(ctx);
+}
+
+static void krb5kdf_reset(void *vctx)
+{
+ KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx;
+
+ ossl_prov_cipher_reset(&ctx->cipher);
+ OPENSSL_clear_free(ctx->key, ctx->key_len);
+ OPENSSL_clear_free(ctx->constant, ctx->constant_len);
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+static int krb5kdf_set_membuf(unsigned char **dst, size_t *dst_len,
+ const OSSL_PARAM *p)
+{
+ OPENSSL_clear_free(*dst, *dst_len);
+ *dst = NULL;
+ return OSSL_PARAM_get_octet_string(p, (void **)dst, 0, dst_len);
+}
+
+static int krb5kdf_derive(void *vctx, unsigned char *key,
+ size_t keylen)
+{
+ KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx;
+ const EVP_CIPHER *cipher = ossl_prov_cipher_cipher(&ctx->cipher);
+ ENGINE *engine = ossl_prov_cipher_engine(&ctx->cipher);
+
+ if (cipher == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CIPHER);
+ return 0;
+ }
+ if (ctx->key == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
+ return 0;
+ }
+ if (ctx->constant == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CONSTANT);
+ return 0;
+ }
+ return KRB5KDF(cipher, engine, ctx->key, ctx->key_len,
+ ctx->constant, ctx->constant_len,
+ key, keylen);
+}
+
+static int krb5kdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ const OSSL_PARAM *p;
+ KRB5KDF_CTX *ctx = vctx;
+ OPENSSL_CTX *provctx = PROV_LIBRARY_CONTEXT_OF(ctx->provctx);
+
+ if (!ossl_prov_cipher_load_from_params(&ctx->cipher, params, provctx))
+ return 0;
+
+ if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY)) != NULL)
+ if (!krb5kdf_set_membuf(&ctx->key, &ctx->key_len, p))
+ return 0;
+
+ if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_CONSTANT))
+ != NULL)
+ if (!krb5kdf_set_membuf(&ctx->constant, &ctx->constant_len, p))
+ return 0;
+
+ return 1;
+}
+
+static const OSSL_PARAM *krb5kdf_settable_ctx_params(void)
+{
+ static const OSSL_PARAM known_settable_ctx_params[] = {
+ OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CIPHER, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_KDF_PARAM_CONSTANT, NULL, 0),
+ OSSL_PARAM_END
+ };
+ return known_settable_ctx_params;
+}
+
+static int krb5kdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ KRB5KDF_CTX *ctx = (KRB5KDF_CTX *)vctx;
+ const EVP_CIPHER *cipher;
+ size_t len;
+ OSSL_PARAM *p;
+
+ cipher = ossl_prov_cipher_cipher(&ctx->cipher);
+ if (cipher)
+ len = EVP_CIPHER_key_length(cipher);
+ else
+ len = EVP_MAX_KEY_LENGTH;
+
+ if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL)
+ return OSSL_PARAM_set_size_t(p, len);
+ return -2;
+}
+
+static const OSSL_PARAM *krb5kdf_gettable_ctx_params(void)
+{
+ static const OSSL_PARAM known_gettable_ctx_params[] = {
+ OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL),
+ OSSL_PARAM_END
+ };
+ return known_gettable_ctx_params;
+}
+
+const OSSL_DISPATCH kdf_krb5kdf_functions[] = {
+ { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))krb5kdf_new },
+ { OSSL_FUNC_KDF_FREECTX, (void(*)(void))krb5kdf_free },
+ { OSSL_FUNC_KDF_RESET, (void(*)(void))krb5kdf_reset },
+ { OSSL_FUNC_KDF_DERIVE, (void(*)(void))krb5kdf_derive },
+ { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS,
+ (void(*)(void))krb5kdf_settable_ctx_params },
+ { OSSL_FUNC_KDF_SET_CTX_PARAMS,
+ (void(*)(void))krb5kdf_set_ctx_params },
+ { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
+ (void(*)(void))krb5kdf_gettable_ctx_params },
+ { OSSL_FUNC_KDF_GET_CTX_PARAMS,
+ (void(*)(void))krb5kdf_get_ctx_params },
+ { 0, NULL }
+};
+
+#ifndef OPENSSL_NO_DES
+/*
+ * DES3 is a special case, it requires a random-to-key function and its
+ * input truncated to 21 bytes of the 24 produced by the cipher.
+ * See RFC3961 6.3.1
+ */
+static int fixup_des3_key(unsigned char *key)
+{
+ unsigned char *cblock;
+ int i, j;
+
+ for (i = 2; i >= 0; i--) {
+ cblock = &key[i * 8];
+ memmove(cblock, &key[i * 7], 7);
+ cblock[7] = 0;
+ for (j = 0; j < 7; j++)
+ cblock[7] |= (cblock[j] & 1) << (j + 1);
+ DES_set_odd_parity((DES_cblock *)cblock);
+ }
+
+ /* fail if keys are such that triple des degrades to single des */
+ if (CRYPTO_memcmp(&key[0], &key[8], 8) == 0 ||
+ CRYPTO_memcmp(&key[8], &key[16], 8) == 0) {
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+
+/*
+ * N-fold(K) where blocksize is N, and constant_len is K
+ * Note: Here |= denotes concatenation
+ *
+ * L = lcm(N,K)
+ * R = L/K
+ *
+ * for r: 1 -> R
+ * s |= constant rot 13*(r-1))
+ *
+ * block = 0
+ * for k: 1 -> K
+ * block += s[N(k-1)..(N-1)k] (one's complement addition)
+ *
+ * Optimizing for space we compute:
+ * for each l in L-1 -> 0:
+ * s[l] = (constant rot 13*(l/K))[l%k]
+ * block[l % N] += s[l] (with carry)
+ * finally add carry if any
+ */
+static void n_fold(unsigned char *block, unsigned int blocksize,
+ const unsigned char *constant, size_t constant_len)
+{
+ unsigned int tmp, gcd, remainder, lcm, carry;
+ int b, l;
+
+ if (constant_len == blocksize) {
+ memcpy(block, constant, constant_len);
+ return;
+ }
+
+ /* Least Common Multiple of lengths: LCM(a,b)*/
+ gcd = blocksize;
+ remainder = constant_len;
+ /* Calculate Great Common Divisor first GCD(a,b) */
+ while (remainder != 0) {
+ tmp = gcd % remainder;
+ gcd = remainder;
+ remainder = tmp;
+ }
+ /* resulting a is the GCD, LCM(a,b) = |a*b|/GCD(a,b) */
+ lcm = blocksize * constant_len / gcd;
+
+ /* now spread out the bits */
+ memset(block, 0, blocksize);
+
+ /* last to first to be able to bring carry forward */
+ carry = 0;
+ for (l = lcm - 1; l >= 0; l--) {
+ unsigned int rotbits, rshift, rbyte;
+
+ /* destination byte in block is l % N */
+ b = l % blocksize;
+ /* Our virtual s buffer is R = L/K long (K = constant_len) */
+ /* So we rotate backwards from R-1 to 0 (none) rotations */
+ rotbits = 13 * (l / constant_len);
+ /* find the byte on s where rotbits falls onto */
+ rbyte = l - (rotbits / 8);
+ /* calculate how much shift on that byte */
+ rshift = rotbits & 0x07;
+ /* rbyte % constant_len gives us the unrotated byte in the
+ * constant buffer, get also the previous byte then
+ * appropriately shift them to get the rotated byte we need */
+ tmp = (constant[(rbyte-1) % constant_len] << (8 - rshift)
+ | constant[rbyte % constant_len] >> rshift)
+ & 0xff;
+ /* add with carry to any value placed by previous passes */
+ tmp += carry + block[b];
+ block[b] = tmp & 0xff;
+ /* save any carry that may be left */
+ carry = tmp >> 8;
+ }
+
+ /* if any carry is left at the end, add it through the number */
+ for (b = blocksize - 1; b >= 0 && carry != 0; b--) {
+ carry += block[b];
+ block[b] = carry & 0xff;
+ carry >>= 8;
+ }
+}
+
+static int cipher_init(EVP_CIPHER_CTX *ctx,
+ const EVP_CIPHER *cipher, ENGINE *engine,
+ const unsigned char *key, size_t key_len)
+{
+ int klen, ret;
+
+ ret = EVP_EncryptInit_ex(ctx, cipher, engine, key, NULL);
+ if (!ret)
+ goto out;
+ /* set the key len for the odd variable key len cipher */
+ klen = EVP_CIPHER_CTX_key_length(ctx);
+ if (key_len != (size_t)klen) {
+ ret = EVP_CIPHER_CTX_set_key_length(ctx, key_len);
+ if (!ret)
+ goto out;
+ }
+ /* we never want padding, either the length requested is a multiple of
+ * the cipher block size or we are passed a cipher that can cope with
+ * partial blocks via techniques like cipher text stealing */
+ ret = EVP_CIPHER_CTX_set_padding(ctx, 0);
+ if (!ret)
+ goto out;
+
+out:
+ return ret;
+}
+
+static int KRB5KDF(const EVP_CIPHER *cipher, ENGINE *engine,
+ const unsigned char *key, size_t key_len,
+ const unsigned char *constant, size_t constant_len,
+ unsigned char *okey, size_t okey_len)
+{
+ EVP_CIPHER_CTX *ctx = NULL;
+ unsigned char block[EVP_MAX_BLOCK_LENGTH * 2];
+ unsigned char *plainblock, *cipherblock;
+ size_t blocksize;
+ size_t cipherlen;
+ size_t osize;
+ int des3_no_fixup = 0;
+ int ret;
+
+ if (key_len != okey_len) {
+ /* special case for 3des, where the caller may be requesting
+ * the random raw key, instead of the fixed up key */
+ if (EVP_CIPHER_nid(cipher) == NID_des_ede3_cbc &&
+ key_len == 24 && okey_len == 21) {
+ des3_no_fixup = 1;
+ } else {
+ ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_OUTPUT_BUFFER_SIZE);
+ return 0;
+ }
+ }
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (ctx == NULL)
+ return 0;
+
+ ret = cipher_init(ctx, cipher, engine, key, key_len);
+ if (!ret)
+ goto out;
+
+ /* Initialize input block */
+ blocksize = EVP_CIPHER_CTX_block_size(ctx);
+
+ if (constant_len > blocksize) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_CONSTANT_LENGTH);
+ ret = 0;
+ goto out;
+ }
+
+ n_fold(block, blocksize, constant, constant_len);
+ plainblock = block;
+ cipherblock = block + EVP_MAX_BLOCK_LENGTH;
+
+ for (osize = 0; osize < okey_len; osize += cipherlen) {
+ int olen;
+
+ ret = EVP_EncryptUpdate(ctx, cipherblock, &olen,
+ plainblock, blocksize);
+ if (!ret)
+ goto out;
+ cipherlen = olen;
+ ret = EVP_EncryptFinal_ex(ctx, cipherblock, &olen);
+ if (!ret)
+ goto out;
+ if (olen != 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_FINAL_BLOCK_LENGTH);
+ ret = 0;
+ goto out;
+ }
+
+ /* write cipherblock out */
+ if (cipherlen > okey_len - osize)
+ cipherlen = okey_len - osize;
+ memcpy(okey + osize, cipherblock, cipherlen);
+
+ if (okey_len > osize + cipherlen) {
+ /* we need to reinitialize cipher context per spec */
+ ret = EVP_CIPHER_CTX_reset(ctx);
+ if (!ret)
+ goto out;
+ ret = cipher_init(ctx, cipher, engine, key, key_len);
+ if (!ret)
+ goto out;
+
+ /* also swap block offsets so last ciphertext becomes new
+ * plaintext */
+ plainblock = cipherblock;
+ if (cipherblock == block) {
+ cipherblock += EVP_MAX_BLOCK_LENGTH;
+ } else {
+ cipherblock = block;
+ }
+ }
+ }
+
+#ifndef OPENSSL_NO_DES
+ if (EVP_CIPHER_nid(cipher) == NID_des_ede3_cbc && !des3_no_fixup) {
+ ret = fixup_des3_key(okey);
+ if (!ret) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY);
+ goto out;
+ }
+ }
+#endif
+
+ ret = 1;
+
+out:
+ EVP_CIPHER_CTX_free(ctx);
+ OPENSSL_cleanse(block, EVP_MAX_BLOCK_LENGTH * 2);
+ return ret;
+}
+
diff --git a/test/evp_kdf_test.c b/test/evp_kdf_test.c
index 21a0c270fe..ddf935b818 100644
--- a/test/evp_kdf_test.c
+++ b/test/evp_kdf_test.c
@@ -732,6 +732,43 @@ static int test_kdf_x942_asn1(void)
}
#endif /* OPENSSL_NO_CMS */
+static int test_kdf_krb5kdf(void)
+{
+ int ret;
+ EVP_KDF_CTX *kctx;
+ OSSL_PARAM params[4], *p = params;
+ unsigned char out[16];
+ static unsigned char key[] = {
+ 0x42, 0x26, 0x3C, 0x6E, 0x89, 0xF4, 0xFC, 0x28,
+ 0xB8, 0xDF, 0x68, 0xEE, 0x09, 0x79, 0x9F, 0x15
+ };
+ static unsigned char constant[] = {
+ 0x00, 0x00, 0x00, 0x02, 0x99
+ };
+ static const unsigned char expected[sizeof(out)] = {
+ 0x34, 0x28, 0x0A, 0x38, 0x2B, 0xC9, 0x27, 0x69,
+ 0xB2, 0xDA, 0x2F, 0x9E, 0xF0, 0x66, 0x85, 0x4B
+ };
+
+ *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_CIPHER,
+ (char *)"AES-128-CBC",
+ sizeof("AES-128-CBC"));
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, key,
+ sizeof(key));
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_CONSTANT,
+ constant, sizeof(constant));
+ *p = OSSL_PARAM_construct_end();
+
+ ret =
+ TEST_ptr(kctx = get_kdfbyname(OSSL_KDF_NAME_KRB5KDF))
+ && TEST_true(EVP_KDF_CTX_set_params(kctx, params))
+ && TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out)), 0)
+ && TEST_mem_eq(out, sizeof(out), expected, sizeof(expected));
+
+ EVP_KDF_CTX_free(kctx);
+ return ret;
+}
+
int setup_tests(void)
{
ADD_TEST(test_kdf_kbkdf_6803_128);
@@ -753,5 +790,6 @@ int setup_tests(void)
#ifndef OPENSSL_NO_CMS
ADD_TEST(test_kdf_x942_asn1);
#endif
+ ADD_TEST(test_kdf_krb5kdf);
return 1;
}
diff --git a/test/evp_test.c b/test/evp_test.c
index b68ad3b9c4..1039c2131a 100644
--- a/test/evp_test.c
+++ b/test/evp_test.c
@@ -2116,6 +2116,15 @@ static int kdf_test_ctrl(EVP_TEST *t, EVP_KDF_CTX *kctx,
if (nid != NID_undef && EVP_get_digestbynid(nid) == NULL)
t->skip = 1;
}
+ if (p != NULL && strcmp(name, "cipher") == 0) {
+ /* If p has an OID and lookup fails assume disabled algorithm */
+ int nid = OBJ_sn2nid(p);
+
+ if (nid == NID_undef)
+ nid = OBJ_ln2nid(p);
+ if (nid != NID_undef && EVP_get_cipherbynid(nid) == NULL)
+ t->skip = 1;
+ }
OPENSSL_free(name);
return 1;
}
diff --git a/test/recipes/30-test_evp_data/evpkdf.txt b/test/recipes/30-test_evp_data/evpkdf.txt
index 3905f17ebc..73d3b3ca9e 100644
--- a/test/recipes/30-test_evp_data/evpkdf.txt
+++ b/test/recipes/30-test_evp_data/evpkdf.txt
@@ -6523,3 +6523,123 @@ Ctrl.hexsecret = hexsecret:000102030405060708090a0b0c0d0e0f10111213
Ctrl.cekalg = cekalg:id-smime-alg-CMSRC2wrap
Ctrl.hexukm = hexukm:0123456789abcdeffedcba98765432010123456789abcdeffedcba98765432010123456789abcdeffedcba98765432010123456789abcdeffedcba9876543201
Output = 48950c46e0530075403cce72889604e0
+
+Title = KRB5KDF tests (from RFC 3961 test vectors and krb5 sources)
+
+#RFC3961
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:dce06b1f64c857a11c3db57c51899b2cc1791008ce973b92
+Ctrl.hexconstant = hexconstant:0000000155
+Output = 925179d04591a79b5d3192c4a7e9c289b049c71f6ee604cd
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:5e13d31c70ef765746578531cb51c15bf11ca82c97cee9f2
+Ctrl.hexconstant = hexconstant:00000001aa
+Output = 9e58e5a146d9942a101c469845d67a20e3c4259ed913f207
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:98e6fd8a04a4b6859b75a176540b9752bad3ecd610a252bc
+Ctrl.hexconstant = hexconstant:0000000155
+Output = 13fef80d763e94ec6d13fd2ca1d085070249dad39808eabf
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:622aec25a2fe2cad7094680b7c64940280084c1a7cec92b5
+Ctrl.hexconstant = hexconstant:00000001aa
+Output = f8dfbf04b097e6d9dc0702686bcb3489d91fd9a4516b703e
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:d3f8298ccb166438dcb9b93ee5a7629286a491f838f802fb
+Ctrl.hexconstant = hexconstant:6b65726265726f73
+Output = 2370da575d2a3da864cebfdc5204d56df779a7df43d9da43
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:c1081649ada74362e6a1459d01dfd30d67c2234c940704da
+Ctrl.hexconstant = hexconstant:0000000155
+Output = 348057ec98fdc48016161c2a4c7a943e92ae492c989175f7
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:5d154af238f46713155719d55e2f1f790dd661f279a7917c
+Ctrl.hexconstant = hexconstant:00000001aa
+Output = a8808ac267dada3dcbe9a7c84626fbc761c294b01315e5c1
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:798562e049852f57dc8c343ba17f2ca1d97394efc8adc443
+Ctrl.hexconstant = hexconstant:0000000155
+Output = c813f88a3be3b334f75425ce9175fbe3c8493b89c8703b49
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:26dce334b545292f2feab9a8701a89a4b99eb9942cecd016
+Ctrl.hexconstant = hexconstant:00000001aa
+Output = f48ffd6e83f83e7354e694fd252cf83bfe58f7d5ba37ec5d
+
+#Krb5 sources
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:850BB51358548CD05E86768C313E3BFEF7511937DCF72C3E
+Ctrl.hexconstant = hexconstant:0000000299
+Output = F78C496D16E6C2DAE0E0B6C24057A84C0426AEEF26FD6DCE
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:850BB51358548CD05E86768C313E3BFEF7511937DCF72C3E
+Ctrl.hexconstant = hexconstant:00000002AA
+Output = 5B5723D0B634CB684C3EBA5264E9A70D52E683231AD3C4CE
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:850BB51358548CD05E86768C313E3BFEF7511937DCF72C3E
+Ctrl.hexconstant = hexconstant:0000000255
+Output = A77C94980E9B7345A81525C423A737CE67F4CD91B6B3DA45
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:AES-128-CBC
+Ctrl.hexkey = hexkey:42263C6E89F4FC28B8DF68EE09799F15
+Ctrl.hexconstant = hexconstant:0000000299
+Output = 34280A382BC92769B2DA2F9EF066854B
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:AES-128-CBC
+Ctrl.hexkey = hexkey:42263C6E89F4FC28B8DF68EE09799F15
+Ctrl.hexconstant = hexconstant:00000002AA
+Output = 5B14FC4E250E14DDF9DCCF1AF6674F53
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:AES-128-CBC
+Ctrl.hexkey = hexkey:42263C6E89F4FC28B8DF68EE09799F15
+Ctrl.hexconstant = hexconstant:0000000255
+Output = 4ED31063621684F09AE8D89991AF3E8F
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:AES-256-CBC
+Ctrl.hexkey = hexkey:FE697B52BC0D3CE14432BA036A92E65BBB52280990A2FA27883998D72AF30161
+Ctrl.hexconstant = hexconstant:0000000299
+Output = BFAB388BDCB238E9F9C98D6A878304F04D30C82556375AC507A7A852790F4674
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:AES-256-CBC
+Ctrl.hexkey = hexkey:FE697B52BC0D3CE14432BA036A92E65BBB52280990A2FA27883998D72AF30161
+Ctrl.hexconstant = hexconstant:00000002AA
+Output = C7CFD9CD75FE793A586A542D87E0D1396F1134A104BB1A9190B8C90ADA3DDF37
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:AES-256-CBC
+Ctrl.hexkey = hexkey:FE697B52BC0D3CE14432BA036A92E65BBB52280990A2FA27883998D72AF30161
+Ctrl.hexconstant = hexconstant:0000000255
+Output = 97151B4C76945063E2EB0529DC067D97D7BBA90776D8126D91F34F3101AEA8BA
+
+#Same as the first but with no "fixup"
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:dce06b1f64c857a11c3db57c51899b2cc1791008ce973b92
+Ctrl.hexconstant = hexconstant:0000000155
+Output = 935079d14490a75c3093c4a6e8c3b049c71e6ee705
+
More information about the openssl-commits
mailing list