/*- * Copyright (C) 2001-2003 by NBMK Encryption Technologies. * All rights reserved. * * NBMK Encryption Technologies provides no support of any kind for * this software. Questions or concerns about it may be addressed to * the members of the relevant open-source community at * . * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ static char const n8_id[] = "$Id: n8_ssltls.c,v 1.1 2008/10/30 12:02:15 darran Exp $"; /*****************************************************************************/ /** @file n8_ssltls.c * @brief SSL 3.0 Packet Level Interfaces * * Implementation of functions for SSL 3.0 Packet Level Interfaces. Functions * include: * N8_SSLEncryptAuthenticate * N8_SSLDecryptVerify * *****************************************************************************/ /***************************************************************************** * Revision history: * * 08/18/03 brr Combine Encrypt/Decrypt command block generators for SSL, * TLS, & IPsec. * 07/28/03 brr Removed obsolete #ifdefs. (Bug 918) * 07/01/03 brr Added option to use no hashing algorithm. * 05/27/03 brr Removed N8_preamble call since N8_PacketInitialize must be * called prior to Encrypt/Decrypt operations. * 05/20/03 brr Modified N8_PacketInitialize to setup function pointers & * lengths used in the Encrypt/Decrypt operations. Eliminated * several switch statements from Encrypt/Decrypt operations. * 11/01/02 jpw If the computedMAC_p parameter from N8_EA_DV is NULL * then don't copy back the MAC value. * 08/02/02 arh Fix N8_SSLTLSEncryptAuthenticate & N8_SSLTLSDecryptVerify * to check packet object ptr before storing mode in it, * preventing segmentation faults if passed ptr is null. * This check got lost when N8_*Memory routines added. * 07/16/02 arh Fix Bug #815: Make the N8_*Memory routines check for * legal values for the mode in the packet object. * 07/14/02 bac Simplified the calculation of the physical address for kernel * buffers. Consolidated logic for kernel buffer requests. * 06/14/02 hml Added the new N8_SSLTLS*Memory calls. The old calls are * still supported. * 06/10/02 hml Handle the new request pools. * 05/20/02 brr Free the request for all error conditions. * 05/07/02 msz New interface for QUEUE_AND_CHECK for new synchronous support. * 03/29/02 hml Works correctly with user allocated kernel buffers. * 03/26/02 brr Allocate the data buffer as part of the API request. * 02/27/02 hml Correctly handles the propagation of the IV. * 02/07/02 bac Deferred loading of the context caused the result handler to * not copy the computed mac back from the correct command. * 01/31/02 brr Eliminated the memory allocation for postProcessingData. * 01/22/02 bac Added code to use software to do SSL and HMAC precomputes. * 01/22/02 bac Added deferred loading of context until the first use. * 01/21/02 bac Changes to support new kernel allocation scheme. * 12/11/01 mel Fixed bug #397: addBlockToFree(postData_p..) and deleted * freeing postData_p from result handlers. * 11/24/01 brr Removed include of obsolete EA & PK specifice Queue files. * 11/12/01 hml Added structure verification and changed PI_PROTOCOL_* * to N8_PROTOCOL_*. * 11/05/01 bac Added missing check of return code after KMALLOC. * 10/11/01 brr Remove warnings exposed when optimization turned up. * 10/02/01 bac Added use of RESULT_HANDLER_WARNING in all result handlers. * 09/26/01 hml Get chip number out of the packet object. * 09/20/01 bac The interface to the command block generators changed and now * accept the command block buffer. All calls to cb_ea methods * changed herein. * 09/14/01 bac Fixed a bug where CHECK_RETURN was not being called in the * correct spot. BUG #208. * 09/12/01 bac Corrected the decrement of the sequence number upon failure of * DES operations that do not use the context memory. The * affected the methods resultHandlerSSLTLSDecrypt and * resultHandlerSSLTLSEncrypt. BUG #195. * 09/06/01 bac Added include of to silence warning. * 07/31/01 bac Added call to N8_preamble for all public interfaces. * 07/30/01 bac Pass chip id to createEARequestBuffer. * 06/28/01 bac Major fixes to get the encrypt and return packet lengths * correct, removed 'freeRequest' from the result handlers as it * now resides in the EventCheck routine. * 06/25/01 bac Changes for kernel memory management. * 06/14/01 bac Changes per code review: free requests upon error on enqueue, * use define for N8_DES_BLOCK_MULTIPLE, correct use of * N8_SSLTLS_MAX_DATA_SIZE_DECRYPT and * N8_SSLTLS_MAX_DATA_SIZE_ENCRYPT * 06/05/01 bac Changes to not rely on N8_SSLTLSPacket_t being packed (Bug * #31). * 05/30/01 bac Improved documentation of structures and return types (bug * #27). Removed reference to API Request pointer in the * QUEUE_AND_CHECK macro as the pointer will have already been * freed (bug #17). * 05/22/01 bac Changes to have N8_SSLTLSEncryptAuthenticate and * N8_SSLTLSDecryptVerify take and return N8_SSLTLSPacket_t. * Also, now calculate and return the packet lengths in the * packet. * 05/21/01 bac Removed unused resultHandler. Converted to * N8_ContextHandler_t. * 05/19/01 bac Free postProcessingData in resultHandlers when required. * 05/18/01 bac Converted to N8_xMALLOC and N8_xFREE * 05/18/01 bac Added support for Decrypt commands. * 05/02/01 bac Original version. ****************************************************************************/ /** @defgroup n8_ssltls Simon SSL/TLS Functions */ #include "n8_enqueue_common.h" #include "n8_util.h" #include "n8_common.h" #include "n8_ssltls.h" #include "n8_cb_ea.h" #include "n8_OS_intf.h" #include "n8_pub_request.h" /* local prototypes */ static void resultHandlerSSLTLSEncrypt(API_Request_t* req_p); static void resultHandlerSSLTLSDecrypt(API_Request_t* req_p); /* * Local structure used to pass data to the result handler. It is hooked to the * API Request in order to be available in the callback. */ typedef struct { N8_Buffer_t *computedMAC_p; N8_SSLTLSPacket_t *resultPacket_p; N8_Packet_t *packetObj_p; N8_Boolean_t *verify_p; int macLength; int encryptedLength; int copyData; unsigned char nextIV[8]; } N8_SSL_Post_Decrypt_Data_t; /* macro defines */ /* exported functions */ /***************************************************************************** * N8_SSLTLSEncryptAuthenticate *****************************************************************************/ /** @ingroup n8_ssltls * @brief Encrypt/Authenticate an SSL or TLS message * * An entire SSL or TLS record is encrypted/authenticated. * * @param packetObj_p RW: Pointer to a packet object which was * previously initialized for SSL or TLS * @param packet_p RO: Pointer to packet * @param result_p RW: Pointer to pre-allocated buffer where the * results will be stored. * @param request RW: Kernel request buffer used when mode = * N8_PACKETMEMORY_REQUEST. * @param event_p RW: Asynchronous event pointer. * * @par Externals * None * * @return * Error condition if raised. * * @par Errors * None * * @par Assumptions * None *****************************************************************************/ N8_Status_t N8_SSLTLSEncryptAuthenticateMemory(N8_Packet_t *packetObj_p, const N8_SSLTLSPacket_t *packet_p, N8_SSLTLSPacket_t *result_p, N8_RequestHandle_t request, N8_Event_t *event_p) { N8_Status_t ret = N8_STATUS_OK; API_Request_t *req_p = NULL; EA_CMD_BLOCK_t *next_cb_p = NULL; uint16_t length; short int encLen; short int packetLen; N8_Buffer_t *res_p = NULL; uint32_t res_a; N8_Buffer_t *input_p = NULL; uint32_t input_a; N8_Buffer_t *ctx_p = NULL; uint32_t ctx_a = 0; int nBytes; unsigned int numCommands = 0; unsigned int numCtxBytes = 0; N8_MemoryHandle_t *request_p; n8_ctxLoadFcn_t ctxLoadFcn; n8_SSLTLSFcn_t encryptFcn; do { /* verify the pointers passed in are not null */ CHECK_OBJECT(packetObj_p, ret); CHECK_STRUCTURE(packetObj_p->structureID, N8_PACKET_STRUCT_ID, ret); CHECK_OBJECT(packet_p, ret); CHECK_OBJECT(result_p, ret); request_p = (N8_MemoryHandle_t *) request; /* Check that request_p & mode are consistent */ if (request_p == NULL) { if (packetObj_p->mode != N8_PACKETMEMORY_NONE) { /* No request_p means mode should be "none" */ ret = N8_INCONSISTENT; break; } } else if (packetObj_p->mode != N8_PACKETMEMORY_REQUEST) { /* They said they would give us a request and they didn't */ ret = N8_INCONSISTENT; break; } /* * convert the length from network order to host order */ length = SSLTLS_EXTRACT_LENGTH(packet_p); /* check to see the data length is within range * [0..N8_SSLTLS_MAX_DATA_SIZE_ENCRYPT] */ if (length > N8_SSLTLS_MAX_DATA_SIZE_ENCRYPT) { ret = N8_INVALID_INPUT_SIZE; break; } numCommands = packetObj_p->encCommands; if (packetObj_p->contextLoadNeeded == N8_TRUE) { numCommands += packetObj_p->ctxLoadCmds; numCtxBytes = NEXT_WORD_SIZE(sizeof(EA_ARC4_CTX)); } /* create a kernel memory structure for temporarily storing the results */ /* compute the lengths for the result packet */ encLen = N8_ComputeEncryptedLength(length, packetObj_p->hashPacket.hashSize, packetObj_p->packetCipher); packetLen = encLen + SSLTLS_HEADER_LEN; /* compute the total number of bytes in kernel space we need to allocate. * note we round up to the next word boundary. */ /* Note that if the in packet is NULL, we don't check the out packet */ if (request_p == NULL) { nBytes = (NEXT_WORD_SIZE(length) + /* input */ NEXT_WORD_SIZE(encLen) + /* output */ numCtxBytes); /* size of context, if needed */ /* create an API request buffer */ ret = createEARequestBuffer(&req_p, packetObj_p->unitID, numCommands, resultHandlerSSLTLSEncrypt, nBytes); CHECK_RETURN(ret); /* User has not provided a request buffer */ res_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset); res_a = req_p->qr.physicalAddress + req_p->dataoffset; input_p = res_p + NEXT_WORD_SIZE(length); input_a = res_a + NEXT_WORD_SIZE(length); ctx_p = input_p + NEXT_WORD_SIZE(encLen); ctx_a = input_a + NEXT_WORD_SIZE(encLen); } else { /* The user has given us a request structure. We just need to initialize it. */ req_p = (API_Request_t *) request_p->VirtualAddress; initializeEARequestBuffer(req_p, request_p, packetObj_p->unitID, numCommands, resultHandlerSSLTLSEncrypt, N8_TRUE); /* User has provided a request packet, which must contain enough space for the input and output packets. The user may reuse the input pointer for the output. */ input_p = (N8_Buffer_t *)((unsigned long) packet_p + SSLTLS_DATA_OFFSET); input_a = N8_VirtToPhys(input_p); res_p = (N8_Buffer_t *)((unsigned long) result_p + SSLTLS_DATA_OFFSET); res_a = N8_VirtToPhys(res_p); /* If we are loading context memory, we load it at the last N8_CTX_BYTES before the data section */ if (numCtxBytes > 0) { ctx_p = (N8_Buffer_t *)((unsigned long) req_p + sizeof(API_Request_t) + N8_COMMAND_BLOCK_BYTES); ctx_a = N8_VirtToPhys(ctx_p); } } next_cb_p = req_p->EA_CommandBlock_ptr; /* generate the command blocks necessary to load the context, if required */ if (packetObj_p->contextLoadNeeded == N8_TRUE) { /* Generate the command blocks for the Context Load */ ctxLoadFcn = (n8_ctxLoadFcn_t)packetObj_p->ctxLoadFcn; ret = ctxLoadFcn(req_p, next_cb_p, packetObj_p, &packetObj_p->cipherInfo, packetObj_p->packetHashAlgorithm, ctx_p, ctx_a, &next_cb_p); CHECK_RETURN(ret); packetObj_p->contextLoadNeeded = N8_FALSE; } req_p->copyBackFrom_p = res_p; req_p->postProcessingData_p = (void *) packetObj_p; /* This sets up the offset for the start of the copy back of the IV */ req_p->postProcessBuffer[0] = encLen - N8_DES_KEY_LENGTH; if (request_p == NULL) { memcpy(input_p, &packet_p[SSLTLS_DATA_OFFSET], length); req_p->copyBackTo_p = &result_p[SSLTLS_DATA_OFFSET]; req_p->copyBackSize = encLen; } else { req_p->copyBackSize = 0; } /* Generate the command blocks for the Encrypt */ encryptFcn = (n8_SSLTLSFcn_t)packetObj_p->SSLTLScmdFcn; ret = encryptFcn(next_cb_p, packetObj_p, packet_p, input_a, res_a, packetObj_p->encOpCode); CHECK_RETURN(ret); /* set up the return packet. note that this can be done before the * command is executed as it is only constant header information. */ memcpy(&result_p[SSLTLS_TYPE_OFFSET], &packet_p[SSLTLS_TYPE_OFFSET], sizeof(uint8_t) + sizeof(uint16_t)); SSLTLS_SET_LENGTH(result_p, encLen); QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up if necessary. note that if there is no error condition, the * request will be de-allocated in the result handler. */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } return ret; } /* N8_SSLEncryptAuthenticateMemory */ /***************************************************************************** * N8_SSLTLSEncryptAuthenticate *****************************************************************************/ /** @ingroup n8_ssltls * @brief Encrypt/Authenticate an SSL or TLS message * * An entire SSL or TLS record is encrypted/authenticated. Note that this call * is now supported as a front end to N8_SSLTLSEncryptAuthenticateMemory. * * @param packetObj_p RW: Pointer to a packet object which was * previously initialized for SSL or TLS * @param packet_p RO: Pointer to packet * @param result_p RW: Pointer to pre-allocated buffer where the * results will be stored. * @param event_p RW: Asynchronous event pointer. * * @par Externals * None * * @return * Error condition if raised. * * @par Errors * None * * @par Assumptions * None *****************************************************************************/ N8_Status_t N8_SSLTLSEncryptAuthenticate(N8_Packet_t *packetObj_p, const N8_SSLTLSPacket_t *packet_p, N8_SSLTLSPacket_t *result_p, N8_Event_t *event_p) { N8_Status_t retCode; N8_PacketMemoryMode_t saveMode; do { CHECK_OBJECT(packetObj_p, retCode); /* save the existing mode and set it */ saveMode = packetObj_p->mode; packetObj_p->mode = N8_PACKETMEMORY_NONE; retCode = N8_SSLTLSEncryptAuthenticateMemory(packetObj_p, packet_p, result_p, NULL, event_p); /* reset the mode */ packetObj_p->mode = saveMode; } while (FALSE); return retCode; } /***************************************************************************** * N8_SSLTLSDecryptVerifyMemory *****************************************************************************/ /** @ingroup n8_ssltls * @brief Decrypt and verify an entire SSL or TLS message. * * Decrypt an verify a SSL or TLS message. If the verification fails, it will * be noted in the return value. * * @param packetObj_p RW: Pre-initialized packet object. * @param packet_p RO: A complete, encrypted SSL or TLS packet * including the header. * @param computedMAC_p RW: Pointer to result space for the MAC * computation output. * @param verify_p: WO: Pointer to a verify flag. If the MAC's * match, the verify flag will be set to N8_TRUE. * @param result_p RW: Pointer to result space for the decrypted * result. * @param request RW: Kernel request buffer used when mode = * N8_PACKETMEMORY_REQUEST. * @param event_p RW: Asynchronous event pointer. * * @par Externals * None * * @return * Error condition if raised. * * @par Errors * N8_MALLOC_FAILED
* N8_INVALID_INPUT_SIZE - the value in the packet header is too large or too * small.
* N8_INCONSISTENT - the version number in the packet header does not * match the designation in the packet object.
* N8_INVALID_OBJECT - packet object is not a valid object initialized * for SSL or TLS
* N8_INVALID_VALUE - the value of the type field in the packet header * is not one of the legal values for SSL or TLS.
* * @par Assumptions * The result_p and computedMAC_p pointers refer to pre-allocated space of * sufficient size. The calling program retains responsibility for freeing this * memory. *****************************************************************************/ N8_Status_t N8_SSLTLSDecryptVerifyMemory(N8_Packet_t *packetObj_p, const N8_SSLTLSPacket_t *packet_p, N8_Buffer_t *computedMAC_p, N8_Boolean_t *verify_p, N8_SSLTLSPacket_t *result_p, N8_RequestHandle_t request, N8_Event_t *event_p) { N8_Status_t ret = N8_STATUS_OK; API_Request_t *req_p = NULL; EA_CMD_BLOCK_t *next_cb_p = NULL; N8_SSL_Post_Decrypt_Data_t *postData_p = NULL; uint16_t length; short int encLen; int nBytes; N8_Buffer_t *res_p = NULL; uint32_t res_a; N8_Buffer_t *input_p = NULL; uint32_t input_a; N8_Buffer_t *ctx_p = NULL; uint32_t ctx_a = 0; unsigned int numCommands = 0; unsigned int numCtxBytes = 0; N8_MemoryHandle_t *request_p; n8_ctxLoadFcn_t ctxLoadFcn; n8_SSLTLSFcn_t decryptFcn; do { /* ensure none of the pointers we're given are null */ CHECK_OBJECT(packetObj_p, ret); CHECK_STRUCTURE(packetObj_p->structureID, N8_PACKET_STRUCT_ID, ret); CHECK_OBJECT(packet_p, ret); #ifdef N8_MAC_COPYBACK CHECK_OBJECT(computedMAC_p, ret); #endif CHECK_OBJECT(result_p, ret); request_p = (N8_MemoryHandle_t *) request; /* Check that request_p & mode are consistent */ if (request_p == NULL) { if (packetObj_p->mode != N8_PACKETMEMORY_NONE) { /* No request_p means mode should be "none" */ ret = N8_INCONSISTENT; break; } } else if (packetObj_p->mode != N8_PACKETMEMORY_REQUEST) { /* They said they would give us a request and they didn't */ ret = N8_INCONSISTENT; break; } /* * convert the length from network order to host order */ length = ntohs(*((uint16_t *) &packet_p[SSLTLS_LENGTH_OFFSET])); /* verify the length is not greater than the max */ if (length > N8_SSLTLS_MAX_DATA_SIZE_DECRYPT) { ret = N8_INVALID_INPUT_SIZE; break; } numCommands = packetObj_p->decCommands; if (packetObj_p->contextLoadNeeded == N8_TRUE) { numCommands += packetObj_p->ctxLoadCmds; numCtxBytes = NEXT_WORD_SIZE(sizeof(EA_ARC4_CTX)); } encLen = N8_ComputeEncryptedLength(length, packetObj_p->hashPacket.hashSize, packetObj_p->packetCipher); /* kernel space is needed for the data portion of the incoming packet plus * the hash and padding. the exact amount is needed for the return * packet. */ /* Note that if the in packet is NULL, we don't check the out packet */ if (request_p == NULL) { nBytes = NEXT_WORD_SIZE(length) * 2 + numCtxBytes; /* create an API request buffer */ ret = createEARequestBuffer(&req_p, packetObj_p->unitID, numCommands, resultHandlerSSLTLSDecrypt, nBytes); CHECK_RETURN(ret); /* User has not provided any buffers */ res_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset); res_a = req_p->qr.physicalAddress + req_p->dataoffset; input_p = res_p + NEXT_WORD_SIZE(length); input_a = res_a + NEXT_WORD_SIZE(length); ctx_p = input_p + NEXT_WORD_SIZE(encLen); ctx_a = input_a + NEXT_WORD_SIZE(encLen); } else { /* User has provided a request packet, which must contain enough space for the input and output packets. The user may reuse the input pointer for the output. */ /* The user has given us a request structure. We just need to initialize it. */ req_p = (API_Request_t *) request_p->VirtualAddress; initializeEARequestBuffer(req_p, request_p, packetObj_p->unitID, numCommands, resultHandlerSSLTLSDecrypt, N8_TRUE); /* Initialize input_p and input_a to the beginning of data area in the request */ input_p = (N8_Buffer_t *)((unsigned long) packet_p + SSLTLS_DATA_OFFSET); input_a = N8_VirtToPhys(input_p); res_p = result_p + SSLTLS_DATA_OFFSET; res_a = N8_VirtToPhys(res_p); /* If we are loading context memory, we load it at the last N8_CTX_BYTES before the data section */ if (numCtxBytes > 0) { ctx_p = (N8_Buffer_t *)((unsigned long) req_p + sizeof(API_Request_t) + N8_COMMAND_BLOCK_BYTES); ctx_a = N8_VirtToPhys(ctx_p); } } next_cb_p = req_p->EA_CommandBlock_ptr; /* generate the command blocks necessary to load the context, if required */ if (packetObj_p->contextLoadNeeded == N8_TRUE) { /* Generate the command blocks for the Context Load */ ctxLoadFcn = (n8_ctxLoadFcn_t)packetObj_p->ctxLoadFcn; ret = ctxLoadFcn(req_p, req_p->EA_CommandBlock_ptr, packetObj_p, &packetObj_p->cipherInfo, packetObj_p->packetHashAlgorithm, ctx_p, ctx_a, &next_cb_p); CHECK_RETURN(ret); packetObj_p->contextLoadNeeded = N8_FALSE; } /* copy the data portion of the incoming packet into the input kernel * buffer */ if (request_p == NULL) { memcpy(input_p, &packet_p[SSLTLS_DATA_OFFSET], length); } /* use the post processing structure in the API Request */ postData_p = (N8_SSL_Post_Decrypt_Data_t *)&req_p->postProcessBuffer; /* now check the length */ if (length < packetObj_p->minLength) { ret = N8_INVALID_INPUT_SIZE; break; } /* if des, ensure the length is a multiple of N8_DES_BLOCK_MULTIPLE */ if ((packetObj_p->packetCipher == N8_CIPHER_DES) && ((length % N8_DES_BLOCK_MULTIPLE) != 0)) { ret = N8_INVALID_INPUT_SIZE; break; } /* set up the copy back for the result packet. we only copy back the data * portion which we get from the kernel buffer. */ req_p->copyBackTo_p = &result_p[SSLTLS_DATA_OFFSET]; req_p->copyBackFrom_p = res_p; /* the length the decrypted data is not known until after the operation is * run. we will calculate it in the resultHandler. set the copyBackSize * to zero as a safe thing to do.*/ req_p->copyBackSize = 0; if (packetObj_p->contextHandle.inUse == N8_FALSE) { /* This sets up the offset for the start of the copy back of the IV. This case can only occur if the cipher is DES, not ARC4 */ memcpy(&postData_p->nextIV, &(packet_p[5 - N8_DES_KEY_LENGTH + length]), N8_DES_KEY_LENGTH); } /* set up the post processing data */ postData_p->macLength = packetObj_p->macLength; postData_p->computedMAC_p = computedMAC_p; postData_p->packetObj_p = packetObj_p; postData_p->verify_p = verify_p; postData_p->encryptedLength = length; if (request_p == NULL) { postData_p->copyData = N8_TRUE; } else { postData_p->copyData = N8_FALSE; } postData_p->resultPacket_p = result_p; /* tell the Queue Manager to copy back the command block results */ req_p->copyBackCommandBlock = N8_TRUE; req_p->postProcessingData_p = (void *) postData_p; /* Generate the command blocks for the Decrypt */ decryptFcn = (n8_SSLTLSFcn_t)packetObj_p->SSLTLScmdFcn; ret = decryptFcn(next_cb_p, packetObj_p, packet_p, input_a, res_a, packetObj_p->decOpCode); CHECK_RETURN(ret); /* set up the return packet * again, recall we cannot set the length in the result packet now and * will have to do it in the result handler. */ memcpy(&result_p[SSLTLS_TYPE_OFFSET], &packet_p[SSLTLS_TYPE_OFFSET], sizeof(uint8_t) + sizeof(uint16_t)); QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up if necessary. note that if there is no error condition, the post * data and request will be de-allocated in the result handler. */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } return ret; } /* N8_SSLTLSDecryptVerify */ /***************************************************************************** * N8_SSLTLSDecryptVerify *****************************************************************************/ /** @ingroup n8_ssltls * @brief Decrypt and verify an entire SSL or TLS message. * * Decrypt an verify a SSL or TLS message. If the verification fails, it will * be noted in the return value. Note that this call is now supported as a front * end to N8_SSLTLSDecryptVerifyMemory. * * @param packetObj_p RW: Pre-initialized packet object. * @param packet_p RO: A complete, encrypted SSL or TLS packet * including the header. * @param computedMAC_p RW: Pointer to result space for the MAC * computation output. * @param verify_p: WO: Pointer to a verify flag. If the MAC's * match, the verify flag will be set to N8_TRUE. * @param result_p RW: Pointer to result space for the decrypted * result. * @param request RW: Kernel request buffer used when mode = * N8_PACKETMEMORY_REQUEST. * @param event_p RW: Asynchronous event pointer. * * @par Externals * None * * @return * Error condition if raised. * * @par Errors * N8_MALLOC_FAILED
* N8_INVALID_INPUT_SIZE - the value in the packet header is too large or too * small.
* N8_INCONSISTENT - the version number in the packet header does not * match the designation in the packet object.
* N8_INVALID_OBJECT - packet object is not a valid object initialized * for SSL or TLS
* N8_INVALID_VALUE - the value of the type field in the packet header * is not one of the legal values for SSL or TLS.
* * @par Assumptions * The result_p and computedMAC_p pointers refer to pre-allocated space of * sufficient size. The calling program retains responsibility for freeing this * memory. *****************************************************************************/ N8_Status_t N8_SSLTLSDecryptVerify(N8_Packet_t *packetObj_p, const N8_SSLTLSPacket_t *packet_p, N8_Buffer_t *computedMAC_p, N8_Boolean_t *verify_p, N8_SSLTLSPacket_t *result_p, N8_Event_t *event_p) { N8_Status_t retCode; N8_PacketMemoryMode_t saveMode; do { CHECK_OBJECT(packetObj_p, retCode); /* save the existing mode and set it */ saveMode = packetObj_p->mode; packetObj_p->mode = N8_PACKETMEMORY_NONE; retCode = N8_SSLTLSDecryptVerifyMemory(packetObj_p, packet_p, computedMAC_p, verify_p, result_p, NULL, event_p); /* reset the mode */ packetObj_p->mode = saveMode; } while (FALSE); return retCode; } /***************************************************************************** * N8_GetHashLen *****************************************************************************/ /** @ingroup n8_ssltls * @brief Compute the length of a hash. * * For a specified type of hash, return the length of the generated hash. * * @param hash RO: Hash to be used * * @par Externals * None * * @return * Length of the hash. Returns -1 if the hash is not supported. * * @par Errors * See above. * * @par Assumptions * None *****************************************************************************/ short int N8_GetHashLength(N8_HashAlgorithm_t hash) { switch (hash) { case N8_MD5: case N8_HMAC_MD5: return MD5_HASH_RESULT_LENGTH; case N8_SHA1: case N8_HMAC_SHA1: return SHA1_HASH_RESULT_LENGTH; case N8_HMAC_MD5_96: case N8_HMAC_SHA1_96: return HMAC_96_HASH_RESULT_LENGTH; case N8_HASH_NONE: return 0; default: return -1; } } /* N8_GetHashLength */ /***************************************************************************** * N8_ComputeEncryptedLength *****************************************************************************/ /** @ingroup n8_ssltls * @brief For a given message size, hash length and cipher, compute the * length of the encrypted message including padding. * * @param size RO: size of the message * @param hashLen RO: length of the hash * @param cipher RO: cipher to use * * @par Externals * None * * @return * Length of the encrypted message (size + hash length + padding). * Returns -1 if the cipher is not recognized. * @par Errors * None * * @par Assumptions * None *****************************************************************************/ short int N8_ComputeEncryptedLength(int size, int hashLen, N8_Cipher_t cipher) { int el = -1; switch (cipher) { case N8_CIPHER_DES: el = (size + hashLen + 8) & ~0x07; break; case N8_CIPHER_ARC4: el = size + hashLen; break; default: break; } return el; } /* N8_ComputeEncryptedLength */ /* local functions */ /********************************************************************** * resultHandlerSSLTLSEncrypt * * Description: * This function is called by the Public Key Request Queue handler when * either the request is completed successfully and all the commands * copied back to the command blocks allocated by the API, or when * the Simon has encountered an error with one of the commands such * that the Simon has locked up. * * Note this function will have to be NON-BLOCKING or it will lock up the * queue handler! * * **********************************************************************/ static void resultHandlerSSLTLSEncrypt(API_Request_t* req_p) { N8_Packet_t *packetObj_p = NULL; char *title = "resultHandlerSSLTLSEncrypt"; /* get the packet object pointer from the request */ packetObj_p = (N8_Packet_t *) req_p->postProcessingData_p; if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK) { DBG(("%s call-back with success\n", title)); /* copy the results back */ if (req_p->copyBackFrom_p != NULL && req_p->copyBackTo_p != NULL && req_p->copyBackSize != 0) { memcpy(req_p->copyBackTo_p, req_p->copyBackFrom_p, req_p->copyBackSize); } /* Reload the IV in the cipher info if needed */ if (packetObj_p->contextHandle.inUse == N8_FALSE) { int IVOffset = req_p->postProcessBuffer[0]; memcpy(&(packetObj_p->cipherInfo.IV), &(req_p->copyBackFrom_p[IVOffset]), N8_DES_KEY_LENGTH); } } else { /* an error has occured. roll back the sequence number if we are not * using context memory. */ /* if we are not using the context */ if (packetObj_p->contextHandle.inUse == N8_FALSE) { /* decrement the sequence number to return it to its previous value */ if (packetObj_p->cipherInfo.sequence_number[1] == 0) { /* decrement the sequence number ms */ packetObj_p->cipherInfo.sequence_number[0]--; } /* decrement the sequence number ls */ packetObj_p->cipherInfo.sequence_number[1]--; } RESULT_HANDLER_WARNING(title, req_p); } /* do not free the postProcessingData_p as it is a the packetObject * controlled by the user */ /* do not free the request in the result handler. it is done by the event * processor. */ } /* resultHandlerSSLTLSEncrypt */ /********************************************************************** * resultHandlerSSLTLSDecrypt * * Description: * This function is called by the Public Key Request Queue handler when * either the request is completed successfully and all the commands * copied back to the command blocks allocated by the API, or when * the Simon has encountered an error with one of the commands such * that the Simon has locked up. * * Note this function will have to be NON-BLOCKING or it will lock up the * queue handler! * * **********************************************************************/ static void resultHandlerSSLTLSDecrypt(API_Request_t* req_p) { char *title = "resultHandlerSSLTLSDecrypt"; N8_Packet_t *packetObj_p = NULL; N8_SSL_Post_Decrypt_Data_t *postData_p = NULL; N8_SSLTLSPacket_t *resultPacket_p; EA_SSL30_DECRYPT_RESULT_CMD_BLOCK_t *cmd_p; int i; short int originalLength; N8_Buffer_t *buf_p; char padLength=0; char *data_p; postData_p = (N8_SSL_Post_Decrypt_Data_t *) req_p->postProcessingData_p; packetObj_p = postData_p->packetObj_p; if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK) { DBG(("%s call-back with success\n", title)); /* get the packet object pointer from the request */ resultPacket_p = postData_p->resultPacket_p; /* copy back the computed mac */ /* isolate the command block */ cmd_p = (EA_SSL30_DECRYPT_RESULT_CMD_BLOCK_t *) req_p->EA_CommandBlock_ptr; /* the copy back should come from the last command block */ cmd_p = &cmd_p[req_p->numNewCmds - 1]; /* If the computedMAC_p parameter from N8_EA_DV is NULL */ /* then don't copy back the MAC value as the user doesn't want it */ if (postData_p->computedMAC_p != NULL ) { buf_p = postData_p->computedMAC_p; for (i = 0; i < postData_p->macLength / sizeof(uint32_t); i++) { uint32_to_BE(cmd_p->mac[i], &buf_p[i*4]); } } /* check the mac mismatch flag and set the verify value */ *(postData_p->verify_p) = ((cmd_p->mismatch & EA_Result_MAC_Mismatch) == 0) ? N8_TRUE : N8_FALSE; /* set the length in the return packet. */ /* data_p = (char *) &resultPacket_p[SSLTLS_DATA_OFFSET]; */ data_p = (char *) req_p->copyBackFrom_p; if (packetObj_p->packetCipher != N8_CIPHER_ARC4) { padLength = data_p[postData_p->encryptedLength - 1] + 1; } originalLength = postData_p->encryptedLength - postData_p->macLength - padLength; /* postData_p->returnLength = htons(originalLength); */ SSLTLS_SET_LENGTH(resultPacket_p, originalLength); /* copy the results back */ /* memcpy(req_p->copyBackTo_p, req_p->copyBackFrom_p, * req_p->copyBackSize); */ if (postData_p->copyData == N8_TRUE) { memcpy(req_p->copyBackTo_p, req_p->copyBackFrom_p, postData_p->encryptedLength); } /* Reload the IV in the cipher info if needed */ if (packetObj_p->contextHandle.inUse == N8_FALSE) { memcpy(&(packetObj_p->cipherInfo.IV), &(postData_p->nextIV), N8_DES_KEY_LENGTH); } } else { /* an error has occured. roll back the sequence number if we are not * using context memory. */ /* if we are not using the context */ if (packetObj_p->contextHandle.inUse == N8_FALSE) { /* decrement the sequence number to return it to its previous value */ if (packetObj_p->cipherInfo.sequence_number[1] == 0) { /* decrement the sequence number ms */ packetObj_p->cipherInfo.sequence_number[0]--; } /* decrement the sequence number ls */ packetObj_p->cipherInfo.sequence_number[1]--; } RESULT_HANDLER_WARNING(title, req_p); } /* free the post processing data holder */ /*N8_UFREE(req_p->postProcessingData_p);*/ /* do not free the request in the result handler. it is done by the event * processor. */ } /* resultHandlerSSLTLSDecrypt */