Skip to content

Commit

Permalink
Implement HKDF expand function based on RFC 8446
Browse files Browse the repository at this point in the history
Use crypto_epoch.c/h for the new functions since they are
linked to the epoch key usage in OpenVPN.

Change-Id: I3a1c6561f4d9a69e2a441d49dff620b4258a1bcc
Signed-off-by: Arne Schwabe <[email protected]>
Acked-by: MaxF <[email protected]>
Acked-by: Gert Doering <[email protected]>
Message-Id: <[email protected]>
URL: https://www.mail-archive.com/[email protected]/msg30149.html
Signed-off-by: Gert Doering <[email protected]>
  • Loading branch information
schwabe authored and cron2 committed Dec 22, 2024
1 parent fb691d2 commit 5d3d2e4
Show file tree
Hide file tree
Showing 7 changed files with 434 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,8 @@ set(SOURCE_FILES
src/openvpn/crypto.c
src/openvpn/crypto.h
src/openvpn/crypto_backend.h
src/openvpn/crypto_epoch.c
src/openvpn/crypto_epoch.h
src/openvpn/crypto_openssl.c
src/openvpn/crypto_openssl.h
src/openvpn/crypto_mbedtls.c
Expand Down Expand Up @@ -715,6 +717,7 @@ if (BUILD_TESTING)
target_sources(test_crypto PRIVATE
src/openvpn/crypto_mbedtls.c
src/openvpn/crypto_openssl.c
src/openvpn/crypto_epoch.c
src/openvpn/crypto.c
src/openvpn/otime.c
src/openvpn/packet_id.c
Expand Down
1 change: 1 addition & 0 deletions src/openvpn/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ openvpn_SOURCES = \
crypto.c crypto.h crypto_backend.h \
crypto_openssl.c crypto_openssl.h \
crypto_mbedtls.c crypto_mbedtls.h \
crypto_epoch.c crypto_epoch.h \
dco.c dco.h dco_internal.h \
dco_freebsd.c dco_freebsd.h \
dco_linux.c dco_linux.h \
Expand Down
114 changes: 114 additions & 0 deletions src/openvpn/crypto_epoch.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2024 OpenVPN Inc <[email protected]>
* Copyright (C) 2024 Arne Schwabe <[email protected]>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/


#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <inttypes.h>
#include "crypto_backend.h"
#include "buffer.h"
#include "integer.h"

void
ovpn_hkdf_expand(const uint8_t *secret,
const uint8_t *info, int info_len,
uint8_t *out, int out_len)
{
hmac_ctx_t *hmac_ctx = hmac_ctx_new();
hmac_ctx_init(hmac_ctx, secret, "SHA256");

const int digest_size = SHA256_DIGEST_LENGTH;

/* T(0) = empty string */
uint8_t t_prev[SHA256_DIGEST_LENGTH];
int t_prev_len = 0;

for (uint8_t block = 1; (block - 1) * digest_size < out_len; block++)
{
hmac_ctx_reset(hmac_ctx);

/* calculate T(block) */
hmac_ctx_update(hmac_ctx, t_prev, t_prev_len);
hmac_ctx_update(hmac_ctx, info, info_len);
hmac_ctx_update(hmac_ctx, &block, 1);
hmac_ctx_final(hmac_ctx, t_prev);
t_prev_len = digest_size;

/* Copy a full hmac output or remaining bytes */
int out_offset = (block - 1) * digest_size;
int copylen = min_int(digest_size, out_len - out_offset);

memcpy(out + out_offset, t_prev, copylen);
}
hmac_ctx_cleanup(hmac_ctx);
hmac_ctx_free(hmac_ctx);
}

bool
ovpn_expand_label(const uint8_t *secret, size_t secret_len,
const uint8_t *label, size_t label_len,
const uint8_t *context, size_t context_len,
uint8_t *out, uint16_t out_len)
{
if (secret_len != 32 || label_len > 250 || context_len > 255
|| label_len < 1)
{
/* Our current implementation is not a general purpose one
* and assumes that the secret size matches the size of the
* hash (SHA256) key. Also label length and context length
* need need to be in range */
return false;
}

struct gc_arena gc = gc_new();
/* 2 byte for the outlen encoded as uint16, 5 bytes for "ovpn ",
* 1 byte for context len byte and 1 byte for label len byte */
const uint8_t *label_prefix = (const uint8_t *) ("ovpn ");
int prefix_len = 5;

int hkdf_label_len = 2 + prefix_len + 1 + label_len + 1 + context_len;
struct buffer hkdf_label = alloc_buf_gc(hkdf_label_len, &gc);

buf_write_u16(&hkdf_label, out_len);
buf_write_u8(&hkdf_label, prefix_len + label_len);
buf_write(&hkdf_label, label_prefix, prefix_len);
buf_write(&hkdf_label, label, label_len);

buf_write_u8(&hkdf_label, context_len);
if (context_len > 0)
{
buf_write(&hkdf_label, context, context_len);
}

ASSERT(buf_len(&hkdf_label) == hkdf_label_len);

ovpn_hkdf_expand(secret, buf_bptr(&hkdf_label),
buf_len(&hkdf_label), out, out_len);

gc_free(&gc);
return true;
}
70 changes: 70 additions & 0 deletions src/openvpn/crypto_epoch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* OpenVPN -- An application to securely tunnel IP networks
* over a single TCP/UDP port, with support for SSL/TLS-based
* session authentication and key exchange,
* packet encryption, packet authentication, and
* packet compression.
*
* Copyright (C) 2024 OpenVPN Inc <[email protected]>
* Copyright (C) 2024 Arne Schwabe <[email protected]>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef CRYPTO_EPOCH_H
#define CRYPTO_EPOCH_H

/**
* Implementation of the RFC5869 HKDF-Expand function with the following
* restrictions
*
* - secret is assumed to be always 32 bytes
* - HASH is always SHA256
*
* @param secret the input keying material (HMAC key)
* @param info context and application specific information
* @param info_len length of the info string
* @param out output keying material
* @param out_len length of output keying material
*/
void
ovpn_hkdf_expand(const uint8_t *secret,
const uint8_t *info, int info_len,
uint8_t *out, int out_len);

/**
* Variant of the RFC 8446 TLS 1.3 HKDF-Expand-Label function with the
* following differences/restrictions:
* - secret must 32 bytes in length
* - label prefix is "ovpn " instead of "tls13 "
* - HASH is always SHA256
*
* @param secret Input secret
* @param secret_len length of the input secret
* @param label Label for the exported key material
* @param label_len length of the label
* @param context optional context
* @param context_len length of the context
* @param out output keying material
* @param out_len length of output keying material
* @return
*/
bool
ovpn_expand_label(const uint8_t *secret, size_t secret_len,
const uint8_t *label, size_t label_len,
const uint8_t *context, size_t context_len,
uint8_t *out, uint16_t out_len);

#endif
1 change: 1 addition & 0 deletions src/openvpn/crypto_mbedtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#ifndef CRYPTO_MBEDTLS_H_
#define CRYPTO_MBEDTLS_H_

#include <stdbool.h>
#include <mbedtls/cipher.h>
#include <mbedtls/md.h>
#include <mbedtls/ctr_drbg.h>
Expand Down
1 change: 1 addition & 0 deletions tests/unit_tests/openvpn/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ crypto_testdriver_SOURCES = test_crypto.c mock_msg.c mock_msg.h \
$(top_srcdir)/src/openvpn/crypto.c \
$(top_srcdir)/src/openvpn/crypto_mbedtls.c \
$(top_srcdir)/src/openvpn/crypto_openssl.c \
$(top_srcdir)/src/openvpn/crypto_epoch.c \
$(top_srcdir)/src/openvpn/otime.c \
$(top_srcdir)/src/openvpn/packet_id.c \
$(top_srcdir)/src/openvpn/platform.c \
Expand Down
Loading

0 comments on commit 5d3d2e4

Please sign in to comment.