Files
m241Neelima/components/ip_net2-6.9/ipmacsec/src/ipmacsec_crypto_if.c
T
2026-07-30 11:19:44 +05:30

1348 lines
45 KiB
C

/* ipmacsec_crypto_if.c - MACsec Crypto Interface implementation */
/*
* Copyright (c) 2010 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,19feb10,mry Created
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
* Implements the MACsec Cryptography Interface Module which abstracts the
* cryptographic operations of the selected cipher.
*/
/*
****************************************************************************
* 2 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_sock.h>
#include <ipcom_syslog.h>
#include <ipcom_sysvar.h>
#include <ipcom_errno.h>
#include <ipcom_err.h>
#include <ipcom_os.h>
#include "ipmacsec_debug.h"
#include "ipmacsec_crypto_if.h"
#include "ipmacsec_h.h"
#include "ipmacsec.h"
#include "ipmacsec_sysvar.h"
#include "openssl/aes.h"
#include "openssl/evp.h"
#include "openssl/aes_gcm.h"
/*
****************************************************************************
* 3 CONFIGURATION
****************************************************************************
*/
#include "ipmacsec_config.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
#define IPMACSEC_CRYPTO_IVBITS ((IPMACSEC_PN_LEN+IPMACSEC_SCI_LEN)*8) /* in bits */
#define IPMACSEC_CRYPTO_IVLEN (IPMACSEC_CRYPTO_IVBITS/8) /* in octets */
/* By default, use the Max acceleration level */
#define IPMACSEC_DEFAULT_GCMAES_ACCEL_LEVEL 4
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/* Cipher context */
typedef struct {
void *cs_ctx; /* cipher specific context */
IP_CONST Ip_u8 *key;
IP_CONST Ip_u8 *iv;
IP_CONST Ip_u8 *aad; /* Additional Authenticated data */
Ip_u8 *pt; /* plain text */
Ip_u8 *ct; /* cipher text */
Ip_u8 *tag; /* Authentication Tag (T), i.e. ICV */
Ip_u32 keylen; /* in octets */
Ip_u32 ivlen; /* in octets */
Ip_u32 aadlen; /* in octets */
Ip_u32 ptlen; /* in octets ; maybe updated by cipher suite when decrypting*/
Ip_u32 ctlen; /* in octets; maybe updated by cipher suite when encrypting*/
Ip_u32 taglen; /* in octets; maybe updated by cipher suite */
Ip_bool confidentiality; /* Request confidentiality (encryption/decryption) */
Ip_u32 confidentialityOffset; /* # of octets to skip during confidentiality operations if applicable */
Ip_bool valid; /* Updated by cipher validate function */
union {
struct {
GCM_ACCEL accel_level; /* Acceleration level */
} gcmaes;
} cipher_options; /* cipher specific options */
} Ipmacsec_cipher_ctx;
/* Cipher specific structure. See 802.1AE section 10.7.24 */
typedef struct Ipmacsec_crypto_cipher_struct {
Ipmacsec_ciphersuite_descriptor desc; /* Cipher suite descriptor */
int (* init)(IP_CONST struct Ipmacsec_crypto_cipher_struct *cipher, void **cs_ctx);
int (* destroy)(IP_CONST struct Ipmacsec_crypto_cipher_struct *cipher, void **cs_ctx);
int (* protect)(IP_CONST struct Ipmacsec_crypto_cipher_struct *cipher, Ipmacsec_cipher_ctx *ctx);
int (* validate)(IP_CONST struct Ipmacsec_crypto_cipher_struct *cipher, Ipmacsec_cipher_ctx *ctx);
} Ipmacsec_crypto_cipher;
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
IP_STATIC int ipmacsec_crypto_init(struct Ipmacsec_crypto_if_struct *crypto, Ip_u8 key_index, Ipmacsec_secy_sak *sak);
IP_STATIC int ipmacsec_crypto_destroy(struct Ipmacsec_crypto_if_struct *crypto, Ip_u8 key_index);
IP_STATIC int ipmacsec_crypto_protect(Ipmacsec_crypto_if *crypto, Ipmacsec_crypto_ctx *ctx);
IP_STATIC int ipmacsec_crypto_validate(Ipmacsec_crypto_if *crypto, Ipmacsec_crypto_ctx *ctx, Ip_bool *valid);
IP_STATIC Ip_bool ipmacsec_crypto_verify(Ipnet_secy *secy);
IP_STATIC Ipmacsec_crypto_cipher IP_CONST *ipmacsec_crypto_find_cipher(IP_CONST Ipmacsec_cipher_suite_index cipher_suite_index);
IP_STATIC Ip_bool ipmacsec_crypto_gcm_aes_config_verify(Ipmacsec_crypto_if IP_CONST *crypto);
/* Cipher specific functions */
IP_STATIC int ipmacsec_gcm_aes_128_init(IP_CONST Ipmacsec_crypto_cipher *cipher, void **cs_ctx);
IP_STATIC int ipmacsec_gcm_aes_128_destroy(IP_CONST Ipmacsec_crypto_cipher *cipher, void **cs_ctx);
IP_STATIC int ipmacsec_gcm_aes_128_protect(IP_CONST Ipmacsec_crypto_cipher *cipher, Ipmacsec_cipher_ctx *ctx);
IP_STATIC int ipmacsec_gcm_aes_128_validate(IP_CONST Ipmacsec_crypto_cipher *cipher, Ipmacsec_cipher_ctx *ctx);
#ifdef IPMACSEC_CRYPTO_ALLOW_NULL_CIPHER
/* Cipher specific functions */
IP_STATIC int ipmacsec_null_cipher_128_init(IP_CONST Ipmacsec_crypto_cipher *cipher, void **cs_ctx);
IP_STATIC int ipmacsec_null_cipher_128_destroy(IP_CONST Ipmacsec_crypto_cipher *cipher, void **cs_ctx);
IP_STATIC int ipmacsec_null_cipher_128_protect(IP_CONST Ipmacsec_crypto_cipher *cipher, Ipmacsec_cipher_ctx *ctx);
IP_STATIC int ipmacsec_null_cipher_128_validate(IP_CONST Ipmacsec_crypto_cipher *cipher, Ipmacsec_cipher_ctx *ctx);
#endif
/*
*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/* Supported IPMACSEC Cipher Suites */
IP_STATIC IP_CONST Ipmacsec_crypto_cipher ipmacsec_ciphers[] = {
{
{
"GCM-AES-128", IPMACSEC_CIPHER_SUITE_ID_GCM_AES_128,
IPMACSEC_CIPHERSUITE_GCM_AES_128,
IP_TRUE /*integrity*/ , IP_TRUE /*confidentiality*/, IP_TRUE /*offsetConfidentiality*/,
IP_FALSE /*changesDataLength*/, IP_TRUE /*mandatory*/,
128 /*key_bits*/, 128 /*icv_bits*/, 1 /*min_iv_bits*/, 0xFFFFFFFFFFFFFFFFLL/*max_iv_bits*/
},
ipmacsec_gcm_aes_128_init, ipmacsec_gcm_aes_128_destroy,
ipmacsec_gcm_aes_128_protect, ipmacsec_gcm_aes_128_validate
}
#ifdef IPMACSEC_CRYPTO_ALLOW_NULL_CIPHER
#warning IPMACSEC_CRYPTO_ALLOW_NULL_CIPHER is turned on. USE ONLY FOR DEVELOPMENT TESTING
,
{
{
"NULL-CIPHER-128", { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
IPMACSEC_CIPHERSUITE_NULL_CIPHER_128,
IP_TRUE /*integrity*/ , IP_TRUE /*confidentiality*/, IP_TRUE /*offsetConfidentiality*/,
IP_FALSE /*changesDataLength*/, IP_FALSE /*mandatory*/,
128 /*key_bits*/, 128 /*icv_bits*/, 1 /*min_iv_bits*/, 0xFFFFFFFFFFFFFFFFLL/*max_iv_bits*/
},
ipmacsec_null_cipher_128_init, ipmacsec_null_cipher_128_destroy,
ipmacsec_null_cipher_128_protect, ipmacsec_null_cipher_128_validate
}
#endif
};
IP_STATIC Ip_u32 ipmacsec_num_ciphers = sizeof(ipmacsec_ciphers)/sizeof(ipmacsec_ciphers[0]);
/*
****************************************************************************
* 9 PRIVATE FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipmacsec_crypto_cipher_suite_supported
*===========================================================================
* Description: See "ipmacsec_crypto_if.h"
* Parameters:
* Returns:
*
*/
IPMACSEC_PRIVATE Ip_bool
ipmacsec_crypto_cipher_suite_supported(IP_CONST Ipmacsec_cipher_suite_index cipher_suite_index) {
if (!IPMACSEC_SECY_VERIFY_CIPHER_SUITE_INDEX(cipher_suite_index)) {
return IP_FALSE;
}
return (ipmacsec_crypto_find_cipher(cipher_suite_index) != IP_NULL);
}
/*
*===========================================================================
* ipmacsec_crypto_cipher_suite_get_info
*===========================================================================
* Description: See "ipmacsec_crypto_if.h"
* Parameters:
* Returns:
*
*/
IPMACSEC_PRIVATE int
ipmacsec_crypto_cipher_suite_get_info(IP_CONST Ipmacsec_cipher_suite_index cipher_suite_index,
Ipmacsec_ciphersuite_descriptor *info) {
Ipmacsec_crypto_cipher IP_CONST *cipher = IP_NULL;
ip_assert(info);
if (!IPMACSEC_SECY_VERIFY_CIPHER_SUITE_INDEX(cipher_suite_index)) {
return IP_FALSE;
}
cipher = ipmacsec_crypto_find_cipher(cipher_suite_index);
if (cipher == IP_NULL) {
return -1;
}
ipcom_memcpy(info, &cipher->desc, sizeof(Ipmacsec_ciphersuite_descriptor));
return 0;
}
/*
*===========================================================================
* ipmacsec_crypto_cipher_suite_id_resolve
*===========================================================================
* Description: See "ipmacsec_crypto_if.h"
* Parameters:
* Returns:
*/
IPMACSEC_PRIVATE int
ipmacsec_crypto_cipher_suite_id_resolve(IP_CONST Ipmacsec_cipher_suite_index cipher_suite_index, Ip_u8 *cipher_suite_id) {
Ipmacsec_crypto_cipher IP_CONST *cipher;
ip_assert(cipher_suite_id);
cipher = ipmacsec_crypto_find_cipher(cipher_suite_index);
if (!cipher) {
return -1;
}
IPMACSEC_COPY_CIPHER_SUITE_ID(cipher_suite_id, cipher->desc.id);
return 0;
}
/*
*===========================================================================
* ipmacsec_crypto_cipher_suite_name
*===========================================================================
* Description: See "ipmacsec_crypto_if.h"
* Parameters:
* Returns:
*/
IPMACSEC_PRIVATE IP_CONST char *
ipmacsec_crypto_cipher_suite_name(IP_CONST Ipmacsec_cipher_suite_index cipher_suite_index) {
Ipmacsec_crypto_cipher IP_CONST *cipher;
if (!IPMACSEC_SECY_VERIFY_CIPHER_SUITE_INDEX(cipher_suite_index)) {
return "***Invalid Cipher***";
}
cipher = ipmacsec_crypto_find_cipher(cipher_suite_index);
if (!cipher) {
return "***Unknown Cipher***";
}
return cipher->desc.name;
}
/*
*===========================================================================
* ipmacsec_crypto_cipher_suite_index_resolve
*===========================================================================
* Description: See "ipmacsec_crypto_if.h"
* Parameters:
* Returns:
*/
IPMACSEC_PRIVATE int
ipmacsec_crypto_cipher_suite_index_resolve(IP_CONST Ip_u8 *cipher_suite_id, Ipmacsec_cipher_suite_index *cipher_suite_index) {
Ip_u32 i;
ip_assert(cipher_suite_id);
ip_assert(cipher_suite_index);
*cipher_suite_index = __IPMACSEC_CIPHERSUITE_INVALID;
for (i = 0; i < ipmacsec_num_ciphers; i++) {
if (ipcom_memcmp(&ipmacsec_ciphers[i].desc.id, cipher_suite_id, IPMACSEC_CIPHER_SUITE_ID_LEN) == 0) {
*cipher_suite_index = ipmacsec_ciphers[i].desc.index;
return 0;
}
}
return -1;
}
/*
*===========================================================================
* ipmacsec_crypto_get_icvbits
*===========================================================================
* Description: See "ipmacsec_crypto_if.h"
* Parameters:
* Returns:
*
*/
IPMACSEC_PRIVATE Ip_u16
ipmacsec_crypto_get_icvbits(Ipnet_secy *secy) {
Ipmacsec_crypto_cipher IP_CONST *cipher;
ip_assert(secy);
cipher = ipmacsec_crypto_find_cipher(secy->config.cipher_suite_index);
if (!cipher) {
return 0;
}
return (Ip_u16)cipher->desc.icv_bits;
}
/*
*===========================================================================
* ipmacsec_crypto_create
*===========================================================================
* Description: See "ipmacsec_crypto_if.h"
* Parameters:
* Returns:
*
*/
IPMACSEC_PRIVATE Ipmacsec_crypto_if *
ipmacsec_crypto_create(Ipnet_secy *secy) {
Ipmacsec_crypto_if *crypto;
Ipmacsec_crypto_cipher IP_CONST *cipher;
ip_assert(secy);
ip_assert(secy->netif);
if (!ipmacsec_crypto_verify(secy)) {
IPCOM_LOG1(CRIT, "IPMACSEC-CRYPTO: Invalid cipher suite configuration for interface %s", secy->netif->ipcom.name);
return IP_NULL;
}
crypto = ipcom_calloc(1, sizeof(Ipmacsec_crypto_if));
if (!crypto) {
IPCOM_LOG1(CRIT, "IPMACSEC-CRYPTO: Crypto memory allocation failed for interface %s", secy->netif->ipcom.name);
return IP_NULL;
}
crypto->priv.secy = secy;
crypto->priv.result_buf_len = secy->netif->ipcom.mtu+IPMACSEC_RESERVED_OCTETS+16; /* add 16 for any padding */
crypto->priv.result_buf = ipcom_malloc(crypto->priv.result_buf_len);
if (crypto->priv.result_buf == IP_NULL) {
ipcom_free(crypto);
return IP_NULL;
}
cipher = ipmacsec_crypto_find_cipher(secy->config.cipher_suite_index);
ip_assert(cipher);
crypto->priv.cipher = cipher;
crypto->icvbits = (Ip_u16)cipher->desc.icv_bits;
crypto->changesDataLength = cipher->desc.changesDataLength;
crypto->cipher_set = IP_TRUE;
crypto->init_cipher = ipmacsec_crypto_init;
crypto->destroy_cipher = ipmacsec_crypto_destroy;
crypto->protect = ipmacsec_crypto_protect;
crypto->validate = ipmacsec_crypto_validate;
crypto->confidentialityOffset = secy->config.confidentialityOffset;
crypto->gcmaes_accel_level = (Ip_u16)ipcom_sysvar_get_as_int(IPMACSEC_SYSVAR_GCMAES_ACCEL_LEVEL, IPMACSEC_DEFAULT_GCMAES_ACCEL_LEVEL);
if (secy->config.cipher_suite_index == IPMACSEC_CIPHERSUITE_GCM_AES_128) {
if (!ipmacsec_crypto_gcm_aes_config_verify(crypto)) {
ipcom_free(crypto->priv.result_buf);
ipcom_free(crypto);
return IP_NULL;
}
}
crypto->valid = IP_TRUE;
#ifdef IPMACSEC_DEBUG_CRYPTO
IPCOM_LOG2(INFO, "IPMACSEC-CRYPTO: Initialized SecY crypto cipher %s for interface %s",
cipher->desc.name, secy->netif->ipcom.name);
#endif
return crypto;
}
/*
*===========================================================================
* ipmacsec_crypto_delete
*===========================================================================
* Description: See "ipmacsec_crypto_if.h"
* Parameters:
* Returns:
*
*/
IPMACSEC_PRIVATE int
ipmacsec_crypto_delete(struct Ipnet_secy_struct *secy, Ipmacsec_crypto_if *crypto) {
Ip_u8 key_index;
IPCOM_UNUSED_ARG(secy);
ip_assert(secy);
if (crypto) {
if (crypto->priv.result_buf) {
ipcom_memset(crypto->priv.result_buf, 0, crypto->priv.result_buf_len);
ipcom_free(crypto->priv.result_buf);
crypto->priv.result_buf = 0;
crypto->priv.result_buf_len = 0;
}
for (key_index = 0 ; key_index < IPMACSEC_MAX_SA; key_index++) {
crypto->destroy_cipher(crypto, key_index);
}
ipcom_memset(crypto, 0 , sizeof(Ipmacsec_crypto_if));
ipcom_free(crypto);
}
return 0;
}
/*
****************************************************************************
* 10 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipmacsec_crypto_find_cipher
*===========================================================================
* Description: Find a cipher in the supported cipher list.
* Parameters:
* Returns:
*
*/
IP_STATIC Ipmacsec_crypto_cipher IP_CONST *
ipmacsec_crypto_find_cipher(IP_CONST Ipmacsec_cipher_suite_index cipher_suite_index) {
Ip_u32 i;
for (i = 0; i < ipmacsec_num_ciphers; i++) {
if (ipmacsec_ciphers[i].desc.index == cipher_suite_index) {
return &ipmacsec_ciphers[i];
}
}
return IP_NULL;
}
/*
*===========================================================================
* ipmacsec_crypto_gcm_aes_config_verify
*===========================================================================
* Description: Verify the relevant configuration values for GCM-AES.
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_bool
ipmacsec_crypto_gcm_aes_config_verify(Ipmacsec_crypto_if IP_CONST *crypto) {
ip_assert(crypto);
switch (crypto->gcmaes_accel_level) {
case GCM_ACCEL_noaccel:
case GCM_ACCEL_level1:
case GCM_ACCEL_level2:
case GCM_ACCEL_level3:
case GCM_ACCEL_level4:
break;
default:
IPCOM_LOG1(CRIT, "IPMACSEC-CRYPTO: Invalid GCM-AES acceleration level %u",
crypto->gcmaes_accel_level);
return IP_FALSE;
}
return IP_TRUE;
}
/*
*===========================================================================
* ipmacsec_crypto_verify
*===========================================================================
* Description: Verify the Crypto Interface configuration.
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_bool
ipmacsec_crypto_verify(Ipnet_secy *secy) {
Ipmacsec_crypto_cipher IP_CONST *cipher = IP_NULL;
if (!IPMACSEC_SECY_VERIFY_CIPHER_SUITE_INDEX(secy->config.cipher_suite_index)) {
IPCOM_LOG1(CRIT, "IPMACSEC-CRYPTO: Invalid cipher suite selector specified (%u)",
(Ip_u32)secy->config.cipher_suite_index);
return IP_FALSE;
}
#ifdef IPMACSEC_CRYPTO_ALLOW_NULL_CIPHER
if (secy->config.cipher_suite_index == IPMACSEC_CIPHERSUITE_NULL_CIPHER_128) {
IPCOM_LOG1(WARNING,"IPMACSEC-SECY_CRTL: Cipher Suite NULL_CIPHER_128 selected for interface %s",
secy->netif->ipcom.name);
}
#endif
cipher = ipmacsec_crypto_find_cipher(secy->config.cipher_suite_index);
if (!cipher) {
IPCOM_LOG1(CRIT, "IPMACSEC-CRYPTO: No supported cipher suite for specified selector (%u)",
(Ip_u32)secy->config.cipher_suite_index);
return IP_FALSE;
}
/* for now since KaY is not setting the Id, we copy it. Later when Kay is supported we may need to check
* for initialization using the id instead of the index */
ipcom_memcpy(secy->config.cipher_suite_id, cipher->desc.id, sizeof(cipher->desc.id));
if ((IPMACSEC_CRYPTO_IVBITS < cipher->desc.min_iv_bits) || (IPMACSEC_CRYPTO_IVBITS > cipher->desc.max_iv_bits)) {
IPCOM_LOG4(CRIT, "IPMACSEC-CRYPTO: cipher %s has incompatible iv size (%u not between %llu-%llu bits)",
cipher->desc.name, IPMACSEC_CRYPTO_IVBITS, cipher->desc.min_iv_bits, cipher->desc.max_iv_bits);
return IP_FALSE;
}
if (secy->config.confidentialityOffset) {
if (!IPMACSEC_SECY_VERIFY_CONFIDENTIALITY_OFFSET(secy->config.confidentialityOffset)) {
IPCOM_LOG2(CRIT, "IPMACSEC-CRYPTO: Invalid confidentialityOffset (%u) for specified cipher suite selector (%u)",
secy->config.confidentialityOffset, (Ip_u32)secy->config.cipher_suite_index);
return IP_FALSE;
}
if (!cipher->desc.offsetConfidentiality) {
IPCOM_LOG1(CRIT, "IPMACSEC-CRYPTO: offsetConfidentiality not supported for specified cipher suite selector (%u)",
(Ip_u32)secy->config.cipher_suite_index);
return IP_FALSE;
}
}
return IP_TRUE;
}
/*
*===========================================================================
* ipmacsec_crypto_init
*===========================================================================
* Description: Initialize the Crypto Interface for the specified key.
* Parameters:
* Returns:
*
*/
IP_STATIC int ipmacsec_crypto_init(struct Ipmacsec_crypto_if_struct *crypto, Ip_u8 key_index, Ipmacsec_secy_sak *sak) {
ip_assert(crypto);
ip_assert(key_index < IPMACSEC_MAX_SA);
if (!crypto->priv.cipher) {
IPCOM_LOG1(CRIT, "IPMACSEC-CRYPTO: no crypto found for interface %s", crypto->priv.secy->netif->ipcom.name);
return -1;
}
if (ipmacsec_sak_copy(&crypto->priv.sak[key_index], sak) != 0) {
IPCOM_LOG2(CRIT, "IPMACSEC-CRYPTO: Failed to create an SAK copy for key_index %u for interface %s",
key_index, crypto->priv.secy->netif->ipcom.name);
return -1;
}
if (crypto->priv.cipher->init(crypto->priv.cipher, &crypto->priv.cs_ctx[key_index]) != 0) {
IPCOM_LOG2(CRIT, "IPMACSEC-CRYPTO: Failed to initialize cipher for key_index %u for interface %s",
key_index, crypto->priv.secy->netif->ipcom.name);
(void)ipmacsec_sak_delete(&crypto->priv.sak[key_index]);
return -1;
}
return 0;
}
/*
*===========================================================================
* ipmacsec_crypto_destroy
*===========================================================================
* Description: Destroy the Crypto Interface for the specified key.
* Parameters:
* Returns:
*
*/
IP_STATIC int ipmacsec_crypto_destroy(struct Ipmacsec_crypto_if_struct *crypto, Ip_u8 key_index) {
ip_assert(crypto);
ip_assert(key_index < IPMACSEC_MAX_SA);
if (crypto->priv.cipher)
(void)crypto->priv.cipher->destroy(crypto->priv.cipher, &crypto->priv.cs_ctx[key_index]);
(void)ipmacsec_sak_delete(&crypto->priv.sak[key_index]);
return 0;
}
/*
*===========================================================================
* ipmacsec_crypto_protect
*===========================================================================
* Description: Crypto Interface Secure Frame Protection function
* Parameters: crypto - ptr to the crypto_if structure
* ctx - Context containing the crypto information for the current operation
* Returns: 0 upon success, < 0 on error
*
*/
IP_STATIC int
ipmacsec_crypto_protect(Ipmacsec_crypto_if *crypto, Ipmacsec_crypto_ctx *ctx) {
Ipmacsec_crypto_cipher IP_CONST *cipher;
Ipmacsec_cipher_ctx cipher_ctx;
Ip_u8 iv[IPMACSEC_CRYPTO_IVLEN];
ip_assert(crypto);
ip_assert(ctx);
cipher = crypto->priv.cipher;
if (!cipher || !crypto->cipher_set) {
#ifdef IPMACSEC_DEBUG_CRYPTO_PROTECT
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_P: cipher not set");
#endif
return -1;
}
if (!cipher->protect) {
#ifdef IPMACSEC_DEBUG_CRYPTO_PROTECT
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_P: cipher protect function not found");
#endif
return -1;
}
if (!ctx->macsec_hdr || !ctx->macsec_hdr_len) {
#ifdef IPMACSEC_DEBUG_CRYPTO_PROTECT
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_P: invalid macsec header");
#endif
return -1;
}
if (!ctx->userdata || !ctx->userdata_len) {
#ifdef IPMACSEC_DEBUG_CRYPTO_PROTECT
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_P: invalid userdata");
#endif
return -1;
}
if (!ctx->icv || (ctx->icv_len < cipher->desc.icv_bits/8)) {
#ifdef IPMACSEC_DEBUG_CRYPTO_PROTECT
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_P: invalid icv");
#endif
return -1;
}
if (ctx->key_index >= IPMACSEC_MAX_SA) {
#ifdef IPMACSEC_DEBUG_CRYPTO_VALIDATE
IPCOM_LOG1(ERR, "IPMACSEC-CRYPTO_P: invalid key_index %u", ctx->key_index);
#endif
return -1;
}
if (ctx->oper.encrypt) {
if (!cipher->desc.confidentialityProtection) {
#ifdef IPMACSEC_DEBUG_CRYPTO_PROTECT
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_P: cipher confidentialityProtection off but encryption requested");
#endif
return -1;
}
if (cipher->desc.changesDataLength) {
#ifdef IPMACSEC_DEBUG_CRYPTO_PROTECT
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_P: cipher changesDataLength; not supported");
#endif
return -1; /* Not supported for now */
}
if (!ctx->securedata) {
/* Use our preallocated result buffer */
ctx->securedata_len = (Ip_u16)crypto->priv.result_buf_len;
ctx->securedata = crypto->priv.result_buf;
}
if (!ctx->securedata || (ctx->securedata_len < ctx->userdata_len)) {
#ifdef IPMACSEC_DEBUG_CRYPTO_PROTECT
IPCOM_LOG2(ERR, "IPMACSEC-CRYPTO_P: invalid securedata_len (%u < %u)", ctx->securedata_len, ctx->userdata_len);
#endif
return -1;
}
} else {
if (!cipher->desc.integrityProtection) {
#ifdef IPMACSEC_DEBUG_CRYPTO_PROTECT
IPCOM_LOG0(CRIT, "IPMACSEC-CRYPTO_P: cipher integrityProtection off");
#endif
return -1;
}
}
cipher_ctx.cs_ctx = crypto->priv.cs_ctx[ctx->key_index];
cipher_ctx.key = crypto->priv.sak[ctx->key_index].buf;
cipher_ctx.keylen = crypto->priv.sak[ctx->key_index].num_octets;
ipcom_memcpy(iv, ctx->sci, IPMACSEC_SCI_LEN);
ipcom_memcpy(&iv[IPMACSEC_SCI_LEN], &ctx->pn, IPMACSEC_PN_LEN);
cipher_ctx.iv = iv;
cipher_ctx.ivlen = IPMACSEC_CRYPTO_IVLEN;
cipher_ctx.aad = ctx->macsec_hdr;
cipher_ctx.aadlen = ctx->macsec_hdr_len;
cipher_ctx.pt = ctx->userdata;
cipher_ctx.ptlen = ctx->userdata_len;
cipher_ctx.ct = ctx->securedata;
cipher_ctx.ctlen = ctx->securedata_len;
cipher_ctx.tag = ctx->icv;
cipher_ctx.taglen = ctx->icv_len;
cipher_ctx.confidentiality = ctx->oper.encrypt;
cipher_ctx.confidentialityOffset = crypto->confidentialityOffset;
cipher_ctx.cipher_options.gcmaes.accel_level = (GCM_ACCEL)crypto->gcmaes_accel_level;
if (cipher->protect(cipher, &cipher_ctx) != 0) {
#ifdef IPMACSEC_DEBUG_CRYPTO_PROTECT
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_P: cipher protection failed");
#endif
return -1;
}
ip_assert(cipher_ctx.ctlen <= ctx->securedata_len);
/* Successful, so update length fields */
ctx->securedata_len = (Ip_u16)cipher_ctx.ctlen;
ctx->icv_len = (Ip_u8)cipher_ctx.taglen;
return 0;
}
/*
*===========================================================================
* ipmacsec_crypto_validate
*===========================================================================
* Description: Crypto Interface Secure Frame Validation function
* Parameters: crypto - ptr to the crypto_if structure
* ctx - Context containing the crypto information for the current operation
* Returns: 0 upon success, < 0 on error
*
*/
IP_STATIC int
ipmacsec_crypto_validate(Ipmacsec_crypto_if *crypto, Ipmacsec_crypto_ctx *ctx, Ip_bool *valid) {
Ipmacsec_crypto_cipher IP_CONST *cipher;
Ipmacsec_cipher_ctx cipher_ctx;
Ip_u8 iv[IPMACSEC_CRYPTO_IVLEN];
ip_assert(crypto);
ip_assert(ctx);
ip_assert(valid);
*valid = IP_FALSE;
cipher = crypto->priv.cipher;
if (!cipher || !crypto->cipher_set) {
#ifdef IPMACSEC_DEBUG_CRYPTO_VALIDATE
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_V: cipher not set");
#endif
return -1;
}
if (!cipher->validate) {
#ifdef IPMACSEC_DEBUG_CRYPTO_VALIDATE
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_V: cipher validate function not found");
#endif
return -1;
}
if (!ctx->macsec_hdr || !ctx->macsec_hdr_len) {
#ifdef IPMACSEC_DEBUG_CRYPTO_VALIDATE
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_V: invalid macsec header");
#endif
return -1;
}
if (!ctx->securedata || !ctx->securedata_len) {
#ifdef IPMACSEC_DEBUG_CRYPTO_VALIDATE
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_V: invalid securedata");
#endif
return -1;
}
if (!ctx->icv || (ctx->icv_len < cipher->desc.icv_bits/8)) {
#ifdef IPMACSEC_DEBUG_CRYPTO_VALIDATE
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_V: invalid icv");
#endif
return -1;
}
if (ctx->key_index >= IPMACSEC_MAX_SA) {
#ifdef IPMACSEC_DEBUG_CRYPTO_VALIDATE
IPCOM_LOG1(ERR, "IPMACSEC-CRYPTO_V: invalid key_index %u", ctx->key_index);
#endif
return -1;
}
if (ctx->oper.decrypt) {
if (!cipher->desc.confidentialityProtection) {
#ifdef IPMACSEC_DEBUG_CRYPTO_VALIDATE
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_V: cipher confidentialityProtection off but decryption requested");
#endif
return -1;
}
if (cipher->desc.changesDataLength) {
#ifdef IPMACSEC_DEBUG_CRYPTO_VALIDATE
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_V: cipher changesDataLength; not supported");
#endif
return -1; /* Not supported for now */
}
if (!ctx->userdata) {
/* Use our preallocated result buffer */
ctx->userdata_len = (Ip_u16)crypto->priv.result_buf_len;
ctx->userdata = crypto->priv.result_buf;
}
if (!ctx->userdata || (ctx->userdata_len < ctx->securedata_len)) {
#ifdef IPMACSEC_DEBUG_CRYPTO_VALIDATE
IPCOM_LOG2(ERR, "IPMACSEC-CRYPTO_V: invalid userdata_len (%u < %u)", ctx->userdata_len, ctx->securedata_len);
#endif
return -1;
}
} else {
if (!cipher->desc.integrityProtection) {
#ifdef IPMACSEC_DEBUG_CRYPTO_VALIDATE
IPCOM_LOG0(CRIT, "IPMACSEC-CRYPTO_V: cipher integrityProtection off");
#endif
return -1;
}
}
cipher_ctx.cs_ctx = crypto->priv.cs_ctx[ctx->key_index];
cipher_ctx.key = crypto->priv.sak[ctx->key_index].buf;
cipher_ctx.keylen = crypto->priv.sak[ctx->key_index].num_octets;
ipcom_memcpy(iv, ctx->sci, IPMACSEC_SCI_LEN);
ipcom_memcpy(&iv[IPMACSEC_SCI_LEN], &ctx->pn, IPMACSEC_PN_LEN);
cipher_ctx.iv = iv;
cipher_ctx.ivlen = IPMACSEC_CRYPTO_IVLEN;
cipher_ctx.aad = ctx->macsec_hdr;
cipher_ctx.aadlen = ctx->macsec_hdr_len;
cipher_ctx.pt = ctx->userdata;
cipher_ctx.ptlen = ctx->userdata_len;
cipher_ctx.ct = ctx->securedata;
cipher_ctx.ctlen = ctx->securedata_len;
cipher_ctx.tag = ctx->icv;
cipher_ctx.taglen = ctx->icv_len;
cipher_ctx.confidentiality = ctx->oper.decrypt;
cipher_ctx.confidentialityOffset = crypto->confidentialityOffset;
cipher_ctx.cipher_options.gcmaes.accel_level = (GCM_ACCEL)crypto->gcmaes_accel_level;
if (cipher->validate(cipher, &cipher_ctx) != 0) {
#ifdef IPMACSEC_DEBUG_CRYPTO_VALIDATE
IPCOM_LOG0(ERR, "IPMACSEC-CRYPTO_V: cipher validation failed");
#endif
return -1;
}
ip_assert(cipher_ctx.ptlen <= ctx->userdata_len);
/* Successful, so update length field and valid state */
ctx->userdata_len = (Ip_u16)cipher_ctx.ptlen;
*valid = cipher_ctx.valid;
return 0;
}
/*
*===========================================================================
* ipmacsec_gcm_aes_128_init
*===========================================================================
* Description: GCM-AES cipher specific initialization function.
* Parameters: cipher - ptr to the GCM-AES cipher structure
* cs_ctx - Pointer to a cipher specific context that is updated by this function
* Returns: 0 upon success, < 0 on error
*
*/
IP_STATIC int ipmacsec_gcm_aes_128_init(IP_CONST Ipmacsec_crypto_cipher *cipher, void **cs_ctx) {
AES_GCM_CTX *gcmctx = IP_NULL;
IPCOM_UNUSED_ARG(cipher);
ip_assert(cipher);
ip_assert(cs_ctx);
gcmctx = (AES_GCM_CTX *)*cs_ctx;
if (gcmctx)
return 0;
/* Allocate context */
gcmctx = AES_GCM_CTX_new();
if (gcmctx == IP_NULL) {
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES
IPCOM_LOG0(ERR, "IPMACSEC-GCMAES_CIPH_I: malloc of AES_GCM_CTX failed");
#endif
return -1;
}
*cs_ctx = (void *)gcmctx;
return 0;
}
/*
*===========================================================================
* ipmacsec_gcm_aes_128_destroy
*===========================================================================
* Description: GCM-AES cipher specific destructor
* Parameters: cipher - ptr to the GCM-AES cipher structure
* cs_ctx - Pointer to a cipher specific context that is was initialized
* by the cipher specific init function
*
* Returns: 0 upon success, < 0 on error
*
*/
IP_STATIC int ipmacsec_gcm_aes_128_destroy(IP_CONST Ipmacsec_crypto_cipher *cipher, void **cs_ctx) {
IPCOM_UNUSED_ARG(cipher);
ip_assert(cipher);
ip_assert(cs_ctx);
if (*cs_ctx) {
AES_GCM_CTX_free((AES_GCM_CTX *)*cs_ctx);
*cs_ctx = IP_NULL;
}
return 0;
}
/*
*===========================================================================
* ipmacsec_gcm_aes_128_protect
*===========================================================================
* Description: GCM-AES cipher specific Secure Frame Protection function
* Parameters: cipher - ptr to the GCM-AES cipher structure
* ctx - Context containing the cipher information for the current operation
* Returns: 0 upon success, < 0 on error
*
*/
IP_STATIC int
ipmacsec_gcm_aes_128_protect(IP_CONST Ipmacsec_crypto_cipher *cipher, Ipmacsec_cipher_ctx *ctx) {
AES_GCM_CTX *gcmctx = IP_NULL;
unsigned long inlen = 0, outlen = 0;
unsigned long total_out = 0;
unsigned char *in = IP_NULL, *out = IP_NULL;
int ret = -1;
ip_assert(cipher);
ip_assert(ctx);
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES_DETAIL
IPCOM_LOG6(DEBUG2, "IPMACSEC-GCMAES_CIPH_P: key 0x%x, iv 0x%x, aad 0x%x, pt 0x%x, ct 0x%x, tag 0x%x",
ctx->key, ctx->iv, ctx->aad, ctx->pt, ctx->ct, ctx->tag);
IPCOM_LOG8(DEBUG2, "IPMACSEC-GCMAES_CIPH_P: keylen %u, ivlen %u, aadlen %u, ptlen %u, ctlen %u, "
"taglen %u, confidentiality %s, confidentialityOffset %u",
ctx->keylen, ctx->ivlen, ctx->aadlen, ctx->ptlen, ctx->ctlen, ctx->taglen,
IPMACSEC_BOOL_STRING(ctx->confidentiality), ctx->confidentialityOffset);
#endif
gcmctx = (AES_GCM_CTX *)ctx->cs_ctx;
if (gcmctx == IP_NULL) {
IPCOM_LOG0(CRIT, "IPMACSEC-GCMAES_CIPH_P: invalid cipher specific context");
return -1;
}
if (!ctx->key) {
IPCOM_LOG0(ERR, "IPMACSEC-GCMAES_CIPH_P: invalid key");
return -1;
}
if (ctx->keylen != cipher->desc.key_bits/8) {
IPCOM_LOG1(ERR, "IPMACSEC-GCMAES_CIPH_P: invalid keylen %u", ctx->keylen);
return -1;
}
if (ctx->taglen < AES_BLOCK_SIZE) {
IPCOM_LOG2(ERR, "IPMACSEC-GCMAES_CIPH_P: invalid ktaglen %u (< %u)", ctx->taglen, AES_BLOCK_SIZE);
return -1;
}
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES_DETAIL
ipmacsec_dump_buffer("key", ctx->key, ctx->keylen);
ipmacsec_dump_buffer("iv", ctx->iv, ctx->ivlen);
ipmacsec_dump_buffer("aad", ctx->aad, ctx->aadlen);
ipmacsec_dump_buffer("pt", ctx->pt, ctx->ptlen);
#endif
/* 1. Init aes gcm with the key and iv. Set the acceleration level */
if (!AES_GCM_Init(gcmctx, (unsigned char *)ctx->iv, ctx->ivlen, (unsigned char *)ctx->key, ctx->keylen)) {
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES
IPCOM_LOG0(ERR, "IPMACSEC-GCMAES_CIPH_P: AES_GCM_Init failed.");
#endif
goto exit_protect;
}
AES_GCM_CTX_ctrl(gcmctx, AES_GCM_CTRL_SET_ACCEL, ctx->cipher_options.gcmaes.accel_level, IP_NULL);
/* 2. Update with associated data (auth only) */
if (ctx->aadlen != 0) {
if (!AES_GCM_EncryptUpdate(gcmctx, (unsigned char *)ctx->aad, ctx->aadlen, IP_NULL, 0, IP_NULL, IP_NULL)) {
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES
IPCOM_LOG0(ERR, "IPMACSEC-GCMAES_CIPH_P: AAES_GCM_EncryptUpdate failed for associated data");
#endif
goto exit_protect;
}
}
/* 3. Update with plain text data (auth only) */
if (!ctx->confidentiality) {
if (!AES_GCM_EncryptUpdate(gcmctx, (unsigned char *)ctx->pt, ctx->ptlen, IP_NULL, 0, IP_NULL, IP_NULL)) {
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES
IPCOM_LOG0(ERR, "IPMACSEC-GCMAES_CIPH_P: AAES_GCM_EncryptUpdate failed for confidentialityOffset");
#endif
goto exit_protect;
}
goto finalize_encrypt;
}
/* 4. This is skipped if we are not doing encryption */
in = (unsigned char *)ctx->pt;
inlen = ctx->ptlen;
out = (unsigned char *)ctx->ct;
/* 4.1 Update with Confidentiality offset octets (auth only) */
if (ctx->confidentialityOffset != 0) {
Ip_u32 skip_len = (Ip_u32)IP_MIN(ctx->confidentialityOffset, inlen);
ipcom_memcpy(out, in, skip_len);
if (skip_len < inlen) {
if (!AES_GCM_EncryptUpdate(gcmctx, in, skip_len, IP_NULL, 0, IP_NULL, IP_NULL)) {
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES
IPCOM_LOG0(ERR, "IPMACSEC-GCMAES_CIPH_P: AAES_GCM_EncryptUpdate failed for confidentialityOffset");
#endif
goto exit_protect;
}
in += skip_len;
inlen -= skip_len;
} else {
in = IP_NULL;
inlen = 0;
}
total_out += skip_len;
}
/* 4.2. Update with plain text (encrypt) */
if (!AES_GCM_EncryptUpdate(gcmctx, IP_NULL, 0, in, inlen, out+total_out, &outlen)) {
if (inlen != 0) {
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES
IPCOM_LOG0(ERR, "IPMACSEC-GCMAES_CIPH_P: AES_GCM_EncryptUpdate failed for plain text (encrypt)");
#endif
goto exit_protect;
}
}
total_out += outlen;
finalize_encrypt:
/* 5. Finalize and get the tag */
if (!AES_GCM_EncryptFinal(gcmctx, out+total_out, &outlen, ctx->tag)) {
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES
IPCOM_LOG0(ERR, "IPMACSEC-GCMAES_CIPH_P: AES_GCM_EncryptFinal failed");
#endif
goto exit_protect;
}
total_out += outlen;
ctx->ctlen = (Ip_u32)total_out;
ctx->taglen = AES_BLOCK_SIZE;
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES_DETAIL
ipmacsec_dump_buffer("computed tag", ctx->tag, ctx->taglen);
if (ctx->confidentiality)
ipmacsec_dump_buffer("encrypted ct", ctx->ct, ctx->ctlen);
#endif
ret = 0;
exit_protect:
return ret;
}
/*
*===========================================================================
* ipmacsec_gcm_aes_128_validate
*===========================================================================
* Description: GCM-AES cipher specific Secure Frame Validation function
* Parameters: cipher - ptr to the GCM-AES cipher structure
* ctx - Context containing the cipher information for the current operation
* Returns: 0 upon success, < 0 on error
*
*/
IP_STATIC int
ipmacsec_gcm_aes_128_validate(IP_CONST Ipmacsec_crypto_cipher *cipher, Ipmacsec_cipher_ctx *ctx) {
AES_GCM_CTX *gcmctx = IP_NULL;
unsigned long inlen = 0, outlen = 0;
unsigned long total_out = 0;
unsigned char *in = IP_NULL, *out = IP_NULL;
int ret = -1;
ip_assert(cipher);
ip_assert(ctx);
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES_DETAIL
IPCOM_LOG6(DEBUG2, "IPMACSEC-GCMAES_CIPH_P: key 0x%x, iv 0x%x, aad 0x%x, pt 0x%x, ct 0x%x, tag 0x%x",
ctx->key, ctx->iv, ctx->aad, ctx->pt, ctx->ct, ctx->tag);
IPCOM_LOG8(DEBUG2, "IPMACSEC-GCMAES_CIPH_P: keylen %u, ivlen %u, aadlen %u, ptlen %u, ctlen %u, "
"taglen %u, confidentiality %s, confidentialityOffset %u",
ctx->keylen, ctx->ivlen, ctx->aadlen, ctx->ptlen, ctx->ctlen, ctx->taglen,
IPMACSEC_BOOL_STRING(ctx->confidentiality), ctx->confidentialityOffset);
#endif
ctx->valid = IP_FALSE;
gcmctx = (AES_GCM_CTX *)ctx->cs_ctx;
if (gcmctx == IP_NULL) {
IPCOM_LOG0(CRIT, "IPMACSEC-GCMAES_CIPH_V: invalid cipher specific context");
return -1;
}
if (!ctx->key) {
IPCOM_LOG0(ERR, "IPMACSEC-GCMAES_CIPH_V: invalid key");
return -1;
}
if (ctx->keylen != cipher->desc.key_bits/8) {
IPCOM_LOG1(ERR, "IPMACSEC-GCMAES_CIPH_V: invalid keylen %u", ctx->keylen);
return -1;
}
if (ctx->taglen < AES_BLOCK_SIZE) {
IPCOM_LOG2(ERR, "IPMACSEC-GCMAES_CIPH_V: invalid ktaglen %u (< %u)", ctx->taglen, AES_BLOCK_SIZE);
return -1;
}
if ((ctx->confidentiality) && (ctx->ptlen < ctx->ctlen)) {
IPCOM_LOG2(ERR, "IPMACSEC-GCMAES_CIPH_V: ptlen %u < ctlen %u", ctx->ptlen, ctx->ctlen);
return -1;
}
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES_DETAIL
ipmacsec_dump_buffer("key", ctx->key, ctx->keylen);
ipmacsec_dump_buffer("iv", ctx->iv, ctx->ivlen);
ipmacsec_dump_buffer("aad", ctx->aad, ctx->aadlen);
ipmacsec_dump_buffer("ct", ctx->ct, ctx->ctlen);
ipmacsec_dump_buffer("tag", ctx->tag, ctx->taglen);
#endif
/* 1. Init aes gcm with the key and iv. Set the acceleration level */
if (!AES_GCM_Init(gcmctx, (unsigned char *)ctx->iv, ctx->ivlen, (unsigned char *)ctx->key, ctx->keylen)) {
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES
IPCOM_LOG0(ERR, "IPMACSEC-GCMAES_CIPH_V: AES_GCM_Init failed.");
#endif
goto exit_verify;
}
AES_GCM_CTX_ctrl(gcmctx, AES_GCM_CTRL_SET_ACCEL, ctx->cipher_options.gcmaes.accel_level, IP_NULL);
/* 2. Update with associated data (auth only) */
if (ctx->aadlen != 0) {
if (!AES_GCM_DecryptUpdate(gcmctx, (unsigned char *)ctx->aad, ctx->aadlen, IP_NULL, 0, IP_NULL, IP_NULL)) {
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES
IPCOM_LOG0(ERR, "IPMACSEC-GCMAES_CIPH_V: AES_GCM_DecryptUpdate failed for associated data");
#endif
goto exit_verify;
}
}
if (!ctx->confidentiality) {
if (!AES_GCM_DecryptUpdate(gcmctx, (unsigned char *)ctx->ct, ctx->ctlen, IP_NULL, 0, IP_NULL, IP_NULL)) {
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES
IPCOM_LOG0(ERR, "IPMACSEC-GCMAES_CIPH_V: AES_GCM_DecryptUpdate failed for confidentialityOffset");
#endif
goto exit_verify;
}
goto finalize_decrypt;
}
/* 4. This is skipped if we are not doing decryption */
in = (unsigned char *)ctx->ct;
inlen = ctx->ctlen;
out = (unsigned char *)ctx->pt;
/* 4.1 Update with Confidentiality offset octets (auth only) */
if (ctx->confidentialityOffset != 0) {
Ip_u32 skip_len = (Ip_u32)IP_MIN(ctx->confidentialityOffset, inlen);
ipcom_memcpy(out, in, skip_len);
if (skip_len < inlen) {
if (!AES_GCM_DecryptUpdate(gcmctx, in, skip_len, IP_NULL, 0, IP_NULL, IP_NULL)) {
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES
IPCOM_LOG0(ERR, "IPMACSEC-GCMAES_CIPH_V: AES_GCM_DecryptUpdate failed for confidentialityOffset");
#endif
goto exit_verify;
}
in += skip_len;
inlen -= skip_len;
} else {
in = IP_NULL;
inlen = 0;
}
total_out += skip_len;
}
/* 4.2. Update with plain text (decrypt) */
if (!AES_GCM_DecryptUpdate(gcmctx, IP_NULL, 0, in, inlen, out+total_out, &outlen)) {
if (inlen != 0) {
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES
IPCOM_LOG0(ERR, "IPMACSEC-GCMAES_CIPH_V: AES_GCM_DecryptUpdate failed for plain text (decrypt)");
#endif
goto exit_verify;
}
}
total_out += outlen;
finalize_decrypt:
/* 5. Finalize and get the tag */
if (!AES_GCM_DecryptFinal(gcmctx, out+total_out, &outlen, ctx->tag, ctx->taglen)) {
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES
IPCOM_LOG0(ERR, "IPMACSEC-GCMAES_CIPH_V: AES_GCM_DecryptFinal failed");
#endif
goto exit_verify;
}
total_out += outlen;
ctx->ptlen = (Ip_u32)total_out;
#ifdef IPMACSEC_DEBUG_CRYPTO_CIPH_GCMAES_DETAIL
if (ctx->confidentiality)
ipmacsec_dump_buffer("decrypted pt", ctx->pt, ctx->ptlen);
#endif
ctx->valid = IP_TRUE;
ret = 0;
exit_verify:
return ret;
}
#ifdef IPMACSEC_CRYPTO_ALLOW_NULL_CIPHER
/* This code implements the NULL cipher and is to be used for Unit testing purposes ONLY.
* It provides no security whatsoever. DO NOT USE IN PRODUCTION CODE.
*/
/*
*===========================================================================
* ipmacsec_null_cipher_128_init
*===========================================================================
* Description: NULL Cipher initialization function.
* Parameters:
* Returns:
*
*/
IP_STATIC int ipmacsec_null_cipher_128_init(IP_CONST Ipmacsec_crypto_cipher *cipher, void **cs_ctx) {
Ip_u8 *tag;
ip_assert(cipher);
ip_assert(cs_ctx);
tag = ipcom_malloc(cipher->desc.icv_bits/8);
if (!tag) {
IPCOM_LOG0(CRIT, "IPMACSEC-NULL_CIPH_V: tag alloc fail");
return -1;
}
ipcom_memset(tag, 0xae, cipher->desc.icv_bits/8);
*cs_ctx = (void *)tag;
return 0;
}
/*
*===========================================================================
* ipmacsec_null_cipher_128_destroy
*===========================================================================
* Description: NULL Cipher destructor
* Parameters:
* Returns:
*
*/
IP_STATIC int ipmacsec_null_cipher_128_destroy(IP_CONST Ipmacsec_crypto_cipher *cipher, void **cs_ctx) {
Ip_u8 *tag;
ip_assert(cipher);
ip_assert(cs_ctx);
tag = (Ip_u8 *)*cs_ctx;
if (tag) {
ipcom_free(tag);
*cs_ctx = IP_NULL;
}
return 0;
}
/*
*===========================================================================
* ipmacsec_null_cipher_128_protect
*===========================================================================
* Description: NULL Cipher Secure Frame Protection function
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipmacsec_null_cipher_128_protect(IP_CONST Ipmacsec_crypto_cipher *cipher, Ipmacsec_cipher_ctx *ctx) {
Ip_u8 *tag;
ip_assert(cipher);
ip_assert(ctx);
#ifdef IPMACSEC_DEBUG_CRYPTO_NULL_CIPHER
IPCOM_LOG6(DEBUG2, "IPMACSEC-NULL_CIPH_P: key 0x%x, iv 0x%x, aad 0x%x, pt 0x%x, ct 0x%x, tag 0x%x",
ctx->key, ctx->iv, ctx->aad, ctx->pt, ctx->ct, ctx->tag);
IPCOM_LOG8(DEBUG2, "IPMACSEC-NULL_CIPH_P: keylen %u, ivlen %u, aadlen %u, ptlen %u, ctlen %u, "
"taglen %u, confidentiality %s, confidentialityOffset %u",
ctx->keylen, ctx->ivlen, ctx->aadlen, ctx->ptlen, ctx->ctlen, ctx->taglen,
IPMACSEC_BOOL_STRING(ctx->confidentiality), ctx->confidentialityOffset);
#endif
if (ctx->keylen != cipher->desc.key_bits/8) {
IPCOM_LOG1(ERR, "IPMACSEC-NULL_CIPH_P: invalid keylen %u", ctx->keylen);
return -1;
}
tag = (Ip_u8 *)ctx->cs_ctx;
if (!tag) {
IPCOM_LOG0(ERR, "IPMACSEC-NULL_CIPH_P: invalid tag");
return -1;
}
if (ctx->confidentiality) {
if (ctx->ctlen < ctx->ptlen) {
IPCOM_LOG2(ERR, "IPMACSEC-NULL_CIPH_P: ctlen %u < ptlen %u", ctx->ctlen, ctx->ptlen);
return -1;
}
ipcom_memcpy(ctx->ct, ctx->pt, ctx->ptlen);
ctx->ctlen = ctx->ptlen;
}
ipcom_memcpy(ctx->tag, tag, ctx->taglen);
/* ctx->taglen unchanged */
return 0;
}
/*
*===========================================================================
* ipmacsec_null_cipher_128_validate
*===========================================================================
* Description: NULL Cipher Secure Frame Validation function
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipmacsec_null_cipher_128_validate(IP_CONST Ipmacsec_crypto_cipher *cipher, Ipmacsec_cipher_ctx *ctx) {
Ip_u8 *tag;
ip_assert(cipher);
ip_assert(ctx);
#ifdef IPMACSEC_DEBUG_CRYPTO_NULL_CIPHER
IPCOM_LOG6(DEBUG2, "IPMACSEC-NULL_CIPH_V: key 0x%x, iv 0x%x, aad 0x%x, pt 0x%x, ct 0x%x, tag 0x%x",
ctx->key, ctx->iv, ctx->aad, ctx->pt, ctx->ct, ctx->tag);
IPCOM_LOG8(DEBUG2, "IPMACSEC-NULL_CIPH_V keylen %u, ivlen %u, aadlen %u, ptlen %u, ctlen %u, "
"taglen %u, confidentiality %s, confidentialityOffset %u",
ctx->keylen, ctx->ivlen, ctx->aadlen, ctx->ptlen, ctx->ctlen, ctx->taglen,
IPMACSEC_BOOL_STRING(ctx->confidentiality), ctx->confidentialityOffset);
#endif
if (ctx->keylen != cipher->desc.key_bits/8) {
IPCOM_LOG1(ERR, "IPMACSEC-NULL_CIPH_V: invalid keylen %u", ctx->keylen);
return -1;
}
if ((ctx->confidentiality) && (ctx->ptlen < ctx->ctlen)) {
IPCOM_LOG2(ERR, "IPMACSEC-NULL_CIPH_V: ptlen %u < ctlen %u", ctx->ptlen, ctx->ctlen);
return -1;
}
tag = (Ip_u8 *)ctx->cs_ctx;
if (!tag) {
IPCOM_LOG0(ERR, "IPMACSEC-NULL_CIPH_V: invalid tag");
return -1;
}
if (ipcom_memcmp(tag, ctx->tag, ctx->taglen) != 0) {
ctx->valid = IP_FALSE;
IPCOM_LOG0(ERR, "IPMACSEC-NULL_CIPH_V: tag mismatch, validation failed");
return 0;
}
if (ctx->confidentiality) {
ipcom_memcpy(ctx->pt, ctx->ct, ctx->ctlen);
ctx->ptlen = ctx->ctlen;
}
/* ctx->taglen unchanged */
ctx->valid = IP_TRUE;
return 0;
}
#endif