📄 ipsec_esp_message.c
字号:
/* ipsec_esp_message.c - WindNet IPsec and IKE - ESP message code *//* * Copyright (c) 2000-2006 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--------------------03u,13jan06,djp removed rwos dependencies03t,12jan06,djp removed rwos dependencies03s,08nov05,rma Replace RWOS container with wrSecList.03r,08nov05,rlm Removed references to rw_packet routines.03q,20oct05,rlm Fix for SPR #114203.03p,19sep05,rlm Removed obsolete ICV computation functions.03o,23aug05,rlm Add comments during informal code review.03n,10aug05,rlm Mods for single-pass encryption/HMAC with hardware acceleration.03m,13apr05,djp Fixed include paths03l,07feb05,rlm All failed alloca() calls now result in taskSuspend().03k,12nov04,rlm Cast UCHAR * to char * for calls to bcopy() under diab to eliminate warnings.03j,03nov04,rlm Fixes for AES-CTR mode when compiled with gcc.03i,23jul04,rlm Added CPU_FAMILY==MIPS check to use memmove() instead of bcopy() (SPR #89530).03h,18jun04,rlm Added optimization for aligned SPI and SEQ numbers to ipsec_esp_message_encrypt_and_serialize_trailer(). Also renamed variables in said function.03g,16jun04,rlm Cipher reorg: refactored encrypt and decrypt functions.03f,20jun03,rks(teamf1) removed WRS change for aligned buffer in CCI calls03e,03Jun03,rks(teamf1) fix a bug in ipsec_decrypt_esp_message. encrypted_packet_length was getting negative while subtracting.03d,15apr03,sam(teamf1) Changes for PMTU support(SPR #86677).03c,18Mar03,rks(teamf1) replaced DES_BLOCK_SIZE with CCI_DES_IV_LENGTH.03c,31Mar03,rparkhil added padding for NULL encryption03b,07Jan03,teamf1 replaced CCI_GET_DIGEST_LENGTH with cci_ctx_digest_length03a,14Nov02,rks(teamf1) changes for CCI intergration02b,27mar02,rpt changed ESP function definitions to integrate with enhanced crypto interface "crypto_if.h"02a,19mar02,rpt replaced IP_MESSAGE by IP_VI_MESSAGE in func definitions 01a,19mar02,rpt Extracted from WindNet IPSec 1.1, added modification history*//******************************************************************************/#include <vxWorks.h>#include <string.h>#include <netinet/in.h>#include <wrn/cci/cci.h>#include "../common/wrSecMem.h"#include "../common/wrSecList.h"#include "../common/wrSecSerialize.h"#include "../crypto/cipher.h"#include "../sadb/sadb_if.h"#ifdef IPSEC_VERBOSE_PACKET_DEBUGGING#include "../ike/ike_print_routines.h"#endif#include "ipsec_if.h"#include "ipsec_esp_message.h"#include "ipsec_print_routines.h"#include "packetBuf.h"/******************************************************************************/LOCAL void CBCModeIVGenerate ( CIPHER *cipher, /* cipher object */ unsigned char *buffer /* where to store IV */ );LOCAL void CTRModeCounterBlockIVExtractAndSet ( CIPHER *cipher, unsigned char *buffer );LOCAL void CTRModeCounterBlockBuild ( CIPHER *cipher, /* cipher object */ unsigned char *buffer /* where to store IV */ );/******************************************************************************/IPSEC_ESP_MESSAGE *ipsec_esp_message_create ( void ) { IPSEC_ESP_MESSAGE *sptr_ipsec_esp_message; sptr_ipsec_esp_message = wrSecAlloc (sizeof (IPSEC_ESP_MESSAGE)); if (sptr_ipsec_esp_message == NULL) { ipsec_printf_mon (IPSEC_ERROR_PRINTF, "IPsec: Error: ipsec_esp_message_create(): wrSecAlloc failed\n"); return (NULL); } return (sptr_ipsec_esp_message); }/******************************************************************************/void ipsec_esp_message_construct ( IPSEC_ESP_MESSAGE *sptr_ipsec_esp_message ) { if (sptr_ipsec_esp_message == NULL) { return; } sptr_ipsec_esp_message->esp_sequence_number = 0; sptr_ipsec_esp_message->spi = 0; }/******************************************************************************/void ipsec_esp_message_destruct ( IPSEC_ESP_MESSAGE *sptr_ipsec_esp_message ) { if (sptr_ipsec_esp_message == NULL) { return; } sptr_ipsec_esp_message->esp_sequence_number = 0; sptr_ipsec_esp_message->spi = 0; }/******************************************************************************/void ipsec_esp_message_delete ( IPSEC_ESP_MESSAGE *sptr_ipsec_esp_message ) { if (sptr_ipsec_esp_message == NULL) { return; } wrSecFree (sptr_ipsec_esp_message); }/******************************************************************************/BOOL ipsec_esp_message_decrypt_and_deserialize_trailer ( IPSEC_ESP_MESSAGE* sptr_ipsec_esp_message, PACKETBUF* pPacketBuf, CIPHER* cipher, SA_SPEC_RET_TYPES* failReason ) { UINT ESPPacketLength; UINT IVLength; UINT dataToDecryptLength; uint32_t SPINumber = 0; /* RFC2406, 2.1 */ uint32_t SEQNumber = 0; /* RFC2406, 2.2 */ UCHAR *pESPPacket; /* [SPI][SEQ][ESP PAYLOAD] */ UCHAR *pESPReceivedIV; UCHAR *pDataToDecrypt; UCHAR *pTrailerFields; BOOL AESCTRMode; cci_st cciStatus; BOOL isAligned; UCHAR padLength; /* RFC2406, 2.5 */ UINT digestLength; /* Note that 'cipher' and 'cipherESP' point to the SAME object; C doesn't * understand our pseudo objects, so to access the derived CIPHER_ESP methods * as well as the base CIPHER methods, it's most convenient to have two pointers. * If this bugs you, or the compiler, too much, feel free to change it. */ CIPHER_ESP * cipherESP = (CIPHER_ESP *)cipher; /* to avoid casting everywhere */ *failReason = SA_SPEC_FAIL; /* assume the worst */ AESCTRMode = FALSE; pESPPacket = packetBufDataGet(pPacketBuf); if (pESPPacket == NULL) { ipsec_printf(IPSEC_ERROR_PRINTF, "IPsec: ERROR: null ESP packet.\n"); *failReason = ESP_NULL_PACKET; return (FALSE); } ESPPacketLength = packetBufDataSizeGet(pPacketBuf); if ((cipher->cipherGet (cipher) == CCI_CIPHER_AES) && (cipher->modeGet (cipher) == CCI_MODE_CTR)) { AESCTRMode = TRUE; } /* NOTE: See RFC2406, "ESP", Section 2. for description of the * ESP payload format. */ digestLength = cipherESP->hmacDigestTruncSizeGet(cipherESP); pTrailerFields = (pESPPacket + ESPPacketLength) - digestLength - LENGTH_OF_PADLEN_AND_NEXTHDR_FIELDS; /* extract iv: it resides just beyond the SPI and SEQ fields of packet */ IVLength = cipher->IVSizeGet (cipher); pESPReceivedIV = pESPPacket + LENGTH_OF_SPI_AND_SEQ_FIELDS; /* Get IV for cipher (NOTE: AES-CTR mode only transmits the 64-bit IV portion of its counter block so this value may be adjusted below) */ if (AESCTRMode) { /* in AES-CTR mode, only IV portion of counter block is transmitted; subtract size of nonce and counter fields. (RFC3686) */ IVLength = IVLength - IPSEC_AES_CTR_NONCE_SIZE - IPSEC_AES_CTR_CTR_SIZE; /* Extract IV from incoming packet, put into AES cipher counter block */ CTRModeCounterBlockIVExtractAndSet (cipher, pESPReceivedIV); #if (defined IPSEC_VERBOSE_PACKET_DEBUGGING || IPSEC_VERBOSE_AES_CTR_DEBUGGING) ike_debug_printf_bytes (IKE_ERROR_PRINTF, "<AES-CTR Counter Block>:", (unsigned char *)cipher->_pIV, cipher->IVSizeGet (cipher)); #endif } else { /* Extract IV from incoming packet, put into CBC-mode cipher's IV */ cipher->IVSet (cipher, pESPReceivedIV); }/* TODO: Are these pointers constant from packet to packet? (Probably not, but check) -rlm */ cipherESP->hmacInBufSet(cipherESP, pESPPacket, LENGTH_OF_SPI_AND_SEQ_FIELDS + IVLength); cipherESP->hmacDigestBufSet(cipherESP, pTrailerFields + LENGTH_OF_PADLEN_AND_NEXTHDR_FIELDS); dataToDecryptLength = ESPPacketLength - LENGTH_OF_SPI_AND_SEQ_FIELDS - IVLength - digestLength; pDataToDecrypt = pESPReceivedIV + IVLength;#ifdef IPSEC_VERBOSE_PACKET_DEBUGGING ike_debug_printf_bytes (IKE_ERROR_PRINTF, "== packet before decryption:", pESPPacket, ESPPacketLength); { char printBuf[1024]; ((C_OBJ *)cipher)->toString ((C_OBJ *)cipher, (unsigned char *)printBuf, 1024); printf ("%s\n", printBuf); }#endif if ((dataToDecryptLength % cipher->blockSizeGet (cipher)) != 0) { ipsec_printf (IPSEC_WARNING_PRINTF, "IPsec: ESP decryption FAILED: %s %u-byte boundary\n", "Ciphertext is not right-aligned on a", cipher->blockSizeGet(cipher)); *failReason = ESP_CIPHERTEXT_ALIGN_ERROR; return (FALSE); } /* decrypt packet */ /* NOTE: this will need to be changed if compressing/expanding algorithms * are ever introduced! (The in and out buffers are currently identical) */ cciStatus = cipher->decrypt (cipher, pDataToDecrypt, dataToDecryptLength, pDataToDecrypt, &dataToDecryptLength); if (cciStatus != CCI_SUCCESS) { if( cciStatus == S_cciLib_AUTHENTICATION_ERROR ) { ipsec_printf(IPSEC_ERROR_PRINTF, "IPsec: ESP Authentication Error.\n"); *failReason = ESP_AUTHENTICATION_ERROR; } else { ipsec_printf (IPSEC_ERROR_PRINTF, "IPsec: Failed Decryption.\n"); *failReason = ESP_DECRYPTION_ERROR; } return (FALSE); }#ifdef IPSEC_VERBOSE_PACKET_DEBUGGING ike_debug_printf_bytes (IKE_ERROR_PRINTF, "== packet after decryption:", pESPPacket, ESPPacketLength); { char printBuf[512]; ((C_OBJ *)cipher)->toString ((C_OBJ *)cipher, (unsigned char *)printBuf, 512); printf ("%s\n", printBuf); }#endif /* Lose auth info now that we're done with it */ ESPPacketLength -= digestLength; /* HMAC no longer exists as far as we're concerned */ if ( (digestLength > 0) && (packetBufReduceBack(pPacketBuf, digestLength) == FALSE) ) { *failReason = ESP_PACKET_RESIZE_ERROR; return (FALSE); } /* deserialize trailer: [padLength.byte][nextHeader.byte] */ padLength = wrSecDeserializeUChar (&pTrailerFields); /* pTrailerFields++ */ sptr_ipsec_esp_message->next_header = (IP_TRANSPORT_PROTOCOL)wrSecDeserializeUChar ( &pTrailerFields); /* pTrailerFields++ */#ifndef WRN_SUPPRESS_INBOUND_MONOTONIC_PADDING_CHECK if (padLength > 0) { UCHAR pad_count; /* RFC2406, 2.6 */ UCHAR *pPadding; pPadding = (pESPPacket + ESPPacketLength) - (padLength + LENGTH_OF_PADLEN_AND_NEXTHDR_FIELDS); for (pad_count = 1; pad_count <= padLength; ++pad_count) { if (*pPadding++ != pad_count) { ipsec_printf (IPSEC_WARNING_PRINTF, "IPsec: ESP processing FAILED: %s\n", "Padding is not a monotonic sequence 1,2,3...."); *failReason = ESP_PADDING_ERROR; return (FALSE); } } }#endif /* WRN_SUPPRESS_INBOUND_MONOTONIC_PADDING_CHECK */ /* TODO: call reduce_data_back just once, for PADLEN,NEXTHDR and auth digest? -rlm */ if (packetBufReduceBack(pPacketBuf, padLength + LENGTH_OF_PADLEN_AND_NEXTHDR_FIELDS) == FALSE) { ipsec_printf(IPSEC_WARNING_PRINTF, "IPsec: ERROR: ESP packet resize failure after decryption.\n"); *failReason = ESP_PACKET_RESIZE_ERROR; return (FALSE); } if (IVLength > 0) { isAligned = ((UINT)(pESPPacket + IVLength) & (sizeof (uint32_t) - 1)) ? FALSE : TRUE; /* shift SPI and SEQ fields forward by IVLength to delete * the IV */ if (isAligned) { SPINumber = *((uint32_t *)pESPPacket); SEQNumber = *((uint32_t *)(pESPPacket + LENGTH_OF_SPI_FIELD)); *((uint32_t *)(pESPPacket + IVLength)) = SPINumber; *((uint32_t *)(pESPPacket + IVLength + LENGTH_OF_SPI_FIELD)) = SEQNumber; } else { /* TRACKSPR #89530: bcopy() (and therefore memcpy()) can copy past the end of * a buffer on MIPS in certain cases. */#if (CPU_FAMILY == MIPS) memmove (pESPPacket + IVLength, pESPPacket, LENGTH_OF_SPI_AND_SEQ_FIELDS);#else bcopy ((char *)pESPPacket, (char *)(pESPPacket + IVLength), LENGTH_OF_SPI_AND_SEQ_FIELDS);#endif } if (packetBufReduceFront(pPacketBuf, IVLength) == FALSE)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -