/*- * 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_hash.c,v 1.1 2008/10/30 12:02:14 darran Exp $"; /*****************************************************************************/ /** @file n8_hash.c * @brief Hashing functionality. * * Implementation of all public functions dealing with management of * hashs. * * References: * MD5: RFC1321 "The MD5 Message-Digest Algorithm", R. Rivest, 4/92 * SHA-1: FIPS Pub 180-1,"Secure Hash Standard", US Dept. of Commerce, * 4/17/95 * HMAC: RFC2104 "HMAC: Keyed-Hashing for Message Authentication", H. Krawczyk, * 2/97. * *****************************************************************************/ /***************************************************************************** * Revision history: * 07/28/03 brr Removed obsolete #ifdefs. (Bug 918) * 07/01/03 brr Added option to use no hashing algorithm. * 05/19/03 brr Use post processing buffer in API request instead of * performing a malloc for it. * 09/10/02 brr Set command complete bit on last command block. * 08/13/02 brr Correctly size hashedKey array. * 08/06/02 bac Fixed Bug #842 -- user's cipher info was being modified. * 05/20/02 brr Free the request for all error conditions. * 05/15/02 brr Removed call to n8_addSubRequest. * 05/07/02 msz New interface for QUEUE_AND_CHECK for new synchronous support. * 05/01/02 brr Memset data segment after return from createEARequestBuffer. * 03/26/02 brr Allocate the data buffer as part of the API request. * 02/28/02 brr Do not include any QMgr include files. * 02/25/02 brr Removed last of the QMgr references. * 02/22/02 spm Converted printf's to DBG's. Added include of n8_OS_intf.h. * 02/21/02 brr Removed references to QMgr_get_valid_unit_num. * 01/23/02 bac Correctly initialize for HMAC by setting the Nl and opad_Nl * values and by setting the hashedHMACKey. * 01/22/02 bac Added code to use software to do SSL and HMAC precomputes. * 01/21/02 bac Changes to support new kernel allocation scheme. * 01/18/02 bac Fixed a problem with kernel memory allocation sizing. * 01/18/02 bac Corrected a bug in the setting of the hashed HMAC key. If the * key was odd in size, the final byte was being dropped. * (BUG #482). Also removed a debugging message that was * inadvertantly left in (BUG #479). * 01/16/02 bac Several routines were allocating the maximum size allowed for * hashing when kernel memory was needed. This was grossly * inefficient and slow. The routines were changed to only * allocate the exact amount needed. * 01/14/02 bac Changed resultHandlerHMACInit to copy the byte-swapped results * back to the kernel memory context for proper formatting in the * subsequent load context request. * 01/12/02 bac Removed all blocking calls within a single API method. This * required the restructuring of the N8_HashInitialize, * N8_HashPartial, and N8_HashEnd calls, especially as they dealt * with HMAC. (BUG #313) * 11/24/01 brr Removed include of obsolete EA & PK specifice Queue files. * 11/15/01 mel Fixed bug #291 : N8_HashInitialize does not modify event * structure * 11/12/01 hml Added unitID to initMD5 and initSHA1. * 11/12/01 hml Added structure verification: bug #261 * 11/08/01 mel Fixed bug #289 : by passing unitID parameter * 11/08/01 mel Fixed bug# 272: N8_IKEEncryptKeyExpand and * N8_IKEKeyMaterialExpand seg faults * 11/08/01 mel Fixed bug# 271: N8_IKEEncryptKeyExpand and * N8_IKEKeyMaterialExpand returns incorrect error code for * outputLength=0. * 11/06/01 dkm Added null error check to MD5_/SHA1_Init. * 10/30/01 bac Removed incrementHashObjectLengths and replaced with shared * function n8_incrLength64 * 10/22/01 mel Re-designed HMAC to make it non-blocking. But it will remain * blocking for HMAC or message longer than 64. * 10/19/01 hml Fixed merge issues. * 10/16/01 mel Made computeSSLHandshakeHash non-bloking. * 10/16/01 spm IKE APIs: removed key physical addr parms in cb calls. * 10/15/01 spm IKE APIs: removed unnecessary IKE result handlers. * msg_length is now compared to N8_MAX_HASH_LENGTH as * NOT N8_MAX_KEY_LENGTH. Miscellaneous optimiations/ * simplifications brought up in the IKE API code review. * Removed unnecessary memsets. User objects are added to * free list before kernel objects are mallocated to avoid * kernel malloc leaks. Changed if-else on alg to switch * on alg. Removed virtual pointer to msg in cb calls. * Had to keep the virtual pointer to key, since the * key has to be copied into the cb itself. Added * N8_64BYTE_IKE_KEY_LIMIT. * 10/15/01 bac Corrected problems with N8_HandshakeHashPartial due to * incorrectly handling computeResidual when the hashing length * was zero. * 10/15/01 mel Redesigned computeSSLhandshake. * 10/11/01 hml Use n8_strdup instead of strdup in getRoleString(). * 10/11/01 hml Added use of RESULT_HANDLER_WARNING for the * N8_HandshakeHashEnd result handler. * 10/10/01 hml Added N8_HashCompleteMessage and added support for the * TLS modes to N8_HandshakeHashEnd. * 10/10/01 brr Free resources in N8_HashEnd if error encountered. * 10/02/01 bac Added use of RESULT_HANDLER_WARNING in all result handlers. * 10/01/01 hml Updated rest of hash interfaces for multiple chips. * 09/26/01 hml Updated to support multiple chips. The N8_HashInitialize, * N8_TLSKeyMaterialHash and N8_SSLKeyMaterialHash were changed. * 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/18/01 bac Updated calls to createEARequestBuffer to pass the number of * commands to be allocated. * 09/17/01 spm Truncated lines >80 chars. * 09/12/01 mel Deleted N8_UNIMPLEMENTED_FUNCTION in N8_HashPartial for HMAC. * 09/10/01 spm Fixed memory leak in N8_IKEEncryptKeyExpand (0 byte not * allocated) * 09/08/01 spm IKE APIs: Swapped order of alg and hashInfo args. * 09/07/01 spm Added IKE APIs * 09/07/01 bac Fixed bug where we weren't checking the return code from a * call to N8_HashPartial in N8_HandshakeHashPartial. * (BUG #159) * 09/07/01 bac Fixed a comment in N8_HashPartial which had the wrong size * limit for data sent to that method. (BUG #60) * 09/06/01 bac Added include of to silence warning. * 08/24/01 bac Removed DBG prints of unterminated buffers. * 08/14/01 bac Fixed memcpy bugs in computeHMAC where the wrong number of * bytes were being moved. Also determined HMAC hashes are not * implemented correctly and have disallowed the use of * N8_HashPartial and N8_HashEnd with HMAC algorithms. This * partially fixes Bug #160. * 08/01/01 bac Changed MIN to N8_MIN to avoid compilation warnings. * 07/31/01 bac Added call to N8_preamble for all public interfaces. * 07/20/01 bac Changed calls to create__RequestBuffer to pass the chip id. * 07/09/01 bac Bug #115 and Bug #116 -- fixed N8_HandshakeHashPartial and * N8_HandshakeHashEnd to use the user-supplied event when * making the final API call. All other API calls made by * these methods remain synchronous but the final one is * non-blocking and correctly indicates the status of * the original call. This is not the final solution. * 07/02/01 mel Fixed comments. * 06/28/01 bac Added HANDLE_EVENT calls as necessary. * 06/28/01 bac Removed calls to 'freeRequest' in the result handlers as * that belongs in the EventCheck routine. * 06/27/01 mel Added init of hash object in computeHMAC between pad0 and * pad 1 compute * 06/25/01 mel In N8_TLSKeyMaterialHash added check : * if the sum of KeyLength, LabelLength, and SeedLength is > * 18 Kbytes, return ERROR. * 06/25/01 bac More changes for QMgr v.1.0.1 * 06/19/01 bac Correct use of kernel memory. * 06/18/01 mel Added N8_TLSKeyMaterialHash API. * 06/17/01 bac Free request upon failure in N8_SSLKeyMaterialHash * 05/30/01 bac Doxygenation. * 05/30/01 bac Test for hashingLength==0 in HashEnd to avoid the suspicion * of memory alloc problems (malloc(0)). * 05/24/01 dws Fixed the pointer arithmetic in the copy of the * N8_HashPartial result to the N8_HashObject_t iv field in * ResultHandlerHashPartial. * 05/19/01 bac Corrected the freeing of postProcessingData. Since the * data passed in this pointer may be user data or local data * sometimes it is appropriate to free it other times it isn't. * Thus, the decision needs to live in the resultHandler, not * the freeRequest utility. * 05/19/01 bac Fixed memory leak. * 05/18/01 mel Fix bug with wrong size memory allocation. * 05/18/01 bac Converted to N8_xMALLOC and N8_xFREE * 05/15/01 bac Fixed a bug where pointers were not initialized to NULL but * were freed under error conditions. * 05/14/01 bac Fixed the copy from results_p to IV to copy the right * amount whether MD5 or SHA-1. * 05/09/01 dws Changed the way that the result bytes are loaded into the * hash object IV in N8_HashPartial. It now uses a series of * BE_to_uint32 operations instead of memcpy. * 04/30/01 dkm Modified N8_HashPartial so that if message is too small * to start a hash, the message is appended onto the * residual and residualLength is updated. * 04/30/01 bac changed printResult to printN8Buffer * 04/26/01 bac Completion of handshake hash functions. * 04/24/01 bac Removed printResult definition. It is now * printN8Buffer in n8_util. * 04/09/01 bac Added functionality for N8_HashInitialize * 03/29/01 bac Original version. ****************************************************************************/ /** @defgroup n8_hash Hashing Functions */ #include "n8_pub_errors.h" #include "n8_hash.h" #include "n8_ea_common.h" #include "n8_cb_ea.h" #include "n8_enqueue_common.h" #include "n8_util.h" #include "n8_API_Initialize.h" #include "n8_precompute.h" #include "n8_OS_intf.h" #include /* * Defines for values and macros */ #define MD5_PAD_LENGTH (48) #define SHA1_PAD_LENGTH (40) /* * Prototypes of local static functions */ static N8_Status_t computeTLSHandshakeHash(N8_HashObject_t *md5Obj_p, N8_HashObject_t *sha1Obj_p, const N8_HashProtocol_t protocol, const char *roleString_p, const N8_Buffer_t *key_p, const unsigned int keyLength, N8_Buffer_t *md5Result_p, N8_Buffer_t *sha1Result_p, N8_Event_t *event_p); static char *getRoleString(const N8_HashProtocol_t protocol, const N8_HashRole_t role); static N8_Status_t computeSSLHandshakeHash(N8_HashObject_t *hObjMD5_p, N8_HashObject_t *hObjSHA_p, const char *roleString_p, const N8_Buffer_t *key_p, const unsigned int keyLength, N8_Buffer_t *resultMD5_p, N8_Buffer_t *resultSHA_p, N8_Event_t *event_p); static N8_Status_t computeResidual(N8_HashObject_t *obj_p, const N8_Buffer_t *msg_p, N8_Buffer_t *hashMsg_p, const unsigned int msgLength, unsigned int *hashingLength); N8_Status_t n8_initializeHMAC(N8_Buffer_t *HMACKey, uint32_t HMACKeyLength, N8_HashObject_t *hashObj_p, N8_Event_t *event_p); N8_Status_t n8_HMACHashEnd_req(N8_HashObject_t *obj_p, N8_Buffer_t *result_p, API_Request_t **req_pp); /* * local structure definitions */ typedef struct { N8_Buffer_t *result_p; N8_Buffer_t *dest_p; int length; } N8_SSLKeyHashResults_t; typedef struct { int outputLength; N8_Buffer_t *result_p; N8_Buffer_t *prS_p[2]; } N8_TLSKeyHashResults_t; typedef struct { uint32_t outputLength; N8_Buffer_t *result_p; /* this buffer is 3*outputLength bytes long */ N8_Buffer_t *SKEYIDd_p; N8_Buffer_t *SKEYIDa_p; N8_Buffer_t *SKEYIDe_p; } N8_IKESKEYIDExpandResults_t; typedef struct { N8_Buffer_t *MD5_results_p; N8_HashObject_t *MD5_obj_p; N8_Buffer_t *SHA_results_p; N8_HashObject_t *SHA_obj_p; } N8_HandshakePartialResults_t; typedef struct { N8_HashProtocol_t protocol; N8_Buffer_t *MD5Result_p; N8_Buffer_t *SHA1Result_p; N8_Buffer_t *resMD5_p; N8_Buffer_t *resSHA1_p; N8_Buffer_t *resMD5PRF_p; N8_Buffer_t *resSHA1PRF_p; } N8_TLSHandshakeHashResults_t; typedef struct { N8_Buffer_t *to_resultSHA_p; N8_Buffer_t *from_end_resultSHA_p; N8_Buffer_t *to_objSHA_p; N8_Buffer_t *from_ivSHA_p; int length_SHA; N8_Buffer_t *to_resultMD5_p; N8_Buffer_t *from_end_resultMD5_p; N8_Buffer_t *to_objMD5_p; N8_Buffer_t *from_ivMD5_p; int length_MD5; } N8_HandshakeEndResults_t; typedef struct { N8_Buffer_t *result1_p; N8_Buffer_t *result2_p; } N8_HMACResults_t; /* * Static Methods */ static void n8_setHashedHMACKey(N8_HashObject_t *obj_p, N8_Buffer_t *key_p, unsigned int keyLength) { N8_Buffer_t *tmp_p; int i; int iterations = CEIL(keyLength, sizeof(uint32_t)); tmp_p = (N8_Buffer_t *) obj_p->hashedHMACKey; /* copy the key to the hashedHMACKey */ memcpy(tmp_p, key_p, keyLength); /* pad the remainder with zeroes */ memset(&tmp_p[keyLength], 0x0, sizeof(obj_p->hashedHMACKey)-keyLength); /* now, byte-swap the key in place */ for (i = 0; i < iterations; i++) { obj_p->hashedHMACKey[i] = BE_to_uint32(tmp_p); tmp_p += 4; } } /* n8_setHashedHMACKey */ /********************************************************************** * resultHandlerHashPartial * * 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 resultHandlerHashPartial(API_Request_t* req_p) { N8_Buffer_t *iv_p; N8_HashObject_t *obj_p; int i; const char *title = "resultHandlerHashPartial"; if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK) { DBG(("%s call-back with success\n", title)); /* the partial hash has been pre-computed. the results must now * be copied back into the hash object */ obj_p = (N8_HashObject_t *) req_p->copyBackTo_p; iv_p = req_p->copyBackFrom_p; #ifdef N8DEBUG printf("result(%d bytes): ", obj_p->hashSize); for (i=0; ihashSize / sizeof(uint32_t); i+=4) { printf("%08x ", *(uint32_t *)(&iv_p[i])); } printf("\n"); #endif for (i = 0; i < obj_p->hashSize / sizeof(uint32_t); i++) { obj_p->iv[i] = BE_to_uint32(iv_p); iv_p += 4; } } else { RESULT_HANDLER_WARNING(title, req_p); } /* freeRequest(req_p); */ } /* resultHandlerHashPartial */ /********************************************************************** * resultHandlerTLSKeyHash * * 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 resultHandlerTLSKeyHash(API_Request_t* req_p) { int i; N8_TLSKeyHashResults_t *keyResults_p; const char *title = "resultHandlerTLSKeyHash"; if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK) { DBG(("%s call-back with success\n", title)); keyResults_p = (N8_TLSKeyHashResults_t* ) req_p->postProcessingData_p; /* produce the key material by XOR-ing pseudorandom streams */ for (i = 0; i < keyResults_p->outputLength; i++) { /* when bug in chip is fixed, don't forget to change index to i+16 * and i+20 */ keyResults_p->result_p[i] = (keyResults_p->prS_p[0][i] ^ keyResults_p->prS_p[1][i]); } } else { RESULT_HANDLER_WARNING(title, req_p); } } /* resultHandlerTLSKeyHash */ /***************************************************************************** * resultHandlerIKESKEYIDExpand *****************************************************************************/ /** @ingroup n8_hash * @brief Handles result for N8_IKESKEYIDExpand * * 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! * * @param req_p RW: pointer to API request structure * * @par Externals: * * @return * void * * @par Errors: * None. * * @par Locks: * None. * * @par Assumptions: *****************************************************************************/ static void resultHandlerIKESKEYIDExpand(API_Request_t* req_p) { N8_IKESKEYIDExpandResults_t *keyResults_p; const char *title = "resultHandlerIKESKEYIDExpand"; if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK) { DBG(("%s call-back with success\n", title)); keyResults_p = (N8_IKESKEYIDExpandResults_t *) req_p->postProcessingData_p; memcpy(keyResults_p->SKEYIDd_p, keyResults_p->result_p, keyResults_p->outputLength); memcpy(keyResults_p->SKEYIDa_p, keyResults_p->result_p+keyResults_p->outputLength, keyResults_p->outputLength); memcpy(keyResults_p->SKEYIDe_p, keyResults_p->result_p+2*keyResults_p->outputLength, keyResults_p->outputLength); } else { RESULT_HANDLER_WARNING(title, req_p); } } /* resultHandlerIKESKEYIDExpand */ /***************************************************************************** * resultHandlerTLSHandshakeHash *****************************************************************************/ /** @ingroup n8_hash * @Handles the result for the N8_TLS_FINISH and N8_TLS_CERT modes in * N8_HandshakeHashEnd. * * This function is called by the EA 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 hardware has encountered an error with one of the commands such * that the hardware has locked up. Note that the function is finishing the * HandshakeHashEnd protocol according to section 5 of RFC 2246. * * @param req_p RW: pointer to API request structure. * * @par Externals: * None. * * @return * Void. * * @par Errors: * None. * * @par Locks: * None. * * @par Assumptions: *****************************************************************************/ static void resultHandlerTLSHandshakeHash(API_Request_t* req_p) { N8_TLSHandshakeHashResults_t *data_p = NULL; int i; unsigned int dataBuffer[NUM_WORDS_TLS_RESULT]; unsigned int *ptr1; unsigned int *ptr2; const char *title = "resultHandlerTLSHandshakeHash"; if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK) { DBG(("resultHandlerTLSHandshakeHash call-back with success\n")); data_p = (N8_TLSHandshakeHashResults_t *) req_p->postProcessingData_p; if (data_p->protocol == N8_TLS_CERT) { memcpy(data_p->MD5Result_p, data_p->resMD5_p, MD5_HASH_RESULT_LENGTH); memcpy(data_p->SHA1Result_p, data_p->resSHA1_p, SHA1_HASH_RESULT_LENGTH); } else { /* This can only be the N8_TLS_FINISH case. This algorithm is defined in section 5 of RFC 2246 */ /* We need to ignore the first sample from each of the MD5 and SHA1 results */ ptr1 = (unsigned int *) (data_p->resMD5PRF_p + MD5_HASH_RESULT_LENGTH); ptr2 = (unsigned int *) (data_p->resSHA1PRF_p + SHA1_HASH_RESULT_LENGTH); /* Now we Xor 12 bytes worth of data. Read the RFC ... */ for (i = 0; i < NUM_WORDS_TLS_RESULT; i++) { dataBuffer[i] = (*ptr1) ^ (*ptr2); ptr1 ++; ptr2 ++; } memcpy(data_p->MD5Result_p, dataBuffer, MD5_HASH_RESULT_LENGTH); } } else { /* Unknown error */ RESULT_HANDLER_WARNING(title, req_p); } N8_UFREE(req_p->postProcessingData_p); /* freeRequest(req_p); */ } /* resultHandlerTLSHandshakeHash */ /***************************************************************************** * resultHandlerHandshakePartial ****************************************************************************/ /** @ingroup n8_hash * @brief Handles the result for the HandshakePartial * * 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 resultHandlerHandshakePartial(API_Request_t* req_p) { const char *title = "resultHandlerHandshakePartial"; N8_Buffer_t *md5_res_p; N8_Buffer_t *sha_res_p; N8_HashObject_t *md5_obj_p; N8_HashObject_t *sha_obj_p; N8_HandshakePartialResults_t *callBackData_p; int i; if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK) { DBG(("%s call-back with success\n", title)); /* the partial hash has been pre-computed. the results must now * be copied back into the hash object */ callBackData_p = (N8_HandshakePartialResults_t *) req_p->postProcessingData_p; /* ensure the call back data is not null */ if (callBackData_p == NULL) { DBG(("ERROR: %s call-back with NULL callBackData_p.", title)); } else { md5_obj_p = callBackData_p->MD5_obj_p; md5_res_p = callBackData_p->MD5_results_p; sha_obj_p = callBackData_p->SHA_obj_p; sha_res_p = callBackData_p->SHA_results_p; for (i = 0; i < md5_obj_p->hashSize / sizeof(uint32_t); i++) { md5_obj_p->iv[i] = BE_to_uint32(md5_res_p); md5_res_p += 4; } for (i = 0; i < sha_obj_p->hashSize / sizeof(uint32_t); i++) { sha_obj_p->iv[i] = BE_to_uint32(sha_res_p); sha_res_p += 4; } } } else { RESULT_HANDLER_WARNING(title, req_p); } /* DO NOT free request (req_p) here */ } /* resultHandlerHandshakePartial */ /********************************************************************** * resultHandlerHandshakeEnd * * 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 resultHandlerHandshakeEnd(API_Request_t* req_p) { char title[] = "resultHandlerHandshakeEnd"; N8_Buffer_t *endresultmd5_p; N8_Buffer_t *endresultsha_p; N8_Buffer_t *resultmd5_p; N8_Buffer_t *resultsha_p; N8_HashObject_t *objmd5_p; N8_HashObject_t *objsha_p; N8_HandshakeEndResults_t *callBackData_p = (N8_HandshakeEndResults_t *) req_p->postProcessingData_p; if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK ) { DBG(("%s call-back with success\n", title)); /* the partial hash has been pre-computed. the results must now * be copied back into the hash object */ resultsha_p = callBackData_p->to_resultSHA_p; endresultsha_p = callBackData_p->from_end_resultSHA_p; objsha_p = (N8_HashObject_t *) callBackData_p->to_objSHA_p; resultmd5_p = callBackData_p->to_resultMD5_p; endresultmd5_p = callBackData_p->from_end_resultMD5_p; objmd5_p = (N8_HashObject_t *) callBackData_p->to_objMD5_p; memcpy(resultmd5_p, endresultmd5_p, objmd5_p->hashSize); memcpy(resultsha_p, endresultsha_p, objsha_p->hashSize); } else { RESULT_HANDLER_WARNING(title, req_p); } } /* resultHandlerHandshakeEnd */ /***************************************************************************** * computeResidual ****************************************************************************/ /** @ingroup n8_hash * @brief Finish compute residual data. * * @param obj_p RW: Hash object to store intermediate results. * @param msg_p RO: Pointer to the message to be hashed. * @param msgLength RO: Length of message to be hashed. * @param event_p RO: Pointer to event for async calls. Null for * synchronous call. * @par Externals: * None * * @return * Status code of type N8_Status. * * @par Errors: * N8_STATUS_OK: A-OK
* N8_INVALID_INPUT_SIZE: message passed was larger than allowed * limit of N8_MAX_HASH_LENGTH
* @par Assumptions: * None ****************************************************************************/ static N8_Status_t computeResidual(N8_HashObject_t *obj_p, const N8_Buffer_t *msg_p, N8_Buffer_t *hashMsg_p, const unsigned int msgLength, unsigned int *hashingLength) { int totalLength; /* length of message + residual */ int nextResidualLength; int hashFromMsgLength; DBG(("computeResidual\n")); totalLength = obj_p->residualLength + msgLength; nextResidualLength = totalLength % N8_HASH_BLOCK_SIZE; *hashingLength = totalLength - nextResidualLength; hashFromMsgLength = *hashingLength - obj_p->residualLength; if (*hashingLength == 0) { /* residualLength + msgLength is less than N8_HASH_BLOCK_SIZE. Just append msg to residual. */ memcpy(&(obj_p->residual[obj_p->residualLength]), msg_p, msgLength); obj_p->residualLength = nextResidualLength; DBG(("Just append msg to residual\n")); DBG(("hash length: %d\n", *hashingLength)); DBG(("msg to hash: %s\n", hashMsg_p)); DBG(("residual length: %d\n", nextResidualLength)); DBG(("residual: %s\n", obj_p->residual)); return N8_STATUS_OK; } /* prepend the residual, if any */ if (obj_p->residualLength > 0) { memcpy(hashMsg_p, obj_p->residual, obj_p->residualLength); } /* now copy the hashable portion of the incoming message */ if (hashFromMsgLength > 0) { memcpy(&(hashMsg_p[obj_p->residualLength]), msg_p, hashFromMsgLength); } /* finally, copy the new residual */ memset(obj_p->residual, 0x0, N8_MAX_RESIDUAL_LEN); if (nextResidualLength > 0) { memcpy(obj_p->residual, &(msg_p[msgLength - nextResidualLength]), nextResidualLength); } obj_p->residualLength = nextResidualLength; n8_incrLength64(&obj_p->Nh, &obj_p->Nl, *hashingLength); DBG(("hash length: %d\n", *hashingLength)); DBG(("residual length: %d\n", nextResidualLength)); DBG(("computeResidual - OK\n")); return N8_STATUS_OK; } /* computeResidual */ /***************************************************************************** * n8_initializeHMAC_req ****************************************************************************/ /** @ingroup n8_hash * @brief Generate the HMAC initialization request. * * @param HMACKey RW: HMAC key * @param HMACKeyLength RW: HMAC key length * @param hashObj_p RW: object to be initialized * @param result_p RW: optional pointer to results area. Used for * IPsec only. * @param req_pp RW: Pointer to request pointer. * * @par Errors * N8_INVALID_HASH - the specified hash is not valid * N8_INVALID_OBJECT - object passed was null
* N8_INVALID_KEY_SIZE - the value of HMACKeyLength is less than 0 * and greater than 18 KBytes. * * @par Assumptions * None ****************************************************************************/ N8_Status_t n8_initializeHMAC_req(N8_Buffer_t *HMACKey, uint32_t HMACKeyLength, N8_HashObject_t *hashObj_p, void *result_p, N8_Buffer_t **ctx_pp, uint32_t *ctxa_p, API_Request_t **req_pp) { API_Request_t *headReq_p = NULL; /* head pointer to request list */ N8_Status_t ret = N8_STATUS_OK; DBG(("n8_initializeHMAC\n")); do { N8_Buffer_t hashedKey[N8_HASH_BLOCK_SIZE]; if (result_p == NULL) { ret = n8_precompute_tls_ipad_opad(hashObj_p->type, HMACKey, hashedKey, &HMACKeyLength, hashObj_p->ipadHMAC_iv, hashObj_p->opadHMAC_iv); memcpy(hashObj_p->iv, hashObj_p->ipadHMAC_iv, 20); } else { N8_CipherInfo_t *obj_p = (N8_CipherInfo_t *) result_p; ret = n8_precompute_tls_ipad_opad(hashObj_p->type, HMACKey, hashedKey, &HMACKeyLength, obj_p->key.IPsecKeyDES.ipad, obj_p->key.IPsecKeyDES.opad); } CHECK_RETURN(ret); hashObj_p->opad_Nl = 64; hashObj_p->Nl = 64; n8_setHashedHMACKey(hashObj_p, hashedKey, HMACKeyLength); } while (FALSE); *req_pp = headReq_p; return ret; } /* n8_initializeHMAC_req */ /***************************************************************************** * n8_initializeHMAC ****************************************************************************/ /** @ingroup n8_hash * @brief Compute HMAC for future hashing and store results in context memory * if needed. * * @param HMACKey RW: HMAC key * @param HMACKeyLength RW: HMAC key length * @param hashObj_p RW: object to be initialized * @param event_p RW: Pointer to asynchronous event structure. * * @par Errors * N8_INVALID_HASH - the specified hash is not valid * N8_INVALID_OBJECT - object passed was null
* N8_INVALID_KEY_SIZE - the value of HMACKeyLength is less than 0 * and greater than 18 KBytes. * * @par Assumptions * None ****************************************************************************/ N8_Status_t n8_initializeHMAC(N8_Buffer_t *HMACKey, uint32_t HMACKeyLength, N8_HashObject_t *hashObj_p, N8_Event_t *event_p) { API_Request_t *req_p = NULL; N8_Status_t ret = N8_STATUS_OK; uint32_t ctx_a; /* unused dummy value */ N8_Buffer_t *ctx_p; /* unused dummy value */ DBG(("N8_HashPartial\n")); do { /* generate the request */ ret = n8_initializeHMAC_req(HMACKey, HMACKeyLength, hashObj_p, NULL, &ctx_p, &ctx_a, &req_p); CHECK_RETURN(ret); if (req_p == NULL) { if (event_p != NULL) { N8_SET_EVENT_FINISHED(event_p, N8_EA); } break; } QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up resources */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } return ret; } /* n8_initializeHMAC */ /***************************************************************************** * N8_HashInitialize ****************************************************************************/ /** @ingroup n8_hash * @brief Initialize a HashObject for future hashing. * * Hashing functions require a HashObject to maintain state across * calls. Before use, the object must be initialized to set the * algorithm and algorith-specific initial conditions. * * @param hashObj_p RW: object to be initialized * @param alg RO: algorithm to be used with this object * @param hashInfo_p RO: pointer to hash info structure for HMAC key. * @par Externals * None * * @return * N8_Status_t * * @par Errors * N8_INVALID_HASH - the specified hash is not valid * N8_INVALID_OBJECT - object passed was null
* N8_INVALID_OBJECT - The unit value specified was invalid
* N8_INVALID_KEY_SIZE - the value of HMACKeyLength is less than 0 and * greater than 18 KBytes. * * @par Assumptions * None ****************************************************************************/ N8_Status_t N8_HashInitialize(N8_HashObject_t *hashObj_p, const N8_HashAlgorithm_t alg, const N8_HashInfo_t *hashInfo_p, N8_Event_t *event_p) { N8_Status_t ret = N8_STATUS_OK; DBG(("N8_HashInitialize\n")); do { ret = N8_preamble(); CHECK_RETURN(ret); CHECK_OBJECT(hashObj_p, ret); hashObj_p->unitID = hashInfo_p->unitID; ret = n8_setInitialIVs(hashObj_p, alg, hashObj_p->unitID); CHECK_RETURN(ret); switch (hashObj_p->type) { case N8_HMAC_MD5: case N8_HMAC_MD5_96: case N8_HMAC_SHA1: case N8_HMAC_SHA1_96: /* check the key length to make sure it is in range */ if (hashInfo_p->keyLength > N8_MAX_HASH_LENGTH) { ret = N8_INVALID_KEY_SIZE; break; } CHECK_OBJECT(hashInfo_p, ret); ret = n8_initializeHMAC(hashInfo_p->key_p, hashInfo_p->keyLength, hashObj_p, event_p); break; default: break; } } while (FALSE); DBG(("N8_HashInitialize after loop\n")); if (ret == N8_STATUS_OK) { /* Set the structure ID */ hashObj_p->structureID = N8_HASH_STRUCT_ID; if ((event_p != NULL) && ((alg == N8_MD5) || (alg == N8_SHA1))) { N8_SET_EVENT_FINISHED(event_p, N8_EA); } } DBG(("N8_HashInitialize - OK\n")); return ret; } /* N8_HashInitialize */ /***************************************************************************** * n8_HashPartial_req *****************************************************************************/ /** @ingroup n8_hash * @brief Generate a request for a N8_HashPartial. * * The generated request is returned but not queued. * * @param obj_p RW: Pointer to hash object * @param msg_p RO: Pointer to message * @param msgLength RO: Message length in bytes * @param req_pp RW: Pointer to request pointer * * @par Externals * None * * @return * Status * * @par Errors * None * * @par Assumptions * None *****************************************************************************/ N8_Status_t n8_HashPartial_req(N8_HashObject_t *obj_p, const N8_Buffer_t *msg_p, const unsigned int msgLength, const n8_IVSrc_t ivSrc, API_Request_t **req_pp) { N8_Status_t ret = N8_STATUS_OK; unsigned int hashingLength; /* totalLength rounded down to the * next multiple of N8_HASH_BLOCK_SIZE */ N8_Buffer_t *hashMsg_p = NULL; unsigned long hashMsg_a; uint32_t result_a; N8_Buffer_t *result_p = NULL; unsigned int nBytes; do { CHECK_OBJECT(req_pp, ret); *req_pp = NULL; /* set the return request to NULL in case we * have to bail out. */ CHECK_OBJECT(obj_p, ret); CHECK_STRUCTURE(obj_p->structureID, N8_HASH_STRUCT_ID, ret); ret = N8_preamble(); CHECK_RETURN(ret); if (msgLength == 0) { /* this is legal but has no effect. do not change any state * and return successfully. */ break; } /* only after verifying that the message length is non-zero, test for * valid msg_p */ CHECK_OBJECT(msg_p, ret); if (msgLength > N8_MAX_HASH_LENGTH) { ret = N8_INVALID_INPUT_SIZE; break; } CHECK_OBJECT(obj_p, ret); CHECK_OBJECT(msg_p, ret); /* create the EA request */ nBytes = (NEXT_WORD_SIZE(obj_p->hashSize) + NEXT_WORD_SIZE(msgLength + N8_MAX_RESIDUAL_LEN)); ret = createEARequestBuffer(req_pp, obj_p->unitID, N8_CB_EA_HASHPARTIAL_NUMCMDS, resultHandlerHashPartial, nBytes); CHECK_RETURN(ret); /* allocate space for the chip to place the result */ result_a = (*req_pp)->qr.physicalAddress + (*req_pp)->dataoffset; result_p = (N8_Buffer_t *) ((int)(*req_pp) + (*req_pp)->dataoffset); memset(result_p, 0, nBytes); hashMsg_a = result_a + NEXT_WORD_SIZE(obj_p->hashSize); hashMsg_p = result_p + NEXT_WORD_SIZE(obj_p->hashSize); /* * The actual input is concat(residual, *msg_p). Of this, we * only hash multiple lengths of N8_HASH_BLOCK_SIZE and save the * rest for the next time around. * * We compute the residual and message first, since we have nothing to do * if the hashing length is zero. */ ret = computeResidual(obj_p, msg_p, hashMsg_p, msgLength, &hashingLength); CHECK_RETURN(ret); /* if the hashing length is 0, then there is nothing to do for this call. * Set the event status to done (if asynchronous) and return. */ if (hashingLength == 0) { freeRequest(*req_pp); *req_pp = NULL; ret = N8_STATUS_OK; break; } /* set up the copy back data for processing in the result handler */ (*req_pp)->copyBackFrom_p = result_p; (*req_pp)->copyBackTo_p = (void *) obj_p; /* handle messages longer than 64 bytes for HMAC */ ret = cb_ea_hashPartial(*req_pp, (*req_pp)->EA_CommandBlock_ptr, obj_p, ivSrc, hashMsg_a, hashingLength, result_a, NULL /* next command block */, N8_TRUE); CHECK_RETURN(ret); } while (FALSE); return ret; } /* n8_HashPartial_req */ /***************************************************************************** * N8_HashPartial ****************************************************************************/ /** @ingroup n8_hash * @brief Hash a partial message. * * To hash a message over 18 K bytes long, multiple calls to this * function must be made processing chunks of the message. After all * chunks are processed a call to the companion function N8_HashEnd * * @param obj_p RW: Hash object to store intermediate results. * @param msg_p RO: Pointer to the message to be hashed. * @param msgLength RO: Length of message to be hashed. * @param event_p RO: Pointer to event for async calls. Null for * synchronous call. * @par Externals: * None * * @return * Status code of type N8_Status. * * @par Errors: * N8_STATUS_OK: A-OK
* N8_INVALID_INPUT_SIZE: message passed was larger than allowed * limit of N8_MAX_HASH_LENGTH
* @par Assumptions: * None ****************************************************************************/ N8_Status_t N8_HashPartial(N8_HashObject_t *obj_p, const N8_Buffer_t *msg_p, const unsigned int msgLength, N8_Event_t *event_p) { API_Request_t *req_p = NULL; N8_Status_t ret = N8_STATUS_OK; DBG(("N8_HashPartial\n")); do { /* generate the request */ ret = n8_HashPartial_req(obj_p, msg_p, msgLength, N8_IV, &req_p); CHECK_RETURN(ret); if (req_p == NULL) { if (event_p != NULL) { N8_SET_EVENT_FINISHED(event_p, N8_EA); } break; } QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up resources */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } DBG(("N8_HashPartial - OK\n")); return ret; } /* N8_HashPartial */ /***************************************************************************** * n8_HMACHashEnd_req *****************************************************************************/ /** @ingroup n8_hash * @brief Generate request for N8_HashEnd for HMAC algorithms only. * * Recall a HMAC consists of the following: * HMAC = H(o + H(i + msg)) * At the time the end is being called, hash partial for all of the msg has been * called and msg is completely consumed. Some portion of it may be in the * residual. The first step to ending the HMAC is to perform a hash end on the * inner portion. The results of this is guaranteed to be small (16 or 20 * bytes, depending upon the hash algorithm in use). Also note that the * initial i and o values are exactly 64 bytes long, so they are hashed with no * residual. So this reduces the complexity of finishing an HMAC hash to: * res1 = hashEnd(obj loaded with inner IV, residual) * res = hashEnd(obj loaded with outer IV, res1) * * @param obj_p RW: Pointer to hash object. * @param result_p RW: Pointer to results buffer provided by * original caller. * @param req_pp RW: Pointer to request pointer. * * @par Externals * None * * @return * Status * * @par Errors * N8_INVALID_OBJECT, N8_INVALID_HASH * * @par Assumptions * The object algorithm has been pre-screened to be one of the supported HMAC * algorithms. *****************************************************************************/ N8_Status_t n8_HMACHashEnd_req(N8_HashObject_t *obj_p, N8_Buffer_t *result_p, API_Request_t **req_pp) { N8_Status_t ret = N8_STATUS_OK; int hashingLength; N8_Buffer_t *hashMsg_p = NULL; uint32_t hashMsg_a; N8_Buffer_t *kResults_p = NULL; uint32_t kResults_a; N8_Buffer_t *tempResults_p = NULL; uint32_t tempResults_a; API_Request_t *req_p; EA_CMD_BLOCK_t *nextCommandBlock_p = NULL; int nBytes; do { ret = N8_preamble(); CHECK_RETURN(ret); CHECK_OBJECT(req_pp, ret); *req_pp = NULL; /* minimal sanity checking on the hash object */ CHECK_OBJECT(obj_p, ret); CHECK_OBJECT(result_p, ret); CHECK_STRUCTURE(obj_p->structureID, N8_HASH_STRUCT_ID, ret); DBG(("residual length: %d\n", obj_p->residualLength)); DBG(("residual: %s\n", obj_p->residual)); hashingLength = obj_p->residualLength; /* * The input to the final hash is the residual in the hash object. */ /* create the request */ nBytes = NEXT_WORD_SIZE(obj_p->hashSize) + /* final results */ NEXT_WORD_SIZE(obj_p->hashSize) + /* temporary results */ NEXT_WORD_SIZE(hashingLength); /* residual */ ret = createEARequestBuffer(req_pp, obj_p->unitID, 2 * N8_CB_EA_HASHEND_NUMCMDS, resultHandlerGeneric, nBytes); CHECK_RETURN(ret); req_p = *req_pp; kResults_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset); memset(kResults_p, 0, nBytes); kResults_a = req_p->qr.physicalAddress + req_p->dataoffset; tempResults_p = kResults_p + NEXT_WORD_SIZE(obj_p->hashSize); tempResults_a = kResults_a + NEXT_WORD_SIZE(obj_p->hashSize); hashMsg_p = tempResults_p + NEXT_WORD_SIZE(obj_p->hashSize); hashMsg_a = tempResults_a + NEXT_WORD_SIZE(obj_p->hashSize); if (hashingLength != 0) { /* copy the residual, which we know to be non-zero in length */ memcpy(hashMsg_p, obj_p->residual, hashingLength); DBG(("hash length: %d\n", hashingLength)); } else { hashMsg_p = NULL; hashMsg_a = 0; DBG(("hash length: %d\n", hashingLength)); DBG(("msg to hash: none\n")); } /* first, do a hash on the residual */ ret = cb_ea_hashEnd(req_p, /* request */ req_p->EA_CommandBlock_ptr, /* command block pointer */ obj_p, /* object pointer */ N8_IV, /* get the IV from the * regular place */ hashMsg_a, /* message to hash */ hashingLength, /* length of message */ tempResults_a, /* results physical address */ &nextCommandBlock_p, /* next command block pointer */ N8_FALSE); CHECK_RETURN(ret); /* next, create a command request to hash the results that were just * generated */ ret = cb_ea_hashEnd(req_p, /* request */ nextCommandBlock_p, /* command block pointer */ obj_p, /* object pointer */ N8_OPAD, /* get the IV from the opad */ tempResults_a, /* message to hash */ obj_p->hashSize, /* length of message */ kResults_a, /* results physical address */ NULL, /* next command block pointer */ N8_TRUE); CHECK_RETURN(ret); req_p->copyBackSize = obj_p->hashSize; req_p->copyBackFrom_p = kResults_p; req_p->copyBackTo_p = result_p; } while (FALSE); return ret; } /* n8_HMACHashEnd_req */ /***************************************************************************** * n8_HashEnd_req *****************************************************************************/ /** @ingroup n8_hash * @brief Generate the request for a Hash End operation for non-HMAC * algorithms. * * @param obj_p RW: Pointer to hash object * @param result_p RW: Results area * @param req_pp RW: Pointer to request pointer * * @par Externals * None * * @return * * * @par Errors *
* * @par Assumptions *
*****************************************************************************/ N8_Status_t n8_HashEnd_req(N8_HashObject_t *obj_p, N8_Buffer_t *result_p, API_Request_t **req_pp) { N8_Status_t ret = N8_STATUS_OK; int totalLength; int hashingLength; N8_Buffer_t *hashMsg_p = NULL; uint32_t hashMsg_a; unsigned long pAddr; char *vAddr; N8_Buffer_t *kResults_p = NULL; uint32_t kResults_a; API_Request_t *req_p; int nBytes; do { ret = N8_preamble(); CHECK_RETURN(ret); CHECK_OBJECT(req_pp, ret); *req_pp = NULL; /* minimal sanity checking on the hash object */ CHECK_OBJECT(obj_p, ret); CHECK_OBJECT(result_p, ret); CHECK_STRUCTURE(obj_p->structureID, N8_HASH_STRUCT_ID, ret); DBG(("residual length: %d\n", obj_p->residualLength)); DBG(("residual: %s\n", obj_p->residual)); totalLength = obj_p->residualLength; hashingLength = totalLength; /* * The input to the final hash is the residual in the hash object. */ /* allocate a kernel buffer for the results and for * the message to hash */ /* The message to hash is ready. Now, create the command * blocks and do the final hash. */ nBytes = NEXT_WORD_SIZE(obj_p->hashSize) + NEXT_WORD_SIZE(hashingLength); ret = createEARequestBuffer(&req_p, obj_p->unitID, N8_CB_EA_HASHEND_NUMCMDS, resultHandlerGeneric, nBytes); CHECK_RETURN(ret); pAddr = req_p->qr.physicalAddress + req_p->dataoffset; vAddr = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset); memset(vAddr, 0, nBytes); kResults_p = vAddr; kResults_a = pAddr; vAddr += NEXT_WORD_SIZE(obj_p->hashSize); pAddr += NEXT_WORD_SIZE(obj_p->hashSize); if (hashingLength != 0) { hashMsg_p = (N8_Buffer_t *) vAddr; hashMsg_a = pAddr; /* copy the residual, which we know to be non-zero in length */ memcpy(hashMsg_p, obj_p->residual, hashingLength); DBG(("hash length: %d\n", hashingLength)); } else { /* even if the hashing length is zero, the hardware call must be made * to finalize the hash. it will see no new data is presented for * hashing and only do the portions necessary to finish the hash in * progress. */ hashMsg_p = NULL; hashMsg_a = 0; DBG(("hash length: %d\n", hashingLength)); DBG(("msg to hash: none\n")); } CHECK_RETURN(ret); ret = cb_ea_hashEnd(req_p, req_p->EA_CommandBlock_ptr, obj_p, N8_IV, /* get the IV from the * regular place */ hashMsg_a, hashingLength, kResults_a, NULL, /* next command block */ N8_TRUE); CHECK_RETURN(ret); req_p->copyBackSize = obj_p->hashSize; req_p->copyBackFrom_p = kResults_p; req_p->copyBackTo_p = result_p; *req_pp = req_p; } while (FALSE); return ret; } /* n8_HashEnd_req */ /***************************************************************************** * N8_HashEnd ****************************************************************************/ /** @ingroup n8_hash * @brief Finalize a hash in progress. * * After one or more calls to N8_HashPartial, after all portions are * hashed, N8_HashEnd is called to compute the final values and return * the hash results. * * @param obj_p RW: Hash object to use * @param result_p RW: Pointer to pre-allocated buffer to * hold returned results * @param event_p RW: Asynchronous event pointer * * @par Externals * None * * @return * Status condition * * @par Errors * N8_INVALID_OBJECT
* N8_MALLOC_FAILED
* * @par Assumptions * Asynchronous calls not implemented. ****************************************************************************/ N8_Status_t N8_HashEnd(N8_HashObject_t *obj_p, N8_Buffer_t *result_p, N8_Event_t *event_p) { API_Request_t *req_p = NULL; N8_Status_t ret = N8_STATUS_OK; DBG(("N8_HashEnd\n")); do { switch (obj_p->type) { case N8_HMAC_MD5: case N8_HMAC_MD5_96: case N8_HMAC_SHA1: case N8_HMAC_SHA1_96: ret = n8_HMACHashEnd_req(obj_p, result_p, &req_p); break; case N8_MD5: case N8_SHA1: ret = n8_HashEnd_req(obj_p, result_p, &req_p); break; default: ret = N8_INVALID_HASH; break; } CHECK_RETURN(ret); QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up resources */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } DBG(("N8_HashEnd - OK\n")); return ret; } /* N8_HashEnd */ /***************************************************************************** * N8_HashClone ****************************************************************************/ /** @ingroup n8_hash * @brief Given a HashObject produce a clone. * * Perform a clone of a given HashObject and return the clone. * * @param orig_p RO: Hash object to be cloned. * @param clone_p RW: Cloned version of hash object. * * @par Externals * None * * @return * Error condition if raised. * * @par Errors * None * * @par Assumptions * Values in the original are unchecked. Only a copy is * performed.
* Clone_p points to a pre-allocated buffer of sufficient size. ****************************************************************************/ N8_Status_t N8_HashClone(const N8_HashObject_t *orig_p, N8_HashObject_t *clone_p) { N8_Status_t ret = N8_STATUS_OK; do { ret = N8_preamble(); CHECK_RETURN(ret); CHECK_OBJECT(orig_p, ret); CHECK_OBJECT(clone_p, ret); CHECK_STRUCTURE(orig_p->structureID, N8_HASH_STRUCT_ID, ret); memcpy(clone_p, orig_p, sizeof(N8_HashObject_t)); } while (FALSE); return ret; } /* N8_HashClone */ /***************************************************************************** * N8_HandshakeHashPartial ****************************************************************************/ /** @ingroup n8_hash * @brief Computes partial handshake hash. * * The SSL and TLS handshake protocol requires the computation of a * hash. A unique message is hashed and that is then hashed with * other known quantities. This function is called repeatedly until * all of the parts of the unique message are hashed. A subsequent * call to the companion functions N8_HandshakeHashEnd wraps up the * handshake. * * @param md5Obj_p RW: Pointer to MD5 hash object. * @param shaObj_p RW: Pointer to SHA-1 hash object. * @param msg_p RW: Pointer to the message portion to * be hashed * @param msgLength RW: Length of message portion to be hashed. * @param event_p RW: Asynchronous event * * @par Externals * None * * @return * Error code if encountered. * * @par Errors * N8_INVALID_HASH * N8_INVALID_OBJECT * N8_INVALID_INPUT_SIZE * N8_MALLOC_FAILED * * @par Assumptions * None ****************************************************************************/ N8_Status_t N8_HandshakeHashPartial(N8_HashObject_t *md5Obj_p, N8_HashObject_t *shaObj_p, const N8_Buffer_t *msg_p, const unsigned int msgLength, N8_Event_t *event_p) { N8_Status_t ret = N8_STATUS_OK; unsigned int hashingLength; N8_Buffer_t *hashMsg_p = NULL; uint32_t hashMsg_a; uint32_t resultMD5_a; N8_Buffer_t *resultMD5_p = NULL; uint32_t resultSHA_a; N8_Buffer_t *resultSHA_p = NULL; API_Request_t *req_p = NULL; int nBytes; EA_CMD_BLOCK_t *nextCommandBlock = NULL; N8_HandshakePartialResults_t *callBackData_p = NULL; do { ret = N8_preamble(); CHECK_RETURN(ret); if (msgLength == 0) { /* legal but has no effect or side-effects */ break; } if (msgLength > N8_MAX_HASH_LENGTH) { ret = N8_INVALID_INPUT_SIZE; break; } CHECK_OBJECT(md5Obj_p, ret); CHECK_OBJECT(shaObj_p, ret); CHECK_OBJECT(msg_p, ret); CHECK_STRUCTURE(md5Obj_p->structureID, N8_HASH_STRUCT_ID, ret); CHECK_STRUCTURE(shaObj_p->structureID, N8_HASH_STRUCT_ID, ret); /* ensure the hash objects were initialized correctly */ if (md5Obj_p->type != N8_MD5 || shaObj_p->type != N8_SHA1) { ret = N8_INVALID_HASH; break; } nBytes = (NEXT_WORD_SIZE(md5Obj_p->hashSize) + NEXT_WORD_SIZE(shaObj_p->hashSize) + NEXT_WORD_SIZE(msgLength + N8_MAX_RESIDUAL_LEN)); /* In order to perform the HandshakeHashPartial, the equivalent of a hash * partial needs to be done for the MD5 object and the SHA-1 object. In * order to perform this in one request, the command blocks are generated * and submitted as a single request to the queue manager. */ ret = createEARequestBuffer(&req_p, md5Obj_p->unitID, 2 * N8_CB_EA_HASHPARTIAL_NUMCMDS, resultHandlerHandshakePartial, nBytes); CHECK_RETURN(ret); /* setup the space for the chip to place the result */ resultMD5_a = req_p->qr.physicalAddress + req_p->dataoffset; resultMD5_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset); memset(resultMD5_p, 0, nBytes); resultSHA_a = resultMD5_a + NEXT_WORD_SIZE(md5Obj_p->hashSize); resultSHA_p = resultMD5_p + NEXT_WORD_SIZE(md5Obj_p->hashSize); hashMsg_a = resultSHA_a + NEXT_WORD_SIZE(shaObj_p->hashSize); hashMsg_p = resultSHA_p + NEXT_WORD_SIZE(shaObj_p->hashSize); /* * The actual input is concat(residual, *msg_p). Of this, we * only hash multiple lengths of N8_HASH_BLOCK_SIZE and save the * rest for the next time around. * Note that the MD5 and SHA-1 messages and residuals will always be the * same. Therefore, we can calculate the hashing message and residual once * and share between the hash objects. */ ret = computeResidual(md5Obj_p, msg_p, hashMsg_p, msgLength, &hashingLength); CHECK_RETURN(ret); /* there is hashing to be done. copy the residual from the MD5 object to * the SHA object. */ memcpy(shaObj_p->residual, md5Obj_p->residual, md5Obj_p->residualLength); shaObj_p->residualLength = md5Obj_p->residualLength; n8_incrLength64(&shaObj_p->Nh, &shaObj_p->Nl, hashingLength); /* if the hashing length is 0, then there is nothing to do for this call. * Set the event status to done (if asynchronous) and return. */ if (hashingLength == 0) { if (event_p != NULL) { N8_SET_EVENT_FINISHED(event_p, N8_EA); } freeRequest(req_p); ret = N8_STATUS_OK; break; } /* The message to hash this time around has been isolated. The * residual is in place for next time. Now, create the command * blocks and do the hash. */ /* create callback structure */ callBackData_p = (N8_HandshakePartialResults_t *)&req_p->postProcessBuffer; callBackData_p->SHA_results_p = resultSHA_p; callBackData_p->SHA_obj_p = shaObj_p; callBackData_p->MD5_results_p = resultMD5_p; callBackData_p->MD5_obj_p = md5Obj_p; req_p->postProcessingData_p = (void *) callBackData_p; ret = cb_ea_hashPartial(req_p, req_p->EA_CommandBlock_ptr, md5Obj_p, N8_IV, hashMsg_a, hashingLength, resultMD5_a, &nextCommandBlock, N8_FALSE); CHECK_RETURN(ret); ret = cb_ea_hashPartial(req_p, nextCommandBlock, shaObj_p, N8_IV, hashMsg_a, hashingLength, resultSHA_a, &nextCommandBlock, N8_TRUE); CHECK_RETURN(ret); DBG(("command block:\n")); QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up resources */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } return ret; } /* N8_HandshakeHashPartial */ /***************************************************************************** * N8_HandshakeHashEnd ****************************************************************************/ /** @ingroup n8_hash * @brief Finishes ongoing handshake hash computation. * * After all portions of the message have been processed by * N8_HandshakeHashPartial this method must be called to do the final * processing. The function produces a hash result for MD5 and SHA-1 * simultaneously. * * @param md5Obj_p RW: MD5 hash object * @param sha1Obj_p RW: SHA-1 hash object * @param protocol RW: Hash protocol specifier (TLS * finish, TLS cert, SSL finish, or * SSL cert) * @param key_p RW: Hash key * @param keyLength RW: Length of hash key * @param role RW: Role of hash (server or client) * @param md5Result_p RW: Pointer to pre-allocated space for * MD5 results. * @param sha1Result_p RW: Pointer to pre-allocated space for * SHA-1 results. * @param event_p RW: Async event. NULL for blocking. * * @par Externals * None * * @return * Error condition if met. * * @par Errors * N8_MALLOC_FAILED
* N8_INVALID_HASH
* N8_INVALID_PROTOCOL * * @par Assumptions * TLS functions not implemented. ****************************************************************************/ N8_Status_t N8_HandshakeHashEnd(N8_HashObject_t *md5Obj_p, N8_HashObject_t *sha1Obj_p, const N8_HashProtocol_t protocol, const N8_Buffer_t *key_p, const unsigned int keyLength, const N8_HashRole_t role, N8_Buffer_t *md5Result_p, N8_Buffer_t *sha1Result_p, N8_Event_t *event_p) { N8_Status_t ret = N8_STATUS_OK; char *roleString_p = NULL; do { ret = N8_preamble(); CHECK_RETURN(ret); CHECK_STRUCTURE(md5Obj_p->structureID, N8_HASH_STRUCT_ID, ret); CHECK_STRUCTURE(sha1Obj_p->structureID, N8_HASH_STRUCT_ID, ret); if (md5Obj_p == NULL || sha1Obj_p == NULL) { ret = N8_INVALID_OBJECT; break; } if (md5Obj_p->type != N8_MD5 || sha1Obj_p->type != N8_SHA1) { ret = N8_INVALID_HASH; break; } roleString_p = getRoleString(protocol, role); switch (protocol) { case N8_TLS_FINISH: case N8_TLS_CERT: ret = computeTLSHandshakeHash(md5Obj_p, sha1Obj_p, protocol, roleString_p, key_p, keyLength, md5Result_p, sha1Result_p, event_p); break; case N8_SSL_FINISH: case N8_SSL_CERT: ret = computeSSLHandshakeHash(md5Obj_p, sha1Obj_p, roleString_p, key_p, keyLength, md5Result_p, sha1Result_p, event_p); break; default: ret = N8_INVALID_PROTOCOL; break; } CHECK_RETURN(ret); } while (FALSE); /* clean up */ N8_UFREE(roleString_p); return ret; } /* N8_HandshakeHashEnd */ /***************************************************************************** * N8_SSLKeyMaterialHash ****************************************************************************/ /** @ingroup n8_hash * @brief * * * * @param obj_p RO: hash info pointer. * @param random_p RO: 64 bytes of random input. * @param outputLength RO: Length of requested output. * @param keyMaterial_p RW: Key material output. * @param event_p RW: Asynch event. * * @par Externals * None * * @return * Error condition if raised. * * @par Errors * N8_INVALID_KEY_SIZE - provided key is the wrong size
* N8_INVALID_OUTPUT_SIZE - the requested output length is wrong
* N8_INVALID_OBJECT - An input is NULL or the specified unit is invalid. * * @par Assumptions * keyMaterial_p points to an allocated buffer of sufficient size. ****************************************************************************/ N8_Status_t N8_SSLKeyMaterialHash (N8_HashInfo_t *obj_p, const N8_Buffer_t *random_p, const unsigned int outputLength, N8_Buffer_t *keyMaterial_p, N8_Event_t *event_p) { API_Request_t *req_p = NULL; N8_Buffer_t *result_p = NULL; unsigned long result_a; N8_Buffer_t *kKey_p = NULL; unsigned long kKey_a; N8_Status_t ret = N8_STATUS_OK; int nBytes; do { ret = N8_preamble(); CHECK_RETURN(ret); CHECK_OBJECT(obj_p, ret); CHECK_OBJECT(obj_p->key_p, ret); CHECK_OBJECT(random_p, ret); /* check requested output size */ if (outputLength > N8_MAX_SSL_KEY_MATERIAL_LENGTH) { ret = N8_INVALID_OUTPUT_SIZE; break; } /* check key length */ if (obj_p->keyLength > N8_MAX_KEY_LENGTH) { ret = N8_INVALID_KEY_SIZE; break; } /* compute space for the chip to place the result */ /* this needs to be larger than the next multiple of 16. rather * than do the computation, just allocate it to the max size, which is * relatively small. */ nBytes = NEXT_WORD_SIZE(N8_MAX_SSL_KEY_MATERIAL_LENGTH) + NEXT_WORD_SIZE(obj_p->keyLength); ret = createEARequestBuffer(&req_p, obj_p->unitID, N8_CB_EA_SSLKEYMATERIALHASH_NUMCMDS, resultHandlerGeneric, nBytes); CHECK_RETURN(ret); result_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset); memset(result_p, 0, nBytes); result_a = req_p->qr.physicalAddress + req_p->dataoffset; /* set up the key in kernel memory and copy the incoming key over */ kKey_p = result_p + NEXT_WORD_SIZE(N8_MAX_SSL_KEY_MATERIAL_LENGTH); kKey_a = result_a + NEXT_WORD_SIZE(N8_MAX_SSL_KEY_MATERIAL_LENGTH); memcpy(kKey_p, obj_p->key_p, obj_p->keyLength); req_p->copyBackTo_p = keyMaterial_p; req_p->copyBackFrom_p = result_p; req_p->copyBackSize = outputLength; ret = cb_ea_SSLKeyMaterialHash(req_p, req_p->EA_CommandBlock_ptr, kKey_a, obj_p->keyLength, random_p, outputLength, result_a); CHECK_RETURN(ret); QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } return ret; } /* N8_SSLKeyMaterialHash */ /***************************************************************************** * N8_TLSKeyMaterialHash ****************************************************************************/ /** @ingroup n8_hash * @brief This computes the TLS Pseudo Random Function (PRF) of the specified * inputs as described in Section 5 of the TLS Specification [TLS]. * * The PRF is used to generate various keying material from a secret key, a * label, and a seed. The values of each of these depends on what's being * generated. The required key is specified by Key and its length by * KeyLength. * The Label is typically an ascii string literal (such as "key expansion" or * "master secret"), as specified by [TLS]; its length is given in * LabelLength. * The Seed is usually the client generated random value concatenated with the * server generated random value (or vice-versa). It is specified in the Seed * parameter and its length in bytes is specified by the SeedLength parameter. * Using these values this routine then generates OutputLength bytes of key * material, according to the TLS Protocol, and returns them in KeyMaterial. * Up to 224 bytes of key material may be generated. * * @param obj_p RO: The Hash info pointer. It contains: * 0 - 18 KBytes of secret key (typically the * TLS master secret) and the length of Key, * from 0 to 18 KBytes inclusive. A length of 0 * is legal; the result is computed with a null key. * Also defined here is the unit ID. * @param label_p RO: A short ascii string; its value depends * on what is being computed. * Specific values are * defined in [TLS]. * @param labelLength RO: The length of Label, from 0 to 18 KBytes * inclusive. * A length of 0 is legal; * the result is * computed with a null label. * @param seed_p RO: A seed value, typically some combination * of random bytes supplied by * the server and client. * Specific values * are defined in [TLS]. * @param seedLength RO: The length of Seed, from 0 to 18 KBytes * inclusive. * A length of 0 is legal; * the result is computed with a * null seed. * @param outputLength RO: The number of bytes of output requested; * i.e. the length of KeyMaterial, * from 0 - 224 inclusive. * @param keyMaterial_p WO: The computed key material. Note only as * many bytes as requested are ever returned, * even if the algorithm may compute more. * (As defined the algorithm almost * always * computes extra bytes.) * @param event_p RW: On input, if null the call * is synchronous and no event is * returned. The operation is * complete when the call returns. * If non-null, then the call is * asynchronous; * an event is returned that can be used to * determine when the operation completes. * * @return * Error condition if raised. * * @par Errors * N8_INVALID_KEY_SIZE - provided key is the wrong size
* N8_INVALID_OUTPUT_SIZE - the requested output length is wrong
* N8_INVALID_OBJECT - data pointer is null
* * @par Assumptions * keyMaterial_p points to an allocated buffer of sufficient size. ****************************************************************************/ N8_Status_t N8_TLSKeyMaterialHash(N8_HashInfo_t *obj_p, const N8_Buffer_t *label_p, const unsigned int labelLength, const N8_Buffer_t *seed_p, const unsigned int seedLength, const unsigned int outputLength, N8_Buffer_t *keyMaterial_p, N8_Event_t *event_p) { API_Request_t *req_p = NULL; N8_Buffer_t *msg_p = NULL; uint32_t msg_a; uint32_t kKey_a; N8_Buffer_t *kKey_p = NULL; uint32_t prS_a[2]; N8_Buffer_t *prS_p[2]; N8_Buffer_t resultStream_p[N8_MAX_TLS_KEY_MATERIAL_LENGTH]; N8_Status_t ret = N8_STATUS_OK; int totalLength; int secretHalves; N8_TLSKeyHashResults_t *keyResultStruct_p; int keyLen, hashLen; unsigned int numCommands; int bufferA_MD5_length; int bufferA_SHA1_length; do { ret = N8_preamble(); CHECK_RETURN(ret); CHECK_OBJECT(obj_p, ret); CHECK_OBJECT(obj_p->key_p, ret); CHECK_OBJECT(label_p, ret); CHECK_OBJECT(seed_p, ret); CHECK_OBJECT(keyMaterial_p, ret); /* check key length */ if (obj_p->keyLength > N8_MAX_KEY_LENGTH) { ret = N8_INVALID_KEY_SIZE; break; } /* check label length */ if (labelLength > N8_MAX_KEY_LENGTH) { ret = N8_INVALID_KEY_SIZE; break; } /* check seed length */ if (seedLength > N8_MAX_KEY_LENGTH) { ret = N8_INVALID_KEY_SIZE; break; } if ((obj_p->keyLength + labelLength + seedLength) > N8_MAX_KEY_LENGTH) { ret = N8_INVALID_KEY_SIZE; break; } /* check output buffer length */ if (outputLength > N8_MAX_TLS_KEY_MATERIAL_LENGTH) { ret = N8_INVALID_KEY_SIZE; break; } numCommands = N8_CB_EA_TLSKEYMATERIALHASH_NUMCMDS(outputLength); /* concatenate label and seeds */ totalLength = labelLength+seedLength; /* allocate kernel memory for the key, psuedo random streams, and msg*/ keyLen = (NEXT_WORD_SIZE(obj_p->keyLength) + (NEXT_WORD_SIZE(N8_MAX_TLS_KEY_MATERIAL_LENGTH) * 2) + NEXT_WORD_SIZE(totalLength)); /* compute the buffer size for the hashes */ bufferA_MD5_length = totalLength + EA_MD5_Hash_Length; bufferA_SHA1_length = totalLength + EA_SHA1_Hash_Length; hashLen = NEXT_WORD_SIZE(bufferA_MD5_length) + NEXT_WORD_SIZE(bufferA_SHA1_length); ret = createEARequestBuffer(&req_p, obj_p->unitID, numCommands, resultHandlerTLSKeyHash, keyLen + hashLen); CHECK_RETURN(ret); kKey_a = req_p->qr.physicalAddress + req_p->dataoffset; kKey_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset); memset(kKey_p, 0, keyLen + hashLen); prS_a[0] = kKey_a + NEXT_WORD_SIZE(obj_p->keyLength); prS_p[0] = kKey_p + NEXT_WORD_SIZE(obj_p->keyLength); prS_a[1] = prS_a[0] + NEXT_WORD_SIZE(N8_MAX_TLS_KEY_MATERIAL_LENGTH); prS_p[1] = prS_p[0] + NEXT_WORD_SIZE(N8_MAX_TLS_KEY_MATERIAL_LENGTH); msg_a = prS_a[1] + NEXT_WORD_SIZE(N8_MAX_TLS_KEY_MATERIAL_LENGTH); msg_p = prS_p[1] + NEXT_WORD_SIZE(N8_MAX_TLS_KEY_MATERIAL_LENGTH); /* copy the input key to the kernel memory area */ memcpy(kKey_p, obj_p->key_p, obj_p->keyLength); memcpy(msg_p, label_p, labelLength); memcpy(msg_p + labelLength, seed_p, seedLength); memset(&resultStream_p[0], 0x0, N8_MAX_TLS_KEY_MATERIAL_LENGTH); memset(prS_p[0], 0x0, N8_MAX_TLS_KEY_MATERIAL_LENGTH); memset(prS_p[1], 0x0, N8_MAX_TLS_KEY_MATERIAL_LENGTH); secretHalves = (int) (obj_p->keyLength / 2); ret = cb_ea_TLSKeyMaterialHash(req_p, req_p->EA_CommandBlock_ptr, msg_p, msg_a, totalLength, kKey_p, kKey_a, secretHalves, outputLength, prS_a[0], prS_a[1], keyLen); CHECK_RETURN(ret); /* create a struct to carry results to the result handler */ keyResultStruct_p = (N8_TLSKeyHashResults_t *)&req_p->postProcessBuffer; keyResultStruct_p->result_p = keyMaterial_p; keyResultStruct_p->prS_p[0] = prS_p[0]; keyResultStruct_p->prS_p[1] = prS_p[1]; keyResultStruct_p->outputLength = outputLength; req_p->postProcessingData_p = (void *) keyResultStruct_p; QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } return ret; } /* N8_TLSKeyMaterialHash */ /***************************************************************************** * N8_IKEPrf ****************************************************************************/ /** @ingroup n8_hash * @brief Computes the PRF/HMAC for the given message and key * * Computes the IKE keyed pseudo-random-function (prf) of the specified Key * of length KeyLength and Message of length MessageLength and returns the * results in Result. As specified in Sec. 4 of RFC 2409 (see [IKE] in * Appendix B: Reference Documentation), the only current pseudo-random * functions are the HMAC version of the negotiated hash algorithm. The hash * algorithm to use, and by implication the length of Result, is indicated * by the enumeration value specified in the Algorithm element of HashInfo. * If the Algorithm element of HashInfo is N8_HMAC_MD5, Result is 16 bytes; * if Algorithm is N8_HMAC_SHA1, Result is 20 bytes. * * * @param alg RO: algorthim (MD5 or SHA-1) * @param hashInfo_p RO: pointer to hash info struct * @param msg_p RO: pointer to message buffer * @param msgLength RO: input message length in bytes * @param result_p RW: pointer where hardware should copy result * @param event_p RW: pointer to event N8 event structure * * @par Externals: * * @return * N8_STATUS_OK * * @par Errors: * N8_INVALID_HASH - The hash algorithm specified in hashInfo is not one * of the constants N8_HMAC_MD5 or N8_HMAC_SHA1. * N8_INVALID_INPUT_SIZE - The value of msgLength is < 0 or > 18KB; no * operation is performed and no result is returned. * N8_INVALID_OBJECT - if any pointers are bad * N8_INVALID_KEY_SIZE - The value of hashInfo_p->keyLength is < 0 or > 64B * @par Locks: * None. * * @par Assumptions: * The caller is responsible for ensuring that sufficient space is allocated * for Result. Hash info must contain valid key pointer and key length. * Key cannot be longer than 64 bytes! ****************************************************************************/ N8_Status_t N8_IKEPrf(const N8_HashAlgorithm_t alg, const N8_HashInfo_t *hashInfo_p, const N8_Buffer_t *msg_p, const uint32_t msgLength, N8_Buffer_t *result_p, N8_Event_t *event_p) { API_Request_t *req_p = NULL; N8_Status_t ret = N8_STATUS_OK; uint32_t nBytes; uint32_t kKey_a; N8_Buffer_t *kKey_p = NULL; uint32_t kRes_a; N8_Buffer_t *kRes_p = NULL; N8_Buffer_t *kMsg_p = NULL; uint32_t kMsg_a; do { ret = N8_preamble(); CHECK_RETURN(ret); CHECK_OBJECT(hashInfo_p, ret); CHECK_OBJECT(hashInfo_p->key_p, ret); CHECK_OBJECT(msg_p, ret); CHECK_OBJECT(result_p, ret); /* Also, if the key length is less than 64 bytes we * need to post-pad the key with 0x00 up to 64 bytes. * The padding is performed by the lower command * block building routine. * If the key length is greater than 64 bytes we * need to hash the key (results in 64 bytes for MD5 or * SHA-1). */ /* TODO: handle the >64 byte key case: * key must be hashed and truncated * to 64 bytes */ /* check key length */ #ifdef N8_64BYTE_IKE_KEY_LIMIT /* for now we will only accept up to 64 bytes of key */ if (hashInfo_p->keyLength > EA_HMAC_Key_Length) #else if (hashInfo->keyLength > N8_MAX_KEY_LENGTH) #endif { ret = N8_INVALID_KEY_SIZE; break; } /* check msg length */ if (msgLength > N8_MAX_HASH_LENGTH) { ret = N8_INVALID_INPUT_SIZE; break; } /* compute kernel memory size for the key and msg */ /* SHA1 result length=20 is greater than MD5 result length */ nBytes = (NEXT_WORD_SIZE(hashInfo_p->keyLength) + NEXT_WORD_SIZE(msgLength) + NEXT_WORD_SIZE(SHA1_HASH_RESULT_LENGTH)); ret = createEARequestBuffer(&req_p, hashInfo_p->unitID, N8_CB_EA_IKEPRF_NUMCMDS, resultHandlerGeneric, nBytes); CHECK_RETURN(ret); /* set up pointers for key | msg | res */ kKey_a = req_p->qr.physicalAddress + req_p->dataoffset; kKey_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset); memset(kKey_p, 0, nBytes); kMsg_a = kKey_a + NEXT_WORD_SIZE(hashInfo_p->keyLength); kMsg_p = kKey_p + NEXT_WORD_SIZE(hashInfo_p->keyLength); kRes_a = kMsg_a + NEXT_WORD_SIZE(msgLength); kRes_p = kMsg_p + NEXT_WORD_SIZE(msgLength); /* copy the input key to the kernel memory area */ memcpy(kKey_p, hashInfo_p->key_p, hashInfo_p->keyLength); /* copy the input msg to the kernel memory area */ memcpy(kMsg_p, msg_p, msgLength); ret = cb_ea_IKEPrf(req_p, req_p->EA_CommandBlock_ptr, alg, kMsg_a, msgLength, kKey_p, hashInfo_p->keyLength, kRes_a); CHECK_RETURN(ret); /* setup up post-processing info */ req_p->copyBackFrom_p = kRes_p; req_p->copyBackTo_p = result_p; /* set copy back size based on alg */ switch (alg) { case N8_HMAC_SHA1: { req_p->copyBackSize = SHA1_HASH_RESULT_LENGTH; break; } case N8_HMAC_MD5: { req_p->copyBackSize = MD5_HASH_RESULT_LENGTH; break; } default: { ret = N8_INVALID_HASH; break; } } CHECK_RETURN(ret); QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } return ret; } /* N8_IKEPrf */ /***************************************************************************** * N8_IKESKEYIDExpand ****************************************************************************/ /** @ingroup n8_hash * @brief Computes SKEYID_d,a,e for the given message and key * * Computes key material from the specified Key of length KeyLength and * Message of length Message-Length, according to the IKE authenticated * keying material generating algorithm in Sec. 5 of RFC 2409 (see [IKE] in * Appendix B: Reference Documentation), returning the three results SKEYID_d, * SKEYID_a, and SKEYID_e. * * The hash algorithm to use, and by implication the lengths of the three * results, is indicated by the enu-meration value specified in the Algorithm\ * element of HashInfo. If Algorithm is N8_HMAC_MD5, each result is 16 bytes; * if Algorithm is N8_HMAC_SHA1 each result is 20 bytes. The caller is * responsible for ensuring that sufficient space is allocated for these * results. (Note that if these result values are shorter than the required * key material, IKE specifies how these results are expanded.) * * @param alg RO: algorthim (MD5 or SHA-1) * @param hashInfo_p RO: a pointer to hashInfo struct * @param msg_p RO: pointer to input message * @param msgLength RO: input message length in bytes * @param SKEYIDd_p RW: pointer to SKEYID_d output buffer * @param SKEYIDa_p RW: pointer to SKEYID_a output buffer * @param SKEYIDe_p RW: pointer to SKEYID_e output buffer * @param event_p RW: pointer to N8 event structure * * @par Externals: * * @return * N8_STATUS_OK * * @par Errors: * N8_INVALID_HASH - The hash algorithm specified in hashInfo is not one * of the constants N8_HMAC_MD5 or N8_HMAC_SHA1. * N8_INVALID_INPUT_SIZE - The value of msgLength is < 0 or > 18KB; no * operation is performed and no result is returned. * N8_INVALID_OBJECT - if any pointers are bad * N8_INVALID_KEY_SIZE - The value of hashInfo_p->keyLength is < 0 or > 64B * * @par Locks: * None. * * @par Assumptions: * The caller is responsible for ensuring that sufficient space is allocated * for Result. Hash info must contain valid key pointer and key length. * Key cannot be longer than 64 bytes! ****************************************************************************/ N8_Status_t N8_IKESKEYIDExpand (const N8_HashAlgorithm_t alg, const N8_HashInfo_t *hashInfo_p, const N8_Buffer_t *msg_p, const uint32_t msgLength, N8_Buffer_t *SKEYIDd_p, N8_Buffer_t *SKEYIDa_p, N8_Buffer_t *SKEYIDe_p, N8_Event_t *event_p) { API_Request_t *req_p = NULL; N8_Status_t ret = N8_STATUS_OK; uint32_t nBytes; uint32_t kKey_a; N8_Buffer_t *kKey_p = NULL; uint32_t kSKEYIDd_a; N8_Buffer_t *kSKEYIDd_p = NULL; N8_Buffer_t *kMsg_p = NULL; uint32_t kMsg_a; N8_IKESKEYIDExpandResults_t *keyResultStruct_p = NULL; do { ret = N8_preamble(); CHECK_RETURN(ret); CHECK_OBJECT(hashInfo_p, ret); CHECK_OBJECT(hashInfo_p->key_p, ret); CHECK_OBJECT(msg_p, ret); CHECK_OBJECT(SKEYIDd_p, ret); CHECK_OBJECT(SKEYIDa_p, ret); CHECK_OBJECT(SKEYIDe_p, ret); /* Also, if the key length is less than 64 bytes we * need to post-pad the key with 0x00 up to 64 bytes. * The padding is performed by the lower command * block building routine. * If the key length is greater than 64 bytes we * need to hash the key (results in 64 bytes for MD5 or * SHA-1). */ /* TODO: handle the >64 byte key case: * key must be hashed and truncated * to 64 bytes */ /* check key length */ #ifdef N8_64BYTE_IKE_KEY_LIMIT /* for now we will only accept up to 64 bytes of key */ if (hashInfo_p->keyLength > EA_HMAC_Key_Length) #else if (hashInfo->keyLength > N8_MAX_KEY_LENGTH) #endif { ret = N8_INVALID_KEY_SIZE; break; } /* check msg length */ if (msgLength > N8_MAX_HASH_LENGTH) { ret = N8_INVALID_INPUT_SIZE; break; } /* compute kernel memory size for the key and msg */ /* SHA1 result length=20 is the max(sha1,md5) * result length */ nBytes = (NEXT_WORD_SIZE(hashInfo_p->keyLength) + NEXT_WORD_SIZE(msgLength) + NEXT_WORD_SIZE(N8_IKE_SKEYID_ITERATIONS*SHA1_HASH_RESULT_LENGTH)); ret = createEARequestBuffer(&req_p, hashInfo_p->unitID, N8_CB_EA_IKESKEYIDEXPAND_NUMCMDS, resultHandlerIKESKEYIDExpand, nBytes); CHECK_RETURN(ret); /* set up pointers for key | msg | res */ kKey_a = req_p->qr.physicalAddress + req_p->dataoffset; kKey_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset); memset(kKey_p, 0, nBytes); kMsg_a = kKey_a + NEXT_WORD_SIZE(hashInfo_p->keyLength); kMsg_p = kKey_p + NEXT_WORD_SIZE(hashInfo_p->keyLength); kSKEYIDd_a = kMsg_a + NEXT_WORD_SIZE(msgLength); kSKEYIDd_p = kMsg_p + NEXT_WORD_SIZE(msgLength); /* copy the input key to the kernel memory area */ memcpy(kKey_p, hashInfo_p->key_p, hashInfo_p->keyLength); /* copy the input msg to the kernel memory area */ memcpy(kMsg_p, msg_p, msgLength); ret = cb_ea_IKESKEYIDExpand(req_p, req_p->EA_CommandBlock_ptr, alg, kMsg_a, msgLength, kKey_p, hashInfo_p->keyLength, kSKEYIDd_a); CHECK_RETURN(ret); /* create a struct to carry results to the result handler */ keyResultStruct_p = (N8_IKESKEYIDExpandResults_t *)&req_p->postProcessBuffer; keyResultStruct_p->result_p = kSKEYIDd_p; keyResultStruct_p->SKEYIDd_p = SKEYIDd_p; keyResultStruct_p->SKEYIDa_p = SKEYIDa_p; keyResultStruct_p->SKEYIDe_p = SKEYIDe_p; /* set output length based on alg */ switch (alg) { case N8_HMAC_SHA1: { keyResultStruct_p->outputLength = SHA1_HASH_RESULT_LENGTH; break; } case N8_HMAC_MD5: { keyResultStruct_p->outputLength = MD5_HASH_RESULT_LENGTH; break; } default: { ret = N8_INVALID_HASH; break; } } CHECK_RETURN(ret); req_p->postProcessingData_p = (void *) keyResultStruct_p; QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } return ret; } /* N8_IKESKEYIDExpand */ /***************************************************************************** * N8_IKEKeyMaterialExpand ****************************************************************************/ /** @ingroup n8_hash * @brief Performs key expansion using the given message and key up to the * specfied length * * Computes OutputLength bytes of key material from the specified Key of * length KeyLength and Mes-sage of length MessageLength using the hash * function specified by the Algorithm element of HashInfo. If * MessageLength is greater than 0, then it denotes the size of Message, * and Message is used to generate key material according to the IKE key * expansion algorithm in Sec. 5.5 of RFC 2409 (see [IKE] in Appendix B: * Reference Documentation). * The generated key material is returned in Output. Up to 240 bytes of key * material may be generated using HMAC-MD5, and up to 300 bytes using * HMAC-SHA-1. The requested number of returned Out-put bytes is specified * in OutputLength. The caller is responsible for ensuring that sufficient * space is allocated for Output. The hash algorithm used is indicated by * the enumeration value in the Algorithm element of HashInfo. * * @param alg RO: algorthim (MD5 or SHA-1) * @param hashInfo_p RO: pointer to hashInfo struct * @param msg_p RO: pointer to input message * @param msgLength RO: input message length in bytes * @param result_p RO: pointer to output buffer * @param result_len RO: number of key expansion bytes requested by caller * @param event_p RW: pointer to N8 event structure * * @par Externals: * * @return * N8_STATUS_OK * * @par Errors: * N8_INVALID_HASH - The hash algorithm specified in hashInfo is not one * of the constants N8_HMAC_MD5 or N8_HMAC_SHA1. * N8_INVALID_INPUT_SIZE - The value of msgLength is < 0 or > 18KB; * no operation is performed and no result is * returned. * N8_INVALID_OUTPUT_SIZE - The value of result_len > 240 when * alg is N8_HMAC_MD5, or > 300 when alg * is N8_HMAC_SHA1; no operation is performed * and no result is returned. * N8_INVALID_OBJECT - if any pointers are bad * N8_INVALID_KEY_SIZE - The value of hashInfo_p->keyLength is < 0 or > 64B * * @par Locks: * None. * * @par Assumptions: * The caller is responsible for ensuring that sufficient space is * allocated for Result. Hash info must contain valid key pointer * and key length. * Key cannot be longer than 64 bytes! ****************************************************************************/ N8_Status_t N8_IKEKeyMaterialExpand(const N8_HashAlgorithm_t alg, const N8_HashInfo_t *hashInfo_p, const N8_Buffer_t *msg_p, const uint32_t msgLength, N8_Buffer_t *result_p, const uint32_t result_len, N8_Event_t *event_p) { API_Request_t *req_p = NULL; N8_Status_t ret = N8_STATUS_OK; uint32_t nBytes; uint32_t kKey_a; N8_Buffer_t *kKey_p = NULL; N8_Buffer_t *kMsg_p = NULL; uint32_t kMsg_a; N8_Buffer_t *kRes_p = NULL; uint32_t kRes_a; uint32_t hash_len = 0; uint32_t i_count; do { ret = N8_preamble(); CHECK_RETURN(ret); /* if result_len is 0 - no computing is done */ if (result_len == 0) { if (event_p != NULL) { N8_SET_EVENT_FINISHED(event_p, N8_EA); } break; } CHECK_OBJECT(hashInfo_p, ret); CHECK_OBJECT(hashInfo_p->key_p, ret); CHECK_OBJECT(msg_p, ret); CHECK_OBJECT(result_p, ret); /* Also, if the key length is less than 64 bytes we * need to post-pad the key with 0x00 up to 64 bytes. * The padding is performed by the lower command * block building routine. * If the key length is greater than 64 bytes we * need to hash the key (results in 64 bytes for MD5 or * SHA-1). */ /* TODO: handle the >64 byte key case: * key must be hashed and truncated * to 64 bytes */ /* check key length */ #ifdef N8_64BYTE_IKE_KEY_LIMIT /* for now we will only accept up to 64 bytes of key */ if (hashInfo_p->keyLength > EA_HMAC_Key_Length) #else if (hashInfo_p->keyLength > N8_MAX_KEY_LENGTH) #endif { ret = N8_INVALID_KEY_SIZE; break; } /* check msg length */ if (msgLength > N8_MAX_HASH_LENGTH) { ret = N8_INVALID_INPUT_SIZE; break; } /* set hash_len based on alg */ switch (alg) { case N8_HMAC_SHA1: { hash_len = SHA1_HASH_RESULT_LENGTH; break; } case N8_HMAC_MD5: { hash_len = MD5_HASH_RESULT_LENGTH; break; } default: { ret = N8_INVALID_HASH; break; } } CHECK_RETURN(ret); /* check output length */ if (result_len > N8_MAX_IKE_ITERATIONS*hash_len) { ret = N8_INVALID_OUTPUT_SIZE; break; } /* compute iteration count: we want the WHOLE number * of iterations we need to produce the requested * amount of data */ if ((result_len % hash_len) != 0) { i_count = result_len/hash_len + 1; } else { i_count = result_len/hash_len; } /* compute kernel memory size for the key and msg */ nBytes = (NEXT_WORD_SIZE(hashInfo_p->keyLength) + NEXT_WORD_SIZE(msgLength) + NEXT_WORD_SIZE(i_count*hash_len)); /* for result */ ret = createEARequestBuffer(&req_p, hashInfo_p->unitID, N8_CB_EA_IKEKEYMATERIALEXPAND_NUMCMDS, resultHandlerGeneric, nBytes); CHECK_RETURN(ret); /* set up pointers for key | msg | res */ kKey_a = req_p->qr.physicalAddress + req_p->dataoffset; kKey_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset); memset(kKey_p, 0, nBytes); kMsg_a = kKey_a + NEXT_WORD_SIZE(hashInfo_p->keyLength); kMsg_p = kKey_p + NEXT_WORD_SIZE(hashInfo_p->keyLength); kRes_a = kMsg_a + NEXT_WORD_SIZE(msgLength); kRes_p = kMsg_p + NEXT_WORD_SIZE(msgLength); /* copy the input key to the kernel memory area */ memcpy(kKey_p, hashInfo_p->key_p, hashInfo_p->keyLength); /* copy the input msg to the kernel memory area */ memcpy(kMsg_p, msg_p, msgLength); ret = cb_ea_IKEKeyMaterialExpand(req_p, req_p->EA_CommandBlock_ptr, alg, kMsg_a, msgLength, kKey_p, hashInfo_p->keyLength, kRes_a, i_count); CHECK_RETURN(ret); /* setup up post-processing info */ req_p->copyBackFrom_p = kRes_p; req_p->copyBackTo_p = result_p; req_p->copyBackSize = result_len; QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } return ret; } /* N8_IKEKeyMaterialExpand */ /***************************************************************************** * N8_IKEEncryptKeyExpand ****************************************************************************/ /** @ingroup n8_hash * @brief Performs key expansion using the given message and key up to the * specfied length * * Computes OutputLength bytes of key material from the specified Key of * length KeyLength using the hash function specified in the Algorithm element * of HashInfo, according to the IKE key expansion algo-rithm in Sec. 5.3 of * RFC 2409. (See [IKE] in Appendix B: Reference Documentation.) The generated * key material is returned in Output. * Up to 240 bytes of key material may be generated using HMAC-MD5, and 300 * bytes using HMAC-SHA-1. The caller is responsible for ensuring that * sufficient space is allocated for Output. The hash algorithm used is * indicated by the enumeration value in the Algorithm element of HashInfo. * Proper computation requires a msg of a single zero byte. This zero byte * is allocated by internally by the API. * * @param alg RO: algorthim (MD5 or SHA-1) * @param hashInfo_p RO: pointer to hashInfo structure * @param result_p RW: pointer to result buffer * @param result_len RO: caller-specified output length in bytes * @param event_p RW: pointer to N8 event structure * * @par Externals: * * @return * N8_STATUS_OK * * @par Errors: * N8_INVALID_HASH - The hash algorithm specified in hashInfo is not one * of the constants N8_HMAC_MD5 or N8_HMAC_SHA1. * N8_INVALID_OUTPUT_SIZE - The value of result_len is < 0 or > 240 when * alg is N8_HMAC_MD5, or < 0 or > 300 when alg * is N8_HMAC_SHA1; no operation is performed * and no result is returned. * N8_INVALID_OBJECT - if any pointers are bad * N8_INVALID_KEY_SIZE - The value of hashInfo_p->keyLength is < 0 or > 64B * * @par Locks: * None. * * @par Assumptions: * The caller is responsible for ensuring that sufficient space is allocated * for Result. Hash info must contain valid key pointer and key length. * Key cannot be longer than 64 bytes! ****************************************************************************/ N8_Status_t N8_IKEEncryptKeyExpand(const N8_HashAlgorithm_t alg, const N8_HashInfo_t *hashInfo_p, N8_Buffer_t *result_p, const uint32_t result_len, N8_Event_t *event_p) { API_Request_t *req_p = NULL; N8_Status_t ret = N8_STATUS_OK; uint32_t nBytes; uint32_t kKey_a; N8_Buffer_t *kKey_p = NULL; N8_Buffer_t *kMsg_p = NULL; uint32_t kMsg_a; N8_Buffer_t *kRes_p = NULL; uint32_t kRes_a; uint32_t hash_len = 0; uint32_t i_count; do { ret = N8_preamble(); CHECK_RETURN(ret); /* if result_len is 0 - no computing is done */ if (result_len == 0) { if (event_p != NULL) { N8_SET_EVENT_FINISHED(event_p, N8_EA); } break; } CHECK_OBJECT(hashInfo_p, ret); CHECK_OBJECT(hashInfo_p->key_p, ret); CHECK_OBJECT(result_p, ret); /* Also, if the key length is less than 64 bytes we * need to post-pad the key with 0x00 up to 64 bytes. * The padding is performed by the lower command * block building routine. * If the key length is greater than 64 bytes we * need to hash the key (results in 64 bytes for MD5 or * SHA-1). */ /* TODO: handle the >64 byte key case: * key must be hashed and truncated * to 64 bytes */ /* check key length */ #ifdef N8_64BYTE_IKE_KEY_LIMIT /* for now we will only accept up to 64 bytes of key */ if (hashInfo_p->keyLength > EA_HMAC_Key_Length) #else if (hashInfo_p->keyLength > N8_MAX_KEY_LENGTH) #endif { ret = N8_INVALID_KEY_SIZE; break; } /* set hash_len based on alg */ switch (alg) { case N8_HMAC_SHA1: { hash_len = SHA1_HASH_RESULT_LENGTH; break; } case N8_HMAC_MD5: { hash_len = MD5_HASH_RESULT_LENGTH; break; } default: { ret = N8_INVALID_HASH; break; } } CHECK_RETURN(ret); /* check output length */ if (result_len > N8_MAX_IKE_ITERATIONS*hash_len) { ret = N8_INVALID_OUTPUT_SIZE; break; } /* compute iteration count: we want the WHOLE number * of iterations we need to produce the requested * amount of data */ if ((result_len % hash_len) != 0) { i_count = result_len/hash_len + 1; } else { i_count = result_len/hash_len; } /* compute kernel memory size for the key and msg */ /* there is a single zero byte message that * always required for this API call */ nBytes = (NEXT_WORD_SIZE(hashInfo_p->keyLength) + NEXT_WORD_SIZE(N8_IKE_ZERO_BYTE_LEN) + /* one zero byte message */ NEXT_WORD_SIZE(i_count*hash_len)); /* for result */ ret = createEARequestBuffer(&req_p, hashInfo_p->unitID, N8_CB_EA_IKEENCRYPTKEYEXPAND_NUMCMDS, resultHandlerGeneric, nBytes); CHECK_RETURN(ret); /* set up pointers for key | res | msg */ kKey_a = req_p->qr.physicalAddress + req_p->dataoffset; kKey_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset); memset(kKey_p, 0, nBytes); kRes_a = kKey_a + NEXT_WORD_SIZE(hashInfo_p->keyLength); kRes_p = kKey_p + NEXT_WORD_SIZE(hashInfo_p->keyLength); kMsg_a = kRes_a + NEXT_WORD_SIZE(i_count*hash_len); kMsg_p = kRes_p + NEXT_WORD_SIZE(i_count*hash_len); /* copy the input key to the kernel memory area */ memcpy(kKey_p, hashInfo_p->key_p, hashInfo_p->keyLength); ret = cb_ea_IKEEncryptKeyExpand(req_p, req_p->EA_CommandBlock_ptr, alg, kMsg_a, N8_IKE_ZERO_BYTE_LEN, kKey_p, hashInfo_p->keyLength, kRes_a, i_count); CHECK_RETURN(ret); /* setup up post-processing info */ req_p->copyBackFrom_p = kRes_p; req_p->copyBackTo_p = result_p; req_p->copyBackSize = result_len; QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } return ret; } /* N8_IKEEncryptKeyExpand */ /***************************************************************************** * n8_setInitialIVs *****************************************************************************/ /** @ingroup n8_hash * @brief Determine the hash type and set the initial IV values for that type. * * @param hashObj_p RW: Pointer to hash object to be initialized. * @param unit RO: Validated unit identifier. * * @par Externals * None * * @return * Status * * @par Errors * N8_INVALID_HASH if the hash is not from the set of supported hashes. * * @par Assumptions * The hash object has the type filed set correctly. *****************************************************************************/ N8_Status_t n8_setInitialIVs(N8_HashObject_t *hashObj_p, const N8_HashAlgorithm_t alg, const N8_Unit_t unit) { N8_Status_t ret = N8_STATUS_OK; switch (alg) { case N8_MD5: case N8_HMAC_MD5: case N8_HMAC_MD5_96: ret = initMD5(hashObj_p, alg, unit); break; case N8_SHA1: case N8_HMAC_SHA1: case N8_HMAC_SHA1_96: ret = initSHA1(hashObj_p, alg, unit); break; case N8_HASH_NONE: break; default: ret = N8_INVALID_HASH; break; } return ret; } /* n8_setInitialIVs */ /***************************************************************************** * initMD5 ****************************************************************************/ /** @ingroup n8_hash * @brief Initialize MD5 hash * * Initialize hash object for subsequent MD5 hashing * * @param obj_p RW: object to be initialized * @param alg RO: algorithm to use (e.g. N8_MD5 or * N8_HMAC_MD5) * * @par Externals * None * * @return * Error code. No abnormal error conditions have been identified. * * @par Errors * None * * @par Assumptions * None ****************************************************************************/ N8_Status_t initMD5(N8_HashObject_t *obj_p, const N8_HashAlgorithm_t alg, int unitID) { N8_Status_t ret = N8_STATUS_OK; do { DBG(("In initMD5 SAPI Layer\n")); CHECK_OBJECT(obj_p, ret); CHECK_RETURN(ret); memset(obj_p, 0, sizeof(N8_HashObject_t)); obj_p->iv[0] = MD5_INIT_A; obj_p->iv[1] = MD5_INIT_B; obj_p->iv[2] = MD5_INIT_C; obj_p->iv[3] = MD5_INIT_D; obj_p->type = alg; obj_p->hashSize = MD5_HASH_RESULT_LENGTH; obj_p->unitID = unitID; obj_p->structureID = N8_HASH_STRUCT_ID; } while (FALSE); DBG(("returning from initMD5 SAPI Layer\n")); return ret; } /* initMD5 */ /***************************************************************************** * initSHA1 ****************************************************************************/ /** @ingroup n8_hash * @brief Initialize SHA-1 hash * * Initialize hash object for subsequent MD5 hashing * * @param obj_p RW: object to be initialized * @param alg RO: algorithm to use (e.g. N8_SHA1 or * N8_HMAC_SHA1) * * @par Externals * None * * @return * Error code. No abnormal error conditions have been identified. * * @par Errors * None * * @par Assumptions * None ****************************************************************************/ N8_Status_t initSHA1(N8_HashObject_t *obj_p, const N8_HashAlgorithm_t alg, int unitID) { N8_Status_t ret = N8_STATUS_OK; do { CHECK_OBJECT(obj_p, ret); CHECK_RETURN(ret); memset(obj_p, 0, sizeof(N8_HashObject_t)); obj_p->iv[0] = SHA1_INIT_H0; obj_p->iv[1] = SHA1_INIT_H1; obj_p->iv[2] = SHA1_INIT_H2; obj_p->iv[3] = SHA1_INIT_H3; obj_p->iv[4] = SHA1_INIT_H4; obj_p->type = alg; obj_p->hashSize = SHA1_HASH_RESULT_LENGTH; obj_p->unitID = unitID; obj_p->structureID = N8_HASH_STRUCT_ID; } while (FALSE); return ret; } /* initSHA1 */ /* * Static Functions */ /***************************************************************************** * getRoleString ****************************************************************************/ /** @ingroup n8_hash * @brief Produce the correct role string for a given protocol and role. * * Various protocols and roles require different constant strings to * be included in a hash. This routine returns the correct string for * a given protocol/role combination. * * @param protocol RO: Protocol in use. * @param role RW: Role in use. * * @par Externals * None * * @return * String to use. * * @par Errors * None * * @par Assumptions * None ****************************************************************************/ static char * getRoleString(const N8_HashProtocol_t protocol, const N8_HashRole_t role) { char *string; switch (protocol) { case N8_SSL_FINISH: if (role == N8_SERVER) { string = n8_strdup("SRVR"); } else { string = n8_strdup("CLNT"); } break; case N8_TLS_FINISH: if (role == N8_SERVER) { string = n8_strdup("server finished"); } else { string = n8_strdup("client finished"); } break; case N8_SSL_CERT: case N8_TLS_CERT: default: string = n8_strdup(""); break; } return string; } /* getRoleString */ /***************************************************************************** * computeSSLHandshakeHash ****************************************************************************/ /** @ingroup n8_hash * @brief Compute the SSL Hash * * Do the work to compute the SSL handshake hash for one specified hash. * * @param hObj_p RW: Hash object to use in performing * the hash. * @param roleString_p RW: String constant for role to be * used in the hash. * @param key_p RW: Key to be used in the hash. * @param keyLength RW: Length of the key. * @param result_p RW: Pointer to buffer for results. * * @par Externals * None * * @return * Status * * @par Errors * Standard * * @par Assumptions * result_p is a pointer to an allocated buffer of adequate size. ****************************************************************************/ static N8_Status_t computeSSLHandshakeHash(N8_HashObject_t *hObjMD5_p, N8_HashObject_t *hObjSHA_p, const char *roleString_p, const N8_Buffer_t *key_p, const unsigned int keyLength, N8_Buffer_t *resultMD5_p, N8_Buffer_t *resultSHA_p, N8_Event_t *event_p) { N8_Status_t ret = N8_STATUS_OK; API_Request_t *req_p = NULL; unsigned int nBytes; N8_HandshakeEndResults_t *callBackData_p = NULL; N8_Buffer_t *innerMsg_md5_p = NULL; uint32_t innerMsg_md5_a; N8_Buffer_t *innerResult_md5_p = NULL; uint32_t innerResult_md5_a; N8_Buffer_t *outerMsg_md5_p = NULL; uint32_t outerMsg_md5_a; N8_Buffer_t *endResult_md5_p = NULL; uint32_t endResult_md5_a; N8_Buffer_t *innerMsg_sha_p = NULL; uint32_t innerMsg_sha_a; N8_Buffer_t *innerResult_sha_p = NULL; uint32_t innerResult_sha_a; N8_Buffer_t *outerMsg_sha_p = NULL; uint32_t outerMsg_sha_a; N8_Buffer_t *endResult_sha_p = NULL; uint32_t endResult_sha_a; N8_Buffer_t *hashMsgMD5_p = NULL; uint32_t hashMsgMD5_a; N8_Buffer_t *hashMsgSHA_p = NULL; uint32_t hashMsgSHA_a; unsigned int roleStringLen = strlen(roleString_p); unsigned int hashingLength_md5 = 0; /* totalLength rounded down to the */ unsigned int hashingLength_sha = 0; /* next multiple of N8_HASH_BLOCK_SIZE */ unsigned int innerMsgLen_md5; unsigned int innerMsgLen_sha; unsigned int outerMsgLen_md5; unsigned int outerMsgLen_sha; unsigned int i; do { innerMsgLen_md5 = keyLength + MD5_PAD_LENGTH + roleStringLen; outerMsgLen_md5 = MD5_HASH_RESULT_LENGTH + keyLength + MD5_PAD_LENGTH; innerMsgLen_sha = keyLength + SHA1_PAD_LENGTH + roleStringLen; outerMsgLen_sha = SHA1_HASH_RESULT_LENGTH + keyLength + SHA1_PAD_LENGTH; /* compute size of the results and the incoming message */ nBytes = NEXT_WORD_SIZE(innerMsgLen_md5) + /* innerMsg_md5 */ NEXT_WORD_SIZE(outerMsgLen_md5) + /* outerMsg_md5 */ NEXT_WORD_SIZE(hObjMD5_p->hashSize) + /* endResult_md5 */ NEXT_WORD_SIZE(innerMsgLen_sha) + /* innerMsg_sha */ NEXT_WORD_SIZE(outerMsgLen_sha) + /* outerMsg_sha */ NEXT_WORD_SIZE(hObjSHA_p->hashSize) + /* endResult_sha */ NEXT_WORD_SIZE(N8_MAX_RESIDUAL_LEN + innerMsgLen_md5) + /* hashMsgmd5 */ NEXT_WORD_SIZE(N8_MAX_RESIDUAL_LEN + innerMsgLen_sha) ; /* hashMsgsha */ ret = createEARequestBuffer(&req_p, hObjMD5_p->unitID, N8_CB_EA_SSLSHANDSHAKEHASH_NUMCMDS, resultHandlerHandshakeEnd, nBytes); /* setup the space for the chip to place the result */ innerMsg_md5_a = req_p->qr.physicalAddress + req_p->dataoffset; innerMsg_md5_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset); memset(innerMsg_md5_p, 0, nBytes); outerMsg_md5_a = innerMsg_md5_a + NEXT_WORD_SIZE(innerMsgLen_md5); outerMsg_md5_p = innerMsg_md5_p + NEXT_WORD_SIZE(innerMsgLen_md5); /* the inner result must start EXACTLY (keyLength + MD5_PAD_LENGTH) bytes * from the beginning of outerMsg_md5. do not round up to the next word * size. */ innerResult_md5_a = outerMsg_md5_a + (keyLength + MD5_PAD_LENGTH); innerResult_md5_p = outerMsg_md5_p + (keyLength + MD5_PAD_LENGTH); endResult_md5_a = outerMsg_md5_a + NEXT_WORD_SIZE(outerMsgLen_md5); endResult_md5_p = outerMsg_md5_p + NEXT_WORD_SIZE(outerMsgLen_md5); innerMsg_sha_a = endResult_md5_a + NEXT_WORD_SIZE(hObjMD5_p->hashSize); innerMsg_sha_p = endResult_md5_p + NEXT_WORD_SIZE(hObjMD5_p->hashSize); outerMsg_sha_a = innerMsg_sha_a + NEXT_WORD_SIZE(innerMsgLen_sha); outerMsg_sha_p = innerMsg_sha_p + NEXT_WORD_SIZE(innerMsgLen_sha); innerResult_sha_a = outerMsg_sha_a + (keyLength + SHA1_PAD_LENGTH); innerResult_sha_p = outerMsg_sha_p + (keyLength + SHA1_PAD_LENGTH); endResult_sha_a = outerMsg_sha_a + NEXT_WORD_SIZE(outerMsgLen_sha); endResult_sha_p = outerMsg_sha_p + NEXT_WORD_SIZE(outerMsgLen_sha); hashMsgMD5_a = endResult_sha_a + NEXT_WORD_SIZE(hObjSHA_p->hashSize); hashMsgMD5_p = endResult_sha_p + NEXT_WORD_SIZE(hObjSHA_p->hashSize); hashMsgSHA_a = hashMsgMD5_a + NEXT_WORD_SIZE(N8_MAX_RESIDUAL_LEN + innerMsgLen_md5); hashMsgSHA_p = hashMsgMD5_p + NEXT_WORD_SIZE(N8_MAX_RESIDUAL_LEN + innerMsgLen_md5); /* construct the remainder of the inner message to be hashed: * innerMsg_p = roleString_p + key_p + pad1_p * note that the hash of the message is already present in the * results of the hash object. */ /* construct the inner message: */ i = 0; memcpy(&(innerMsg_md5_p[i]), roleString_p, roleStringLen); i += roleStringLen; memcpy(&(innerMsg_md5_p[i]), key_p, keyLength); i += keyLength; memset(&(innerMsg_md5_p[i]), PAD1, MD5_PAD_LENGTH); i = 0; memcpy(&(innerMsg_sha_p[i]), roleString_p, roleStringLen); i += roleStringLen; memcpy(&(innerMsg_sha_p[i]), key_p, keyLength); i += keyLength; memset(&(innerMsg_sha_p[i]), PAD1, SHA1_PAD_LENGTH); /* prepend the residual, if any */ if (hObjMD5_p->residualLength > 0) { memcpy(hashMsgMD5_p, hObjMD5_p->residual, hObjMD5_p->residualLength); hashingLength_md5 = hObjMD5_p->residualLength; } memcpy(&(hashMsgMD5_p[hObjMD5_p->residualLength]), innerMsg_md5_p, innerMsgLen_md5); hashingLength_md5 += innerMsgLen_md5; /* prepend the residual, if any */ if (hObjSHA_p->residualLength > 0) { memcpy(hashMsgSHA_p, hObjSHA_p->residual, hObjSHA_p->residualLength); hashingLength_sha = hObjSHA_p->residualLength; } memcpy(&(hashMsgSHA_p[hObjSHA_p->residualLength]), innerMsg_sha_p, innerMsgLen_sha); hashingLength_sha += innerMsgLen_sha; /* construct the outer message: * outerMsg_p = key + pad2 + innerResult */ i = 0; memcpy(&(outerMsg_sha_p[i]), key_p, keyLength); i+= keyLength; memset(&(outerMsg_sha_p[i]), PAD2, SHA1_PAD_LENGTH); i = 0; memcpy(&(outerMsg_md5_p[i]), key_p, keyLength); i+= keyLength; memset(&(outerMsg_md5_p[i]), PAD2, MD5_PAD_LENGTH); /* create callback structure */ callBackData_p = (N8_HandshakeEndResults_t *)&req_p->postProcessBuffer; callBackData_p->to_resultSHA_p = resultSHA_p; callBackData_p->from_end_resultSHA_p = endResult_sha_p; callBackData_p->to_objSHA_p = (void *) hObjSHA_p; callBackData_p->to_resultMD5_p = resultMD5_p; callBackData_p->from_end_resultMD5_p = endResult_md5_p; callBackData_p->to_objMD5_p = (void *) hObjMD5_p; req_p->postProcessingData_p = (void *) callBackData_p; ret = cb_ea_SSLHandshakeHash(req_p, req_p->EA_CommandBlock_ptr, hObjMD5_p, innerResult_md5_a, hashMsgMD5_a, hashingLength_md5, hObjSHA_p, innerResult_sha_a, hashMsgSHA_a, hashingLength_sha, endResult_md5_a, endResult_sha_a, outerMsg_md5_a, outerMsgLen_md5, outerMsg_sha_a, outerMsgLen_sha); CHECK_RETURN(ret); QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up resources */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } return ret; } /* computeSSLHandshakeHash */ /***************************************************************************** * computeTLSHandshakeHash *****************************************************************************/ /** @ingroup n8_hash * @brief Generate the command blocks and set up the result handler for * the TLS modes of the N8_HandshakeHashEnd command. * * This function completes the N8_Handshake in either TLS_FINISH or TLS_CERT * mode. The TLS_FINISH calculation is done according to RFC 2246, section 5. * * @param md5Obj_p RO: Contains the md5 partial result to complete. * @param sha1Obj_p RO: Contains the sha1 partial result to complete. * @param protocol RO: N8_TLS_CERT or N8_TLS_FINISH * @param roleString_p RO: Either "server finished" or "client finished" * @param key_p RO: The key (secret) for the TLS PRF. * @param md5Result_p RW: The md5 result pointer passed in from API. * @param sha1Result_p RW: The sha1 result pointer passed in from API. * @param event_p RO: The event pointer * * @par Externals: * None. * * @return * N8_STATUS_OK: The function has succeeded. * * @par Errors: * N8_INVALID_OBJECT: One of the input parameters in invalid. * * @par Locks: * None. * * @par Assumptions: *****************************************************************************/ N8_Status_t computeTLSHandshakeHash(N8_HashObject_t *md5Obj_p, N8_HashObject_t *sha1Obj_p, const N8_HashProtocol_t protocol, const char *roleString_p, const N8_Buffer_t *key_p, const unsigned int keyLength, N8_Buffer_t *md5Result_p, N8_Buffer_t *sha1Result_p, N8_Event_t *event_p) { N8_Status_t ret = N8_STATUS_OK; N8_Buffer_t *hashMsgMD5_p = NULL; uint32_t hashMsgMD5_a; N8_Buffer_t *resMD5_p = NULL; uint32_t resMD5_a; N8_Buffer_t *hashMsgSHA1_p = NULL; uint32_t hashMsgSHA1_a; N8_Buffer_t *resSHA1_p = NULL; uint32_t resSHA1_a; N8_Buffer_t *resMD5PRF_p = NULL; uint32_t resMD5PRF_a; N8_Buffer_t *resSHA1PRF_p = NULL; uint32_t resSHA1PRF_a; N8_Buffer_t *roleStr_p = NULL; uint32_t roleStr_a; API_Request_t *req_p = NULL; int nBytes; N8_TLSHandshakeHashResults_t *hashResultStruct_p; int nCmdBlocks = 0; int roleSize; do { CHECK_OBJECT(md5Obj_p, ret); CHECK_OBJECT(sha1Obj_p, ret); CHECK_OBJECT(md5Result_p, ret); CHECK_OBJECT(sha1Result_p, ret); CHECK_OBJECT(roleString_p, ret); CHECK_OBJECT(key_p, ret); /* Note: If we are not doing TLS_FINISH or TLS_CERT we won't be in this function */ if (protocol == N8_TLS_FINISH) { nCmdBlocks = N8_CB_EA_FINISHTLSHANDSHAKE_NUMCMDS; } else if (protocol == N8_TLS_CERT) { nCmdBlocks = N8_CB_EA_CERTTLSHANDSHAKE_NUMCMDS; } /* We need to allocate kernel space for the role string, but we don't want to include the null terminator */ roleSize = strlen(roleString_p); /* allocate kernel memory for the keys and msgs */ /* The number of bytes is derived as follows: We are going to complete the MD5 and SHA1 hashes (using opcodes 0x10 and 0x20). This requires the MD5 residual lengh, the SHA1 residual length and 1 * hashSize for each of MD5 and SHA1. The additional 2 * hashSize for each of MD5 and SHA1 are used for the TLS Pseudo Random Function required for the N8_TLS_FINISH protocol (using opcodes 0x18 and 0x28). We are also allocating NEXT_WORD_SIZE(roleSize) bytes for the role string (either "client finished" or "server finished"). We use the NEXT_WORD_SIZE macro to add the extra bytes for the role string because we expect to need those extra bytes in the buffer when we restore word alignment. Of course, if we are doing a TLS_CERT instead of a TLS_FINISH, we could get by with less memory but this works fine and handles both cases correctly. */ nBytes = ((3 * NEXT_WORD_SIZE(md5Obj_p->hashSize)) + (3 * NEXT_WORD_SIZE(sha1Obj_p->hashSize)) + NEXT_WORD_SIZE(md5Obj_p->residualLength) + NEXT_WORD_SIZE(sha1Obj_p->residualLength) + NEXT_WORD_SIZE(roleSize)); /* Notice that we are using the unit from the MD5 object. At some point in the future we might like to use different units for each of the requests, but that will require a more general solution */ ret = createEARequestBuffer(&req_p, md5Obj_p->unitID, nCmdBlocks, resultHandlerTLSHandshakeHash, nBytes); CHECK_RETURN(ret); /* Set up the addresses. Note that we are setting this up so that after the first two command blocks the role string, the completed MD5 hash, and the completed SHA1 hash are contiguous in physical memory. This is because the last two steps of the TLS Finish protocol use this concatenation as an input. Also note that since the role strings are both 15 bytes, the MD5 and SHA1 result buffers are not word aligned. */ /* The role string */ roleStr_a = req_p->qr.physicalAddress + req_p->dataoffset; roleStr_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset); memset(roleStr_p, 0, nBytes); /* Results of MD5 hash */ resMD5_a = roleStr_a + roleSize; resMD5_p = roleStr_p + roleSize; /* Results of SHA1 hash */ resSHA1_a = resMD5_a + md5Obj_p->hashSize; resSHA1_p = resMD5_p + md5Obj_p->hashSize; /* Input for MD5 hash. The use of NEXT_WORD_SIZE on the resSHA1 ptrs is to restore word alignment. */ hashMsgMD5_a = NEXT_WORD_SIZE(resSHA1_a) + NEXT_WORD_SIZE(sha1Obj_p->hashSize); hashMsgMD5_p = (N8_Buffer_t *) NEXT_WORD_SIZE((uint32_t) resSHA1_p) + NEXT_WORD_SIZE(sha1Obj_p->hashSize); /* Input for SHA1 hash */ hashMsgSHA1_a = hashMsgMD5_a + NEXT_WORD_SIZE(md5Obj_p->residualLength); hashMsgSHA1_p = hashMsgMD5_p + NEXT_WORD_SIZE(md5Obj_p->residualLength); /* Results of MD5 PRF */ resMD5PRF_a = hashMsgSHA1_a + NEXT_WORD_SIZE(sha1Obj_p->residualLength); resMD5PRF_p = hashMsgSHA1_p + NEXT_WORD_SIZE(sha1Obj_p->residualLength); /* Results of SHA1 PRF */ resSHA1PRF_a = resMD5PRF_a + (2 * NEXT_WORD_SIZE(md5Obj_p->hashSize)); resSHA1PRF_p = resMD5PRF_p + (2 * NEXT_WORD_SIZE(md5Obj_p->hashSize)); /* Copy in the role string */ memcpy(roleStr_p, roleString_p, roleSize); /* Copy in messages to hash */ /* preappend the residual, if any */ if (md5Obj_p->residualLength > 0) { memcpy(hashMsgMD5_p, md5Obj_p->residual, md5Obj_p->residualLength); } /* prepend the residual, if any */ if (sha1Obj_p->residualLength > 0) { memcpy(hashMsgSHA1_p, sha1Obj_p->residual, sha1Obj_p->residualLength); } ret = cb_ea_TLSHandshakeHash(req_p, protocol, resMD5_a, hashMsgMD5_a, md5Obj_p, md5Obj_p->residualLength, resSHA1_a, hashMsgSHA1_a, sha1Obj_p, sha1Obj_p->residualLength, resMD5PRF_a, resSHA1PRF_a, key_p, keyLength, roleStr_a); CHECK_RETURN(ret); /* create a struct to carry results to the result handler */ CREATE_UOBJECT(hashResultStruct_p, N8_TLSHandshakeHashResults_t, ret); hashResultStruct_p->protocol = protocol; hashResultStruct_p->MD5Result_p = md5Result_p; hashResultStruct_p->SHA1Result_p = sha1Result_p; hashResultStruct_p->resMD5_p = resMD5_p; hashResultStruct_p->resSHA1_p = resSHA1_p; hashResultStruct_p->resMD5PRF_p = resMD5PRF_p; hashResultStruct_p->resSHA1PRF_p = resSHA1PRF_p; req_p->postProcessingData_p = (void *) hashResultStruct_p; QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up resources */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } return ret; } /***************************************************************************** * n8_HashCompleteMessage_req *****************************************************************************/ /** @ingroup n8_hash * @brief Generate the request for N8_HashCompleteMessage * * @param obj_p RW: Hash object pointer. * @param msg_p RO: Message to be hashed. * @param msgLength RO: Length of message to be hashed. * @param result_p RW: Destination of hash results. * @param resultHandler RO: Pointer to callback function. If NULL * the default is used. * @param req_pp RW: Pointer to request pointer. * * @par Externals * None * * @return * Status * * @par Errors * N8_INVALID_OBJECT if req_pp is NULL
* N8_INVALID_INPUT_SIZE if the msgLength is greater than N8_MAX_HASH_LENGTH * * @par Assumptions * None *****************************************************************************/ N8_Status_t n8_HashCompleteMessage_req(N8_HashObject_t *obj_p, const N8_Buffer_t *msg_p, const unsigned int msgLength, N8_Buffer_t *result_p, const void *resultHandler, API_Request_t **req_pp) { N8_Status_t ret = N8_STATUS_OK; N8_Buffer_t *hashMsg_p = NULL; unsigned long hashMsg_a; uint32_t res_a; N8_Buffer_t *res_p = NULL; int nBytes; do { CHECK_OBJECT(req_pp, ret); *req_pp = NULL; /* set the return request to NULL in case we * have to bail out. */ ret = N8_preamble(); CHECK_RETURN(ret); if (resultHandler == NULL) { resultHandler = resultHandlerGeneric; } if (msgLength > N8_MAX_HASH_LENGTH) { ret = N8_INVALID_INPUT_SIZE; break; } CHECK_OBJECT(obj_p, ret); if (msgLength > 0) { CHECK_OBJECT(msg_p, ret); } CHECK_OBJECT(result_p, ret); CHECK_STRUCTURE(obj_p->structureID, N8_HASH_STRUCT_ID, ret); /* comput the size for the results and the incoming message. */ nBytes = (NEXT_WORD_SIZE(obj_p->hashSize) + NEXT_WORD_SIZE(msgLength)); /* create the command blocks and do the hash. */ ret = createEARequestBuffer(req_pp, obj_p->unitID, N8_CB_EA_HASHCOMPLETEMESSAGE_NUMCMDS, resultHandler, nBytes); CHECK_RETURN(ret); /* allocate space for the chip to place the result */ res_a = (*req_pp)->qr.physicalAddress + (*req_pp)->dataoffset; res_p = (N8_Buffer_t *) ((int)(*req_pp) + (*req_pp)->dataoffset); memset(res_p, 0, nBytes); hashMsg_a = res_a + NEXT_WORD_SIZE(obj_p->hashSize); hashMsg_p = res_p + NEXT_WORD_SIZE(obj_p->hashSize); /* Copy in message to hash */ memcpy(hashMsg_p, msg_p, msgLength); DBG(("hash length: %d\n", msgLength)); (*req_pp)->copyBackFrom_p = res_p; (*req_pp)->copyBackTo_p = (void *) result_p; (*req_pp)->copyBackSize = obj_p->hashSize; ret = cb_ea_hashCompleteMessage(*req_pp, (*req_pp)->EA_CommandBlock_ptr, obj_p, hashMsg_a, msgLength, res_a); CHECK_RETURN(ret); } while (FALSE); return ret; } /* n8_HashCompleteMessage_req */ N8_Status_t n8_HashCompleteMessage_req_uio(N8_HashObject_t *obj_p, struct uio *msg_p, const unsigned int msgLength, N8_Buffer_t *result_p, const void *resultHandler, API_Request_t **req_pp) { N8_Status_t ret = N8_STATUS_OK; N8_Buffer_t *hashMsg_p = NULL; unsigned long hashMsg_a; uint32_t res_a; N8_Buffer_t *res_p = NULL; int nBytes; do { CHECK_OBJECT(req_pp, ret); *req_pp = NULL; /* set the return request to NULL in case we * have to bail out. */ ret = N8_preamble(); CHECK_RETURN(ret); if (resultHandler == NULL) { resultHandler = resultHandlerGeneric; } if (msgLength > N8_MAX_HASH_LENGTH) { ret = N8_INVALID_INPUT_SIZE; break; } CHECK_OBJECT(obj_p, ret); if (msgLength > 0) { CHECK_OBJECT(msg_p, ret); } CHECK_OBJECT(result_p, ret); CHECK_STRUCTURE(obj_p->structureID, N8_HASH_STRUCT_ID, ret); /* comput the size for the results and the incoming message. */ nBytes = (NEXT_WORD_SIZE(obj_p->hashSize) + NEXT_WORD_SIZE(msgLength)); /* create the command blocks and do the hash. */ ret = createEARequestBuffer(req_pp, obj_p->unitID, N8_CB_EA_HASHCOMPLETEMESSAGE_NUMCMDS, resultHandler, nBytes); CHECK_RETURN(ret); /* allocate space for the chip to place the result */ res_a = (*req_pp)->qr.physicalAddress + (*req_pp)->dataoffset; res_p = (N8_Buffer_t *) ((int)(*req_pp) + (*req_pp)->dataoffset); memset(res_p, 0, nBytes); hashMsg_a = res_a + NEXT_WORD_SIZE(obj_p->hashSize); hashMsg_p = res_p + NEXT_WORD_SIZE(obj_p->hashSize); /* Copy in message to hash */ cuio_copydata(msg_p, 0, msgLength, hashMsg_p); DBG(("hash length: %d\n", msgLength)); DBG(("cleartext: %08x|%08x|%08x|%08x\n", *(((uint32_t *)hashMsg_p)), *(((uint32_t *)hashMsg_p)+1), *(((uint32_t *)hashMsg_p)+2), *(((uint32_t *)hashMsg_p)+3))); (*req_pp)->copyBackFrom_p = res_p; (*req_pp)->copyBackTo_p = result_p; (*req_pp)->copyBackTo_uio = NULL; (*req_pp)->copyBackSize = obj_p->hashSize; ret = cb_ea_hashCompleteMessage(*req_pp, (*req_pp)->EA_CommandBlock_ptr, obj_p, hashMsg_a, msgLength, res_a); CHECK_RETURN(ret); } while (FALSE); return ret; } /* n8_HashCompleteMessage_req */ /***************************************************************************** * N8_HashCompleteMessage ****************************************************************************/ /** @ingroup n8_hash * @brief Hash a complete message. * * To hash a message under 18 K bytes long use this function. Any * hash greater than that should make multiple calls to * N8_HashPartial. * * @param obj_p RW: Hash object to store intermediate results. * @param msg_p RO: Pointer to the message to be hashed. * @param msgLength RO: Length of message to be hashed. * @param result_p WO: Pointer to hashed message. * @param event_p RO: Pointer to event for async calls. Null for * synchronous call. * @par Externals: * None * * @return * Status code of type N8_Status. * * @par Errors: * N8_STATUS_OK: A-OK
* N8_INVALID_INPUT_SIZE: message passed was larger than allowed * limit of N8_MAX_HASH_LENGTH
* N8_INVALID_OBJECT Invalid or null input parameter. * @par Assumptions: * None ****************************************************************************/ N8_Status_t N8_HashCompleteMessage(N8_HashObject_t *obj_p, const N8_Buffer_t *msg_p, const unsigned int msgLength, N8_Buffer_t *result_p, N8_Event_t *event_p) { N8_Status_t ret = N8_STATUS_OK; API_Request_t *req_p = NULL; DBG(("N8_HashCompleteMessage\n")); do { /* generate the request */ ret = n8_HashCompleteMessage_req(obj_p, msg_p, msgLength, result_p, NULL, /* result handler -- use default */ &req_p); if (req_p == NULL) { if (event_p != NULL) { N8_SET_EVENT_FINISHED(event_p, N8_EA); } break; } QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up resources */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } DBG(("N8_HashCompleteMessage - OK\n")); return ret; } /* N8_HashCompleteMessage */ /* same as above, but for uio iovec i/o */ N8_Status_t N8_HashCompleteMessage_uio(N8_HashObject_t *obj_p, struct uio *msg_p, const unsigned int msgLength, N8_Buffer_t *result_p, N8_Event_t *event_p) { N8_Status_t ret = N8_STATUS_OK; API_Request_t *req_p = NULL; DBG(("N8_HashCompleteMessage\n")); do { /* generate the request */ ret = n8_HashCompleteMessage_req_uio(obj_p, msg_p, msgLength, result_p, NULL, /* result handler -- use default */ &req_p); if (req_p == NULL) { if (event_p != NULL) { N8_SET_EVENT_FINISHED(event_p, N8_EA); } break; } QUEUE_AND_CHECK(event_p, req_p, ret); HANDLE_EVENT(event_p, req_p, ret); } while (FALSE); /* clean up resources */ if (ret != N8_STATUS_OK) { freeRequest(req_p); } DBG(("N8_HashCompleteMessage - OK\n")); return ret; } /* N8_HashCompleteMessage */