@ -8,32 +8,33 @@
*/
# include <stdlib.h>
# include <stdarg.h>
# include <string.h>
# include <openssl/hmac.h>
# include <openssl/kdf.h>
# include <openssl/evp.h>
# include <openssl/kdf.h>
# include "internal/cryptlib.h"
# include "internal/evp_int.h"
# include "kdf_local.h"
# define HKDF_MAXBUF 1024
static unsigned char * HKDF ( const EVP_MD * evp_md ,
const unsigned char * salt , size_t salt_len ,
const unsigned char * key , size_t key_len ,
const unsigned char * info , size_t info_len ,
unsigned char * okm , size_t okm_len ) ;
static unsigned char * HKDF_Extract ( const EVP_MD * evp_md ,
const unsigned char * salt , size_t salt_len ,
const unsigned char * key , size_t key_len ,
unsigned char * prk , size_t * prk_len ) ;
static unsigned char * HKDF_Expand ( const EVP_MD * evp_md ,
const unsigned char * prk , size_t prk_len ,
const unsigned char * info , size_t info_len ,
unsigned char * okm , size_t okm_len ) ;
typedef struct {
static void kdf_hkdf_reset ( EVP_KDF_IMPL * impl ) ;
static int HKDF ( const EVP_MD * evp_md ,
const unsigned char * salt , size_t salt_len ,
const unsigned char * key , size_t key_len ,
const unsigned char * info , size_t info_len ,
unsigned char * okm , size_t okm_len ) ;
static int HKDF_Extract ( const EVP_MD * evp_md ,
const unsigned char * salt , size_t salt_len ,
const unsigned char * key , size_t key_len ,
unsigned char * prk , size_t prk_len ) ;
static int HKDF_Expand ( const EVP_MD * evp_md ,
const unsigned char * prk , size_t prk_len ,
const unsigned char * info , size_t info_len ,
unsigned char * okm , size_t okm_len ) ;
struct evp_kdf_impl_st {
int mode ;
const EVP_MD * md ;
unsigned char * salt ;
@ -42,230 +43,208 @@ typedef struct {
size_t key_len ;
unsigned char info [ HKDF_MAXBUF ] ;
size_t info_len ;
} HKDF_PKEY_CTX ;
} ;
static int pkey_hkdf_init ( EVP_PKEY_CTX * ctx )
static EVP_KDF_IMPL * kdf_hkdf_new ( void )
{
HKDF_PKEY_CTX * kctx ;
EVP_KDF_IMPL * impl ;
if ( ( kctx = OPENSSL_zalloc ( sizeof ( * kctx ) ) ) = = NULL ) {
KDFerr ( KDF_F_PKEY_HKDF_INIT , ERR_R_MALLOC_FAILURE ) ;
return 0 ;
}
ctx - > data = kctx ;
if ( ( impl = OPENSSL_zalloc ( sizeof ( * impl ) ) ) = = NULL )
KDFerr ( KDF_F_KDF_HKDF_NEW , ERR_R_MALLOC_FAILURE ) ;
return impl ;
}
return 1 ;
static void kdf_hkdf_free ( EVP_KDF_IMPL * impl )
{
kdf_hkdf_reset ( impl ) ;
OPENSSL_free ( impl ) ;
}
static void pkey_hkdf_cleanup ( EVP_PKEY_CTX * ctx )
static void kdf_hkdf_reset ( EVP_KDF_IMPL * impl )
{
HKDF_PKEY_CTX * kctx = ctx - > data ;
OPENSSL_clear_free ( kctx - > salt , kctx - > salt_len ) ;
OPENSSL_clear_free ( kctx - > key , kctx - > key_len ) ;
OPENSSL_cleanse ( kctx - > info , kctx - > info_len ) ;
OPENSSL_free ( kctx ) ;
OPENSSL_free ( impl - > salt ) ;
OPENSSL_clear_free ( impl - > key , impl - > key_len ) ;
OPENSSL_cleanse ( impl - > info , impl - > info_len ) ;
memset ( impl , 0 , sizeof ( * impl ) ) ;
}
static int pkey_hkdf_ctrl ( EVP_PKEY_CTX * ctx , int type , int p1 , void * p2 )
static int kdf_hkdf_ctrl ( EVP_KDF_IMPL * impl , int cmd , va_list args )
{
HKDF_PKEY_CTX * kctx = ctx - > data ;
const unsigned char * p ;
size_t len ;
const EVP_MD * md ;
switch ( type ) {
case EVP_PKEY_CTRL_HKDF_MD :
if ( p2 = = NULL )
switch ( cmd ) {
case EVP_KDF_CTRL_SET_MD :
md = va_arg ( args , const EVP_MD * ) ;
if ( md = = NULL )
return 0 ;
kctx - > md = p2 ;
impl - > md = md ;
return 1 ;
case EVP_PKEY_CTRL _HKDF_MODE :
kctx - > mode = p1 ;
case EVP_KDF_CTRL_SET _HKDF_MODE :
impl - > mode = va_arg ( args , int ) ;
return 1 ;
case EVP_PKEY_CTRL_HKDF_SALT :
if ( p1 = = 0 | | p2 = = NULL )
case EVP_KDF_CTRL_SET_SALT :
p = va_arg ( args , const unsigned char * ) ;
len = va_arg ( args , size_t ) ;
if ( len = = 0 | | p = = NULL )
return 1 ;
if ( p1 < 0 )
OPENSSL_free ( impl - > salt ) ;
impl - > salt = OPENSSL_memdup ( p , len ) ;
if ( impl - > salt = = NULL )
return 0 ;
if ( kctx - > salt ! = NULL )
OPENSSL_clear_free ( kctx - > salt , kctx - > salt_len ) ;
kctx - > salt = OPENSSL_memdup ( p2 , p1 ) ;
if ( kctx - > salt = = NULL )
return 0 ;
kctx - > salt_len = p1 ;
impl - > salt_len = len ;
return 1 ;
case EVP_PKEY_CTRL_HKDF_KEY :
if ( p1 < 0 )
case EVP_KDF_CTRL_SET_KEY :
p = va_arg ( args , const unsigned char * ) ;
len = va_arg ( args , size_t ) ;
OPENSSL_clear_free ( impl - > key , impl - > key_len ) ;
impl - > key = OPENSSL_memdup ( p , len ) ;
if ( impl - > key = = NULL )
return 0 ;
if ( kctx - > key ! = NULL )
OPENSSL_clear_free ( kctx - > key , kctx - > key_len ) ;
kctx - > key = OPENSSL_memdup ( p2 , p1 ) ;
if ( kctx - > key = = NULL )
return 0 ;
impl - > key_len = len ;
return 1 ;
kctx - > key_len = p1 ;
case EVP_KDF_CTRL_RESET_HKDF_INFO :
OPENSSL_cleanse ( impl - > info , impl - > info_len ) ;
impl - > info_len = 0 ;
return 1 ;
case EVP_PKEY_CTRL_HKDF_INFO :
if ( p1 = = 0 | | p2 = = NULL )
case EVP_KDF_CTRL_ADD_HKDF_INFO :
p = va_arg ( args , const unsigned char * ) ;
len = va_arg ( args , size_t ) ;
if ( len = = 0 | | p = = NULL )
return 1 ;
if ( p1 < 0 | | p1 > ( int ) ( HKDF_MAXBUF - kctx - > info_len ) )
if ( len > ( HKDF_MAXBUF - impl - > info_len ) )
return 0 ;
memcpy ( kctx - > info + kctx - > info_len , p2 , p1 ) ;
kctx - > info_len + = p1 ;
memcpy ( impl - > info + impl - > info_len , p , len ) ;
impl - > info_len + = len ;
return 1 ;
default :
return - 2 ;
}
}
static int pkey_hkdf_ctrl_str ( EVP_PKEY_CTX * ctx , const char * type ,
const char * value )
static int kdf_hkdf_ctrl_str ( EVP_KDF_IMPL * impl , const char * type ,
const char * value )
{
if ( strcmp ( type , " mode " ) = = 0 ) {
int mode ;
if ( strcmp ( value , " EXTRACT_AND_EXPAND " ) = = 0 )
mode = EVP_PKEY_HKDE F_MODE_EXTRACT_AND_EXPAND ;
mode = EVP_KDF_HKD F_MODE_EXTRACT_AND_EXPAND ;
else if ( strcmp ( value , " EXTRACT_ONLY " ) = = 0 )
mode = EVP_PKEY_HKDE F_MODE_EXTRACT_ONLY ;
mode = EVP_KDF_HKD F_MODE_EXTRACT_ONLY ;
else if ( strcmp ( value , " EXPAND_ONLY " ) = = 0 )
mode = EVP_PKEY_HKDE F_MODE_EXPAND_ONLY ;
mode = EVP_KDF_HKD F_MODE_EXPAND_ONLY ;
else
return 0 ;
return EVP_PKEY_CTX_hkdf_mode ( ctx , mode ) ;
return call_ctrl ( kdf_hkdf_ctrl , impl , EVP_KDF_CTRL_SET_HKDF_MODE , mode ) ;
}
if ( strcmp ( type , " md " ) = = 0 )
return EVP_PKEY_CTX_md ( ctx , EVP_PKEY_OP_DERIVE ,
EVP_PKEY_CTRL_HKDF_MD , value ) ;
if ( strcmp ( type , " digest " ) = = 0 )
return kdf_md2ctrl ( impl , kdf_hkdf_ctrl , EVP_KDF_CTRL_SET_MD , value ) ;
if ( strcmp ( type , " salt " ) = = 0 )
return EVP_PKEY_CTX_str2ctrl ( ctx , EVP_PKEY_CTRL_HKDF _SALT, value ) ;
return kdf_str2ctrl ( impl , kdf_hkdf_ctrl , EVP_KDF_CTRL_SET _SALT, value ) ;
if ( strcmp ( type , " hexsalt " ) = = 0 )
return EVP_PKEY_CTX_hex2ctrl ( ctx , EVP_PKEY_CTRL_HKDF _SALT, value ) ;
return kdf_hex2ctrl ( impl , kdf_hkdf_ctrl , EVP_KDF_CTRL_SET _SALT, value ) ;
if ( strcmp ( type , " key " ) = = 0 )
return EVP_PKEY_CTX_str2ctrl ( ctx , EVP_PKEY_CTRL_HKDF _KEY, value ) ;
return kdf_str2ctrl ( impl , kdf_hkdf_ctrl , EVP_KDF_CTRL_SET _KEY, value ) ;
if ( strcmp ( type , " hexkey " ) = = 0 )
return EVP_PKEY_CTX_hex2ctrl ( ctx , EVP_PKEY_CTRL_HKDF _KEY, value ) ;
return kdf_hex2ctrl ( impl , kdf_hkdf_ctrl , EVP_KDF_CTRL_SET _KEY, value ) ;
if ( strcmp ( type , " info " ) = = 0 )
return EVP_PKEY_CTX_str2ctrl ( ctx , EVP_PKEY_CTRL_HKDF_INFO , value ) ;
return kdf_str2ctrl ( impl , kdf_hkdf_ctrl , EVP_KDF_CTRL_ADD_HKDF_INFO ,
value ) ;
if ( strcmp ( type , " hexinfo " ) = = 0 )
return EVP_PKEY_CTX_hex2ctrl ( ctx , EVP_PKEY_CTRL_HKDF_INFO , value ) ;
return kdf_hex2ctrl ( impl , kdf_hkdf_ctrl , EVP_KDF_CTRL_ADD_HKDF_INFO ,
value ) ;
KDFerr ( KDF_F_PKEY_HKDF_CTRL_STR , KDF_R_UNKNOWN_PARAMETER_TYPE ) ;
return - 2 ;
}
static int pkey_hkdf_derive_init ( EVP_PKEY_CTX * ctx )
static size_t kdf_hkdf_size ( EVP_KDF_IMPL * impl )
{
HKDF_PKEY_CTX * kctx = ctx - > data ;
OPENSSL_clear_free ( kctx - > key , kctx - > key_len ) ;
OPENSSL_clear_free ( kctx - > salt , kctx - > salt_len ) ;
OPENSSL_cleanse ( kctx - > info , kctx - > info_len ) ;
memset ( kctx , 0 , sizeof ( * kctx ) ) ;
if ( impl - > mode ! = EVP_KDF_HKDF_MODE_EXTRACT_ONLY )
return SIZE_MAX ;
return 1 ;
if ( impl - > md = = NULL ) {
KDFerr ( KDF_F_KDF_HKDF_SIZE , KDF_R_MISSING_MESSAGE_DIGEST ) ;
return 0 ;
}
return EVP_MD_size ( impl - > md ) ;
}
static int pkey_hkdf_derive ( EVP_PKEY_CTX * ctx , unsigned char * key ,
size_t * keylen )
static int kdf_hkdf_derive ( EVP_KDF_IMPL * impl , unsigned char * key ,
size_t keylen )
{
HKDF_PKEY_CTX * kctx = ctx - > data ;
if ( kctx - > md = = NULL ) {
KDFerr ( KDF_F_PKEY_HKDF_DERIVE , KDF_R_MISSING_MESSAGE_DIGEST ) ;
if ( impl - > md = = NULL ) {
KDFerr ( KDF_F_KDF_HKDF_DERIVE , KDF_R_MISSING_MESSAGE_DIGEST ) ;
return 0 ;
}
if ( kctx - > key = = NULL ) {
KDFerr ( KDF_F_PKEY _HKDF_DERIVE , KDF_R_MISSING_KEY ) ;
if ( impl - > key = = NULL ) {
KDFerr ( KDF_F_KDF _HKDF_DERIVE , KDF_R_MISSING_KEY ) ;
return 0 ;
}
switch ( kctx - > mode ) {
case EVP_PKEY_HKDE F_MODE_EXTRACT_AND_EXPAND :
return HKDF ( kctx - > md , kctx - > salt , kctx - > salt_len , kctx - > key ,
kctx - > key_len , kctx - > info , kctx - > info_len , key ,
* keylen ) ! = NULL ;
switch ( impl - > mode ) {
case EVP_KDF_HKD F_MODE_EXTRACT_AND_EXPAND :
return HKDF ( impl - > md , impl - > salt , impl - > salt_len , impl - > key ,
impl - > key_len , impl - > info , impl - > info_len , key ,
keylen ) ;
case EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY :
if ( key = = NULL ) {
* keylen = EVP_MD_size ( kctx - > md ) ;
return 1 ;
}
return HKDF_Extract ( kctx - > md , kctx - > salt , kctx - > salt_len , kctx - > key ,
kctx - > key_len , key , keylen ) ! = NULL ;
case EVP_KDF_HKDF_MODE_EXTRACT_ONLY :
return HKDF_Extract ( impl - > md , impl - > salt , impl - > salt_len , impl - > key ,
impl - > key_len , key , keylen ) ;
case EVP_PKEY_HKDE F_MODE_EXPAND_ONLY :
return HKDF_Expand ( kctx - > md , kctx - > key , kctx - > key_len , kctx - > info ,
kctx - > info_len , key , * keylen ) ! = NULL ;
case EVP_KDF_HKDF_MODE_EXPAND_ONLY :
return HKDF_Expand ( impl - > md , impl - > key , impl - > key_len , impl - > info ,
impl - > info_len , key , keylen ) ;
default :
return 0 ;
}
}
const EVP_PKEY_METHOD hkdf_pkey_meth = {
EVP_PKEY_HKDF ,
0 ,
pkey_hkdf_init ,
0 ,
pkey_hkdf_cleanup ,
0 , 0 ,
0 , 0 ,
0 ,
0 ,
0 ,
0 ,
0 , 0 ,
0 , 0 , 0 , 0 ,
0 , 0 ,
0 , 0 ,
pkey_hkdf_derive_init ,
pkey_hkdf_derive ,
pkey_hkdf_ctrl ,
pkey_hkdf_ctrl_str
const EVP_KDF_METHOD hkdf_kdf_meth = {
EVP_KDF_HKDF ,
kdf_hkdf_new ,
kdf_hkdf_free ,
kdf_hkdf_reset ,
kdf_hkdf_ctrl ,
kdf_hkdf_ctrl_str ,
kdf_hkdf_size ,
kdf_hkdf_derive
} ;
static uns ig ned char * HKDF ( const EVP_MD * evp_md ,
const unsigned char * salt , size_t salt_len ,
const unsigned char * key , size_t key_len ,
const unsigned char * info , size_t info_len ,
unsigned char * okm , size_t okm_len )
static int HKDF ( const EVP_MD * evp_md ,
const unsigned char * salt , size_t salt_len ,
const unsigned char * key , size_t key_len ,
const unsigned char * info , size_t info_len ,
unsigned char * okm , size_t okm_len )
{
unsigned char prk [ EVP_MAX_MD_SIZE ] ;
uns ig ned char * ret ;
size_t prk_len ;
int ret ;
size_t prk_len = EVP_MD_size ( evp_md ) ;
if ( ! HKDF_Extract ( evp_md , salt , salt_len , key , key_len , prk , & prk_len ) )
return NULL ;
if ( ! HKDF_Extract ( evp_md , salt , salt_len , key , key_len , prk , prk_len ) )
return 0 ;
ret = HKDF_Expand ( evp_md , prk , prk_len , info , info_len , okm , okm_len ) ;
OPENSSL_cleanse ( prk , sizeof ( prk ) ) ;
@ -273,43 +252,38 @@ static unsigned char *HKDF(const EVP_MD *evp_md,
return ret ;
}
static uns ig ned char * HKDF_Extract ( const EVP_MD * evp_md ,
const unsigned char * salt , size_t salt_len ,
const unsigned char * key , size_t key_len ,
unsigned char * prk , size_t * prk_len )
static int HKDF_Extract ( const EVP_MD * evp_md ,
const unsigned char * salt , size_t salt_len ,
const unsigned char * key , size_t key_len ,
unsigned char * prk , size_t prk_len )
{
unsigned int tmp_len ;
if ( ! HMAC ( evp_md , salt , salt_len , key , key_len , prk , & tmp_len ) )
return NULL ;
* prk_len = tmp_len ;
return prk ;
if ( prk_len ! = ( size_t ) EVP_MD_size ( evp_md ) ) {
KDFerr ( KDF_F_HKDF_EXTRACT , KDF_R_WRONG_OUTPUT_BUFFER_SIZE ) ;
return 0 ;
}
return HMAC ( evp_md , salt , salt_len , key , key_len , prk , NULL ) ! = NULL ;
}
static uns ig ned char * HKDF_Expand ( const EVP_MD * evp_md ,
const unsigned char * prk , size_t prk_len ,
const unsigned char * info , size_t info_len ,
unsigned char * okm , size_t okm_len )
static int HKDF_Expand ( const EVP_MD * evp_md ,
const unsigned char * prk , size_t prk_len ,
const unsigned char * info , size_t info_len ,
unsigned char * okm , size_t okm_len )
{
HMAC_CTX * hmac ;
unsigned char * ret = NULL ;
int ret = 0 ;
unsigned int i ;
unsigned char prev [ EVP_MAX_MD_SIZE ] ;
size_t done_len = 0 , dig_len = EVP_MD_size ( evp_md ) ;
size_t n = okm_len / dig_len ;
if ( okm_len % dig_len )
n + + ;
if ( n > 255 | | okm = = NULL )
return NULL ;
return 0 ;
if ( ( hmac = HMAC_CTX_new ( ) ) = = NULL )
return