2622 lines
90 KiB
C
2622 lines
90 KiB
C
/* ipwps_protocol_crypto.c - IPWPS Protocol Cryptographic helper module implementation */
|
|
|
|
/*
|
|
* Copyright (c) 2009 Wind River Systems, Inc.
|
|
*
|
|
* The right to copy, distribute, modify, or otherwise make use
|
|
* of this software may be licensed only pursuant to the terms
|
|
* of an applicable Wind River license agreement.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
modification history
|
|
--------------------
|
|
01a,03Feb09,mry Created
|
|
*/
|
|
|
|
/* DESCRIPTION:
|
|
* ===========
|
|
* This library contains the IPWPS Protocol Cryptographic helper module
|
|
* implementation.
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
#include "ipwps_config.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
|
|
#include <ipcom_type.h>
|
|
#include <ipcom_cstyle.h>
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_syslog.h>
|
|
/* Openssl header files */
|
|
#include <openssl/rand.h>
|
|
#include <openssl/dh.h>
|
|
#include <openssl/sha.h>
|
|
#include <openssl/hmac.h>
|
|
|
|
#include "ipwps_protocol.h"
|
|
#include "ipwps_protocol_handler.h"
|
|
#include "ipwps_private_api.h"
|
|
#include "ipwps_common.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPWPS_PROTO_KEYLEN_DHKEY SHA256_DIGEST_LENGTH
|
|
#define IPWPS_PROTO_KEYLEN_KDK SHA256_DIGEST_LENGTH
|
|
#define IPWPS_PROTO_KEYLEN_PSK 16 /* i.e. 128 bits */
|
|
|
|
#define IPWPS_PROTO_CRYPTO_RANDSEED_LEN 256
|
|
|
|
#define IPWPS_PROTO_KDK_KDF_PERSONALIZATION_STR "Wi-Fi Easy and Secure Key Derivation"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
typedef struct Ipwps_proto_dh_group_st {
|
|
Ip_u8 *prime_value;
|
|
Ip_u32 prime_len;
|
|
Ip_u32 generator;
|
|
} Ipwps_proto_dh_group;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
#ifdef IPWPS_DEBUG
|
|
Ip_bool ipwps_proto_no_data_encryption = IP_FALSE; /* For Testing purposes */
|
|
#endif
|
|
|
|
/* As specified by WPS spec, use the "1536-bit MODP Group" from RFC3526.
|
|
* The prime is: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }
|
|
* The generator of 2.
|
|
*/
|
|
IP_STATIC Ip_u8 IPWPS_PROTO_RFC3526_1536_MODP_GROUP_PRIME[]= {
|
|
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
|
|
0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
|
|
0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
|
|
0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
|
|
0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
|
|
0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
|
|
0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
|
|
0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
|
|
0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
|
|
0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
|
|
0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
|
|
0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
|
|
0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
|
|
0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
|
|
0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
|
|
0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
};
|
|
#define IPWPS_PROTO_RFC3526_1536_MODP_GROUP_GENERATOR 2
|
|
|
|
IP_STATIC Ipwps_proto_dh_group ipwps_proto_dh_group_rfc3526_1536_modp = {
|
|
IPWPS_PROTO_RFC3526_1536_MODP_GROUP_PRIME,
|
|
sizeof(IPWPS_PROTO_RFC3526_1536_MODP_GROUP_PRIME),
|
|
IPWPS_PROTO_RFC3526_1536_MODP_GROUP_GENERATOR
|
|
};
|
|
|
|
IP_STATIC Ipwps_proto_dh_group *ipwps_proto_default_dh_group = &ipwps_proto_dh_group_rfc3526_1536_modp;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
IP_STATIC Ipwps_proto_dh_group *
|
|
ipwps_proto_get_dh_group(Ipwps_proto_ctx *proto_ctx);
|
|
|
|
IP_GLOBAL DH *
|
|
ipwps_proto_generate_dh_keys(Ipwps_proto_dh_group *dh_grp, Ipwps_proto_key *pubkey);
|
|
|
|
IP_STATIC Ip_err
|
|
ipwps_proto_derive_dh_sharedsecret(DH *dh, Ipwps_proto_key *peer_pubkey, Ipwps_proto_key *secret);
|
|
|
|
IP_STATIC Ip_err
|
|
ipwps_proto_derive_dhkey(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_key *shared_secret, Ipwps_proto_key *dh_key);
|
|
|
|
IP_STATIC Ip_err
|
|
ipwps_proto_derive_kdk(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_key *dh_key, Ipwps_proto_key *kdk);
|
|
|
|
IP_STATIC Ip_err
|
|
ipwps_proto_perform_kdf(Ipwps_proto_key *key, Ipwps_proto_container **dataset,
|
|
IP_CONST char *p_string, Ipwps_proto_key *result);
|
|
|
|
IP_STATIC Ip_err
|
|
ipwps_proto_perform_kdk_kdf(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_key *kdk, Ipwps_proto_key *session_keys);
|
|
|
|
IP_STATIC void
|
|
ipwps_proto_delete_dh(Ipwps_proto_ctx *proto_ctx);
|
|
|
|
IP_STATIC Ip_err
|
|
ipwps_proto_kwf_encrypt_data_with_iv(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_container *data_to_encrypt,
|
|
Ipwps_proto_container *encrypted_data, Ipwps_proto_nonce *iv_to_use);
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
IP_GLOBAL void ipwps_proto_crypto_randgen(Ip_u8 *buf, Ip_u16 nbytes);
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_crypto_init
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_crypto_init(Ipwps_proto_ctx *proto_ctx) {
|
|
#ifdef IPWPS_SEED_CRYPTO
|
|
Ip_u32 rnd[IPWPS_PROTO_CRYPTO_RANDSEED_LEN];
|
|
#endif
|
|
ip_assert(proto_ctx);
|
|
|
|
if (proto_ctx->crypto_init) {
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
#if IPWPS_SEED_CRYPTO
|
|
ipwps_proto_crypto_randgen((Ip_u8 *)rnd, sizeof(rnd));
|
|
RAND_seed((Ip_u8 *)rnd, sizeof(rnd));
|
|
#endif
|
|
proto_ctx->crypto_init = IP_TRUE;
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_crypto_randgen
|
|
*===========================================================================
|
|
* Description: Generate a Random byte stream of "nbytes" and store it in
|
|
* provided buffer.
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL void ipwps_proto_crypto_randgen(Ip_u8 *buf, Ip_u16 nbytes) {
|
|
#if defined (IPWPS_USE_IPCOM_RAND) && defined(IPCOM_RAND) && IPCOM_RAND == 1
|
|
Ip_u16 remlen = nbytes;
|
|
Ip_u32 *ptr = (Ip_u32 *)buf;
|
|
Ip_u32 rand;
|
|
|
|
ip_assert(buf);
|
|
|
|
while (remlen > sizeof(Ip_u32)) {
|
|
rand = ipcom_rand();
|
|
*ptr = rand;
|
|
remlen -= sizeof(Ip_u32);
|
|
ptr++;
|
|
}
|
|
if (remlen) {
|
|
rand = ipcom_rand();
|
|
ipcom_memcpy((Ip_u8 *)ptr, &rand, remlen);
|
|
}
|
|
#else
|
|
(void)RAND_bytes(buf, nbytes);
|
|
#endif
|
|
#ifdef IPWPS_DEBUG_PROTO_CRYPTO_RANDGEN
|
|
ipwps_dump_data("ipwps_proto_crypto_randgen ::", buf, nbytes);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_crypto_randdata
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_crypto_randdata(Ipwps_proto_container *container) {
|
|
|
|
ip_assert(container);
|
|
|
|
if (!IPWPS_PROTO_CONTAINER_ISVALID(*container)) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_crypto_randdata :: Invalid container.");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
ipwps_proto_crypto_randgen(container->data, container->len);
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_set_device_password
|
|
*===========================================================================
|
|
* Description: Set the device password associated with the protocol handler
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_set_device_password(Ipwps_proto_ctx *proto_ctx, Ip_u8 *buf, Ip_u16 len) {
|
|
|
|
ip_assert(proto_ctx);
|
|
|
|
if (!buf || !len) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_set_device_password :: null buf or zero len");
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
if (ipwps_proto_alloc_and_copy_data(&proto_ctx->dev_pwd, buf, len) != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_set_device_password :: failed to copy device password");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_generate_local_keys
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_generate_local_keys(Ipwps_proto_ctx *proto_ctx) {
|
|
Ipwps_proto_dh_group *dh_grp;
|
|
|
|
ip_assert(proto_ctx);
|
|
|
|
if (IPWPS_PROTO_KEY_ISVALID(proto_ctx->local_pub_key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_generate_local_keys :: dh keys already generated");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
dh_grp = ipwps_proto_get_dh_group(proto_ctx);
|
|
if (!dh_grp) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_generate_local_keys :: failed to retrieve dh group");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
proto_ctx->dh = ipwps_proto_generate_dh_keys(dh_grp, &proto_ctx->local_pub_key);
|
|
if (!proto_ctx->dh) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_generate_local_keys :: failed to generate dh keys");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->local_pub_key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_generate_local_keys :: Invalid dh key public key");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_generate_local_keys :: local_pub_key:", proto_ctx->local_pub_key);
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_derive_session_keys
|
|
*===========================================================================
|
|
* Description:
|
|
* DH structure is deleted when the shared secret is available.
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_derive_session_keys(Ipwps_proto_ctx *proto_ctx) {
|
|
Ipwps_proto_key shared_secret, dh_key, kdk, session_keys;
|
|
Ip_err rc;
|
|
|
|
ip_assert(proto_ctx);
|
|
|
|
IPWPS_PROTO_KEY_INIT(shared_secret);
|
|
IPWPS_PROTO_KEY_INIT(dh_key);
|
|
IPWPS_PROTO_KEY_INIT(kdk);
|
|
IPWPS_PROTO_KEY_INIT(session_keys);
|
|
|
|
if (!proto_ctx->dh) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: Invalid dh context");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->peer_pub_key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: Invalid peer public key");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
rc = ipwps_proto_derive_dh_sharedsecret(proto_ctx->dh, &proto_ctx->peer_pub_key, &shared_secret);
|
|
if (rc != IPCOM_SUCCESS || !IPWPS_PROTO_KEY_ISVALID(shared_secret)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: failed to derive shared secret");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_sessionkeys;
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_session_keys :: shared_secret:", shared_secret);
|
|
|
|
rc = ipwps_proto_derive_dhkey(proto_ctx, &shared_secret, &dh_key);
|
|
if (rc != IPCOM_SUCCESS || !IPWPS_PROTO_KEY_ISVALID(dh_key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: failed to derive dhkey");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_sessionkeys;
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_session_keys :: dh_key:", dh_key);
|
|
|
|
rc = ipwps_proto_derive_kdk(proto_ctx, &dh_key, &kdk);
|
|
if (rc != IPCOM_SUCCESS || !IPWPS_PROTO_KEY_ISVALID(kdk)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: failed to derive kdk");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_sessionkeys;
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_session_keys :: kdk:", kdk);
|
|
|
|
rc = ipwps_proto_perform_kdk_kdf(proto_ctx, &kdk, &session_keys);
|
|
if (rc != IPCOM_SUCCESS || !IPWPS_PROTO_KEY_ISVALID(session_keys)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: failed to perform kdf");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_sessionkeys;
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_session_keys :: session_keys:", session_keys);
|
|
|
|
rc = ipwps_proto_copy_data(&proto_ctx->auth_key, &session_keys, 0, IPWPS_PROTO_KEYLEN_AUTHKEY);
|
|
if (rc != IPCOM_SUCCESS || !IPWPS_PROTO_KEY_ISVALID(proto_ctx->auth_key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: failed to copy auth_key");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_sessionkeys;
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_session_keys :: auth_key:", proto_ctx->auth_key);
|
|
|
|
rc = ipwps_proto_copy_data(&proto_ctx->key_wrap_key, &session_keys,
|
|
IPWPS_PROTO_KEYLEN_AUTHKEY, IPWPS_PROTO_KEYLEN_KEYWRAPKEY);
|
|
if (rc != IPCOM_SUCCESS || !IPWPS_PROTO_KEY_ISVALID(proto_ctx->key_wrap_key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: failed to copy key_wrap_key");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_sessionkeys;
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_session_keys :: key_wrap_key:", proto_ctx->key_wrap_key);
|
|
|
|
rc = ipwps_proto_copy_data(&proto_ctx->emsk, &session_keys,
|
|
IPWPS_PROTO_KEYLEN_AUTHKEY+IPWPS_PROTO_KEYLEN_KEYWRAPKEY,
|
|
IPWPS_PROTO_KEYLEN_EMSK);
|
|
if (rc != IPCOM_SUCCESS || !IPWPS_PROTO_KEY_ISVALID(proto_ctx->emsk)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_session_keys :: failed to copy emsk");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_sessionkeys;
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_session_keys :: emsk:", proto_ctx->emsk);
|
|
|
|
rc = IPCOM_SUCCESS;
|
|
done_sessionkeys:
|
|
ipwps_proto_delete_dh(proto_ctx); /* Done with it now */
|
|
ipwps_proto_container_delete(&shared_secret);
|
|
ipwps_proto_container_delete(&dh_key);
|
|
ipwps_proto_container_delete(&kdk);
|
|
ipwps_proto_container_delete(&session_keys);
|
|
if (rc != IPCOM_SUCCESS) {
|
|
ipwps_proto_container_delete(&proto_ctx->auth_key);
|
|
ipwps_proto_container_delete(&proto_ctx->key_wrap_key);
|
|
ipwps_proto_container_delete(&proto_ctx->emsk);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_derive_psks
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_derive_psks(Ipwps_proto_ctx *proto_ctx) {
|
|
Ip_err rc = IPCOM_ERR_FAILED;
|
|
HMAC_CTX hmac_ctx;
|
|
Ip_u8 result[SHA256_DIGEST_LENGTH], *pwd_half;
|
|
unsigned int len = SHA256_DIGEST_LENGTH, pwd_halflen;
|
|
|
|
ip_assert(proto_ctx);
|
|
|
|
if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->auth_key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_psks :: invalid auth_key");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_CONTAINER_ISVALID(proto_ctx->dev_pwd)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_psks :: invalid dev_pwd");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
/* For PSK1: Perform HMAC-SHA-256_AuthKey(1st half of device password) and use the 1st 128 bits of the result */
|
|
pwd_half = proto_ctx->dev_pwd.data;
|
|
pwd_halflen = (proto_ctx->dev_pwd.len + 1) /2;
|
|
HMAC_CTX_init(&hmac_ctx);
|
|
HMAC_Init(&hmac_ctx, proto_ctx->auth_key.data, proto_ctx->auth_key.len, EVP_sha256());
|
|
HMAC_Update(&hmac_ctx, pwd_half, pwd_halflen);
|
|
HMAC_Final(&hmac_ctx, result, &len);
|
|
|
|
rc = ipwps_proto_alloc_and_copy_data(&proto_ctx->psk1, result, IPWPS_PROTO_KEYLEN_PSK);
|
|
ipcom_memset(result, 0, sizeof(result));
|
|
if ((rc != IPCOM_SUCCESS) || !IPWPS_PROTO_KEY_ISVALID(proto_ctx->psk1) ||
|
|
(proto_ctx->psk1.len != IPWPS_PROTO_KEYLEN_PSK)) {
|
|
IPCOM_LOG1(ERR,"ipwps_proto_derive_psks :: Invalid psk1 (%d)", proto_ctx->psk1.len);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
/* For PSK2: Perform HMAC-SHA-256_AuthKey(2nd half of device password) and use the 1st 128 bits of the result */
|
|
pwd_half = proto_ctx->dev_pwd.data + pwd_halflen;
|
|
pwd_halflen = proto_ctx->dev_pwd.len /2;
|
|
HMAC_CTX_init(&hmac_ctx);
|
|
HMAC_Init(&hmac_ctx, proto_ctx->auth_key.data, proto_ctx->auth_key.len, EVP_sha256());
|
|
HMAC_Update(&hmac_ctx, pwd_half, pwd_halflen);
|
|
HMAC_Final(&hmac_ctx, result, &len);
|
|
|
|
rc = ipwps_proto_alloc_and_copy_data(&proto_ctx->psk2, result, IPWPS_PROTO_KEYLEN_PSK);
|
|
ipcom_memset(result, 0, sizeof(result));
|
|
if ((rc != IPCOM_SUCCESS) || !IPWPS_PROTO_KEY_ISVALID(proto_ctx->psk2) ||
|
|
(proto_ctx->psk2.len != IPWPS_PROTO_KEYLEN_PSK)) {
|
|
IPCOM_LOG1(ERR,"ipwps_proto_derive_psks :: Invalid psk2 (%d)", proto_ctx->psk2.len);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_derive_devpwd_proof_hash
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err ipwps_proto_derive_devpwd_proof_hash
|
|
(
|
|
Ipwps_proto_ctx *proto_ctx,
|
|
Ipwps_proto_nonce *snonce,
|
|
Ipwps_proto_key *psk,
|
|
Ipwps_proto_key *pk_e,
|
|
Ipwps_proto_key *pk_r,
|
|
Ipwps_proto_hash *hash
|
|
) {
|
|
Ip_err rc = IPCOM_ERR_FAILED;
|
|
HMAC_CTX hmac_ctx;
|
|
Ip_u8 result[SHA256_DIGEST_LENGTH];
|
|
unsigned int len = SHA256_DIGEST_LENGTH;
|
|
|
|
ip_assert(proto_ctx);
|
|
ip_assert(snonce);
|
|
ip_assert(psk);
|
|
ip_assert(pk_e);
|
|
ip_assert(pk_r);
|
|
ip_assert(hash);
|
|
|
|
if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->auth_key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_devpwd_proof_hash :: invalid auth_key");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_NONCE_ISVALID(*snonce)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_devpwd_proof_hash :: invalid snonce");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_KEY_ISVALID(*psk)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_devpwd_proof_hash :: invalid psk");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_KEY_ISVALID(*pk_e)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_devpwd_proof_hash :: invalid pk_e");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_KEY_ISVALID(*pk_r)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_devpwd_proof_hash :: invalid pk_r");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
/* Perform HMAC-SHA-256_AuthKey(snonce || psk || PKe || PKr) and use the 1st 128 bits of the result */
|
|
HMAC_CTX_init(&hmac_ctx);
|
|
HMAC_Init(&hmac_ctx, proto_ctx->auth_key.data, proto_ctx->auth_key.len, EVP_sha256());
|
|
HMAC_Update(&hmac_ctx, snonce->data, snonce->len);
|
|
HMAC_Update(&hmac_ctx, psk->data, psk->len);
|
|
HMAC_Update(&hmac_ctx, pk_e->data, pk_e->len);
|
|
HMAC_Update(&hmac_ctx, pk_r->data, pk_r->len);
|
|
HMAC_Final(&hmac_ctx, result, &len);
|
|
|
|
rc = ipwps_proto_alloc_and_copy_data(hash, result, IPWPS_PROTO_HASH_SIZE);
|
|
ipcom_memset(result, 0, sizeof(result));
|
|
if ((rc != IPCOM_SUCCESS) || !IPWPS_PROTO_HASH_ISVALID(*hash) ||
|
|
(hash->len != IPWPS_PROTO_HASH_SIZE)) {
|
|
IPCOM_LOG1(ERR,"ipwps_proto_derive_devpwd_proof_hash :: Invalid hash (%d)", hash->len);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_calc_kwa
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_calc_kwa(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_container *data) {
|
|
HMAC_CTX hmac_ctx;
|
|
Ip_u8 result[SHA256_DIGEST_LENGTH];
|
|
unsigned int offset, len = SHA256_DIGEST_LENGTH;
|
|
|
|
ip_assert(proto_ctx);
|
|
ip_assert(data);
|
|
|
|
if (!IPWPS_PROTO_CONTAINER_ISVALID(*data)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_calc_kwa :: invalid data");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->auth_key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_calc_kwa :: invalid auth_key");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
/* Perform HMAC-SHA-256_AuthKey(data*) */
|
|
HMAC_CTX_init(&hmac_ctx);
|
|
HMAC_Init(&hmac_ctx, proto_ctx->auth_key.data, proto_ctx->auth_key.len, EVP_sha256());
|
|
HMAC_Update(&hmac_ctx, data->data, data->len-IWPPS_PROTO_ATTR_SIZE(IPWPS_PROTO_LEN_KEYWRAPAUTH));
|
|
HMAC_Final(&hmac_ctx, result, &len);
|
|
|
|
/* Copy authenticator bytes into end of msg2 and zero out result */
|
|
offset = data->len - IPWPS_PROTO_LEN_KEYWRAPAUTH;
|
|
ipcom_memcpy(data->data+offset, result, IPWPS_PROTO_LEN_KEYWRAPAUTH);
|
|
ipcom_memset(result, 0 , SHA256_DIGEST_LENGTH);
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_verify_kwa
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_verify_kwa(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_container *data) {
|
|
Ip_err rc = IPCOM_SUCCESS;
|
|
HMAC_CTX hmac_ctx;
|
|
Ip_u8 result[SHA256_DIGEST_LENGTH];
|
|
unsigned int offset, len = SHA256_DIGEST_LENGTH;
|
|
|
|
ip_assert(proto_ctx);
|
|
ip_assert(data);
|
|
|
|
if (!IPWPS_PROTO_CONTAINER_ISVALID(*data)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_verify_kwa :: invalid data");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->auth_key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_verify_kwa :: invalid auth_key");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
/* Perform HMAC-SHA-256_AuthKey(msg || msg2*) */
|
|
HMAC_CTX_init(&hmac_ctx);
|
|
HMAC_Init(&hmac_ctx, proto_ctx->auth_key.data, proto_ctx->auth_key.len, EVP_sha256());
|
|
HMAC_Update(&hmac_ctx, data->data, data->len-IWPPS_PROTO_ATTR_SIZE(IPWPS_PROTO_LEN_KEYWRAPAUTH));
|
|
HMAC_Final(&hmac_ctx, result, &len);
|
|
|
|
/* Copy authenticator bytes into end of msg2 and zero out result */
|
|
offset = data->len - IPWPS_PROTO_LEN_KEYWRAPAUTH;
|
|
if (ipcom_memcmp(data->data+offset, result, IPWPS_PROTO_LEN_KEYWRAPAUTH) != 0) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_verify_kwa :: key Wrap Authenticator mismatch");
|
|
rc = IPCOM_ERR_FAILED;
|
|
}
|
|
ipcom_memset(result, 0, sizeof(result));
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_calc_msgauth
|
|
*===========================================================================
|
|
* Description: Calculate the Message authenticator: HMAC_AuthKey(msg1 ||msg2*)
|
|
* excluding the last authenticator portion of msg2 and storing the result in
|
|
* the excluded section of msg2.
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_calc_msgauth(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_data *msg1, Ipwps_proto_data *msg2) {
|
|
HMAC_CTX hmac_ctx;
|
|
Ip_u8 result[SHA256_DIGEST_LENGTH];
|
|
unsigned int offset, len = SHA256_DIGEST_LENGTH;
|
|
|
|
ip_assert(proto_ctx);
|
|
ip_assert(msg1);
|
|
ip_assert(msg2);
|
|
|
|
if (!msg1->len) {
|
|
IPCOM_LOG1(ERR,"ipwps_proto_calc_msgauth :: invalid msg1 len", msg1->len);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (msg2->len <= IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR) {
|
|
IPCOM_LOG1(ERR,"ipwps_proto_calc_msgauth :: invalid msg2 len", msg2->len);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->auth_key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_calc_msgauth :: invalid auth_key");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
/* Perform HMAC-SHA-256_AuthKey(msg || msg2*) */
|
|
HMAC_CTX_init(&hmac_ctx);
|
|
HMAC_Init(&hmac_ctx, proto_ctx->auth_key.data, proto_ctx->auth_key.len, EVP_sha256());
|
|
HMAC_Update(&hmac_ctx, msg1->data, msg1->len);
|
|
HMAC_Update(&hmac_ctx, msg2->data, msg2->len-IWPPS_PROTO_ATTR_SIZE(IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR));
|
|
HMAC_Final(&hmac_ctx, result, &len);
|
|
|
|
/* Copy authenticator bytes into end of msg2 and zero out result */
|
|
offset = msg2->len - IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR;
|
|
ipcom_memcpy(msg2->data+offset, result, IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR);
|
|
ipcom_memset(result, 0 , sizeof(result));
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_verify_msgauth
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_verify_msgauth(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_data *msg1, Ipwps_proto_data *msg2) {
|
|
Ip_err rc = IPCOM_SUCCESS;
|
|
HMAC_CTX hmac_ctx;
|
|
Ip_u8 result[SHA256_DIGEST_LENGTH];
|
|
unsigned int offset, len = SHA256_DIGEST_LENGTH;
|
|
|
|
ip_assert(proto_ctx);
|
|
ip_assert(msg1);
|
|
ip_assert(msg2);
|
|
|
|
if (!msg1->len) {
|
|
IPCOM_LOG1(ERR,"ipwps_proto_verify_msgauth :: invalid msg1 len", msg1->len);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (msg2->len <= IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR) {
|
|
IPCOM_LOG1(ERR,"ipwps_proto_verify_msgauth :: invalid msg2 len", msg2->len);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->auth_key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_verify_msgauth :: invalid auth_key");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
/* Perform HMAC-SHA-256_AuthKey(msg || msg2*) */
|
|
HMAC_CTX_init(&hmac_ctx);
|
|
HMAC_Init(&hmac_ctx, proto_ctx->auth_key.data, proto_ctx->auth_key.len, EVP_sha256());
|
|
HMAC_Update(&hmac_ctx, msg1->data, msg1->len);
|
|
HMAC_Update(&hmac_ctx, msg2->data, msg2->len-IWPPS_PROTO_ATTR_SIZE(IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR));
|
|
HMAC_Final(&hmac_ctx, result, &len);
|
|
|
|
/* Compary authenticator bytes to end of msg2 and zero out result */
|
|
offset = msg2->len - IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR;
|
|
if (ipcom_memcmp(msg2->data+offset, result, IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR) != 0) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_verify_msgauth :: authenticator mismatch");
|
|
ipwps_dump_data("ipwps_proto_verify_msgauth :: msg2->data+offset:", msg2->data+offset, IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR);
|
|
ipwps_dump_data("ipwps_proto_verify_msgauth :: calculated auth:", result, IPWPS_PROTO_ATTR_LEN_AUTHENTICATOR);
|
|
rc = IPCOM_ERR_FAILED;
|
|
}
|
|
ipcom_memset(result, 0, sizeof(result));
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_crypto_delete_all
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL void
|
|
ipwps_proto_crypto_delete_all(Ipwps_proto_ctx *proto_ctx) {
|
|
|
|
ip_assert(proto_ctx);
|
|
|
|
ipwps_proto_delete_dh(proto_ctx);
|
|
|
|
ipwps_proto_container_delete(&proto_ctx->local_pub_key);
|
|
ipwps_proto_container_delete(&proto_ctx->peer_pub_key);
|
|
ipwps_proto_container_delete(&proto_ctx->auth_key);
|
|
ipwps_proto_container_delete(&proto_ctx->key_wrap_key);
|
|
ipwps_proto_container_delete(&proto_ctx->emsk);
|
|
ipwps_proto_container_delete(&proto_ctx->nonce1);
|
|
ipwps_proto_container_delete(&proto_ctx->nonce2);
|
|
ipwps_proto_container_delete(&proto_ctx->dev_pwd);
|
|
ipwps_proto_container_delete(&proto_ctx->psk1);
|
|
ipwps_proto_container_delete(&proto_ctx->psk2);
|
|
ipwps_proto_container_delete(&proto_ctx->e_snonce1);
|
|
ipwps_proto_container_delete(&proto_ctx->e_snonce2);
|
|
ipwps_proto_container_delete(&proto_ctx->r_snonce1);
|
|
ipwps_proto_container_delete(&proto_ctx->r_snonce2);
|
|
ipwps_proto_container_delete(&proto_ctx->e_hash1);
|
|
ipwps_proto_container_delete(&proto_ctx->e_hash2);
|
|
ipwps_proto_container_delete(&proto_ctx->r_hash1);
|
|
ipwps_proto_container_delete(&proto_ctx->r_hash2);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_kwf_encrypt_data
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_kwf_encrypt_data(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_container *data_to_encrypt,
|
|
Ipwps_proto_container *encrypted_data) {
|
|
return ipwps_proto_kwf_encrypt_data_with_iv(proto_ctx, data_to_encrypt, encrypted_data, IP_NULL);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_kwf_encrypt_data_with_iv
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipwps_proto_kwf_encrypt_data_with_iv(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_container *data_to_encrypt,
|
|
Ipwps_proto_container *encrypted_data, Ipwps_proto_nonce *iv_to_use) {
|
|
Ip_err rc = IPCOM_SUCCESS;
|
|
int remlen;
|
|
Ip_u8 *ptr;
|
|
Ipwps_proto_nonce iv;
|
|
EVP_CIPHER_CTX cipher_ctx;
|
|
int out_len=0;
|
|
Ip_u8 block_size, padlen;
|
|
Ipwps_proto_container pad;
|
|
|
|
ip_assert(proto_ctx);
|
|
ip_assert(data_to_encrypt);
|
|
ip_assert(encrypted_data);
|
|
|
|
IPWPS_PROTO_NONCE_INIT(iv);
|
|
IPWPS_PROTO_CONTAINER_INIT(pad);
|
|
|
|
if (!IPWPS_PROTO_CONTAINER_ISVALID(*data_to_encrypt)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_kwf_encrypt_data :: invalid data_to_encrypt");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_CONTAINER_ISVALID(*encrypted_data)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_kwf_encrypt_data :: invalid encrypted_data");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->key_wrap_key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_kwf_encrypt_data :: invalid key_wrap_key");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
#ifdef IPWPS_DEBUG
|
|
if (ipwps_proto_no_data_encryption) {
|
|
/* pass in the clear without IV */
|
|
if (encrypted_data->len < data_to_encrypt->len) {
|
|
IPCOM_LOG1(ERR,"ipwps_proto_kwf_encrypt_data :: invalid encrypted_data->len (%d)", encrypted_data->len);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
IPCOM_LOG0(WARNING,"ipwps_proto_kwf_encrypt_data :: PASSING UNENCRYPTED DATA");
|
|
ipcom_memcpy(encrypted_data->data, data_to_encrypt->data, data_to_encrypt->len);
|
|
encrypted_data->len = data_to_encrypt->len;
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
/* Create a random IV and add it to start of encrypted data container*/
|
|
remlen = encrypted_data->len;
|
|
ptr = encrypted_data->data;
|
|
if (remlen < IPWPS_PROTO_IV_SIZE) {
|
|
IPCOM_LOG2(ERR, "ipwps_proto_kwf_encrypt_data :: Not enough room to add IV (remlen = %d < %d)",
|
|
remlen, IPWPS_PROTO_IV_SIZE);
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_encrypt;
|
|
}
|
|
iv.len = IPWPS_PROTO_IV_SIZE;
|
|
iv.data = ptr;
|
|
if (iv_to_use && IPWPS_PROTO_NONCE_ISVALID(*iv_to_use) && (iv_to_use->len == IPWPS_PROTO_IV_SIZE)) {
|
|
IPCOM_LOG0(DEBUG2,"ipwps_proto_kwf_encrypt_data :: using passed in IV");
|
|
ipcom_memcpy(iv.data, iv_to_use->data, IPWPS_PROTO_IV_SIZE);
|
|
} else {
|
|
if (ipwps_proto_crypto_randdata(&iv) != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_kwf_encrypt_data :: ipwps_proto_crypto_randdata(&iv) failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_encrypt;
|
|
}
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_kwf_encrypt_data :: iv:", iv);
|
|
ptr += IPWPS_PROTO_IV_SIZE;
|
|
remlen -= IPWPS_PROTO_IV_SIZE;
|
|
|
|
/* Initialize a Cipher context */
|
|
(void)EVP_CIPHER_CTX_init(&cipher_ctx);
|
|
if (EVP_EncryptInit(&cipher_ctx, EVP_aes_128_cbc(), proto_ctx->key_wrap_key.data, iv.data) <= 0) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_kwf_encrypt_data :: EVP_EncryptInit failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_encrypt;
|
|
}
|
|
(void)EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0); /* We will do the paddind ourselves */
|
|
|
|
/* Allocate and initialize pad data (PKCS#5) */
|
|
block_size = EVP_CIPHER_CTX_block_size(&cipher_ctx);
|
|
padlen = block_size - (data_to_encrypt->len % block_size);
|
|
if (ipwps_proto_alloc_data(&pad, padlen) != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_kwf_encrypt_data :: failed to alloc pad data.");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_encrypt;
|
|
}
|
|
ipcom_memset(pad.data, padlen, padlen);
|
|
|
|
/* Encrypt the data along with the pad */
|
|
if (EVP_EncryptUpdate(&cipher_ctx, ptr, &out_len, data_to_encrypt->data, data_to_encrypt->len) <= 0) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_kwf_encrypt_data :: EVP_EncryptUpdate failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_encrypt;
|
|
}
|
|
ptr += out_len;
|
|
remlen -= out_len;
|
|
if (remlen <= 0) {
|
|
IPCOM_LOG1(ERR, "ipwps_proto_kwf_encrypt_data :: Not enough room to encrypt (remlen = %d)", remlen);
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_encrypt;
|
|
}
|
|
if (EVP_EncryptUpdate(&cipher_ctx, ptr, &out_len, pad.data, pad.len) <= 0) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_kwf_encrypt_data :: EVP_EncryptUpdate failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_encrypt;
|
|
}
|
|
ptr += out_len;
|
|
remlen -= out_len;
|
|
if (remlen < 0) {
|
|
IPCOM_LOG1(ERR, "ipwps_proto_kwf_encrypt_data :: Not enough room to encrypt pad (remlen = %d)", remlen);
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_encrypt;
|
|
}
|
|
if (EVP_EncryptFinal(&cipher_ctx, ptr, &out_len) <= 0) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_kwf_encrypt_data :: EVP_EncryptFinal failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_encrypt;
|
|
}
|
|
ptr += out_len;
|
|
remlen -= out_len;
|
|
if (remlen < 0) {
|
|
IPCOM_LOG1(CRIT, "ipwps_proto_kwf_encrypt_data :: remlen = %d at end of encryption", remlen);
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_encrypt;
|
|
}
|
|
encrypted_data->len -= remlen;
|
|
|
|
done_encrypt:
|
|
ipwps_proto_container_delete(&pad);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_kwf_decrypt_data
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_kwf_decrypt_data(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_container *data_to_decrypt,
|
|
Ipwps_proto_container *decrypted_data) {
|
|
Ip_err rc = IPCOM_SUCCESS;
|
|
int inlen, remlen;
|
|
Ip_u8 *inptr, *outptr;
|
|
Ipwps_proto_nonce iv;
|
|
EVP_CIPHER_CTX cipher_ctx;
|
|
int out_len=0;
|
|
|
|
ip_assert(proto_ctx);
|
|
ip_assert(data_to_decrypt);
|
|
ip_assert(decrypted_data);
|
|
|
|
IPWPS_PROTO_NONCE_INIT(iv);
|
|
|
|
if (!IPWPS_PROTO_CONTAINER_ISVALID(*data_to_decrypt)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_kwf_decrypt_data :: invalid data_to_decrypt");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_CONTAINER_ISVALID(*decrypted_data)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_kwf_decrypt_data :: invalid decrypted_data");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
if (!IPWPS_PROTO_KEY_ISVALID(proto_ctx->key_wrap_key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_kwf_decrypt_data :: invalid key_wrap_key");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
#ifdef IPWPS_DEBUG
|
|
if (ipwps_proto_no_data_encryption) {
|
|
/* copy clear data without IV */
|
|
if (decrypted_data->len < data_to_decrypt->len) {
|
|
IPCOM_LOG1(ERR,"ipwps_proto_kwf_decrypt_data :: invalid decrypted_data->len (%d)",
|
|
decrypted_data->len);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
IPCOM_LOG0(WARNING,"ipwps_proto_kwf_decrypt_data :: COPYING UNENCRYPTED DATA");
|
|
ipcom_memcpy(decrypted_data->data, data_to_decrypt->data, data_to_decrypt->len);
|
|
decrypted_data->len = data_to_decrypt->len;
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
#endif
|
|
/* Retrieve the IV prepended to the encrypted data container*/
|
|
inlen = data_to_decrypt->len;
|
|
inptr = data_to_decrypt->data;
|
|
if (inlen < IPWPS_PROTO_IV_SIZE) {
|
|
IPCOM_LOG2(ERR, "ipwps_proto_kwf_decrypt_data :: Not enough room to retrieve IV (inlen = %d < %d)",
|
|
inlen, IPWPS_PROTO_IV_SIZE);
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_decrypt;
|
|
}
|
|
iv.len = IPWPS_PROTO_IV_SIZE;
|
|
iv.data = inptr;
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_kwf_decrypt_data :: iv:", iv);
|
|
inptr += IPWPS_PROTO_IV_SIZE;
|
|
inlen -= IPWPS_PROTO_IV_SIZE;
|
|
|
|
if (inlen == 0) {
|
|
IPCOM_LOG2(ERR, "ipwps_proto_kwf_decrypt_data :: No data to decrypt",
|
|
inlen, IPWPS_PROTO_IV_SIZE);
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_decrypt;
|
|
}
|
|
if (decrypted_data->len < inlen) {
|
|
IPCOM_LOG2(ERR, "ipwps_proto_kwf_decrypt_data :: Not enough room to decrypt data (%d < %d)",
|
|
decrypted_data->len, inlen);
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_decrypt;
|
|
}
|
|
|
|
outptr = decrypted_data->data;
|
|
remlen = decrypted_data->len;
|
|
/* Initialize a Cipher context and Decrypt the data */
|
|
(void)EVP_CIPHER_CTX_init(&cipher_ctx);
|
|
if (EVP_DecryptInit(&cipher_ctx, EVP_aes_128_cbc(), proto_ctx->key_wrap_key.data, iv.data) <= 0) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_kwf_decrypt_data :: EVP_DecryptInit failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_decrypt;
|
|
}
|
|
(void)EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0); /* We do the padding ourselves */
|
|
if (EVP_EncryptUpdate(&cipher_ctx, outptr, &out_len, inptr, inlen) <= 0) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_kwf_decrypt_data :: EVP_EncryptUpdate failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_decrypt;
|
|
}
|
|
outptr += out_len;
|
|
decrypted_data->len = out_len;
|
|
remlen -= out_len;
|
|
if (EVP_EncryptFinal(&cipher_ctx, outptr, &out_len) <= 0) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_kwf_decrypt_data :: EVP_EncryptFinal failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_decrypt;
|
|
}
|
|
outptr += out_len;
|
|
decrypted_data->len += out_len;
|
|
remlen -= out_len;
|
|
if (remlen < 0) {
|
|
IPCOM_LOG1(CRIT, "ipwps_proto_kwf_decrypt_data :: remlen = %d at end of decryption", remlen);
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_decrypt;
|
|
}
|
|
|
|
/* Now remove padding */
|
|
decrypted_data->len -= decrypted_data->data[decrypted_data->len-1];
|
|
|
|
done_decrypt:
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_derive_dhkey
|
|
*===========================================================================
|
|
* Description: Derive the WPS DHKey using the provided shared secret and
|
|
* copy the result to the supplied dh_key.
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipwps_proto_derive_dhkey(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_key *shared_secret, Ipwps_proto_key *dh_key) {
|
|
|
|
ip_assert(proto_ctx);
|
|
ip_assert(shared_secret);
|
|
ip_assert(dh_key);
|
|
|
|
if (!IPWPS_PROTO_KEY_ISVALID(*shared_secret)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_dhkey :: invalid shared_secret");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
/* Perform SHA-256(shared_secret) and copy result to dh_key.
|
|
* Note that shared_secret was calculated to be (g^AB mod p)
|
|
*/
|
|
dh_key->data = ipcom_malloc(IPWPS_PROTO_KEYLEN_DHKEY);
|
|
if (!dh_key->data) {
|
|
IPCOM_LOG0(CRIT, "ipwps_proto_derive_dhkey :: out of memory");
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
}
|
|
SHA256(shared_secret->data, shared_secret->len, dh_key->data);
|
|
dh_key->len = IPWPS_PROTO_KEYLEN_DHKEY;
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_derive_kdk
|
|
*===========================================================================
|
|
* Description: Derive the WPS KDK using the provided DHKey and the nonce
|
|
* values in the provided protocol context and then copy the
|
|
* result to the supplied kdk.
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipwps_proto_derive_kdk(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_key *dh_key, Ipwps_proto_key *kdk) {
|
|
Ip_err rc;
|
|
unsigned int kdk_len = 0;
|
|
HMAC_CTX hmac_ctx;
|
|
#ifdef IPWPS_DEBUG_PROTO_CRYPTO_DATA
|
|
Ipwps_proto_container mac_addr;
|
|
#endif
|
|
ip_assert(proto_ctx);
|
|
ip_assert(dh_key);
|
|
ip_assert(kdk);
|
|
|
|
rc = ipwps_proto_alloc_data(kdk, IPWPS_PROTO_KEYLEN_KDK);
|
|
if ((rc != IPCOM_SUCCESS) || !IPWPS_PROTO_KEY_ISVALID(*kdk)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_kdk :: Invalid kdk");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_KEY_ISVALID(*dh_key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_kdk :: Invalid dh_key");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_NONCE_ISVALID(proto_ctx->nonce1)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_kdk :: Invalid nonce1");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_NONCE_ISVALID(proto_ctx->nonce2)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_kdk :: Invalid nonce2");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if ((proto_ctx->enrollee_mac[0] | proto_ctx->enrollee_mac[1] | proto_ctx->enrollee_mac[2] |
|
|
proto_ctx->enrollee_mac[3] | proto_ctx->enrollee_mac[4] | proto_ctx->enrollee_mac[5]) == 0) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_derive_kdk :: Invalid enrollee_mac");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
#ifdef IPWPS_DEBUG_PROTO_CRYPTO_DATA
|
|
mac_addr.data = proto_ctx->enrollee_mac;
|
|
mac_addr.len = 6;
|
|
#endif
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_derive_kdk :: enrollee_mac:", mac_addr);
|
|
|
|
/* Perform HMAC-SHA-256_DHKey(NONCE1 || EnrolleeMAC || NONCE2) and copy result to kdk */
|
|
HMAC_CTX_init(&hmac_ctx);
|
|
HMAC_Init(&hmac_ctx, dh_key->data, dh_key->len, EVP_sha256());
|
|
HMAC_Update(&hmac_ctx, proto_ctx->nonce1.data, proto_ctx->nonce1.len);
|
|
HMAC_Update(&hmac_ctx, proto_ctx->enrollee_mac, 6);
|
|
HMAC_Update(&hmac_ctx, proto_ctx->nonce2.data, proto_ctx->nonce2.len);
|
|
HMAC_Final(&hmac_ctx, kdk->data, &kdk_len);
|
|
kdk->len = (Ip_u16)kdk_len;
|
|
if (kdk->len != IPWPS_PROTO_KEYLEN_KDK) {
|
|
IPCOM_LOG2(ERR,"ipwps_proto_derive_kdk :: Invalid kdk len (%d, exp: %d)", kdk->len, IPWPS_PROTO_KEYLEN_KDK);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_perform_kdf
|
|
*===========================================================================
|
|
* Description: Perform the WPS KDF function using the key and an optional set of data
|
|
* using the personalization string provided and total key bits required.
|
|
* Parameters:
|
|
* Ipwps_proto_ctx *proto_ctx - A valid
|
|
* Ipwps_proto_key *key - key to be used in the KDF function
|
|
* Ipwps_proto_container **dataset - An array containing the data to be used in the kdf
|
|
* by being prepended to the personalization string.
|
|
* MUST be terminated with a NULL key element.
|
|
* char *pstring - personalization string.
|
|
* Ipwps_proto_key *result - The key to hold the result.
|
|
* MUST have a valid allocated data and cotain as its length the total_key_bits required.
|
|
* Returns:
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipwps_proto_perform_kdf(Ipwps_proto_key *key, Ipwps_proto_container **dataset, IP_CONST char *pstring, Ipwps_proto_key *result) {
|
|
Ip_u32 i, iterations, plen, temp_len, remlen,
|
|
digestlen = SHA256_DIGEST_LENGTH;
|
|
Ip_u8 total_key_bits[4];
|
|
Ip_u8 temp_result[SHA256_DIGEST_LENGTH];
|
|
Ipwps_proto_container *optdata;
|
|
|
|
ip_assert(key);
|
|
ip_assert(pstring);
|
|
ip_assert(result);
|
|
|
|
if (!IPWPS_PROTO_KEY_ISVALID(*key)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_perform_kdf :: Invalid key");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
plen = strlen(pstring);
|
|
if (!plen) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_perform_kdf :: Invalid plen");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!IPWPS_PROTO_KEY_ISVALID(*result)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_perform_kdf :: Invalid result");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
IP_SET_HTONL(total_key_bits, (result->len * 8));
|
|
iterations = ((result->len*8) + (digestlen*8) -1)/(digestlen*8);
|
|
temp_len = digestlen;
|
|
remlen = result->len;
|
|
|
|
/* Perform PRF (HMAC-SHA-256) */
|
|
for (i = 1; i <= iterations ; i++) {
|
|
HMAC_CTX hmac_ctx;
|
|
Ip_u8 i_be[4];
|
|
IP_SET_HTONL(i_be, i);
|
|
HMAC_CTX_init(&hmac_ctx);
|
|
HMAC_Init(&hmac_ctx, key->data, key->len, EVP_sha256());
|
|
HMAC_Update(&hmac_ctx, i_be, sizeof(i_be));
|
|
if (dataset) {
|
|
int j=0;
|
|
optdata = dataset[j];
|
|
while (optdata && IPWPS_PROTO_KEY_ISVALID(*optdata)) {
|
|
HMAC_Update(&hmac_ctx, optdata->data, optdata->len);
|
|
j++;
|
|
}
|
|
}
|
|
HMAC_Update(&hmac_ctx, (Ip_u8 *)pstring, plen);
|
|
HMAC_Update(&hmac_ctx, total_key_bits, sizeof(total_key_bits));
|
|
HMAC_Final(&hmac_ctx, temp_result, (unsigned int *)&temp_len);
|
|
#if 0
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_dhkey :: result (before):", *result);
|
|
#endif
|
|
if (i < iterations) {
|
|
ipcom_memcpy(result->data+((i-1)*digestlen), temp_result, digestlen);
|
|
remlen -= digestlen;
|
|
} else {
|
|
/* on last iter only copy enough */
|
|
ipcom_memcpy(result->data+((i-1)*digestlen), temp_result, remlen);
|
|
remlen = 0;
|
|
}
|
|
ipcom_memset(temp_result, 0, sizeof(temp_result));
|
|
#if 0
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_dhkey :: result (after):", *result);
|
|
#endif
|
|
}
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_perform_kdk_kdf
|
|
*===========================================================================
|
|
* Description: Perform the WPS KDF function to generate the session keys
|
|
* using the provided KDK.
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipwps_proto_perform_kdk_kdf(Ipwps_proto_ctx *proto_ctx, Ipwps_proto_key *kdk, Ipwps_proto_key *session_keys) {
|
|
IP_CONST char *personalization_string = IPWPS_PROTO_KDK_KDF_PERSONALIZATION_STR;
|
|
|
|
ip_assert(proto_ctx);
|
|
ip_assert(kdk);
|
|
ip_assert(session_keys);
|
|
|
|
if (!IPWPS_PROTO_KEY_ISVALID(*kdk)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_perform_kdk_kdf :: Invalid kdk");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (ipwps_proto_alloc_data(session_keys, IPWPS_PROTO_KEYLEN_SESSIONKEYS_TOTAL) != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_perform_kdk_kdf :: failed to alloc session_keys");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
/* Perform kdf(KDK, "Wi-Fi Easy and Secure Key Derivation", IPWPS_PROTO_KEYLEN_SESSIONKEYS_TOTAL) */
|
|
if (ipwps_proto_perform_kdf(kdk, IP_NULL, personalization_string, session_keys) != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_perform_kdk_kdf :: failed to perform kdf");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (session_keys->len != IPWPS_PROTO_KEYLEN_SESSIONKEYS_TOTAL) {
|
|
IPCOM_LOG2(ERR,"ipwps_proto_perform_kdk_kdf :: Invalid kdk len (%d, exp: %d)", kdk->len, IPWPS_PROTO_KEYLEN_KDK);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_alloc_data
|
|
*===========================================================================
|
|
* Description:
|
|
* Allocate container data of length "len".
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_alloc_data(Ipwps_proto_container *container, Ip_u16 len) {
|
|
|
|
ip_assert(container);
|
|
|
|
/* Delete any lingering memory */
|
|
if (container->data) {
|
|
ipcom_free(container->data);
|
|
}
|
|
container->len = 0;
|
|
container->data = ipcom_calloc(1, len);
|
|
if (!container->data) {
|
|
IPCOM_LOG0(CRIT,"ipwps_proto_alloc_data :: out of memory");
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
}
|
|
container->alloc_len = len;
|
|
container->len = len;
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_alloc_and_copy_data
|
|
*===========================================================================
|
|
* Description:
|
|
* Allocate container data of length "len" and copy "data" into it.
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_alloc_and_copy_data(Ipwps_proto_container *container, Ip_u8 *data, Ip_u16 len) {
|
|
Ip_err rc = IPCOM_SUCCESS;
|
|
|
|
ip_assert(container);
|
|
|
|
if (!len || !data)
|
|
return IPCOM_ERR_FAILED;
|
|
|
|
rc = ipwps_proto_alloc_data(container, len);
|
|
if (rc == IPCOM_SUCCESS) {
|
|
ipcom_memcpy(container->data, data, len);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_duplicate_data
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_duplicate_data(Ipwps_proto_container *to, Ipwps_proto_container *from) {
|
|
|
|
ip_assert(to);
|
|
ip_assert(from);
|
|
|
|
if (!from->data || !from->len) {
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
return ipwps_proto_alloc_and_copy_data(to, from->data, from->len);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_copy_data
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_copy_data(Ipwps_proto_container *dest, Ipwps_proto_container *src, Ip_u16 src_offset, Ip_u16 copy_len) {
|
|
|
|
ip_assert(dest);
|
|
ip_assert(src);
|
|
|
|
if (!IPWPS_PROTO_CONTAINER_ISVALID(*src)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_copy_data :: Invalid src");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if ((src_offset+copy_len) > src->len) {
|
|
IPCOM_LOG3(ERR,"ipwps_proto_copy_data :: Invalid copy values (off: %d, copy: %d, len %d))",
|
|
src_offset, copy_len, src->len);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (ipwps_proto_alloc_data(dest, copy_len) != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_copy_data :: ipwps_proto_alloc_data() failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
ipcom_memcpy(dest->data, src->data+src_offset, copy_len);
|
|
dest->len = copy_len;
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_compare_data
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_bool
|
|
ipwps_proto_compare_data(Ipwps_proto_container *c1, Ipwps_proto_container *c2) {
|
|
|
|
ip_assert(c1);
|
|
ip_assert(c2);
|
|
|
|
if (!IPWPS_PROTO_CONTAINER_ISVALID(*c1) || !IPWPS_PROTO_CONTAINER_ISVALID(*c2))
|
|
return IP_FALSE;
|
|
if (c1->len != c2->len)
|
|
return IP_FALSE;
|
|
if (ipcom_memcmp(c1->data, c2->data, c1->len) != 0)
|
|
return IP_FALSE;
|
|
return IP_TRUE;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_container_delete
|
|
*===========================================================================
|
|
* Description: Delete a data container after clearing its buffer
|
|
* ONLY is the container has an allocated buffer.
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL void
|
|
ipwps_proto_container_delete(Ipwps_proto_container *container) {
|
|
|
|
ip_assert(container);
|
|
|
|
if (container->alloc_len && container->data) {
|
|
ipcom_memset(container->data, 0, container->len);
|
|
ipcom_free(container->data);
|
|
}
|
|
container->data = IP_NULL;
|
|
container->len = 0;
|
|
container->alloc_len = 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_generate_dh_keys
|
|
*===========================================================================
|
|
* Description:
|
|
* Generate Diffie-Hellman Private/Public key pair using the specified dh group
|
|
* and copy the public key into the provided key structure.
|
|
* DH structure is preserved since it contains the private key, but will be
|
|
* destroyed once the dh shared secrets are computed by calling
|
|
* ipwps_proto_derive_dh_sharedsecret().
|
|
* Parameters:
|
|
*
|
|
* Returns:
|
|
* Pointer to a new DH structure if successful, IP_NULL otherwise.
|
|
*/
|
|
IP_GLOBAL DH *
|
|
ipwps_proto_generate_dh_keys(Ipwps_proto_dh_group *dh_grp, Ipwps_proto_key *pubkey) {
|
|
DH *dh;
|
|
#if 0
|
|
int dh_codes;
|
|
#endif
|
|
|
|
ip_assert(pubkey);
|
|
ip_assert(dh_grp);
|
|
ip_assert(dh_grp->prime_value);
|
|
|
|
dh = DH_new();
|
|
if (!dh) {
|
|
IPCOM_LOG0(CRIT,"ipwps_proto_generate_dh_keys :: out of memory");
|
|
DH_free(dh);
|
|
return IP_NULL;
|
|
}
|
|
dh->g = BN_new();
|
|
dh->p = BN_new();
|
|
if (!dh->g || !dh->p) {
|
|
IPCOM_LOG0(CRIT,"ipwps_proto_generate_dh_keys :: out of memory (2)");
|
|
DH_free(dh);
|
|
return IP_NULL;
|
|
}
|
|
|
|
(void)BN_set_word(dh->g, dh_grp->generator);
|
|
(void)BN_bin2bn(dh_grp->prime_value, dh_grp->prime_len, dh->p);
|
|
|
|
#if 0
|
|
if (!DH_check(dh, &dh_codes)) {
|
|
IPCOM_LOG0(ERR,"ipwps_proto_generate_dh_keys :: DH_check() failed");
|
|
return IP_NULL;
|
|
}
|
|
if (dh_codes) {
|
|
if (dh_codes & DH_CHECK_P_NOT_PRIME)
|
|
IPCOM_LOG0(ERR,"ipwps_proto_generate_dh_keys :: p value is not prime");
|
|
if (dh_codes & DH_CHECK_P_NOT_SAFE_PRIME)
|
|
IPCOM_LOG0(ERR,"ipwps_proto_generate_dh_keys :: p value is not a safe prime");
|
|
if (dh_codes & DH_UNABLE_TO_CHECK_GENERATOR)
|
|
IPCOM_LOG0(ERR,"ipwps_proto_generate_dh_keys :: unable to check the generator value");
|
|
if (dh_codes & DH_NOT_SUITABLE_GENERATOR)
|
|
IPCOM_LOG0(ERR,"ipwps_proto_generate_dh_keys :: the g value is not a generator");
|
|
return IP_NULL;
|
|
}
|
|
#endif
|
|
|
|
if (!DH_generate_key(dh)) {
|
|
IPCOM_LOG2(ERR, "ipwps_proto_generate_dh_keys :: failed to generate DH key, (len %d, generator %d)",
|
|
dh_grp->prime_len, dh_grp->generator);
|
|
DH_free(dh);
|
|
return IP_NULL;
|
|
}
|
|
|
|
pubkey->data = ipcom_malloc(BN_num_bytes(dh->pub_key));
|
|
if (!pubkey->data) {
|
|
IPCOM_LOG0(CRIT, "ipwps_proto_generate_dh_keys: out of memory (2)");
|
|
DH_free(dh);
|
|
return IP_NULL;
|
|
}
|
|
pubkey->len = BN_bn2bin(dh->pub_key, pubkey->data);
|
|
|
|
return dh;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_derive_dh_sharedsecret
|
|
*===========================================================================
|
|
* Description:
|
|
* Generate Diffie-Hellman shared secret using the specified dh struct
|
|
* and peer public key, then copy the result into the provided key structure.
|
|
* Parameters:
|
|
*
|
|
* Returns:
|
|
* IPCOM_SUCCESS if successful, error otherwise.
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipwps_proto_derive_dh_sharedsecret(DH *dh, Ipwps_proto_key *peer_pubkey, Ipwps_proto_key *secret) {
|
|
BIGNUM *bn_pub_key;
|
|
int len;
|
|
Ip_u32 n;
|
|
Ip_err rc;
|
|
|
|
ip_assert(dh);
|
|
ip_assert(peer_pubkey);
|
|
ip_assert(secret);
|
|
|
|
bn_pub_key = BN_bin2bn(peer_pubkey->data, peer_pubkey->len, IP_NULL);
|
|
if (!bn_pub_key) {
|
|
IPCOM_LOG0(CRIT, "ipwps_proto_derive_dh_sharedsecret :: out of memory");
|
|
rc = IPCOM_ERR_NO_MEMORY;
|
|
goto clean_up;
|
|
}
|
|
|
|
secret->data = ipcom_malloc(DH_size(dh));
|
|
if (!secret->data) {
|
|
IPCOM_LOG0(CRIT, "ipwps_proto_derive_dh_sharedsecret :: out of memory (2)");
|
|
rc = IPCOM_ERR_NO_MEMORY;
|
|
goto clean_up;
|
|
}
|
|
|
|
len = DH_compute_key(secret->data, bn_pub_key, dh);
|
|
if (len == -1) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_derive_dh_sharedsecret :: failed to create the DH derived shared secret");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto clean_up;
|
|
}
|
|
secret->len = (Ip_u16)len;
|
|
|
|
/* Pad key with zero to the left if key length less then dh key size */
|
|
n = DH_size(dh) - secret->len;
|
|
if (n > 0) {
|
|
ipcom_memmove(secret->data + n, secret->data, secret->len);
|
|
ipcom_memset(secret->data, 0, (int)n);
|
|
secret->len += n;
|
|
}
|
|
rc = IPCOM_SUCCESS;
|
|
|
|
clean_up:
|
|
BN_clear_free(bn_pub_key);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_delete_dh
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC void
|
|
ipwps_proto_delete_dh(Ipwps_proto_ctx *proto_ctx) {
|
|
ip_assert(proto_ctx);
|
|
|
|
if (proto_ctx->dh) {
|
|
DH_free(proto_ctx->dh);
|
|
proto_ctx->dh = IP_NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_get_dh_group
|
|
*===========================================================================
|
|
* Description: Retrieve the Diffie-Hellman group used by IPWPS
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_STATIC Ipwps_proto_dh_group *
|
|
ipwps_proto_get_dh_group(Ipwps_proto_ctx *proto_ctx) {
|
|
ip_assert(proto_ctx);
|
|
return ipwps_proto_default_dh_group;
|
|
}
|
|
|
|
|
|
#define IPWPS_PROTO_CRYPTO_TEST
|
|
#ifdef IPWPS_PROTO_CRYPTO_TEST
|
|
/* typedefs */
|
|
typedef struct Ipwps_proto_crypto_test_st {
|
|
Ip_err (*testfn)(void);
|
|
char *testname;
|
|
} Ipwps_proto_crypto_test;
|
|
|
|
typedef struct Ipwps_proto_dhkey_test_vector_st {
|
|
char *input;
|
|
Ip_u8 result[IPWPS_PROTO_KEYLEN_DHKEY];
|
|
} Ipwps_proto_dhkey_test_vector;
|
|
|
|
typedef struct Ipwps_proto_kdf_test_vector_st {
|
|
Ip_u8 key[256];
|
|
Ip_u16 keylen;
|
|
char *personalization_string;
|
|
Ip_u16 keybits;
|
|
Ip_u8 result[256];
|
|
} Ipwps_proto_kdf_test_vector;
|
|
|
|
typedef struct Ipwps_proto_hmacsha256_test_vector_st {
|
|
Ip_u8 key[256];
|
|
Ip_u16 keylen;
|
|
Ip_u16 numblocks;
|
|
struct {
|
|
Ip_u8 data[256];
|
|
Ip_u16 len;
|
|
} block[16];
|
|
Ip_u8 result[SHA256_DIGEST_LENGTH];
|
|
Ip_u8 trancate_len; /* if not 0, indicates truncated result length */
|
|
} Ipwps_proto_hmacsha256_test_vector;
|
|
|
|
typedef struct Ipwps_proto_kwf_test_vector_st {
|
|
Ip_u8 keywrapkey[IPWPS_PROTO_KEYLEN_KEYWRAPKEY];
|
|
Ip_u8 iv[IPWPS_PROTO_NONCE_SIZE];
|
|
char *cleartext;
|
|
Ip_u8 ciphertext[256];
|
|
Ip_u16 ciphertext_len;
|
|
} Ipwps_proto_kwf_test_vector;
|
|
|
|
/* Forward declerations */
|
|
IP_GLOBAL Ip_err ipwps_proto_cryptotest_sessionkeys(void);
|
|
IP_GLOBAL Ip_err ipwps_proto_cryptotest_dhsharedsecrets(void);
|
|
IP_GLOBAL Ip_err ipwps_proto_cryptotest_dhkey(void);
|
|
IP_GLOBAL Ip_err ipwps_proto_cryptotest_hmacsha256(void);
|
|
IP_GLOBAL Ip_err ipwps_proto_cryptotest_kdf(void);
|
|
IP_GLOBAL Ip_err ipwps_proto_cryptotest_kwf(void);
|
|
|
|
/* Data */
|
|
IP_STATIC Ipwps_proto_crypto_test ipwps_proto_crypto_tests[] = {
|
|
{ipwps_proto_cryptotest_dhkey, "DH KEY GENERATION"},
|
|
{ipwps_proto_cryptotest_hmacsha256, "HMAC-SHA-256"},
|
|
{ipwps_proto_cryptotest_kdf, "KDF FUNCTION"},
|
|
{ipwps_proto_cryptotest_dhsharedsecrets, "DH SHARED SECRETS"},
|
|
{ipwps_proto_cryptotest_sessionkeys, "SESSION KEYS"},
|
|
{ipwps_proto_cryptotest_kwf, "KWF ENCRYPTION/DECRYPTION"},
|
|
|
|
/* KEEP THIS LAST */
|
|
{IP_NULL, IP_NULL}
|
|
};
|
|
|
|
IP_STATIC Ipwps_proto_dhkey_test_vector ipwps_proto_dhkey_test_vectors[] = {
|
|
#if 0 /* Our code doesn't accept 0 length data currently */
|
|
{"",
|
|
{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
|
|
0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
|
|
0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
|
|
0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}
|
|
},
|
|
#endif
|
|
{"abc",
|
|
{0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
|
|
0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
|
|
0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
|
|
0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}
|
|
},
|
|
|
|
{"message digest",
|
|
{0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e,
|
|
0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad,
|
|
0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef,
|
|
0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50}
|
|
},
|
|
|
|
{"secure hash algorithm",
|
|
{0xf3, 0x0c, 0xeb, 0x2b, 0xb2, 0x82, 0x9e, 0x79,
|
|
0xe4, 0xca, 0x97, 0x53, 0xd3, 0x5a, 0x8e, 0xcc,
|
|
0x00, 0x26, 0x2d, 0x16, 0x4c, 0xc0, 0x77, 0x08,
|
|
0x02, 0x95, 0x38, 0x1c, 0xbd, 0x64, 0x3f, 0x0d}
|
|
},
|
|
|
|
{"SHA256 is considered to be safe",
|
|
{0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e,
|
|
0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9,
|
|
0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15,
|
|
0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30}
|
|
},
|
|
|
|
{"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
|
{0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
|
|
0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
|
|
0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
|
|
0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}
|
|
},
|
|
|
|
{"For this sample, this 63-byte string will be used as input data",
|
|
{0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b,
|
|
0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e,
|
|
0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5,
|
|
0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42}
|
|
},
|
|
|
|
{"This is exactly 64 bytes long, not counting the terminating byte",
|
|
{0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46,
|
|
0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26,
|
|
0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82,
|
|
0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8}
|
|
}
|
|
};
|
|
|
|
IP_STATIC Ipwps_proto_hmacsha256_test_vector ipwps_proto_hmacsha256_test_vectors[] = {
|
|
{
|
|
/* RFC 4231 Test Case 1 */
|
|
{0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
|
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
|
0x0b, 0x0b, 0x0b, 0x0b}, /*key */
|
|
20, /* keylen */
|
|
1, /* numblocks */
|
|
{
|
|
{{0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65}/*{Hi There"},*/,
|
|
8} /* block #1 */
|
|
},
|
|
{0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53,
|
|
0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b,
|
|
0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
|
|
0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7}, /* result */
|
|
0, /*trancate_len = none*/
|
|
},
|
|
|
|
/* RFC 4231 Test Case 2 */
|
|
{
|
|
{0x4a, 0x65, 0x66, 0x65}, /*key = "Jefe"*/
|
|
4, /* keylen */
|
|
2, /* numblocks */
|
|
{
|
|
{{0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20,
|
|
0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20}, /*"what do ya want "*/
|
|
16}, /* block #1 */
|
|
{{0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68,
|
|
0x69, 0x6e, 0x67, 0x3f}, /*"for nothing?"*/
|
|
12} /* block #2 */
|
|
},
|
|
{0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e,
|
|
0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
|
|
0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
|
|
0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43}, /* result */
|
|
0, /*trancate_len = none*/
|
|
},
|
|
|
|
/* RFC 4231 Test Case 3 */
|
|
{
|
|
{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa,}, /*key */
|
|
20, /* keylen */
|
|
1, /* numblocks */
|
|
{
|
|
{{0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
|
|
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
|
|
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
|
|
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
|
|
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
|
|
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
|
|
0xdd, 0xdd},
|
|
50} /* block #1 */
|
|
},
|
|
{0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46,
|
|
0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7,
|
|
0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22,
|
|
0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe}, /* result */
|
|
0, /*trancate_len = none*/
|
|
},
|
|
|
|
/* RFC 4231 Test Case 4 */
|
|
{
|
|
{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
|
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
|
|
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
|
0x19}, /*key */
|
|
25, /* keylen */
|
|
1, /* numblocks */
|
|
{
|
|
{{0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
|
|
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
|
|
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
|
|
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
|
|
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
|
|
0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
|
|
0xcd, 0xcd},
|
|
50}, /* block #1 */
|
|
},
|
|
{0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e,
|
|
0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a,
|
|
0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07,
|
|
0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b}, /* result */
|
|
0, /*trancate_len = none*/
|
|
},
|
|
|
|
/* RFC 4231 Test Case 5 */
|
|
{
|
|
{0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c}, /*key */
|
|
20, /* keylen */
|
|
2, /* numblocks */
|
|
{
|
|
{{0x54, 0x65, 0x73, 0x74, 0x20, 0x57, 0x69, 0x74,
|
|
0x68, 0x20, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61}, /*"Test With Trunca"*/
|
|
16}, /* block #1 */
|
|
{{0x74, 0x69, 0x6f, 0x6e}, /*"tion"*/
|
|
4}, /* block #2 */
|
|
},
|
|
{0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0,
|
|
0x6e, 0x0c, 0x79, 0x6c, 0x29, 0x55, 0x55, 0x2b}, /* result */
|
|
16, /*trancate_len = 16*/
|
|
},
|
|
|
|
/* RFC 4231 Test Case 6 */
|
|
{
|
|
{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa}, /*key */
|
|
131, /* keylen */
|
|
4, /* numblocks */
|
|
{
|
|
{{0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69,
|
|
0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65}, /*"Test Using Large"*/
|
|
16}, /* block #1 */
|
|
{{0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42,
|
|
0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a}, /*"r Than Block-Siz"*/
|
|
16}, /* block #2 */
|
|
{{0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20,
|
|
0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79}, /*"e Key - Hash Key"*/
|
|
16}, /* block #3 */
|
|
{{0x20, 0x46, 0x69, 0x72, 0x73, 0x74}, /*" First" */
|
|
6}, /* block #4 */
|
|
},
|
|
{0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f,
|
|
0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f,
|
|
0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14,
|
|
0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54}, /* result */
|
|
0, /*trancate_len = none*/
|
|
},
|
|
|
|
/* RFC 4231 Test Case 7 */
|
|
{
|
|
{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
|
|
0xaa, 0xaa, 0xaa}, /*key */
|
|
131, /* keylen */
|
|
10, /* numblocks */
|
|
{
|
|
{{0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
|
|
0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75}, /*"This is a test u"*/
|
|
16}, /* block #1 */
|
|
{{0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c,
|
|
0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68}, /*"sing a larger th"*/
|
|
16}, /* block #2 */
|
|
{{0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
|
|
0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65}, /*"an block-size ke"*/
|
|
16}, /* block #3 */
|
|
{{0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20,
|
|
0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74}, /*"y and a larger t"*/
|
|
16}, /* block #4 */
|
|
{{0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63,
|
|
0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64}, /*"han block-size d"*/
|
|
16}, /* block #5 */
|
|
{{0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65,
|
|
0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65}, /*"ata. The key nee"*/
|
|
16}, /* block #6 */
|
|
{{0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65,
|
|
0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20}, /*"ds to be hashed "*/
|
|
16}, /* block #7 */
|
|
{{0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62,
|
|
0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65}, /*"before being use"*/
|
|
16}, /* block #8 */
|
|
{{0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65,
|
|
0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c}, /*"d by the HMAC al"*/
|
|
16}, /* block #9 */
|
|
{{0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e}, /*"gorithm."*/
|
|
8}, /* block #10 */
|
|
},
|
|
{0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb,
|
|
0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44,
|
|
0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93,
|
|
0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2}, /* result */
|
|
0, /*trancate_len = none*/
|
|
},
|
|
|
|
};
|
|
|
|
IP_STATIC Ipwps_proto_kdf_test_vector ipwps_proto_kdf_test_vector[] = {
|
|
{
|
|
{
|
|
0x7c, 0x44, 0xd6, 0xca, 0x35, 0x55, 0x51, 0x5d,
|
|
0x38, 0xeb, 0xea, 0xe5, 0x92, 0x40, 0x4e, 0x4c,
|
|
0xf4, 0x13, 0x8e, 0x74, 0x5a, 0x90, 0x4b, 0xce,
|
|
0x77, 0x6f, 0x46, 0xb5, 0x0b, 0xb9, 0x40, 0x42
|
|
},
|
|
IPWPS_PROTO_KEYLEN_KDK,
|
|
IPWPS_PROTO_KDK_KDF_PERSONALIZATION_STR,
|
|
IPWPS_PROTO_KEYLEN_SESSIONKEYS_TOTAL*8,
|
|
{
|
|
0xBB, 0xDB, 0x05, 0x4F, 0x92, 0x29, 0x66, 0x55,
|
|
0xC6, 0x31, 0xA3, 0xA9, 0x4A, 0x7C, 0xE1, 0xA0,
|
|
0xE5, 0x3B, 0xD0, 0xF6, 0xF7, 0x0C, 0x6E, 0x5F,
|
|
0x6E, 0xBD, 0xA3, 0xD9, 0x56, 0x2E, 0x48, 0x5F,
|
|
0xD0, 0x03, 0xFC, 0x98, 0xD8, 0x97, 0x23, 0x1C,
|
|
0x73, 0x89, 0x65, 0x0A, 0x81, 0x44, 0x8E, 0xCC,
|
|
0x1E, 0x6A, 0xD3, 0x2E, 0xC5, 0x67, 0x24, 0x6B,
|
|
0x5A, 0xE3, 0xF5, 0x6B, 0x90, 0x16, 0x4B, 0x52,
|
|
0x6F, 0x03, 0xBE, 0x17, 0x22, 0xCE, 0x81, 0xE7,
|
|
0xD3, 0x35, 0x9D, 0xD5, 0x8A, 0x89, 0x92, 0xEE
|
|
}
|
|
},
|
|
{
|
|
{
|
|
0xdf, 0x28, 0xb5, 0x4a, 0x06, 0x87, 0x38, 0x13,
|
|
0x64, 0xfa, 0xbb, 0x2a, 0x4f, 0x80, 0x13, 0x0e,
|
|
0x71, 0xe6, 0xb5, 0xd2, 0xa9, 0x42, 0x30, 0x7b,
|
|
0xf8, 0x93, 0x52, 0x25, 0x77, 0x67, 0x0e, 0xfa
|
|
},
|
|
IPWPS_PROTO_KEYLEN_KDK,
|
|
IPWPS_PROTO_KDK_KDF_PERSONALIZATION_STR,
|
|
IPWPS_PROTO_KEYLEN_SESSIONKEYS_TOTAL*8,
|
|
{
|
|
0xC6, 0x2A, 0x04, 0xCA, 0xF2, 0xD4, 0x71, 0x0F,
|
|
0x9E, 0x31, 0x35, 0xB6, 0x82, 0x67, 0xC0, 0x15,
|
|
0xF7, 0x2D, 0x82, 0xBE, 0x1D, 0x76, 0x45, 0xEB,
|
|
0x15, 0x91, 0x03, 0xE5, 0x9A, 0xA0, 0x2B, 0xC2,
|
|
0x36, 0xA9, 0xF0, 0xE3, 0x4D, 0x2C, 0xEB, 0xC0,
|
|
0xCA, 0x5A, 0x98, 0x0A, 0x65, 0x3C, 0xB8, 0xAE,
|
|
0x50, 0x7D, 0x2E, 0x2C, 0xC1, 0x68, 0x91, 0x05,
|
|
0x21, 0x5B, 0xD4, 0x3B, 0xD8, 0xD3, 0xF6, 0xEE,
|
|
0x1E, 0x96, 0xA0, 0x67, 0xF9, 0x55, 0x36, 0x3F,
|
|
0xB7, 0x8B, 0x46, 0x4F, 0xEA, 0x77, 0x6D, 0x20
|
|
}
|
|
},
|
|
{
|
|
{
|
|
0x1f, 0x2b, 0xfd, 0x06, 0x3d, 0x6c, 0xd2, 0x47,
|
|
0xaf, 0xe5, 0x49, 0xfd, 0xc0, 0x4e, 0xc9, 0x53,
|
|
0x14, 0xa3, 0xff, 0x3c, 0xcb, 0x2e, 0x27, 0xfa,
|
|
0x93, 0x82, 0x96, 0xb4, 0x22, 0x70, 0xc0, 0x79
|
|
},
|
|
IPWPS_PROTO_KEYLEN_KDK,
|
|
IPWPS_PROTO_KDK_KDF_PERSONALIZATION_STR,
|
|
IPWPS_PROTO_KEYLEN_SESSIONKEYS_TOTAL*8,
|
|
{
|
|
0xAA, 0x38, 0x4F, 0xC8, 0xDD, 0x9F, 0x8B, 0xD5,
|
|
0xD5, 0xC4, 0x7C, 0xA8, 0x5C, 0x43, 0x00, 0x2E,
|
|
0x7C, 0x1D, 0x91, 0xC5, 0x13, 0x74, 0x6A, 0xD3,
|
|
0xBC, 0x2E, 0xBF, 0xB9, 0xAF, 0x6B, 0x29, 0xC4,
|
|
0x8C, 0xE5, 0x10, 0x21, 0xBC, 0x88, 0x20, 0x14,
|
|
0xF1, 0x0A, 0x0A, 0xEB, 0xD6, 0x34, 0x80, 0x07,
|
|
0x7E, 0x02, 0x42, 0x4B, 0xD2, 0xEB, 0x54, 0x05,
|
|
0x40, 0x3C, 0xB1, 0x16, 0xA8, 0x4E, 0x2B, 0xFE,
|
|
0x1F, 0xD3, 0x13, 0x4C, 0x0C, 0x76, 0x13, 0x8C,
|
|
0x2E, 0xCF, 0x21, 0x92, 0x8C, 0xD4, 0x45, 0x61
|
|
}
|
|
},
|
|
{
|
|
{
|
|
0x34, 0x48, 0xfb, 0x02, 0xe6, 0x0d, 0xb0, 0x7c,
|
|
0x21, 0x80, 0xcc, 0x69, 0x1f, 0x6b, 0x42, 0x49,
|
|
0x72, 0x98, 0x79, 0x4f, 0x63, 0xc7, 0xbc, 0xd7,
|
|
0x1a, 0xe6, 0x70, 0x16, 0x86, 0x2e, 0x4e, 0xc9
|
|
},
|
|
32,
|
|
"This is a Personalization String",
|
|
384,
|
|
{
|
|
0x64, 0xDC, 0x0A, 0xA7, 0x00, 0xBC, 0x59, 0x75,
|
|
0xC7, 0xF0, 0x0B, 0xC8, 0xCE, 0xC8, 0xC5, 0xB2,
|
|
0xCC, 0xB9, 0x07, 0x2B, 0xB9, 0x50, 0xCE, 0x8B,
|
|
0x7D, 0x46, 0xF5, 0x36, 0x0C, 0x84, 0xB8, 0x2D,
|
|
0x53, 0x3A, 0xCC, 0xE4, 0x20, 0x95, 0x18, 0x72,
|
|
0x1E, 0xDC, 0xDE, 0x90, 0x28, 0xD8, 0xED, 0xD3
|
|
}
|
|
}
|
|
};
|
|
|
|
IP_STATIC Ipwps_proto_kwf_test_vector ipwps_proto_kwf_test_vector[] = {
|
|
{
|
|
{
|
|
0x34, 0x48, 0xFB, 0x02, 0xE6, 0x0D, 0xB0, 0x7C,
|
|
0x21, 0x80, 0xCC, 0x69, 0x1F, 0x6B, 0x42, 0x49
|
|
},
|
|
{
|
|
0x8D, 0x6D, 0xC3, 0xAB, 0xF0, 0xA1, 0xD3, 0x47,
|
|
0x5B, 0x3E, 0xAB, 0x78, 0x65, 0xDB, 0x1C, 0xE3
|
|
},
|
|
"This is data that matches a 16 octet block size", /* 48 bytes */
|
|
{
|
|
0x27, 0xDF, 0x74, 0xC2, 0x13, 0x1A, 0xB2, 0x8E,
|
|
0x9A, 0x92, 0xB9, 0xFC, 0xDD, 0x12, 0x0F, 0xFB,
|
|
0xEE, 0x4B, 0x99, 0x0E, 0x9A, 0x35, 0xC3, 0xAE,
|
|
0xEF, 0xF2, 0xB8, 0xA3, 0xE7, 0xC2, 0x1B, 0x08,
|
|
0x87, 0x23, 0xB1, 0xA9, 0xE3, 0x10, 0x41, 0x71,
|
|
0xC6, 0x9F, 0x07, 0xCF, 0x62, 0x3A, 0xA0, 0x64,
|
|
0xF5, 0x86, 0x1E, 0xB6, 0x6C, 0x4A, 0xBC, 0xC0,
|
|
0x9F, 0xD0, 0xBD, 0x99, 0x32, 0x70, 0xAE, 0x71
|
|
},
|
|
64
|
|
},
|
|
{
|
|
{
|
|
0x34, 0x48, 0xFB, 0x02, 0xE6, 0x0D, 0xB0, 0x7C,
|
|
0x21, 0x80, 0xCC, 0x69, 0x1F, 0x6B, 0x42, 0x49
|
|
},
|
|
{
|
|
0x0A, 0x9F, 0xAB, 0x6F, 0xEE, 0xD2, 0x57, 0x6B,
|
|
0x54, 0xF8, 0xB7, 0x63, 0x67, 0x80, 0x72, 0x09
|
|
},
|
|
"This is data that is even less than a block", /* 44 bytes */
|
|
{
|
|
0xF9, 0xEC, 0xDA, 0x79, 0x9C, 0x37, 0xCF, 0x6A,
|
|
0xA0, 0x68, 0xF0, 0xBF, 0x46, 0x5B, 0x17, 0xB3,
|
|
0x2F, 0x9A, 0xA7, 0x9F, 0xD8, 0xDE, 0x39, 0x51,
|
|
0x4E, 0x4D, 0xCB, 0x81, 0xD2, 0xC5, 0x81, 0xA8,
|
|
0x24, 0x63, 0x7E, 0x3E, 0x37, 0xB7, 0x05, 0x96,
|
|
0x88, 0x25, 0xFE, 0x53, 0xFA, 0x5C, 0x04, 0x86
|
|
},
|
|
48
|
|
},
|
|
{
|
|
{
|
|
0x34, 0x48, 0xFB, 0x02, 0xE6, 0x0D, 0xB0, 0x7C,
|
|
0x21, 0x80, 0xCC, 0x69, 0x1F, 0x6B, 0x42, 0x49
|
|
},
|
|
{
|
|
0xAA, 0xFA, 0x5D, 0xFA, 0x66, 0x07, 0xD9, 0x9D,
|
|
0x88, 0x5B, 0xD3, 0x03, 0x03, 0xE8, 0x3D, 0x12
|
|
},
|
|
"This is data that is an odd size more than block", /* 49 bytes */
|
|
{
|
|
0x9B, 0x3C, 0x5A, 0x8A, 0xE5, 0x31, 0xCF, 0xA5,
|
|
0x3D, 0xD5, 0x51, 0x90, 0x71, 0x69, 0xC9, 0x3D,
|
|
0x47, 0x11, 0xB3, 0x81, 0xE2, 0xFC, 0xCD, 0x33,
|
|
0x50, 0x76, 0x2F, 0x24, 0x20, 0x15, 0x2F, 0xD8,
|
|
0xB1, 0xF0, 0x49, 0xED, 0xB2, 0xAA, 0xDD, 0x33,
|
|
0x50, 0x18, 0x20, 0xD0, 0xF9, 0x8F, 0x17, 0xEC,
|
|
0xBC, 0xC8, 0x6B, 0x60, 0x55, 0x03, 0xA8, 0x65,
|
|
0x29, 0xFC, 0x70, 0xBC, 0x63, 0x08, 0x23, 0x7D
|
|
},
|
|
64
|
|
},
|
|
{
|
|
{
|
|
0x34, 0x48, 0xFB, 0x02, 0xE6, 0x0D, 0xB0, 0x7C,
|
|
0x21, 0x80, 0xCC, 0x69, 0x1F, 0x6B, 0x42, 0x49
|
|
},
|
|
{
|
|
0xF4, 0x51, 0x41, 0xE9, 0x6C, 0xB6, 0xA8, 0x96,
|
|
0x37, 0x9E, 0x12, 0x28, 0xD7, 0xF7, 0xEE, 0x7B
|
|
},
|
|
"This is data that is odd size less than block", /* 47 bytes */
|
|
{
|
|
0x44, 0x47, 0x68, 0x73, 0xDA, 0x6C, 0x7E, 0xDE,
|
|
0x8A, 0xCB, 0x11, 0x9B, 0x4B, 0x68, 0x9F, 0xE1,
|
|
0x6F, 0xB8, 0x0B, 0xBB, 0xDC, 0x74, 0xAA, 0x74,
|
|
0x6F, 0x55, 0xAF, 0x45, 0x13, 0xFE, 0x00, 0xB2,
|
|
0x9F, 0xBD, 0x4C, 0x79, 0xB7, 0xE4, 0x8F, 0xAD,
|
|
0x76, 0xA7, 0x93, 0xD7, 0x8D, 0xB6, 0x55, 0x7B
|
|
},
|
|
48
|
|
}
|
|
};
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_cryptotest_runall
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_cryptotest_runall(void) {
|
|
Ip_err rc = IPCOM_SUCCESS;
|
|
Ipwps_proto_crypto_test *test = ipwps_proto_crypto_tests;
|
|
|
|
while (test->testfn) {
|
|
IPCOM_LOG1(INFO, "***** WPS CRYPTO TEST - %s (STARTED) *****", test->testname);
|
|
if (test->testfn() != IPCOM_SUCCESS) {
|
|
IPCOM_LOG1(ERR, "***** WPS CRYPTO TEST - %s (FAILED) *****", test->testname);
|
|
rc = IPCOM_ERR_FAILED;
|
|
} else {
|
|
IPCOM_LOG1(INFO, "***** WPS CRYPTO TEST - %s (SUCCESSFUL) *****", test->testname);
|
|
}
|
|
test++;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_cryptotest_sessionkeys
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err ipwps_proto_cryptotest_sessionkeys(void) {
|
|
Ip_err rc = IPCOM_SUCCESS;
|
|
Ip_u8 test_enrollee_mac[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
|
|
Ipwps_proto_ctx *proto_ctx1, *proto_ctx2;
|
|
Ipwps_proto_nonce nonce1, nonce2;
|
|
|
|
IPWPS_PROTO_NONCE_INIT(nonce1);
|
|
IPWPS_PROTO_NONCE_INIT(nonce2);
|
|
|
|
proto_ctx1 = ipcom_calloc(1, sizeof(Ipwps_proto_ctx));
|
|
proto_ctx2 = ipcom_calloc(1, sizeof(Ipwps_proto_ctx));
|
|
if (!proto_ctx1 || !proto_ctx2) {
|
|
IPCOM_LOG0(CRIT, "ipwps_proto_cryptotest_sessionkeys :: out of memory");
|
|
rc = IPCOM_ERR_NO_MEMORY;
|
|
goto done_test1;
|
|
}
|
|
|
|
rc = ipwps_proto_generate_local_keys(proto_ctx1);
|
|
if (rc != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: ipwps_proto_generate_local_keys(proto_ctx1) failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_test1;
|
|
}
|
|
rc = ipwps_proto_generate_local_keys(proto_ctx2);
|
|
if (rc != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: ipwps_proto_generate_local_keys(proto_ctx2) failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_test1;
|
|
}
|
|
ipwps_proto_copy_data(&proto_ctx1->peer_pub_key, &proto_ctx2->local_pub_key, 0, proto_ctx2->local_pub_key.len);
|
|
ipwps_proto_copy_data(&proto_ctx2->peer_pub_key, &proto_ctx1->local_pub_key, 0, proto_ctx1->local_pub_key.len);
|
|
|
|
ipcom_memcpy(proto_ctx1->enrollee_mac, test_enrollee_mac, 6);
|
|
ipcom_memcpy(proto_ctx2->enrollee_mac, test_enrollee_mac, 6);
|
|
IPCOM_LOG6(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: enrollee_mac: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
|
|
test_enrollee_mac[0], test_enrollee_mac[1], test_enrollee_mac[2],
|
|
test_enrollee_mac[3], test_enrollee_mac[4], test_enrollee_mac[5]);
|
|
|
|
/* Alloc and Init nonces 1 and 2 */
|
|
if(ipwps_proto_alloc_data(&nonce1, IPWPS_PROTO_NONCE_SIZE) != IPCOM_SUCCESS)
|
|
{
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_test1;
|
|
}
|
|
|
|
if (ipwps_proto_crypto_randdata(&nonce1) != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: ipwps_proto_crypto_randdata(&nonce1) failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_test1;
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_sessionkeys :: nonce1:", nonce1);
|
|
|
|
if(ipwps_proto_alloc_data(&nonce2, IPWPS_PROTO_NONCE_SIZE) != IPCOM_SUCCESS)
|
|
{
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_test1;
|
|
}
|
|
if (ipwps_proto_crypto_randdata(&nonce2) != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: ipwps_proto_crypto_randdata(&nonce2) failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_test1;
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_sessionkeys :: nonce2:", nonce2);
|
|
|
|
ipwps_proto_copy_data(&proto_ctx1->nonce1, &nonce1, 0, nonce1.len);
|
|
ipwps_proto_copy_data(&proto_ctx1->nonce2, &nonce2, 0, nonce2.len);
|
|
ipwps_proto_copy_data(&proto_ctx2->nonce1, &nonce1, 0, nonce1.len);
|
|
ipwps_proto_copy_data(&proto_ctx2->nonce2, &nonce2, 0, nonce2.len);
|
|
|
|
rc = ipwps_proto_derive_session_keys(proto_ctx1);
|
|
if (rc != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: ipwps_proto_derive_session_keys(proto_ctx1) failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_test1;
|
|
}
|
|
rc = ipwps_proto_derive_session_keys(proto_ctx2);
|
|
if (rc != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: ipwps_proto_derive_session_keys(proto_ctx2) failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_test1;
|
|
}
|
|
|
|
if (!ipwps_proto_compare_data(&proto_ctx1->auth_key, &proto_ctx2->auth_key)) {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: auth_key mismatch");
|
|
rc = IPCOM_ERR_FAILED;
|
|
}
|
|
if (!ipwps_proto_compare_data(&proto_ctx1->key_wrap_key, &proto_ctx2->key_wrap_key)) {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: key_wrap_key mismatch");
|
|
rc = IPCOM_ERR_FAILED;
|
|
}
|
|
if (!ipwps_proto_compare_data(&proto_ctx1->emsk, &proto_ctx2->emsk)) {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: emsk mismatch");
|
|
rc = IPCOM_ERR_FAILED;
|
|
}
|
|
if (rc == IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_sessionkeys :: session keys MATCH (OK)");
|
|
}
|
|
|
|
done_test1:
|
|
if (proto_ctx1) {
|
|
ipwps_proto_crypto_delete_all(proto_ctx1);
|
|
ipcom_free(proto_ctx1);
|
|
}
|
|
if (proto_ctx2) {
|
|
ipwps_proto_crypto_delete_all(proto_ctx2);
|
|
ipcom_free(proto_ctx2);
|
|
}
|
|
ipwps_proto_container_delete(&nonce1);
|
|
ipwps_proto_container_delete(&nonce2);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_cryptotest_dhsharedsecrets
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err ipwps_proto_cryptotest_dhsharedsecrets(void) {
|
|
Ip_err rc = IPCOM_SUCCESS;
|
|
Ipwps_proto_ctx *proto_ctx1, *proto_ctx2;
|
|
Ipwps_proto_key shared_secret1, shared_secret2;
|
|
|
|
IPWPS_PROTO_KEY_INIT(shared_secret1);
|
|
IPWPS_PROTO_KEY_INIT(shared_secret2);
|
|
|
|
proto_ctx1 = ipcom_calloc(1, sizeof(Ipwps_proto_ctx));
|
|
proto_ctx2 = ipcom_calloc(1, sizeof(Ipwps_proto_ctx));
|
|
if (!proto_ctx1 || !proto_ctx2) {
|
|
IPCOM_LOG0(CRIT, "ipwps_proto_cryptotest_dhsharedsecrets :: out of memory");
|
|
rc = IPCOM_ERR_NO_MEMORY;
|
|
goto done_test2;
|
|
}
|
|
|
|
rc = ipwps_proto_generate_local_keys(proto_ctx1);
|
|
if (rc != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_dhsharedsecrets :: ipwps_proto_generate_local_keys(proto_ctx1) failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_test2;
|
|
}
|
|
rc = ipwps_proto_generate_local_keys(proto_ctx2);
|
|
if (rc != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_dhsharedsecrets :: ipwps_proto_generate_local_keys(proto_ctx2) failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_test2;
|
|
}
|
|
|
|
ipwps_proto_copy_data(&proto_ctx1->peer_pub_key, &proto_ctx2->local_pub_key, 0, proto_ctx2->local_pub_key.len);
|
|
ipwps_proto_copy_data(&proto_ctx2->peer_pub_key, &proto_ctx1->local_pub_key, 0, proto_ctx1->local_pub_key.len);
|
|
|
|
rc = ipwps_proto_derive_dh_sharedsecret(proto_ctx1->dh, &proto_ctx1->peer_pub_key, &shared_secret1);
|
|
if (rc != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_dhsharedsecrets :: ipwps_proto_derive_dh_sharedsecret(proto_ctx1) failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_test2;
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_dhsharedsecrets :: shared_secret1:", shared_secret1);
|
|
rc = ipwps_proto_derive_dh_sharedsecret(proto_ctx2->dh, &proto_ctx2->peer_pub_key, &shared_secret2);
|
|
if (rc != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_dhsharedsecrets :: ipwps_proto_derive_dh_sharedsecret(proto_ctx2) failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto done_test2;
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_dhsharedsecrets :: shared_secret2:", shared_secret2);
|
|
|
|
if (!ipwps_proto_compare_data(&shared_secret1, &shared_secret2)) {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_dhsharedsecrets :: shared_secret2 mismatch (FAIL)");
|
|
rc = IPCOM_ERR_FAILED;
|
|
} else {
|
|
IPCOM_LOG0(DEBUG2, "ipwps_proto_cryptotest_dhsharedsecrets :: shared secrets MATCH (OK)");
|
|
}
|
|
|
|
done_test2:
|
|
if (proto_ctx1) {
|
|
ipwps_proto_crypto_delete_all(proto_ctx1);
|
|
ipcom_free(proto_ctx1);
|
|
}
|
|
if (proto_ctx2) {
|
|
ipwps_proto_crypto_delete_all(proto_ctx2);
|
|
ipcom_free(proto_ctx2);
|
|
}
|
|
ipwps_proto_container_delete(&shared_secret1);
|
|
ipwps_proto_container_delete(&shared_secret2);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_cryptotest_dhkey
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_cryptotest_dhkey(void) {
|
|
Ip_err rc = IPCOM_SUCCESS;
|
|
Ipwps_proto_dhkey_test_vector *vector;
|
|
int i, numvectors = sizeof(ipwps_proto_dhkey_test_vectors)/sizeof(ipwps_proto_dhkey_test_vectors[0]);
|
|
Ipwps_proto_ctx *proto_ctx;
|
|
Ipwps_proto_key shared_secret, dh_key, result;
|
|
|
|
IPWPS_PROTO_KEY_INIT(shared_secret);
|
|
IPWPS_PROTO_KEY_INIT(dh_key);
|
|
IPWPS_PROTO_KEY_INIT(result);
|
|
|
|
proto_ctx = ipcom_calloc(1, sizeof(Ipwps_proto_ctx));
|
|
if (!proto_ctx) {
|
|
IPCOM_LOG0(CRIT, "ipwps_proto_cryptotest_dhkeys :: out of memory");
|
|
rc = IPCOM_ERR_NO_MEMORY;
|
|
goto done_test3;
|
|
}
|
|
|
|
for (i = 0; i < numvectors; i++) {
|
|
IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_dhkey :: testing vector %i", i);
|
|
vector = &ipwps_proto_dhkey_test_vectors[i];
|
|
shared_secret.data = (Ip_u8 *)vector->input;
|
|
shared_secret.len = strlen(vector->input);
|
|
result.data = vector->result;
|
|
result.len = IPWPS_PROTO_KEYLEN_DHKEY;
|
|
if (ipwps_proto_derive_dhkey(proto_ctx, &shared_secret, &dh_key) != IPCOM_SUCCESS) {
|
|
IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_dhkey :: ipwps_proto_derive_dhkey() failed, vector %d test (FAILED)", i);
|
|
rc = IPCOM_ERR_FAILED;
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPASCII("ipwps_proto_cryptotest_dhkey :: input:", shared_secret.data, shared_secret.len);
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_dhkey :: dh_key:", dh_key);
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_dhkey :: result:", result);
|
|
if ((rc == IPCOM_SUCCESS) && !ipwps_proto_compare_data(&dh_key, &result)) {
|
|
IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_dhkey :: dh_key mismatch, vector %d test (FAILED)", i);
|
|
rc = IPCOM_ERR_FAILED;
|
|
} else {
|
|
IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_dhkey :: vector %d test (PASSED)", i);
|
|
}
|
|
ipwps_proto_container_delete(&dh_key);
|
|
}
|
|
|
|
done_test3:
|
|
if (proto_ctx) {
|
|
ipwps_proto_crypto_delete_all(proto_ctx);
|
|
ipcom_free(proto_ctx);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_cryptotest_dhkey
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_cryptotest_hmacsha256(void) {
|
|
Ipwps_proto_hmacsha256_test_vector *vector;
|
|
int numvectors = sizeof(ipwps_proto_hmacsha256_test_vectors) / sizeof(ipwps_proto_hmacsha256_test_vectors[0]);
|
|
Ip_err rc = IPCOM_SUCCESS, fullrc = IPCOM_SUCCESS;
|
|
Ipwps_proto_key key;
|
|
Ipwps_proto_hash digest, result;
|
|
HMAC_CTX hmac_ctx;
|
|
int i,j;
|
|
|
|
IPWPS_PROTO_KEY_INIT(key);
|
|
IPWPS_PROTO_HASH_INIT(digest);
|
|
IPWPS_PROTO_HASH_INIT(result);
|
|
|
|
for (i = 0; i < numvectors; i++) {
|
|
rc = IPCOM_SUCCESS;
|
|
IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_hmacsha256 :: testing vector %i", i);
|
|
vector = &ipwps_proto_hmacsha256_test_vectors[i];
|
|
key.data = vector->key;
|
|
key.len = vector->keylen;
|
|
result.data = vector->result;
|
|
result.len = (vector->trancate_len ? vector->trancate_len : SHA256_DIGEST_LENGTH);
|
|
if (ipwps_proto_alloc_data(&digest, SHA256_DIGEST_LENGTH) != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_cryptotest_hmacsha256 :: out of memeory. TERMINATING test.");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
HMAC_CTX_init(&hmac_ctx);
|
|
HMAC_Init(&hmac_ctx, key.data, key.len, EVP_sha256());
|
|
for (j = 0; j < vector->numblocks; j++) {
|
|
HMAC_Update(&hmac_ctx, vector->block[j].data, vector->block[j].len);
|
|
}
|
|
HMAC_Final(&hmac_ctx, digest.data, (unsigned int *)&digest.len);
|
|
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_hmacsha256 :: digest:", digest);
|
|
if (vector->trancate_len) {
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_hmacsha256 :: result (truncated):", result);
|
|
if (vector->trancate_len > digest.len) {
|
|
IPCOM_LOG3(DEBUG2, "ipwps_proto_cryptotest_hmacsha256 :: digest len invalid for vector %d (%d > %d)",
|
|
i, vector->trancate_len, digest.len);
|
|
rc = IPCOM_ERR_FAILED;
|
|
} else {
|
|
digest.len = vector->trancate_len;
|
|
}
|
|
} else {
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_hmacsha256 :: result:", result);
|
|
}
|
|
if ((rc == IPCOM_SUCCESS) && !ipwps_proto_compare_data(&digest, &result)) {
|
|
IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_hmacsha256 :: digest mismatch for vector %d", i);
|
|
rc = IPCOM_ERR_FAILED;
|
|
}
|
|
if (rc == IPCOM_SUCCESS) {
|
|
IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_hmacsha256 :: vector %d test (PASSED)", i);
|
|
} else {
|
|
IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_hmacsha256 :: vector %d test (FAILED)", i);
|
|
fullrc = IPCOM_ERR_FAILED;
|
|
}
|
|
ipwps_proto_container_delete(&digest);
|
|
}
|
|
return fullrc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_cryptotest_kdk_kdf
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_cryptotest_kdf(void) {
|
|
Ip_err rc = IPCOM_SUCCESS;
|
|
Ipwps_proto_kdf_test_vector *vector;
|
|
int i, numvectors = sizeof(ipwps_proto_kdf_test_vector)/sizeof(ipwps_proto_kdf_test_vector[0]);
|
|
Ipwps_proto_key key, derived_key, result;
|
|
char *pstring;
|
|
|
|
IPWPS_PROTO_KEY_INIT(key);
|
|
IPWPS_PROTO_KEY_INIT(derived_key);
|
|
IPWPS_PROTO_KEY_INIT(result);
|
|
|
|
for (i = 0; i < numvectors; i++) {
|
|
rc = IPCOM_SUCCESS;
|
|
IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_kdf :: testing vector %i", i);
|
|
vector = &ipwps_proto_kdf_test_vector[i];
|
|
key.data = vector->key;
|
|
key.len = vector->keylen;
|
|
result.len = (vector->keybits)/8;
|
|
result.data = vector->result;
|
|
pstring = vector->personalization_string;
|
|
if (ipwps_proto_alloc_data(&derived_key, result.len) != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_cryptotest_kdf :: out of memeory. TERMINATING test.");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (ipwps_proto_perform_kdf(&key, IP_NULL, pstring, &derived_key) != IPCOM_SUCCESS) {
|
|
IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_kdf :: ipwps_proto_perform_kdf() failed, vector %d test (FAILED)", i);
|
|
rc = IPCOM_ERR_FAILED;
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kdf :: key:", key);
|
|
IPCOM_LOG2(DEBUG2, "ipwps_proto_cryptotest_kdf :: keybits=%d, Personalization String: \"%s\"", vector->keybits, pstring);
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX(" :: derived_key:", derived_key);
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX(" :: result:", result);
|
|
if ((rc == IPCOM_SUCCESS) && !ipwps_proto_compare_data(&derived_key, &result)) {
|
|
IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_kdf :: derived_key mismatch, vector %d test (FAILED)", i);
|
|
rc = IPCOM_ERR_FAILED;
|
|
} else {
|
|
IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_dhkey :: vector %d test (PASSED)", i);
|
|
}
|
|
ipwps_proto_container_delete(&derived_key);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipwps_proto_cryptotest_kwf
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipwps_proto_cryptotest_kwf(void) {
|
|
Ip_err rc = IPCOM_SUCCESS, fullrc = IPCOM_SUCCESS;
|
|
Ipwps_proto_kwf_test_vector *vector;
|
|
int i, numvectors = sizeof(ipwps_proto_kwf_test_vector)/sizeof(ipwps_proto_kwf_test_vector[0]);
|
|
Ipwps_proto_nonce iv;
|
|
Ipwps_proto_ctx *proto_ctx;
|
|
Ipwps_proto_container dte, dtd, encr_result, expected_result, decr_result;
|
|
|
|
IPWPS_PROTO_NONCE_INIT(iv);
|
|
IPWPS_PROTO_CONTAINER_INIT(dte);
|
|
IPWPS_PROTO_CONTAINER_INIT(dtd);
|
|
IPWPS_PROTO_CONTAINER_INIT(encr_result);
|
|
IPWPS_PROTO_CONTAINER_INIT(expected_result);
|
|
IPWPS_PROTO_CONTAINER_INIT(decr_result);
|
|
|
|
proto_ctx = ipcom_calloc(1, sizeof(Ipwps_proto_ctx));
|
|
if (!proto_ctx) {
|
|
IPCOM_LOG0(CRIT, "ipwps_proto_cryptotest_kwf :: out of memory");
|
|
rc = fullrc = IPCOM_ERR_NO_MEMORY;
|
|
goto done_test4;
|
|
}
|
|
|
|
for (i = 0; i < numvectors; i++) {
|
|
rc = IPCOM_SUCCESS;
|
|
IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_kwf :: testing vector %i", i);
|
|
vector = &ipwps_proto_kwf_test_vector[i];
|
|
proto_ctx->key_wrap_key.len = IPWPS_PROTO_KEYLEN_KEYWRAPKEY;
|
|
proto_ctx->key_wrap_key.data = vector->keywrapkey;
|
|
iv.len = IPWPS_PROTO_NONCE_SIZE;
|
|
iv.data = vector->iv;
|
|
dte.len = strlen(vector->cleartext)+1;
|
|
dte.data = (Ip_u8 *)vector->cleartext;
|
|
expected_result.len = vector->ciphertext_len;
|
|
expected_result.data = vector->ciphertext;
|
|
if (ipwps_proto_alloc_data(&dtd, 256) != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_cryptotest_kwf :: out of memeory. TERMINATING test.");
|
|
rc = fullrc = IPCOM_ERR_FAILED;
|
|
goto done_test4;
|
|
}
|
|
rc = ipwps_proto_kwf_encrypt_data_with_iv(proto_ctx, &dte, &dtd, &iv);
|
|
if ( rc != IPCOM_SUCCESS) {
|
|
IPCOM_LOG1(ERR, "ipwps_proto_cryptotest_kwf :: Failed to encrypt vector %i", i);
|
|
fullrc = IPCOM_ERR_FAILED;
|
|
continue;
|
|
}
|
|
encr_result.len = dtd.len - IPWPS_PROTO_NONCE_SIZE;
|
|
encr_result.data = dtd.data + IPWPS_PROTO_NONCE_SIZE;
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kwf :: key_wrap_key:", proto_ctx->key_wrap_key);
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kwf :: iv:", iv);
|
|
IPWPS_PROTO_CRYPTO_DUMPASCII("ipwps_proto_cryptotest_kwf :: dte:", dte.data, dte.len);
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kwf :: dte:", dte);
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kwf :: dtd:", dtd);
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kwf :: encr_result:", encr_result);
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kwf :: expected_result:", expected_result);
|
|
|
|
/* Verify encryption result */
|
|
if (!ipwps_proto_compare_data(&expected_result, &encr_result)) {
|
|
IPCOM_LOG1(ERR, "ipwps_proto_cryptotest_kwf ::encryption result mismatch, vector %d test (FAILED)", i);
|
|
rc = fullrc = IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
/* Decrypt and verify decryption result */
|
|
if (ipwps_proto_alloc_data(&decr_result, 256) != IPCOM_SUCCESS) {
|
|
IPCOM_LOG0(ERR, "ipwps_proto_cryptotest_kwf :: out of memeory. TERMINATING test.");
|
|
rc = fullrc = IPCOM_ERR_FAILED;
|
|
goto done_test4;
|
|
}
|
|
if (ipwps_proto_kwf_decrypt_data(proto_ctx, &dtd, &decr_result) != IPCOM_SUCCESS) {
|
|
IPCOM_LOG1(ERR, "ipwps_proto_cryptotest_kwf :: Failed to decrypt vector %i", i);
|
|
rc = fullrc = IPCOM_ERR_FAILED;
|
|
continue;
|
|
}
|
|
IPWPS_PROTO_CRYPTO_DUMPHEX("ipwps_proto_cryptotest_kwf :: decr_result:", decr_result);
|
|
|
|
if (!ipwps_proto_compare_data(&dte, &decr_result)) {
|
|
IPCOM_LOG1(ERR, "ipwps_proto_cryptotest_kwf ::decryption result mismatch, vector %d test (FAILED)", i);
|
|
rc = fullrc = IPCOM_ERR_FAILED;
|
|
continue;
|
|
} else {
|
|
IPWPS_PROTO_CRYPTO_DUMPASCII("ipwps_proto_cryptotest_kwf :: decr_result:", decr_result.data, decr_result.len);
|
|
}
|
|
|
|
if (rc == IPCOM_SUCCESS) {
|
|
IPCOM_LOG1(DEBUG2, "ipwps_proto_cryptotest_dhkey :: vector %d test (PASSED)", i);
|
|
}
|
|
}
|
|
|
|
done_test4:
|
|
if (proto_ctx) {
|
|
ipwps_proto_container_delete(&dtd);
|
|
ipwps_proto_container_delete(&decr_result);
|
|
ipwps_proto_crypto_delete_all(proto_ctx);
|
|
ipcom_free(proto_ctx);
|
|
}
|
|
return fullrc;
|
|
}
|
|
#endif
|