📄 ipsec_esp_message.c
字号:
{ ipsec_printf(IPSEC_WARNING_PRINTF, "IPsec: ERROR: ESP packet resize failure after IV removal.\n"); *failReason = ESP_PACKET_RESIZE_ERROR; return (FALSE); } } *failReason = SA_SPEC_SUCCESS; return (TRUE); } /* end ipsec_esp_message_decrypt_and_deserialize_trailer() *//******************************************************************************/BOOL ipsec_esp_message_deserialize_header ( IPSEC_ESP_MESSAGE* sptr_ipsec_esp_message, PACKETBUF* pPacketBuf ) { UCHAR *bptr_packet; UINT header_length; bptr_packet = packetBufDataGet(pPacketBuf); if (bptr_packet == NULL) { return (FALSE); } sptr_ipsec_esp_message->spi = wrSecDeserializeULong (&bptr_packet); sptr_ipsec_esp_message->esp_sequence_number = wrSecDeserializeULong (&bptr_packet); /* spi + sequence number */ header_length = LENGTH_OF_SPI_AND_SEQ_FIELDS; if (packetBufReduceFront(pPacketBuf, header_length) == FALSE) { return (FALSE); } return (TRUE); }/******************************************************************************/UINT ipsec_esp_message_serialize_header ( IPSEC_ESP_MESSAGE* sptr_ipsec_esp_message, PACKETBUF* pPacketBuf ) { UCHAR *bptr_packet; UINT header_length; /* spi + sequence number */ header_length = LENGTH_OF_SPI_AND_SEQ_FIELDS; bptr_packet = packetBufWritableHeaderGet(pPacketBuf, header_length); if (bptr_packet == NULL) { return (0); } wrSecSerializeULong (sptr_ipsec_esp_message->spi, &bptr_packet); wrSecSerializeULong (sptr_ipsec_esp_message->esp_sequence_number, &bptr_packet); if (packetBufExtendFront(pPacketBuf, header_length) == FALSE) { return (0); } return (header_length); } /******************************************************************************/#ifndef IPSEC_NO_RANDOM_IV#define IPSEC_RAND_POOL_SIZE 4096LOCAL UCHAR randPool[IPSEC_RAND_POOL_SIZE];LOCAL UINT randPoolIndex = IPSEC_RAND_POOL_SIZE;/******************************************************************************* CBCModeRandIVGet - generate random IV for CBC mode ESP encryption** Generates a random IV for CBC mode encryption. A random pool is maintained* for outgoing IVs. If hardware is available which provides a true RNG, it is* used to fill the pool. If the default pseudo-RNG is all that is available,* this is used to fill the pool, then the pool is encrypted to add more* unpredictability.** NOTE that this routine uses taskLock()/taskUnlock() to make the update of* the pool index atomic. It is possible that a thread may read from the random* pool while it is being refilled by another thread, but this is OK as it's* meant to be random. The taskLock/taskUnlock() calls guarantee that no two* threads will reuse an IV from the pool.** RETURNS: <none>** ERRNO:** NOMANUAL*/LOCAL BOOL CBCModeRandIVGet ( CIPHER *cipher, /* cipher object */ UCHAR *IVBuffer, /* buffer to receive random IV */ UINT IVBufferSize /* in bytes */ ) { UINT localIndex; /* randPoolIndex is atomically copied here */ UINT ciphertextLength; UINT cciHMACAlg; cci_st cciStatus; BOOL randAvailable; CIPHER_ESP *cipherESP = (CIPHER_ESP *)cipher; cciStatus = CCI_SUCCESS; randAvailable = FALSE; /* assume the worst */ taskLock (); localIndex = randPoolIndex; /* MUST update atomically for thread safety! */ randPoolIndex += IVBufferSize; taskUnlock (); if (localIndex < IPSEC_RAND_POOL_SIZE) { randAvailable = TRUE; } else { /* Uh oh, not enough random data left -- refill pool */ randPoolIndex = 0; localIndex = 0; cciStatus = cciRand (CCI_APP_PROVIDER_ID, randPool, IPSEC_RAND_POOL_SIZE); if (cciStatus != CCI_SUCCESS) { ipsec_printf (IPSEC_ERROR_PRINTF, "== Error replenishing randPool. Future IVs are NOT secure. ==\n"); } else { if (cciIsNative (CCI_APP_PROVIDER_ID, CCI_CLASS_RNG, CCI_RNG_GENERIC) == FALSE) { /* non-default provider -- we trust it is a true RNG... */ randAvailable = TRUE; } else { /* Software RNG -- encrypt the RNG pool */ ciphertextLength = IPSEC_RAND_POOL_SIZE; /* Temporarily disable HMAC generation -- we just want encryption */ cciHMACAlg = cipherESP->hmacGet(cipherESP); if( cipherESP->hmacSet(cipherESP, CCI_HMAC_NONE) != OK ) { ipsec_printf(IPSEC_ERROR_PRINTF, "== %s: Error setting HMAC algorithm to HMAC_NONE.\n", __FUNCTION__); } else { /* Now encrypt the pool for added obfuscation */ cciStatus = cipher->encrypt (cipher, randPool, IPSEC_RAND_POOL_SIZE, randPool, &ciphertextLength); if (cciStatus != CCI_SUCCESS) { ipsec_printf (IPSEC_ERROR_PRINTF, "== Error encrypting randPool. Future IVs are NOT secure. ==\n"); } else { /* Restore HMAC algorithm */ if( cipherESP->hmacSet(cipherESP,cciHMACAlg) != OK ) { ipsec_printf(IPSEC_ERROR_PRINTF, "== %s: Error restoring HMAC algorithm.\n", __FUNCTION__); } else { randAvailable = TRUE; } } } } } } if (randAvailable == TRUE) { memcpy (IVBuffer, &randPool[localIndex], IVBufferSize); cipher->IVSet (cipher, IVBuffer); } return randAvailable; } /* end CBCModeRandIVGet() */#endif /* IPSEC_NO_RANDOM_IV *//******************************************************************************/LOCAL void CBCModeIVGenerate ( CIPHER *cipher, /* cipher object */ unsigned char *buffer /* where to store IV */ ) {#ifdef IPSEC_NO_RANDOM_IV /* Old ESP RFC way - just use last block of ciphertext from last packet as IV * This is now considered insecure, so it is DISABLED by default. */ cipher->IVGet (cipher, buffer);#else /* Generate random IVs to prevent CBC mode explicit IV attacks * (see: http://crypto.knu.ac.kr/board/data/process/1053022220/0114_1.pdf), * http://www.hut.fi/~anuoppon/espiv.pdf) */ if( CBCModeRandIVGet (cipher, buffer, cipher->IVSizeGet (cipher)) == FALSE ) { ipsec_printf(IPSEC_ERROR_PRINTF, "== %s: Future IVs are NOT secure. ==\n", __FUNCTION__); }#endif return; } /* end CBCModeIVGenerate() *//******************************************************************************/LOCAL void CTRModeCounterBlockIVExtractAndSet ( CIPHER *cipher, /* cipher object */ unsigned char *buffer /* where to store IV */ ) { AES_CTRBLK *pCounterBlock; pCounterBlock = (AES_CTRBLK *)(cipher->_pIV); /* splice in received IV */ pCounterBlock->IV[0] = *(uint32_t *)buffer; pCounterBlock->IV[1] = *(uint32_t *)(buffer + sizeof (uint32_t)); /* reset counter field */ /* [RFC3686, 4.] Counter must be network order */ pCounterBlock->ctr = htonl (0x00000001L); /* Tell object we've diddled IV */ cipher->IVSet (cipher, (unsigned char *)pCounterBlock); return; } /* end CTRModeCounterBlockIVExtractAndSet() *//******************************************************************************/LOCAL void CTRModeCounterBlockBuild ( CIPHER *cipher, /* cipher object */ unsigned char *buffer /* where to store IV */ ) { AES_CTRBLK *pCounterBlock; pCounterBlock = (AES_CTRBLK *)(cipher->_pIV); /* increment IV [RFC3686, 3.1] */ pCounterBlock->IV[1]++; if (pCounterBlock->IV[1] == 0L) pCounterBlock->IV[0]++; /* carry for 64-bit CTR */ /* reset counter field */ /* [RFC3686, 4.] Counter must be network order */ pCounterBlock->ctr = htonl (0x00000001L); /* Tell object we've diddled IV */ cipher->IVSet (cipher, (unsigned char *)pCounterBlock); /* and finally, put transmitted portion of counter block into outgoing packet */ memcpy (buffer, &(pCounterBlock->IV), sizeof (uint64_t)); return; } /* end CTRModeCounterBlockBuild() *//******************************************************************************/BOOL ipsec_esp_message_encrypt_and_serialize_trailer ( IPSEC_ESP_MESSAGE* pESPMessage, PACKETBUF* pPacketBuf, CIPHER* cipher ) { UCHAR *pPacket; /* pointer to entire packet ([SPI][SEQ][plaintext]) */ UCHAR *pOutgoingIV; UCHAR *pPlaintext; /* pointer to plaintext */ UINT plaintextLength; UCHAR *pCiphertext; /* pointer to ciphertext */ UINT ciphertextLength; UINT padLength; UCHAR *pTrailerFields; UINT IVLength; UINT maxTrailerLength; BOOL AESCTRMode; cci_st cciStatus; /* 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 */ AESCTRMode = FALSE; pCiphertext = NULL; padLength = 0; pPacket = packetBufDataGet(pPacketBuf); if (pPacket == NULL) { return (FALSE); } if ((cipher->cipherGet (cipher) == CCI_CIPHER_AES) && (cipher->modeGet (cipher) == CCI_MODE_CTR)) { AESCTRMode = TRUE; } /* TODO: Can we adapt code to use MBUF library instead of RWOS generic rw_packet funcs? -rlm */ /* NOTE: packetLength includes SPI and SEQ fields which we are NOT encrypting */ plaintextLength = packetBufDataSizeGet(pPacketBuf) - LENGTH_OF_SPI_AND_SEQ_FIELDS; /* Ask cipher how much room we need for transmitted portion of IV * in outgoing packet. */ IVLength = cipher->IVSizeGet (cipher);#ifdef IPSEC_VERBOSE_PACKET_DEBUGGING printf ("== IVLength = 0x%08x\n", IVLength); ike_debug_printf_bytes (IKE_ERROR_PRINTF, "== packet before IV insertion:", pPacket, packetBufDataSizeGet(pPacketBuf));#endif if (IVLength > 0) { /* resize packet header to make room for IV */ /* NOTE: for AES-CTR mode, CCI treats the whole counter block as its IV, but we only transmit a portion (the IV field of the counter block) in the outgoing ESP packet (RFC3686). */ if (AESCTRMode) { IVLength = IVLength - IPSEC_AES_CTR_NONCE_SIZE - IPSEC_AES_CTR_CTR_SIZE; } /* TODO: Investigate moving all rw_packet() funcs used by this file into * TODO: local funcs, hopefully inlined. -rlm */ /* NOTE: packetBufWritableHeaderGet() verifies we have enough slack * space before the packet to add the IV. Additionally, however, * since we're adding stuff before the existing plaintext, the * pointer to the buffer is changed (pPacket). */ if ((pPacket = packetBufWritableHeaderGet(pPacketBuf, IVLength)) == NULL) { return (FALSE); } /* NOTE: Update the meta-info to record the new size and start address * of the packet. */ if (packetBufExtendFront(pPacketBuf, IVLength) == FALSE) { return (FALSE); } /* Move SPI and SEQ fields back to make room for IV */ /* TRACKSPR #89530: bcopy() (and therefore memcpy()) can copy past the end of * a buffer on MIPS in certain cases. */#if (CPU_FAMILY == MIPS) memmove (pPacket, pPacket + IVLength, LENGTH_OF_SPI_AND_SEQ_FIELDS);#else bcopy ((char *)(pPacket + IVLength), (char *)pPacket, LENGTH_OF_SPI_AND_SEQ_FIELDS);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -