Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dev / pci / n8 / common / api / n8_hash.c
blob93c08ea632d0d8453ec5b862c6d70294037b931b
1 /*-
2 * Copyright (C) 2001-2003 by NBMK Encryption Technologies.
3 * All rights reserved.
5 * NBMK Encryption Technologies provides no support of any kind for
6 * this software. Questions or concerns about it may be addressed to
7 * the members of the relevant open-source community at
8 * <tech-crypto@netbsd.org>.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are
12 * met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above
18 * copyright notice, this list of conditions and the following
19 * disclaimer in the documentation and/or other materials provided
20 * with the distribution.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 static char const n8_id[] = "$Id: n8_hash.c,v 1.1 2008/10/30 12:02:14 darran Exp $";
36 /*****************************************************************************/
37 /** @file n8_hash.c
38 * @brief Hashing functionality.
40 * Implementation of all public functions dealing with management of
41 * hashs.
43 * References:
44 * MD5: RFC1321 "The MD5 Message-Digest Algorithm", R. Rivest, 4/92
45 * SHA-1: FIPS Pub 180-1,"Secure Hash Standard", US Dept. of Commerce,
46 * 4/17/95
47 * HMAC: RFC2104 "HMAC: Keyed-Hashing for Message Authentication", H. Krawczyk,
48 * 2/97.
50 *****************************************************************************/
52 /*****************************************************************************
53 * Revision history:
54 * 07/28/03 brr Removed obsolete #ifdefs. (Bug 918)
55 * 07/01/03 brr Added option to use no hashing algorithm.
56 * 05/19/03 brr Use post processing buffer in API request instead of
57 * performing a malloc for it.
58 * 09/10/02 brr Set command complete bit on last command block.
59 * 08/13/02 brr Correctly size hashedKey array.
60 * 08/06/02 bac Fixed Bug #842 -- user's cipher info was being modified.
61 * 05/20/02 brr Free the request for all error conditions.
62 * 05/15/02 brr Removed call to n8_addSubRequest.
63 * 05/07/02 msz New interface for QUEUE_AND_CHECK for new synchronous support.
64 * 05/01/02 brr Memset data segment after return from createEARequestBuffer.
65 * 03/26/02 brr Allocate the data buffer as part of the API request.
66 * 02/28/02 brr Do not include any QMgr include files.
67 * 02/25/02 brr Removed last of the QMgr references.
68 * 02/22/02 spm Converted printf's to DBG's. Added include of n8_OS_intf.h.
69 * 02/21/02 brr Removed references to QMgr_get_valid_unit_num.
70 * 01/23/02 bac Correctly initialize for HMAC by setting the Nl and opad_Nl
71 * values and by setting the hashedHMACKey.
72 * 01/22/02 bac Added code to use software to do SSL and HMAC precomputes.
73 * 01/21/02 bac Changes to support new kernel allocation scheme.
74 * 01/18/02 bac Fixed a problem with kernel memory allocation sizing.
75 * 01/18/02 bac Corrected a bug in the setting of the hashed HMAC key. If the
76 * key was odd in size, the final byte was being dropped.
77 * (BUG #482). Also removed a debugging message that was
78 * inadvertantly left in (BUG #479).
79 * 01/16/02 bac Several routines were allocating the maximum size allowed for
80 * hashing when kernel memory was needed. This was grossly
81 * inefficient and slow. The routines were changed to only
82 * allocate the exact amount needed.
83 * 01/14/02 bac Changed resultHandlerHMACInit to copy the byte-swapped results
84 * back to the kernel memory context for proper formatting in the
85 * subsequent load context request.
86 * 01/12/02 bac Removed all blocking calls within a single API method. This
87 * required the restructuring of the N8_HashInitialize,
88 * N8_HashPartial, and N8_HashEnd calls, especially as they dealt
89 * with HMAC. (BUG #313)
90 * 11/24/01 brr Removed include of obsolete EA & PK specifice Queue files.
91 * 11/15/01 mel Fixed bug #291 : N8_HashInitialize does not modify event
92 * structure
93 * 11/12/01 hml Added unitID to initMD5 and initSHA1.
94 * 11/12/01 hml Added structure verification: bug #261
95 * 11/08/01 mel Fixed bug #289 : by passing unitID parameter
96 * 11/08/01 mel Fixed bug# 272: N8_IKEEncryptKeyExpand and
97 * N8_IKEKeyMaterialExpand seg faults
98 * 11/08/01 mel Fixed bug# 271: N8_IKEEncryptKeyExpand and
99 * N8_IKEKeyMaterialExpand returns incorrect error code for
100 * outputLength=0.
101 * 11/06/01 dkm Added null error check to MD5_/SHA1_Init.
102 * 10/30/01 bac Removed incrementHashObjectLengths and replaced with shared
103 * function n8_incrLength64
104 * 10/22/01 mel Re-designed HMAC to make it non-blocking. But it will remain
105 * blocking for HMAC or message longer than 64.
106 * 10/19/01 hml Fixed merge issues.
107 * 10/16/01 mel Made computeSSLHandshakeHash non-bloking.
108 * 10/16/01 spm IKE APIs: removed key physical addr parms in cb calls.
109 * 10/15/01 spm IKE APIs: removed unnecessary IKE result handlers.
110 * msg_length is now compared to N8_MAX_HASH_LENGTH as
111 * NOT N8_MAX_KEY_LENGTH. Miscellaneous optimiations/
112 * simplifications brought up in the IKE API code review.
113 * Removed unnecessary memsets. User objects are added to
114 * free list before kernel objects are mallocated to avoid
115 * kernel malloc leaks. Changed if-else on alg to switch
116 * on alg. Removed virtual pointer to msg in cb calls.
117 * Had to keep the virtual pointer to key, since the
118 * key has to be copied into the cb itself. Added
119 * N8_64BYTE_IKE_KEY_LIMIT.
120 * 10/15/01 bac Corrected problems with N8_HandshakeHashPartial due to
121 * incorrectly handling computeResidual when the hashing length
122 * was zero.
123 * 10/15/01 mel Redesigned computeSSLhandshake.
124 * 10/11/01 hml Use n8_strdup instead of strdup in getRoleString().
125 * 10/11/01 hml Added use of RESULT_HANDLER_WARNING for the
126 * N8_HandshakeHashEnd result handler.
127 * 10/10/01 hml Added N8_HashCompleteMessage and added support for the
128 * TLS modes to N8_HandshakeHashEnd.
129 * 10/10/01 brr Free resources in N8_HashEnd if error encountered.
130 * 10/02/01 bac Added use of RESULT_HANDLER_WARNING in all result handlers.
131 * 10/01/01 hml Updated rest of hash interfaces for multiple chips.
132 * 09/26/01 hml Updated to support multiple chips. The N8_HashInitialize,
133 * N8_TLSKeyMaterialHash and N8_SSLKeyMaterialHash were changed.
134 * 09/20/01 bac The interface to the command block generators changed and now
135 * accept the command block buffer. All calls to cb_ea methods
136 * changed herein.
137 * 09/18/01 bac Updated calls to createEARequestBuffer to pass the number of
138 * commands to be allocated.
139 * 09/17/01 spm Truncated lines >80 chars.
140 * 09/12/01 mel Deleted N8_UNIMPLEMENTED_FUNCTION in N8_HashPartial for HMAC.
141 * 09/10/01 spm Fixed memory leak in N8_IKEEncryptKeyExpand (0 byte not
142 * allocated)
143 * 09/08/01 spm IKE APIs: Swapped order of alg and hashInfo args.
144 * 09/07/01 spm Added IKE APIs
145 * 09/07/01 bac Fixed bug where we weren't checking the return code from a
146 * call to N8_HashPartial in N8_HandshakeHashPartial.
147 * (BUG #159)
148 * 09/07/01 bac Fixed a comment in N8_HashPartial which had the wrong size
149 * limit for data sent to that method. (BUG #60)
150 * 09/06/01 bac Added include of <string.h> to silence warning.
151 * 08/24/01 bac Removed DBG prints of unterminated buffers.
152 * 08/14/01 bac Fixed memcpy bugs in computeHMAC where the wrong number of
153 * bytes were being moved. Also determined HMAC hashes are not
154 * implemented correctly and have disallowed the use of
155 * N8_HashPartial and N8_HashEnd with HMAC algorithms. This
156 * partially fixes Bug #160.
157 * 08/01/01 bac Changed MIN to N8_MIN to avoid compilation warnings.
158 * 07/31/01 bac Added call to N8_preamble for all public interfaces.
159 * 07/20/01 bac Changed calls to create__RequestBuffer to pass the chip id.
160 * 07/09/01 bac Bug #115 and Bug #116 -- fixed N8_HandshakeHashPartial and
161 * N8_HandshakeHashEnd to use the user-supplied event when
162 * making the final API call. All other API calls made by
163 * these methods remain synchronous but the final one is
164 * non-blocking and correctly indicates the status of
165 * the original call. This is not the final solution.
166 * 07/02/01 mel Fixed comments.
167 * 06/28/01 bac Added HANDLE_EVENT calls as necessary.
168 * 06/28/01 bac Removed calls to 'freeRequest' in the result handlers as
169 * that belongs in the EventCheck routine.
170 * 06/27/01 mel Added init of hash object in computeHMAC between pad0 and
171 * pad 1 compute
172 * 06/25/01 mel In N8_TLSKeyMaterialHash added check :
173 * if the sum of KeyLength, LabelLength, and SeedLength is >
174 * 18 Kbytes, return ERROR.
175 * 06/25/01 bac More changes for QMgr v.1.0.1
176 * 06/19/01 bac Correct use of kernel memory.
177 * 06/18/01 mel Added N8_TLSKeyMaterialHash API.
178 * 06/17/01 bac Free request upon failure in N8_SSLKeyMaterialHash
179 * 05/30/01 bac Doxygenation.
180 * 05/30/01 bac Test for hashingLength==0 in HashEnd to avoid the suspicion
181 * of memory alloc problems (malloc(0)).
182 * 05/24/01 dws Fixed the pointer arithmetic in the copy of the
183 * N8_HashPartial result to the N8_HashObject_t iv field in
184 * ResultHandlerHashPartial.
185 * 05/19/01 bac Corrected the freeing of postProcessingData. Since the
186 * data passed in this pointer may be user data or local data
187 * sometimes it is appropriate to free it other times it isn't.
188 * Thus, the decision needs to live in the resultHandler, not
189 * the freeRequest utility.
190 * 05/19/01 bac Fixed memory leak.
191 * 05/18/01 mel Fix bug with wrong size memory allocation.
192 * 05/18/01 bac Converted to N8_xMALLOC and N8_xFREE
193 * 05/15/01 bac Fixed a bug where pointers were not initialized to NULL but
194 * were freed under error conditions.
195 * 05/14/01 bac Fixed the copy from results_p to IV to copy the right
196 * amount whether MD5 or SHA-1.
197 * 05/09/01 dws Changed the way that the result bytes are loaded into the
198 * hash object IV in N8_HashPartial. It now uses a series of
199 * BE_to_uint32 operations instead of memcpy.
200 * 04/30/01 dkm Modified N8_HashPartial so that if message is too small
201 * to start a hash, the message is appended onto the
202 * residual and residualLength is updated.
203 * 04/30/01 bac changed printResult to printN8Buffer
204 * 04/26/01 bac Completion of handshake hash functions.
205 * 04/24/01 bac Removed printResult definition. It is now
206 * printN8Buffer in n8_util.
207 * 04/09/01 bac Added functionality for N8_HashInitialize
208 * 03/29/01 bac Original version.
209 ****************************************************************************/
210 /** @defgroup n8_hash Hashing Functions
213 #include "n8_pub_errors.h"
214 #include "n8_hash.h"
215 #include "n8_ea_common.h"
216 #include "n8_cb_ea.h"
217 #include "n8_enqueue_common.h"
218 #include "n8_util.h"
219 #include "n8_API_Initialize.h"
220 #include "n8_precompute.h"
221 #include "n8_OS_intf.h"
222 #include <opencrypto/cryptodev.h>
224 * Defines for values and macros
226 #define MD5_PAD_LENGTH (48)
227 #define SHA1_PAD_LENGTH (40)
230 * Prototypes of local static functions
232 static N8_Status_t
233 computeTLSHandshakeHash(N8_HashObject_t *md5Obj_p,
234 N8_HashObject_t *sha1Obj_p,
235 const N8_HashProtocol_t protocol,
236 const char *roleString_p,
237 const N8_Buffer_t *key_p,
238 const unsigned int keyLength,
239 N8_Buffer_t *md5Result_p,
240 N8_Buffer_t *sha1Result_p,
241 N8_Event_t *event_p);
243 static char *getRoleString(const N8_HashProtocol_t protocol,
244 const N8_HashRole_t role);
245 static N8_Status_t computeSSLHandshakeHash(N8_HashObject_t *hObjMD5_p,
246 N8_HashObject_t *hObjSHA_p,
247 const char *roleString_p,
248 const N8_Buffer_t *key_p,
249 const unsigned int keyLength,
250 N8_Buffer_t *resultMD5_p,
251 N8_Buffer_t *resultSHA_p,
252 N8_Event_t *event_p);
253 static N8_Status_t computeResidual(N8_HashObject_t *obj_p,
254 const N8_Buffer_t *msg_p,
255 N8_Buffer_t *hashMsg_p,
256 const unsigned int msgLength,
257 unsigned int *hashingLength);
259 N8_Status_t n8_initializeHMAC(N8_Buffer_t *HMACKey,
260 uint32_t HMACKeyLength,
261 N8_HashObject_t *hashObj_p,
262 N8_Event_t *event_p);
263 N8_Status_t n8_HMACHashEnd_req(N8_HashObject_t *obj_p,
264 N8_Buffer_t *result_p,
265 API_Request_t **req_pp);
267 * local structure definitions
269 typedef struct
271 N8_Buffer_t *result_p;
272 N8_Buffer_t *dest_p;
273 int length;
274 } N8_SSLKeyHashResults_t;
276 typedef struct
278 int outputLength;
279 N8_Buffer_t *result_p;
280 N8_Buffer_t *prS_p[2];
281 } N8_TLSKeyHashResults_t;
283 typedef struct
285 uint32_t outputLength;
286 N8_Buffer_t *result_p; /* this buffer is 3*outputLength bytes long */
287 N8_Buffer_t *SKEYIDd_p;
288 N8_Buffer_t *SKEYIDa_p;
289 N8_Buffer_t *SKEYIDe_p;
290 } N8_IKESKEYIDExpandResults_t;
292 typedef struct
294 N8_Buffer_t *MD5_results_p;
295 N8_HashObject_t *MD5_obj_p;
296 N8_Buffer_t *SHA_results_p;
297 N8_HashObject_t *SHA_obj_p;
299 } N8_HandshakePartialResults_t;
301 typedef struct
303 N8_HashProtocol_t protocol;
304 N8_Buffer_t *MD5Result_p;
305 N8_Buffer_t *SHA1Result_p;
306 N8_Buffer_t *resMD5_p;
307 N8_Buffer_t *resSHA1_p;
308 N8_Buffer_t *resMD5PRF_p;
309 N8_Buffer_t *resSHA1PRF_p;
310 } N8_TLSHandshakeHashResults_t;
311 typedef struct
313 N8_Buffer_t *to_resultSHA_p;
314 N8_Buffer_t *from_end_resultSHA_p;
315 N8_Buffer_t *to_objSHA_p;
316 N8_Buffer_t *from_ivSHA_p;
317 int length_SHA;
318 N8_Buffer_t *to_resultMD5_p;
319 N8_Buffer_t *from_end_resultMD5_p;
320 N8_Buffer_t *to_objMD5_p;
321 N8_Buffer_t *from_ivMD5_p;
322 int length_MD5;
323 } N8_HandshakeEndResults_t;
325 typedef struct
327 N8_Buffer_t *result1_p;
328 N8_Buffer_t *result2_p;
329 } N8_HMACResults_t;
333 * Static Methods
335 static void n8_setHashedHMACKey(N8_HashObject_t *obj_p,
336 N8_Buffer_t *key_p,
337 unsigned int keyLength)
339 N8_Buffer_t *tmp_p;
340 int i;
341 int iterations = CEIL(keyLength, sizeof(uint32_t));
342 tmp_p = (N8_Buffer_t *) obj_p->hashedHMACKey;
343 /* copy the key to the hashedHMACKey */
344 memcpy(tmp_p, key_p, keyLength);
345 /* pad the remainder with zeroes */
346 memset(&tmp_p[keyLength], 0x0, sizeof(obj_p->hashedHMACKey)-keyLength);
347 /* now, byte-swap the key in place */
348 for (i = 0; i < iterations; i++)
350 obj_p->hashedHMACKey[i] = BE_to_uint32(tmp_p);
351 tmp_p += 4;
353 } /* n8_setHashedHMACKey */
355 /**********************************************************************
356 * resultHandlerHashPartial
358 * Description:
359 * This function is called by the Public Key Request Queue handler when
360 * either the request is completed successfully and all the commands
361 * copied back to the command blocks allocated by the API, or when
362 * the Simon has encountered an error with one of the commands such
363 * that the Simon has locked up.
365 * Note this function will have to be NON-BLOCKING or it will lock up the
366 * queue handler!
369 **********************************************************************/
370 static void resultHandlerHashPartial(API_Request_t* req_p)
372 N8_Buffer_t *iv_p;
373 N8_HashObject_t *obj_p;
374 int i;
375 const char *title = "resultHandlerHashPartial";
376 if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK)
378 DBG(("%s call-back with success\n", title));
379 /* the partial hash has been pre-computed. the results must now
380 * be copied back into the hash object */
381 obj_p = (N8_HashObject_t *) req_p->copyBackTo_p;
382 iv_p = req_p->copyBackFrom_p;
383 #ifdef N8DEBUG
384 printf("result(%d bytes): ", obj_p->hashSize);
385 for (i=0; i<obj_p->hashSize / sizeof(uint32_t); i+=4) {
386 printf("%08x ", *(uint32_t *)(&iv_p[i]));
388 printf("\n");
389 #endif
391 for (i = 0; i < obj_p->hashSize / sizeof(uint32_t); i++)
393 obj_p->iv[i] = BE_to_uint32(iv_p);
394 iv_p += 4;
397 else
399 RESULT_HANDLER_WARNING(title, req_p);
401 /* freeRequest(req_p); */
402 } /* resultHandlerHashPartial */
405 /**********************************************************************
406 * resultHandlerTLSKeyHash
408 * Description:
409 * This function is called by the Public Key Request Queue handler when
410 * either the request is completed successfully and all the commands
411 * copied back to the command blocks allocated by the API, or when
412 * the Simon has encountered an error with one of the commands such
413 * that the Simon has locked up.
415 * Note this function will have to be NON-BLOCKING or it will lock up the
416 * queue handler!
419 **********************************************************************/
420 static void resultHandlerTLSKeyHash(API_Request_t* req_p)
422 int i;
423 N8_TLSKeyHashResults_t *keyResults_p;
424 const char *title = "resultHandlerTLSKeyHash";
425 if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK)
427 DBG(("%s call-back with success\n", title));
428 keyResults_p =
429 (N8_TLSKeyHashResults_t* ) req_p->postProcessingData_p;
430 /* produce the key material by XOR-ing pseudorandom streams */
431 for (i = 0; i < keyResults_p->outputLength; i++)
433 /* when bug in chip is fixed, don't forget to change index to i+16
434 * and i+20 */
435 keyResults_p->result_p[i] = (keyResults_p->prS_p[0][i] ^
436 keyResults_p->prS_p[1][i]);
439 else
441 RESULT_HANDLER_WARNING(title, req_p);
443 } /* resultHandlerTLSKeyHash */
445 /*****************************************************************************
446 * resultHandlerIKESKEYIDExpand
447 *****************************************************************************/
448 /** @ingroup n8_hash
449 * @brief Handles result for N8_IKESKEYIDExpand
451 * Description:
452 * This function is called by the Public Key Request Queue handler when
453 * either the request is completed successfully and all the commands
454 * copied back to the command blocks allocated by the API, or when
455 * the Simon has encountered an error with one of the commands such
456 * that the Simon has locked up.
458 * Note this function will have to be NON-BLOCKING or it will lock up the
459 * queue handler!
461 * @param req_p RW: pointer to API request structure
463 * @par Externals:
465 * @return
466 * void
468 * @par Errors:
469 * None.
471 * @par Locks:
472 * None.
474 * @par Assumptions:
475 *****************************************************************************/
476 static void resultHandlerIKESKEYIDExpand(API_Request_t* req_p)
478 N8_IKESKEYIDExpandResults_t *keyResults_p;
479 const char *title = "resultHandlerIKESKEYIDExpand";
481 if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK)
483 DBG(("%s call-back with success\n", title));
484 keyResults_p =
485 (N8_IKESKEYIDExpandResults_t *) req_p->postProcessingData_p;
487 memcpy(keyResults_p->SKEYIDd_p, keyResults_p->result_p,
488 keyResults_p->outputLength);
489 memcpy(keyResults_p->SKEYIDa_p,
490 keyResults_p->result_p+keyResults_p->outputLength,
491 keyResults_p->outputLength);
492 memcpy(keyResults_p->SKEYIDe_p,
493 keyResults_p->result_p+2*keyResults_p->outputLength,
494 keyResults_p->outputLength);
496 else
498 RESULT_HANDLER_WARNING(title, req_p);
501 } /* resultHandlerIKESKEYIDExpand */
503 /*****************************************************************************
504 * resultHandlerTLSHandshakeHash
505 *****************************************************************************/
506 /** @ingroup n8_hash
507 * @Handles the result for the N8_TLS_FINISH and N8_TLS_CERT modes in
508 * N8_HandshakeHashEnd.
510 * This function is called by the EA Request Queue handler when
511 * either the request is completed successfully and all the commands
512 * copied back to the command blocks allocated by the API, or when
513 * the hardware has encountered an error with one of the commands such
514 * that the hardware has locked up. Note that the function is finishing the
515 * HandshakeHashEnd protocol according to section 5 of RFC 2246.
517 * @param req_p RW: pointer to API request structure.
519 * @par Externals:
520 * None.
522 * @return
523 * Void.
525 * @par Errors:
526 * None.
528 * @par Locks:
529 * None.
531 * @par Assumptions:
532 *****************************************************************************/
534 static void resultHandlerTLSHandshakeHash(API_Request_t* req_p)
536 N8_TLSHandshakeHashResults_t *data_p = NULL;
537 int i;
538 unsigned int dataBuffer[NUM_WORDS_TLS_RESULT];
539 unsigned int *ptr1;
540 unsigned int *ptr2;
541 const char *title = "resultHandlerTLSHandshakeHash";
544 if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK)
546 DBG(("resultHandlerTLSHandshakeHash call-back with success\n"));
547 data_p = (N8_TLSHandshakeHashResults_t *) req_p->postProcessingData_p;
549 if (data_p->protocol == N8_TLS_CERT)
551 memcpy(data_p->MD5Result_p,
552 data_p->resMD5_p,
553 MD5_HASH_RESULT_LENGTH);
555 memcpy(data_p->SHA1Result_p,
556 data_p->resSHA1_p,
557 SHA1_HASH_RESULT_LENGTH);
560 else
562 /* This can only be the N8_TLS_FINISH case. This algorithm is
563 defined in section 5 of RFC 2246 */
564 /* We need to ignore the first sample from each of the MD5 and
565 SHA1 results */
566 ptr1 =
567 (unsigned int *) (data_p->resMD5PRF_p + MD5_HASH_RESULT_LENGTH);
568 ptr2 =
569 (unsigned int *) (data_p->resSHA1PRF_p + SHA1_HASH_RESULT_LENGTH);
571 /* Now we Xor 12 bytes worth of data. Read the RFC ... */
572 for (i = 0; i < NUM_WORDS_TLS_RESULT; i++)
574 dataBuffer[i] = (*ptr1) ^ (*ptr2);
575 ptr1 ++;
576 ptr2 ++;
579 memcpy(data_p->MD5Result_p, dataBuffer, MD5_HASH_RESULT_LENGTH);
583 else
585 /* Unknown error */
586 RESULT_HANDLER_WARNING(title, req_p);
589 N8_UFREE(req_p->postProcessingData_p);
590 /* freeRequest(req_p); */
592 } /* resultHandlerTLSHandshakeHash */
595 /*****************************************************************************
596 * resultHandlerHandshakePartial
597 ****************************************************************************/
598 /** @ingroup n8_hash
599 * @brief Handles the result for the HandshakePartial
601 * Description:
602 * This function is called by the Public Key Request Queue handler when
603 * either the request is completed successfully and all the commands
604 * copied back to the command blocks allocated by the API, or when
605 * the Simon has encountered an error with one of the commands such
606 * that the Simon has locked up.
608 * Note this function will have to be NON-BLOCKING or it will lock up the
609 * queue handler!
612 **********************************************************************/
613 static void resultHandlerHandshakePartial(API_Request_t* req_p)
615 const char *title = "resultHandlerHandshakePartial";
617 N8_Buffer_t *md5_res_p;
618 N8_Buffer_t *sha_res_p;
619 N8_HashObject_t *md5_obj_p;
620 N8_HashObject_t *sha_obj_p;
621 N8_HandshakePartialResults_t *callBackData_p;
623 int i;
625 if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK)
627 DBG(("%s call-back with success\n", title));
628 /* the partial hash has been pre-computed. the results must now
629 * be copied back into the hash object */
631 callBackData_p = (N8_HandshakePartialResults_t *)
632 req_p->postProcessingData_p;
633 /* ensure the call back data is not null */
634 if (callBackData_p == NULL)
636 DBG(("ERROR: %s call-back with NULL callBackData_p.", title));
638 else
640 md5_obj_p = callBackData_p->MD5_obj_p;
641 md5_res_p = callBackData_p->MD5_results_p;
642 sha_obj_p = callBackData_p->SHA_obj_p;
643 sha_res_p = callBackData_p->SHA_results_p;
645 for (i = 0; i < md5_obj_p->hashSize / sizeof(uint32_t); i++)
647 md5_obj_p->iv[i] = BE_to_uint32(md5_res_p);
648 md5_res_p += 4;
650 for (i = 0; i < sha_obj_p->hashSize / sizeof(uint32_t); i++)
652 sha_obj_p->iv[i] = BE_to_uint32(sha_res_p);
653 sha_res_p += 4;
657 else
659 RESULT_HANDLER_WARNING(title, req_p);
661 /* DO NOT free request (req_p) here */
662 } /* resultHandlerHandshakePartial */
664 /**********************************************************************
665 * resultHandlerHandshakeEnd
667 * Description:
668 * This function is called by the Public Key Request Queue handler when
669 * either the request is completed successfully and all the commands
670 * copied back to the command blocks allocated by the API, or when
671 * the Simon has encountered an error with one of the commands such
672 * that the Simon has locked up.
674 * Note this function will have to be NON-BLOCKING or it will lock up the
675 * queue handler!
678 **********************************************************************/
679 static void resultHandlerHandshakeEnd(API_Request_t* req_p)
681 char title[] = "resultHandlerHandshakeEnd";
682 N8_Buffer_t *endresultmd5_p;
683 N8_Buffer_t *endresultsha_p;
684 N8_Buffer_t *resultmd5_p;
685 N8_Buffer_t *resultsha_p;
686 N8_HashObject_t *objmd5_p;
687 N8_HashObject_t *objsha_p;
688 N8_HandshakeEndResults_t *callBackData_p
689 = (N8_HandshakeEndResults_t *) req_p->postProcessingData_p;
691 if (req_p->qr.requestError == N8_QUEUE_REQUEST_OK )
693 DBG(("%s call-back with success\n", title));
694 /* the partial hash has been pre-computed. the results must now
695 * be copied back into the hash object */
696 resultsha_p = callBackData_p->to_resultSHA_p;
697 endresultsha_p = callBackData_p->from_end_resultSHA_p;
698 objsha_p = (N8_HashObject_t *) callBackData_p->to_objSHA_p;
699 resultmd5_p = callBackData_p->to_resultMD5_p;
700 endresultmd5_p = callBackData_p->from_end_resultMD5_p;
701 objmd5_p = (N8_HashObject_t *) callBackData_p->to_objMD5_p;
703 memcpy(resultmd5_p, endresultmd5_p, objmd5_p->hashSize);
704 memcpy(resultsha_p, endresultsha_p, objsha_p->hashSize);
706 else
708 RESULT_HANDLER_WARNING(title, req_p);
710 } /* resultHandlerHandshakeEnd */
712 /*****************************************************************************
713 * computeResidual
714 ****************************************************************************/
715 /** @ingroup n8_hash
716 * @brief Finish compute residual data.
718 * @param obj_p RW: Hash object to store intermediate results.
719 * @param msg_p RO: Pointer to the message to be hashed.
720 * @param msgLength RO: Length of message to be hashed.
721 * @param event_p RO: Pointer to event for async calls. Null for
722 * synchronous call.
723 * @par Externals:
724 * None
726 * @return
727 * Status code of type N8_Status.
729 * @par Errors:
730 * N8_STATUS_OK: A-OK<br>
731 * N8_INVALID_INPUT_SIZE: message passed was larger than allowed
732 * limit of N8_MAX_HASH_LENGTH<br>
733 * @par Assumptions:
734 * None
735 ****************************************************************************/
736 static N8_Status_t computeResidual(N8_HashObject_t *obj_p,
737 const N8_Buffer_t *msg_p,
738 N8_Buffer_t *hashMsg_p,
739 const unsigned int msgLength,
740 unsigned int *hashingLength)
742 int totalLength; /* length of message + residual */
743 int nextResidualLength;
744 int hashFromMsgLength;
746 DBG(("computeResidual\n"));
748 totalLength = obj_p->residualLength + msgLength;
749 nextResidualLength = totalLength % N8_HASH_BLOCK_SIZE;
750 *hashingLength = totalLength - nextResidualLength;
751 hashFromMsgLength = *hashingLength - obj_p->residualLength;
753 if (*hashingLength == 0) {
754 /* residualLength + msgLength is less than N8_HASH_BLOCK_SIZE.
755 Just append msg to residual. */
756 memcpy(&(obj_p->residual[obj_p->residualLength]), msg_p, msgLength);
757 obj_p->residualLength = nextResidualLength;
758 DBG(("Just append msg to residual\n"));
759 DBG(("hash length: %d\n", *hashingLength));
760 DBG(("msg to hash: %s\n", hashMsg_p));
761 DBG(("residual length: %d\n", nextResidualLength));
762 DBG(("residual: %s\n", obj_p->residual));
763 return N8_STATUS_OK;
766 /* prepend the residual, if any */
767 if (obj_p->residualLength > 0)
769 memcpy(hashMsg_p, obj_p->residual, obj_p->residualLength);
771 /* now copy the hashable portion of the incoming message */
772 if (hashFromMsgLength > 0)
774 memcpy(&(hashMsg_p[obj_p->residualLength]), msg_p,
775 hashFromMsgLength);
777 /* finally, copy the new residual */
778 memset(obj_p->residual, 0x0, N8_MAX_RESIDUAL_LEN);
779 if (nextResidualLength > 0)
781 memcpy(obj_p->residual,
782 &(msg_p[msgLength - nextResidualLength]),
783 nextResidualLength);
785 obj_p->residualLength = nextResidualLength;
786 n8_incrLength64(&obj_p->Nh, &obj_p->Nl, *hashingLength);
787 DBG(("hash length: %d\n", *hashingLength));
788 DBG(("residual length: %d\n", nextResidualLength));
789 DBG(("computeResidual - OK\n"));
790 return N8_STATUS_OK;
791 } /* computeResidual */
794 /*****************************************************************************
795 * n8_initializeHMAC_req
796 ****************************************************************************/
797 /** @ingroup n8_hash
798 * @brief Generate the HMAC initialization request.
800 * @param HMACKey RW: HMAC key
801 * @param HMACKeyLength RW: HMAC key length
802 * @param hashObj_p RW: object to be initialized
803 * @param result_p RW: optional pointer to results area. Used for
804 * IPsec only.
805 * @param req_pp RW: Pointer to request pointer.
807 * @par Errors
808 * N8_INVALID_HASH - the specified hash is not valid
809 * N8_INVALID_OBJECT - object passed was null<br>
810 * N8_INVALID_KEY_SIZE - the value of HMACKeyLength is less than 0
811 * and greater than 18 KBytes.
813 * @par Assumptions
814 * None
815 ****************************************************************************/
816 N8_Status_t n8_initializeHMAC_req(N8_Buffer_t *HMACKey,
817 uint32_t HMACKeyLength,
818 N8_HashObject_t *hashObj_p,
819 void *result_p,
820 N8_Buffer_t **ctx_pp,
821 uint32_t *ctxa_p,
822 API_Request_t **req_pp)
824 API_Request_t *headReq_p = NULL; /* head pointer to request list */
825 N8_Status_t ret = N8_STATUS_OK;
827 DBG(("n8_initializeHMAC\n"));
831 N8_Buffer_t hashedKey[N8_HASH_BLOCK_SIZE];
832 if (result_p == NULL)
834 ret = n8_precompute_tls_ipad_opad(hashObj_p->type,
835 HMACKey,
836 hashedKey,
837 &HMACKeyLength,
838 hashObj_p->ipadHMAC_iv,
839 hashObj_p->opadHMAC_iv);
840 memcpy(hashObj_p->iv, hashObj_p->ipadHMAC_iv, 20);
842 else
844 N8_CipherInfo_t *obj_p = (N8_CipherInfo_t *) result_p;
845 ret = n8_precompute_tls_ipad_opad(hashObj_p->type,
846 HMACKey,
847 hashedKey,
848 &HMACKeyLength,
849 obj_p->key.IPsecKeyDES.ipad,
850 obj_p->key.IPsecKeyDES.opad);
852 CHECK_RETURN(ret);
853 hashObj_p->opad_Nl = 64;
854 hashObj_p->Nl = 64;
855 n8_setHashedHMACKey(hashObj_p, hashedKey, HMACKeyLength);
856 } while (FALSE);
858 *req_pp = headReq_p;
859 return ret;
860 } /* n8_initializeHMAC_req */
862 /*****************************************************************************
863 * n8_initializeHMAC
864 ****************************************************************************/
865 /** @ingroup n8_hash
866 * @brief Compute HMAC for future hashing and store results in context memory
867 * if needed.
869 * @param HMACKey RW: HMAC key
870 * @param HMACKeyLength RW: HMAC key length
871 * @param hashObj_p RW: object to be initialized
872 * @param event_p RW: Pointer to asynchronous event structure.
874 * @par Errors
875 * N8_INVALID_HASH - the specified hash is not valid
876 * N8_INVALID_OBJECT - object passed was null<br>
877 * N8_INVALID_KEY_SIZE - the value of HMACKeyLength is less than 0
878 * and greater than 18 KBytes.
880 * @par Assumptions
881 * None
882 ****************************************************************************/
883 N8_Status_t n8_initializeHMAC(N8_Buffer_t *HMACKey,
884 uint32_t HMACKeyLength,
885 N8_HashObject_t *hashObj_p,
886 N8_Event_t *event_p)
888 API_Request_t *req_p = NULL;
889 N8_Status_t ret = N8_STATUS_OK;
890 uint32_t ctx_a; /* unused dummy value */
891 N8_Buffer_t *ctx_p; /* unused dummy value */
892 DBG(("N8_HashPartial\n"));
895 /* generate the request */
896 ret = n8_initializeHMAC_req(HMACKey, HMACKeyLength,
897 hashObj_p,
898 NULL,
899 &ctx_p,
900 &ctx_a,
901 &req_p);
902 CHECK_RETURN(ret);
903 if (req_p == NULL)
905 if (event_p != NULL)
907 N8_SET_EVENT_FINISHED(event_p, N8_EA);
909 break;
911 QUEUE_AND_CHECK(event_p, req_p, ret);
912 HANDLE_EVENT(event_p, req_p, ret);
914 while (FALSE);
915 /* clean up resources */
916 if (ret != N8_STATUS_OK)
918 freeRequest(req_p);
920 return ret;
921 } /* n8_initializeHMAC */
922 /*****************************************************************************
923 * N8_HashInitialize
924 ****************************************************************************/
925 /** @ingroup n8_hash
926 * @brief Initialize a HashObject for future hashing.
928 * Hashing functions require a HashObject to maintain state across
929 * calls. Before use, the object must be initialized to set the
930 * algorithm and algorith-specific initial conditions.
932 * @param hashObj_p RW: object to be initialized
933 * @param alg RO: algorithm to be used with this object
934 * @param hashInfo_p RO: pointer to hash info structure for HMAC key.
935 * @par Externals
936 * None
938 * @return
939 * N8_Status_t
941 * @par Errors
942 * N8_INVALID_HASH - the specified hash is not valid
943 * N8_INVALID_OBJECT - object passed was null<br>
944 * N8_INVALID_OBJECT - The unit value specified was invalid<br>
945 * N8_INVALID_KEY_SIZE - the value of HMACKeyLength is less than 0 and
946 * greater than 18 KBytes.
948 * @par Assumptions
949 * None
950 ****************************************************************************/
951 N8_Status_t N8_HashInitialize(N8_HashObject_t *hashObj_p,
952 const N8_HashAlgorithm_t alg,
953 const N8_HashInfo_t *hashInfo_p,
954 N8_Event_t *event_p)
956 N8_Status_t ret = N8_STATUS_OK;
958 DBG(("N8_HashInitialize\n"));
961 ret = N8_preamble();
962 CHECK_RETURN(ret);
964 CHECK_OBJECT(hashObj_p, ret);
966 hashObj_p->unitID = hashInfo_p->unitID;
967 ret = n8_setInitialIVs(hashObj_p, alg, hashObj_p->unitID);
968 CHECK_RETURN(ret);
969 switch (hashObj_p->type)
971 case N8_HMAC_MD5:
972 case N8_HMAC_MD5_96:
973 case N8_HMAC_SHA1:
974 case N8_HMAC_SHA1_96:
975 /* check the key length to make sure it is in range */
976 if (hashInfo_p->keyLength > N8_MAX_HASH_LENGTH)
978 ret = N8_INVALID_KEY_SIZE;
979 break;
981 CHECK_OBJECT(hashInfo_p, ret);
982 ret = n8_initializeHMAC(hashInfo_p->key_p,
983 hashInfo_p->keyLength,
984 hashObj_p,
985 event_p);
986 break;
987 default:
988 break;
990 } while (FALSE);
992 DBG(("N8_HashInitialize after loop\n"));
993 if (ret == N8_STATUS_OK)
995 /* Set the structure ID */
996 hashObj_p->structureID = N8_HASH_STRUCT_ID;
997 if ((event_p != NULL) &&
998 ((alg == N8_MD5) || (alg == N8_SHA1)))
1000 N8_SET_EVENT_FINISHED(event_p, N8_EA);
1004 DBG(("N8_HashInitialize - OK\n"));
1005 return ret;
1006 } /* N8_HashInitialize */
1007 /*****************************************************************************
1008 * n8_HashPartial_req
1009 *****************************************************************************/
1010 /** @ingroup n8_hash
1011 * @brief Generate a request for a N8_HashPartial.
1013 * The generated request is returned but not queued.
1015 * @param obj_p RW: Pointer to hash object
1016 * @param msg_p RO: Pointer to message
1017 * @param msgLength RO: Message length in bytes
1018 * @param req_pp RW: Pointer to request pointer
1020 * @par Externals
1021 * None
1023 * @return
1024 * Status
1026 * @par Errors
1027 * None
1029 * @par Assumptions
1030 * None
1031 *****************************************************************************/
1032 N8_Status_t n8_HashPartial_req(N8_HashObject_t *obj_p,
1033 const N8_Buffer_t *msg_p,
1034 const unsigned int msgLength,
1035 const n8_IVSrc_t ivSrc,
1036 API_Request_t **req_pp)
1038 N8_Status_t ret = N8_STATUS_OK;
1040 unsigned int hashingLength; /* totalLength rounded down to the
1041 * next multiple of N8_HASH_BLOCK_SIZE */
1042 N8_Buffer_t *hashMsg_p = NULL;
1043 unsigned long hashMsg_a;
1044 uint32_t result_a;
1045 N8_Buffer_t *result_p = NULL;
1046 unsigned int nBytes;
1050 CHECK_OBJECT(req_pp, ret);
1051 *req_pp = NULL; /* set the return request to NULL in case we
1052 * have to bail out. */
1053 CHECK_OBJECT(obj_p, ret);
1054 CHECK_STRUCTURE(obj_p->structureID, N8_HASH_STRUCT_ID, ret);
1056 ret = N8_preamble();
1057 CHECK_RETURN(ret);
1059 if (msgLength == 0)
1061 /* this is legal but has no effect. do not change any state
1062 * and return successfully.
1064 break;
1067 /* only after verifying that the message length is non-zero, test for
1068 * valid msg_p */
1069 CHECK_OBJECT(msg_p, ret);
1071 if (msgLength > N8_MAX_HASH_LENGTH)
1073 ret = N8_INVALID_INPUT_SIZE;
1074 break;
1076 CHECK_OBJECT(obj_p, ret);
1077 CHECK_OBJECT(msg_p, ret);
1079 /* create the EA request */
1080 nBytes = (NEXT_WORD_SIZE(obj_p->hashSize) +
1081 NEXT_WORD_SIZE(msgLength + N8_MAX_RESIDUAL_LEN));
1082 ret = createEARequestBuffer(req_pp,
1083 obj_p->unitID,
1084 N8_CB_EA_HASHPARTIAL_NUMCMDS,
1085 resultHandlerHashPartial, nBytes);
1086 CHECK_RETURN(ret);
1088 /* allocate space for the chip to place the result */
1089 result_a = (*req_pp)->qr.physicalAddress + (*req_pp)->dataoffset;
1090 result_p = (N8_Buffer_t *) ((int)(*req_pp) + (*req_pp)->dataoffset);
1091 memset(result_p, 0, nBytes);
1093 hashMsg_a = result_a + NEXT_WORD_SIZE(obj_p->hashSize);
1094 hashMsg_p = result_p + NEXT_WORD_SIZE(obj_p->hashSize);
1097 * The actual input is concat(residual, *msg_p). Of this, we
1098 * only hash multiple lengths of N8_HASH_BLOCK_SIZE and save the
1099 * rest for the next time around.
1101 * We compute the residual and message first, since we have nothing to do
1102 * if the hashing length is zero.
1104 ret = computeResidual(obj_p,
1105 msg_p,
1106 hashMsg_p,
1107 msgLength,
1108 &hashingLength);
1109 CHECK_RETURN(ret);
1110 /* if the hashing length is 0, then there is nothing to do for this call.
1111 * Set the event status to done (if asynchronous) and return.
1113 if (hashingLength == 0)
1115 freeRequest(*req_pp);
1116 *req_pp = NULL;
1117 ret = N8_STATUS_OK;
1118 break;
1121 /* set up the copy back data for processing in the result handler */
1122 (*req_pp)->copyBackFrom_p = result_p;
1123 (*req_pp)->copyBackTo_p = (void *) obj_p;
1125 /* handle messages longer than 64 bytes for HMAC */
1126 ret = cb_ea_hashPartial(*req_pp,
1127 (*req_pp)->EA_CommandBlock_ptr,
1128 obj_p,
1129 ivSrc,
1130 hashMsg_a,
1131 hashingLength,
1132 result_a,
1133 NULL /* next command block */,
1134 N8_TRUE);
1135 CHECK_RETURN(ret);
1136 } while (FALSE);
1137 return ret;
1138 } /* n8_HashPartial_req */
1140 /*****************************************************************************
1141 * N8_HashPartial
1142 ****************************************************************************/
1143 /** @ingroup n8_hash
1144 * @brief Hash a partial message.
1146 * To hash a message over 18 K bytes long, multiple calls to this
1147 * function must be made processing chunks of the message. After all
1148 * chunks are processed a call to the companion function N8_HashEnd
1150 * @param obj_p RW: Hash object to store intermediate results.
1151 * @param msg_p RO: Pointer to the message to be hashed.
1152 * @param msgLength RO: Length of message to be hashed.
1153 * @param event_p RO: Pointer to event for async calls. Null for
1154 * synchronous call.
1155 * @par Externals:
1156 * None
1158 * @return
1159 * Status code of type N8_Status.
1161 * @par Errors:
1162 * N8_STATUS_OK: A-OK<br>
1163 * N8_INVALID_INPUT_SIZE: message passed was larger than allowed
1164 * limit of N8_MAX_HASH_LENGTH<br>
1165 * @par Assumptions:
1166 * None
1167 ****************************************************************************/
1168 N8_Status_t N8_HashPartial(N8_HashObject_t *obj_p,
1169 const N8_Buffer_t *msg_p,
1170 const unsigned int msgLength,
1171 N8_Event_t *event_p)
1173 API_Request_t *req_p = NULL;
1174 N8_Status_t ret = N8_STATUS_OK;
1176 DBG(("N8_HashPartial\n"));
1179 /* generate the request */
1180 ret = n8_HashPartial_req(obj_p, msg_p, msgLength, N8_IV, &req_p);
1181 CHECK_RETURN(ret);
1182 if (req_p == NULL)
1184 if (event_p != NULL)
1186 N8_SET_EVENT_FINISHED(event_p, N8_EA);
1188 break;
1190 QUEUE_AND_CHECK(event_p, req_p, ret);
1191 HANDLE_EVENT(event_p, req_p, ret);
1193 while (FALSE);
1194 /* clean up resources */
1195 if (ret != N8_STATUS_OK)
1197 freeRequest(req_p);
1199 DBG(("N8_HashPartial - OK\n"));
1200 return ret;
1201 } /* N8_HashPartial */
1203 /*****************************************************************************
1204 * n8_HMACHashEnd_req
1205 *****************************************************************************/
1206 /** @ingroup n8_hash
1207 * @brief Generate request for N8_HashEnd for HMAC algorithms only.
1209 * Recall a HMAC consists of the following:
1210 * HMAC = H(o + H(i + msg))
1211 * At the time the end is being called, hash partial for all of the msg has been
1212 * called and msg is completely consumed. Some portion of it may be in the
1213 * residual. The first step to ending the HMAC is to perform a hash end on the
1214 * inner portion. The results of this is guaranteed to be small (16 or 20
1215 * bytes, depending upon the hash algorithm in use). Also note that the
1216 * initial i and o values are exactly 64 bytes long, so they are hashed with no
1217 * residual. So this reduces the complexity of finishing an HMAC hash to:
1218 * res1 = hashEnd(obj loaded with inner IV, residual)
1219 * res = hashEnd(obj loaded with outer IV, res1)
1221 * @param obj_p RW: Pointer to hash object.
1222 * @param result_p RW: Pointer to results buffer provided by
1223 * original caller.
1224 * @param req_pp RW: Pointer to request pointer.
1226 * @par Externals
1227 * None
1229 * @return
1230 * Status
1232 * @par Errors
1233 * N8_INVALID_OBJECT, N8_INVALID_HASH
1235 * @par Assumptions
1236 * The object algorithm has been pre-screened to be one of the supported HMAC
1237 * algorithms.
1238 *****************************************************************************/
1239 N8_Status_t n8_HMACHashEnd_req(N8_HashObject_t *obj_p,
1240 N8_Buffer_t *result_p,
1241 API_Request_t **req_pp)
1243 N8_Status_t ret = N8_STATUS_OK;
1244 int hashingLength;
1245 N8_Buffer_t *hashMsg_p = NULL;
1246 uint32_t hashMsg_a;
1247 N8_Buffer_t *kResults_p = NULL;
1248 uint32_t kResults_a;
1249 N8_Buffer_t *tempResults_p = NULL;
1250 uint32_t tempResults_a;
1251 API_Request_t *req_p;
1252 EA_CMD_BLOCK_t *nextCommandBlock_p = NULL;
1253 int nBytes;
1257 ret = N8_preamble();
1258 CHECK_RETURN(ret);
1259 CHECK_OBJECT(req_pp, ret);
1260 *req_pp = NULL;
1262 /* minimal sanity checking on the hash object */
1263 CHECK_OBJECT(obj_p, ret);
1264 CHECK_OBJECT(result_p, ret);
1265 CHECK_STRUCTURE(obj_p->structureID, N8_HASH_STRUCT_ID, ret);
1267 DBG(("residual length: %d\n", obj_p->residualLength));
1268 DBG(("residual: %s\n", obj_p->residual));
1270 hashingLength = obj_p->residualLength;
1273 * The input to the final hash is the residual in the hash object.
1276 /* create the request */
1277 nBytes = NEXT_WORD_SIZE(obj_p->hashSize) + /* final results */
1278 NEXT_WORD_SIZE(obj_p->hashSize) + /* temporary results */
1279 NEXT_WORD_SIZE(hashingLength); /* residual */
1280 ret = createEARequestBuffer(req_pp,
1281 obj_p->unitID,
1282 2 * N8_CB_EA_HASHEND_NUMCMDS,
1283 resultHandlerGeneric, nBytes);
1284 CHECK_RETURN(ret);
1286 req_p = *req_pp;
1288 kResults_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
1289 memset(kResults_p, 0, nBytes);
1290 kResults_a = req_p->qr.physicalAddress + req_p->dataoffset;
1291 tempResults_p = kResults_p + NEXT_WORD_SIZE(obj_p->hashSize);
1292 tempResults_a = kResults_a + NEXT_WORD_SIZE(obj_p->hashSize);
1293 hashMsg_p = tempResults_p + NEXT_WORD_SIZE(obj_p->hashSize);
1294 hashMsg_a = tempResults_a + NEXT_WORD_SIZE(obj_p->hashSize);
1296 if (hashingLength != 0)
1298 /* copy the residual, which we know to be non-zero in length */
1299 memcpy(hashMsg_p, obj_p->residual, hashingLength);
1300 DBG(("hash length: %d\n", hashingLength));
1302 else
1304 hashMsg_p = NULL;
1305 hashMsg_a = 0;
1306 DBG(("hash length: %d\n", hashingLength));
1307 DBG(("msg to hash: none\n"));
1310 /* first, do a hash on the residual */
1311 ret = cb_ea_hashEnd(req_p, /* request */
1312 req_p->EA_CommandBlock_ptr, /* command block pointer */
1313 obj_p, /* object pointer */
1314 N8_IV, /* get the IV from the
1315 * regular place */
1316 hashMsg_a, /* message to hash */
1317 hashingLength, /* length of message */
1318 tempResults_a, /* results physical address */
1319 &nextCommandBlock_p, /* next command block pointer */
1320 N8_FALSE);
1321 CHECK_RETURN(ret);
1323 /* next, create a command request to hash the results that were just
1324 * generated */
1325 ret = cb_ea_hashEnd(req_p, /* request */
1326 nextCommandBlock_p, /* command block pointer */
1327 obj_p, /* object pointer */
1328 N8_OPAD, /* get the IV from the opad */
1329 tempResults_a, /* message to hash */
1330 obj_p->hashSize, /* length of message */
1331 kResults_a, /* results physical address */
1332 NULL, /* next command block pointer */
1333 N8_TRUE);
1334 CHECK_RETURN(ret);
1336 req_p->copyBackSize = obj_p->hashSize;
1337 req_p->copyBackFrom_p = kResults_p;
1338 req_p->copyBackTo_p = result_p;
1340 } while (FALSE);
1342 return ret;
1344 } /* n8_HMACHashEnd_req */
1346 /*****************************************************************************
1347 * n8_HashEnd_req
1348 *****************************************************************************/
1349 /** @ingroup n8_hash
1350 * @brief Generate the request for a Hash End operation for non-HMAC
1351 * algorithms.
1353 * @param obj_p RW: Pointer to hash object
1354 * @param result_p RW: Results area
1355 * @param req_pp RW: Pointer to request pointer
1357 * @par Externals
1358 * None
1360 * @return
1361 * <description of return value>
1363 * @par Errors
1364 * <description of possible errors><br>
1366 * @par Assumptions
1367 * <description of assumptions><br>
1368 *****************************************************************************/
1369 N8_Status_t n8_HashEnd_req(N8_HashObject_t *obj_p,
1370 N8_Buffer_t *result_p,
1371 API_Request_t **req_pp)
1373 N8_Status_t ret = N8_STATUS_OK;
1374 int totalLength;
1375 int hashingLength;
1376 N8_Buffer_t *hashMsg_p = NULL;
1377 uint32_t hashMsg_a;
1378 unsigned long pAddr;
1379 char *vAddr;
1380 N8_Buffer_t *kResults_p = NULL;
1381 uint32_t kResults_a;
1382 API_Request_t *req_p;
1383 int nBytes;
1387 ret = N8_preamble();
1388 CHECK_RETURN(ret);
1389 CHECK_OBJECT(req_pp, ret);
1390 *req_pp = NULL;
1392 /* minimal sanity checking on the hash object */
1393 CHECK_OBJECT(obj_p, ret);
1394 CHECK_OBJECT(result_p, ret);
1395 CHECK_STRUCTURE(obj_p->structureID, N8_HASH_STRUCT_ID, ret);
1397 DBG(("residual length: %d\n", obj_p->residualLength));
1398 DBG(("residual: %s\n", obj_p->residual));
1400 totalLength = obj_p->residualLength;
1401 hashingLength = totalLength;
1404 * The input to the final hash is the residual in the hash object.
1406 /* allocate a kernel buffer for the results and for
1407 * the message to hash
1410 /* The message to hash is ready. Now, create the command
1411 * blocks and do the final hash.
1413 nBytes = NEXT_WORD_SIZE(obj_p->hashSize) + NEXT_WORD_SIZE(hashingLength);
1414 ret = createEARequestBuffer(&req_p,
1415 obj_p->unitID,
1416 N8_CB_EA_HASHEND_NUMCMDS,
1417 resultHandlerGeneric, nBytes);
1418 CHECK_RETURN(ret);
1420 pAddr = req_p->qr.physicalAddress + req_p->dataoffset;
1421 vAddr = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
1422 memset(vAddr, 0, nBytes);
1424 kResults_p = vAddr;
1425 kResults_a = pAddr;
1426 vAddr += NEXT_WORD_SIZE(obj_p->hashSize);
1427 pAddr += NEXT_WORD_SIZE(obj_p->hashSize);
1431 if (hashingLength != 0)
1433 hashMsg_p = (N8_Buffer_t *) vAddr;
1434 hashMsg_a = pAddr;
1435 /* copy the residual, which we know to be non-zero in length */
1436 memcpy(hashMsg_p, obj_p->residual, hashingLength);
1437 DBG(("hash length: %d\n", hashingLength));
1439 else
1441 /* even if the hashing length is zero, the hardware call must be made
1442 * to finalize the hash. it will see no new data is presented for
1443 * hashing and only do the portions necessary to finish the hash in
1444 * progress. */
1445 hashMsg_p = NULL;
1446 hashMsg_a = 0;
1447 DBG(("hash length: %d\n", hashingLength));
1448 DBG(("msg to hash: none\n"));
1451 CHECK_RETURN(ret);
1452 ret = cb_ea_hashEnd(req_p,
1453 req_p->EA_CommandBlock_ptr,
1454 obj_p,
1455 N8_IV, /* get the IV from the
1456 * regular place */
1457 hashMsg_a,
1458 hashingLength,
1459 kResults_a,
1460 NULL, /* next command block */
1461 N8_TRUE);
1462 CHECK_RETURN(ret);
1464 req_p->copyBackSize = obj_p->hashSize;
1465 req_p->copyBackFrom_p = kResults_p;
1466 req_p->copyBackTo_p = result_p;
1468 *req_pp = req_p;
1469 } while (FALSE);
1471 return ret;
1473 } /* n8_HashEnd_req */
1474 /*****************************************************************************
1475 * N8_HashEnd
1476 ****************************************************************************/
1477 /** @ingroup n8_hash
1478 * @brief Finalize a hash in progress.
1480 * After one or more calls to N8_HashPartial, after all portions are
1481 * hashed, N8_HashEnd is called to compute the final values and return
1482 * the hash results.
1484 * @param obj_p RW: Hash object to use
1485 * @param result_p RW: Pointer to pre-allocated buffer to
1486 * hold returned results
1487 * @param event_p RW: Asynchronous event pointer
1489 * @par Externals
1490 * None
1492 * @return
1493 * Status condition
1495 * @par Errors
1496 * N8_INVALID_OBJECT<br>
1497 * N8_MALLOC_FAILED<br>
1499 * @par Assumptions
1500 * Asynchronous calls not implemented.
1501 ****************************************************************************/
1502 N8_Status_t N8_HashEnd(N8_HashObject_t *obj_p,
1503 N8_Buffer_t *result_p,
1504 N8_Event_t *event_p)
1506 API_Request_t *req_p = NULL;
1507 N8_Status_t ret = N8_STATUS_OK;
1509 DBG(("N8_HashEnd\n"));
1512 switch (obj_p->type)
1514 case N8_HMAC_MD5:
1515 case N8_HMAC_MD5_96:
1516 case N8_HMAC_SHA1:
1517 case N8_HMAC_SHA1_96:
1518 ret = n8_HMACHashEnd_req(obj_p, result_p, &req_p);
1519 break;
1520 case N8_MD5:
1521 case N8_SHA1:
1522 ret = n8_HashEnd_req(obj_p, result_p, &req_p);
1523 break;
1524 default:
1525 ret = N8_INVALID_HASH;
1526 break;
1528 CHECK_RETURN(ret);
1529 QUEUE_AND_CHECK(event_p, req_p, ret);
1530 HANDLE_EVENT(event_p, req_p, ret);
1531 } while (FALSE);
1533 /* clean up resources */
1534 if (ret != N8_STATUS_OK)
1536 freeRequest(req_p);
1539 DBG(("N8_HashEnd - OK\n"));
1540 return ret;
1541 } /* N8_HashEnd */
1543 /*****************************************************************************
1544 * N8_HashClone
1545 ****************************************************************************/
1546 /** @ingroup n8_hash
1547 * @brief Given a HashObject produce a clone.
1549 * Perform a clone of a given HashObject and return the clone.
1551 * @param orig_p RO: Hash object to be cloned.
1552 * @param clone_p RW: Cloned version of hash object.
1554 * @par Externals
1555 * None
1557 * @return
1558 * Error condition if raised.
1560 * @par Errors
1561 * None
1563 * @par Assumptions
1564 * Values in the original are unchecked. Only a copy is
1565 * performed.<br>
1566 * Clone_p points to a pre-allocated buffer of sufficient size.
1567 ****************************************************************************/
1568 N8_Status_t N8_HashClone(const N8_HashObject_t *orig_p,
1569 N8_HashObject_t *clone_p)
1571 N8_Status_t ret = N8_STATUS_OK;
1574 ret = N8_preamble();
1575 CHECK_RETURN(ret);
1577 CHECK_OBJECT(orig_p, ret);
1578 CHECK_OBJECT(clone_p, ret);
1579 CHECK_STRUCTURE(orig_p->structureID, N8_HASH_STRUCT_ID, ret);
1580 memcpy(clone_p, orig_p, sizeof(N8_HashObject_t));
1581 } while (FALSE);
1582 return ret;
1583 } /* N8_HashClone */
1585 /*****************************************************************************
1586 * N8_HandshakeHashPartial
1587 ****************************************************************************/
1588 /** @ingroup n8_hash
1589 * @brief Computes partial handshake hash.
1591 * The SSL and TLS handshake protocol requires the computation of a
1592 * hash. A unique message is hashed and that is then hashed with
1593 * other known quantities. This function is called repeatedly until
1594 * all of the parts of the unique message are hashed. A subsequent
1595 * call to the companion functions N8_HandshakeHashEnd wraps up the
1596 * handshake.
1598 * @param md5Obj_p RW: Pointer to MD5 hash object.
1599 * @param shaObj_p RW: Pointer to SHA-1 hash object.
1600 * @param msg_p RW: Pointer to the message portion to
1601 * be hashed
1602 * @param msgLength RW: Length of message portion to be hashed.
1603 * @param event_p RW: Asynchronous event
1605 * @par Externals
1606 * None
1608 * @return
1609 * Error code if encountered.
1611 * @par Errors
1612 * N8_INVALID_HASH
1613 * N8_INVALID_OBJECT
1614 * N8_INVALID_INPUT_SIZE
1615 * N8_MALLOC_FAILED
1617 * @par Assumptions
1618 * None
1619 ****************************************************************************/
1620 N8_Status_t N8_HandshakeHashPartial(N8_HashObject_t *md5Obj_p,
1621 N8_HashObject_t *shaObj_p,
1622 const N8_Buffer_t *msg_p,
1623 const unsigned int msgLength,
1624 N8_Event_t *event_p)
1626 N8_Status_t ret = N8_STATUS_OK;
1627 unsigned int hashingLength;
1629 N8_Buffer_t *hashMsg_p = NULL;
1630 uint32_t hashMsg_a;
1631 uint32_t resultMD5_a;
1632 N8_Buffer_t *resultMD5_p = NULL;
1633 uint32_t resultSHA_a;
1634 N8_Buffer_t *resultSHA_p = NULL;
1635 API_Request_t *req_p = NULL;
1636 int nBytes;
1637 EA_CMD_BLOCK_t *nextCommandBlock = NULL;
1638 N8_HandshakePartialResults_t *callBackData_p = NULL;
1641 ret = N8_preamble();
1642 CHECK_RETURN(ret);
1644 if (msgLength == 0)
1646 /* legal but has no effect or side-effects */
1647 break;
1649 if (msgLength > N8_MAX_HASH_LENGTH)
1651 ret = N8_INVALID_INPUT_SIZE;
1652 break;
1654 CHECK_OBJECT(md5Obj_p, ret);
1655 CHECK_OBJECT(shaObj_p, ret);
1656 CHECK_OBJECT(msg_p, ret);
1657 CHECK_STRUCTURE(md5Obj_p->structureID, N8_HASH_STRUCT_ID, ret);
1658 CHECK_STRUCTURE(shaObj_p->structureID, N8_HASH_STRUCT_ID, ret);
1660 /* ensure the hash objects were initialized correctly */
1661 if (md5Obj_p->type != N8_MD5 || shaObj_p->type != N8_SHA1)
1663 ret = N8_INVALID_HASH;
1664 break;
1667 nBytes = (NEXT_WORD_SIZE(md5Obj_p->hashSize) +
1668 NEXT_WORD_SIZE(shaObj_p->hashSize) +
1669 NEXT_WORD_SIZE(msgLength + N8_MAX_RESIDUAL_LEN));
1670 /* In order to perform the HandshakeHashPartial, the equivalent of a hash
1671 * partial needs to be done for the MD5 object and the SHA-1 object. In
1672 * order to perform this in one request, the command blocks are generated
1673 * and submitted as a single request to the queue manager. */
1674 ret = createEARequestBuffer(&req_p,
1675 md5Obj_p->unitID,
1676 2 * N8_CB_EA_HASHPARTIAL_NUMCMDS,
1677 resultHandlerHandshakePartial, nBytes);
1678 CHECK_RETURN(ret);
1680 /* setup the space for the chip to place the result */
1681 resultMD5_a = req_p->qr.physicalAddress + req_p->dataoffset;
1682 resultMD5_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
1683 memset(resultMD5_p, 0, nBytes);
1685 resultSHA_a = resultMD5_a + NEXT_WORD_SIZE(md5Obj_p->hashSize);
1686 resultSHA_p = resultMD5_p + NEXT_WORD_SIZE(md5Obj_p->hashSize);
1688 hashMsg_a = resultSHA_a + NEXT_WORD_SIZE(shaObj_p->hashSize);
1689 hashMsg_p = resultSHA_p + NEXT_WORD_SIZE(shaObj_p->hashSize);
1692 * The actual input is concat(residual, *msg_p). Of this, we
1693 * only hash multiple lengths of N8_HASH_BLOCK_SIZE and save the
1694 * rest for the next time around.
1695 * Note that the MD5 and SHA-1 messages and residuals will always be the
1696 * same. Therefore, we can calculate the hashing message and residual once
1697 * and share between the hash objects.
1699 ret = computeResidual(md5Obj_p,
1700 msg_p,
1701 hashMsg_p,
1702 msgLength,
1703 &hashingLength);
1705 CHECK_RETURN(ret);
1707 /* there is hashing to be done. copy the residual from the MD5 object to
1708 * the SHA object. */
1709 memcpy(shaObj_p->residual, md5Obj_p->residual, md5Obj_p->residualLength);
1710 shaObj_p->residualLength = md5Obj_p->residualLength;
1711 n8_incrLength64(&shaObj_p->Nh, &shaObj_p->Nl, hashingLength);
1713 /* if the hashing length is 0, then there is nothing to do for this call.
1714 * Set the event status to done (if asynchronous) and return.
1716 if (hashingLength == 0)
1718 if (event_p != NULL)
1720 N8_SET_EVENT_FINISHED(event_p, N8_EA);
1722 freeRequest(req_p);
1723 ret = N8_STATUS_OK;
1724 break;
1728 /* The message to hash this time around has been isolated. The
1729 * residual is in place for next time. Now, create the command
1730 * blocks and do the hash.
1733 /* create callback structure */
1734 callBackData_p = (N8_HandshakePartialResults_t *)&req_p->postProcessBuffer;
1735 callBackData_p->SHA_results_p = resultSHA_p;
1736 callBackData_p->SHA_obj_p = shaObj_p;
1737 callBackData_p->MD5_results_p = resultMD5_p;
1738 callBackData_p->MD5_obj_p = md5Obj_p;
1739 req_p->postProcessingData_p = (void *) callBackData_p;
1741 ret = cb_ea_hashPartial(req_p,
1742 req_p->EA_CommandBlock_ptr,
1743 md5Obj_p,
1744 N8_IV,
1745 hashMsg_a,
1746 hashingLength,
1747 resultMD5_a,
1748 &nextCommandBlock,
1749 N8_FALSE);
1750 CHECK_RETURN(ret);
1751 ret = cb_ea_hashPartial(req_p,
1752 nextCommandBlock,
1753 shaObj_p,
1754 N8_IV,
1755 hashMsg_a,
1756 hashingLength,
1757 resultSHA_a,
1758 &nextCommandBlock,
1759 N8_TRUE);
1760 CHECK_RETURN(ret);
1762 DBG(("command block:\n"));
1764 QUEUE_AND_CHECK(event_p, req_p, ret);
1765 HANDLE_EVENT(event_p, req_p, ret);
1767 while (FALSE);
1769 /* clean up resources */
1770 if (ret != N8_STATUS_OK)
1772 freeRequest(req_p);
1774 return ret;
1775 } /* N8_HandshakeHashPartial */
1777 /*****************************************************************************
1778 * N8_HandshakeHashEnd
1779 ****************************************************************************/
1780 /** @ingroup n8_hash
1781 * @brief Finishes ongoing handshake hash computation.
1783 * After all portions of the message have been processed by
1784 * N8_HandshakeHashPartial this method must be called to do the final
1785 * processing. The function produces a hash result for MD5 and SHA-1
1786 * simultaneously.
1788 * @param md5Obj_p RW: MD5 hash object
1789 * @param sha1Obj_p RW: SHA-1 hash object
1790 * @param protocol RW: Hash protocol specifier (TLS
1791 * finish, TLS cert, SSL finish, or
1792 * SSL cert)
1793 * @param key_p RW: Hash key
1794 * @param keyLength RW: Length of hash key
1795 * @param role RW: Role of hash (server or client)
1796 * @param md5Result_p RW: Pointer to pre-allocated space for
1797 * MD5 results.
1798 * @param sha1Result_p RW: Pointer to pre-allocated space for
1799 * SHA-1 results.
1800 * @param event_p RW: Async event. NULL for blocking.
1802 * @par Externals
1803 * None
1805 * @return
1806 * Error condition if met.
1808 * @par Errors
1809 * N8_MALLOC_FAILED<br>
1810 * N8_INVALID_HASH<br>
1811 * N8_INVALID_PROTOCOL
1813 * @par Assumptions
1814 * TLS functions not implemented.
1815 ****************************************************************************/
1816 N8_Status_t N8_HandshakeHashEnd(N8_HashObject_t *md5Obj_p,
1817 N8_HashObject_t *sha1Obj_p,
1818 const N8_HashProtocol_t protocol,
1819 const N8_Buffer_t *key_p,
1820 const unsigned int keyLength,
1821 const N8_HashRole_t role,
1822 N8_Buffer_t *md5Result_p,
1823 N8_Buffer_t *sha1Result_p,
1824 N8_Event_t *event_p)
1826 N8_Status_t ret = N8_STATUS_OK;
1827 char *roleString_p = NULL;
1831 ret = N8_preamble();
1832 CHECK_RETURN(ret);
1833 CHECK_STRUCTURE(md5Obj_p->structureID, N8_HASH_STRUCT_ID, ret);
1834 CHECK_STRUCTURE(sha1Obj_p->structureID, N8_HASH_STRUCT_ID, ret);
1836 if (md5Obj_p == NULL || sha1Obj_p == NULL)
1838 ret = N8_INVALID_OBJECT;
1839 break;
1841 if (md5Obj_p->type != N8_MD5 || sha1Obj_p->type != N8_SHA1)
1843 ret = N8_INVALID_HASH;
1844 break;
1846 roleString_p = getRoleString(protocol, role);
1848 switch (protocol)
1850 case N8_TLS_FINISH:
1851 case N8_TLS_CERT:
1852 ret = computeTLSHandshakeHash(md5Obj_p,
1853 sha1Obj_p,
1854 protocol,
1855 roleString_p,
1856 key_p,
1857 keyLength,
1858 md5Result_p,
1859 sha1Result_p,
1860 event_p);
1861 break;
1862 case N8_SSL_FINISH:
1863 case N8_SSL_CERT:
1864 ret = computeSSLHandshakeHash(md5Obj_p,
1865 sha1Obj_p,
1866 roleString_p,
1867 key_p, keyLength,
1868 md5Result_p,
1869 sha1Result_p,
1870 event_p);
1871 break;
1872 default:
1873 ret = N8_INVALID_PROTOCOL;
1874 break;
1876 CHECK_RETURN(ret);
1878 while (FALSE);
1880 /* clean up */
1881 N8_UFREE(roleString_p);
1883 return ret;
1884 } /* N8_HandshakeHashEnd */
1886 /*****************************************************************************
1887 * N8_SSLKeyMaterialHash
1888 ****************************************************************************/
1889 /** @ingroup n8_hash
1890 * @brief <One line description of the function.>
1892 * <More detailed description of the function including any unusual algorithms
1893 * or suprising details.>
1895 * @param obj_p RO: hash info pointer.
1896 * @param random_p RO: 64 bytes of random input.
1897 * @param outputLength RO: Length of requested output.
1898 * @param keyMaterial_p RW: Key material output.
1899 * @param event_p RW: Asynch event.
1901 * @par Externals
1902 * None
1904 * @return
1905 * Error condition if raised.
1907 * @par Errors
1908 * N8_INVALID_KEY_SIZE - provided key is the wrong size<br>
1909 * N8_INVALID_OUTPUT_SIZE - the requested output length is wrong<br>
1910 * N8_INVALID_OBJECT - An input is NULL or the specified unit is invalid.
1912 * @par Assumptions
1913 * keyMaterial_p points to an allocated buffer of sufficient size.
1914 ****************************************************************************/
1915 N8_Status_t N8_SSLKeyMaterialHash (N8_HashInfo_t *obj_p,
1916 const N8_Buffer_t *random_p,
1917 const unsigned int outputLength,
1918 N8_Buffer_t *keyMaterial_p,
1919 N8_Event_t *event_p)
1921 API_Request_t *req_p = NULL;
1922 N8_Buffer_t *result_p = NULL;
1923 unsigned long result_a;
1924 N8_Buffer_t *kKey_p = NULL;
1925 unsigned long kKey_a;
1926 N8_Status_t ret = N8_STATUS_OK;
1927 int nBytes;
1931 ret = N8_preamble();
1932 CHECK_RETURN(ret);
1934 CHECK_OBJECT(obj_p, ret);
1935 CHECK_OBJECT(obj_p->key_p, ret);
1936 CHECK_OBJECT(random_p, ret);
1938 /* check requested output size */
1939 if (outputLength > N8_MAX_SSL_KEY_MATERIAL_LENGTH)
1941 ret = N8_INVALID_OUTPUT_SIZE;
1942 break;
1944 /* check key length */
1945 if (obj_p->keyLength > N8_MAX_KEY_LENGTH)
1947 ret = N8_INVALID_KEY_SIZE;
1948 break;
1951 /* compute space for the chip to place the result */
1952 /* this needs to be larger than the next multiple of 16. rather
1953 * than do the computation, just allocate it to the max size, which is
1954 * relatively small.
1956 nBytes = NEXT_WORD_SIZE(N8_MAX_SSL_KEY_MATERIAL_LENGTH) +
1957 NEXT_WORD_SIZE(obj_p->keyLength);
1959 ret = createEARequestBuffer(&req_p,
1960 obj_p->unitID,
1961 N8_CB_EA_SSLKEYMATERIALHASH_NUMCMDS,
1962 resultHandlerGeneric, nBytes);
1964 CHECK_RETURN(ret);
1966 result_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
1967 memset(result_p, 0, nBytes);
1968 result_a = req_p->qr.physicalAddress + req_p->dataoffset;
1970 /* set up the key in kernel memory and copy the incoming key over */
1971 kKey_p = result_p + NEXT_WORD_SIZE(N8_MAX_SSL_KEY_MATERIAL_LENGTH);
1972 kKey_a = result_a + NEXT_WORD_SIZE(N8_MAX_SSL_KEY_MATERIAL_LENGTH);
1974 memcpy(kKey_p, obj_p->key_p, obj_p->keyLength);
1976 req_p->copyBackTo_p = keyMaterial_p;
1977 req_p->copyBackFrom_p = result_p;
1978 req_p->copyBackSize = outputLength;
1980 ret = cb_ea_SSLKeyMaterialHash(req_p,
1981 req_p->EA_CommandBlock_ptr,
1982 kKey_a,
1983 obj_p->keyLength,
1984 random_p,
1985 outputLength,
1986 result_a);
1987 CHECK_RETURN(ret);
1989 QUEUE_AND_CHECK(event_p, req_p, ret);
1990 HANDLE_EVENT(event_p, req_p, ret);
1992 while (FALSE);
1993 /* clean up */
1994 if (ret != N8_STATUS_OK)
1996 freeRequest(req_p);
1998 return ret;
1999 } /* N8_SSLKeyMaterialHash */
2001 /*****************************************************************************
2002 * N8_TLSKeyMaterialHash
2003 ****************************************************************************/
2004 /** @ingroup n8_hash
2005 * @brief This computes the TLS Pseudo Random Function (PRF) of the specified
2006 * inputs as described in Section 5 of the TLS Specification [TLS].
2008 * The PRF is used to generate various keying material from a secret key, a
2009 * label, and a seed. The values of each of these depends on what's being
2010 * generated. The required key is specified by Key and its length by
2011 * KeyLength.
2012 * The Label is typically an ascii string literal (such as "key expansion" or
2013 * "master secret"), as specified by [TLS]; its length is given in
2014 * LabelLength.
2015 * The Seed is usually the client generated random value concatenated with the
2016 * server generated random value (or vice-versa). It is specified in the Seed
2017 * parameter and its length in bytes is specified by the SeedLength parameter.
2018 * Using these values this routine then generates OutputLength bytes of key
2019 * material, according to the TLS Protocol, and returns them in KeyMaterial.
2020 * Up to 224 bytes of key material may be generated.
2022 * @param obj_p RO: The Hash info pointer. It contains:
2023 * 0 - 18 KBytes of secret key (typically the
2024 * TLS master secret) and the length of Key,
2025 * from 0 to 18 KBytes inclusive. A length of 0
2026 * is legal; the result is computed with a null key.
2027 * Also defined here is the unit ID.
2028 * @param label_p RO: A short ascii string; its value depends
2029 * on what is being computed.
2030 * Specific values are
2031 * defined in [TLS].
2032 * @param labelLength RO: The length of Label, from 0 to 18 KBytes
2033 * inclusive.
2034 * A length of 0 is legal;
2035 * the result is
2036 * computed with a null label.
2037 * @param seed_p RO: A seed value, typically some combination
2038 * of random bytes supplied by
2039 * the server and client.
2040 * Specific values
2041 * are defined in [TLS].
2042 * @param seedLength RO: The length of Seed, from 0 to 18 KBytes
2043 * inclusive.
2044 * A length of 0 is legal;
2045 * the result is computed with a
2046 * null seed.
2047 * @param outputLength RO: The number of bytes of output requested;
2048 * i.e. the length of KeyMaterial,
2049 * from 0 - 224 inclusive.
2050 * @param keyMaterial_p WO: The computed key material. Note only as
2051 * many bytes as requested are ever returned,
2052 * even if the algorithm may compute more.
2053 * (As defined the algorithm almost
2054 * always
2055 * computes extra bytes.)
2056 * @param event_p RW: On input, if null the call
2057 * is synchronous and no event is
2058 * returned. The operation is
2059 * complete when the call returns.
2060 * If non-null, then the call is
2061 * asynchronous;
2062 * an event is returned that can be used to
2063 * determine when the operation completes.
2065 * @return
2066 * Error condition if raised.
2068 * @par Errors
2069 * N8_INVALID_KEY_SIZE - provided key is the wrong size<br>
2070 * N8_INVALID_OUTPUT_SIZE - the requested output length is wrong<br>
2071 * N8_INVALID_OBJECT - data pointer is null<br>
2073 * @par Assumptions
2074 * keyMaterial_p points to an allocated buffer of sufficient size.
2075 ****************************************************************************/
2076 N8_Status_t N8_TLSKeyMaterialHash(N8_HashInfo_t *obj_p,
2077 const N8_Buffer_t *label_p,
2078 const unsigned int labelLength,
2079 const N8_Buffer_t *seed_p,
2080 const unsigned int seedLength,
2081 const unsigned int outputLength,
2082 N8_Buffer_t *keyMaterial_p,
2083 N8_Event_t *event_p)
2085 API_Request_t *req_p = NULL;
2086 N8_Buffer_t *msg_p = NULL;
2087 uint32_t msg_a;
2088 uint32_t kKey_a;
2089 N8_Buffer_t *kKey_p = NULL;
2090 uint32_t prS_a[2];
2091 N8_Buffer_t *prS_p[2];
2092 N8_Buffer_t resultStream_p[N8_MAX_TLS_KEY_MATERIAL_LENGTH];
2093 N8_Status_t ret = N8_STATUS_OK;
2094 int totalLength;
2095 int secretHalves;
2096 N8_TLSKeyHashResults_t *keyResultStruct_p;
2097 int keyLen, hashLen;
2098 unsigned int numCommands;
2099 int bufferA_MD5_length;
2100 int bufferA_SHA1_length;
2104 ret = N8_preamble();
2105 CHECK_RETURN(ret);
2107 CHECK_OBJECT(obj_p, ret);
2108 CHECK_OBJECT(obj_p->key_p, ret);
2109 CHECK_OBJECT(label_p, ret);
2110 CHECK_OBJECT(seed_p, ret);
2111 CHECK_OBJECT(keyMaterial_p, ret);
2113 /* check key length */
2114 if (obj_p->keyLength > N8_MAX_KEY_LENGTH)
2116 ret = N8_INVALID_KEY_SIZE;
2117 break;
2120 /* check label length */
2121 if (labelLength > N8_MAX_KEY_LENGTH)
2123 ret = N8_INVALID_KEY_SIZE;
2124 break;
2127 /* check seed length */
2128 if (seedLength > N8_MAX_KEY_LENGTH)
2130 ret = N8_INVALID_KEY_SIZE;
2131 break;
2134 if ((obj_p->keyLength + labelLength + seedLength) > N8_MAX_KEY_LENGTH)
2136 ret = N8_INVALID_KEY_SIZE;
2137 break;
2140 /* check output buffer length */
2141 if (outputLength > N8_MAX_TLS_KEY_MATERIAL_LENGTH)
2143 ret = N8_INVALID_KEY_SIZE;
2144 break;
2147 numCommands = N8_CB_EA_TLSKEYMATERIALHASH_NUMCMDS(outputLength);
2149 /* concatenate label and seeds */
2150 totalLength = labelLength+seedLength;
2152 /* allocate kernel memory for the key, psuedo random streams, and msg*/
2153 keyLen = (NEXT_WORD_SIZE(obj_p->keyLength) +
2154 (NEXT_WORD_SIZE(N8_MAX_TLS_KEY_MATERIAL_LENGTH) * 2) +
2155 NEXT_WORD_SIZE(totalLength));
2157 /* compute the buffer size for the hashes */
2158 bufferA_MD5_length = totalLength + EA_MD5_Hash_Length;
2159 bufferA_SHA1_length = totalLength + EA_SHA1_Hash_Length;
2160 hashLen = NEXT_WORD_SIZE(bufferA_MD5_length) +
2161 NEXT_WORD_SIZE(bufferA_SHA1_length);
2163 ret = createEARequestBuffer(&req_p,
2164 obj_p->unitID,
2165 numCommands,
2166 resultHandlerTLSKeyHash,
2167 keyLen + hashLen);
2168 CHECK_RETURN(ret);
2170 kKey_a = req_p->qr.physicalAddress + req_p->dataoffset;
2171 kKey_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
2172 memset(kKey_p, 0, keyLen + hashLen);
2173 prS_a[0] = kKey_a + NEXT_WORD_SIZE(obj_p->keyLength);
2174 prS_p[0] = kKey_p + NEXT_WORD_SIZE(obj_p->keyLength);
2175 prS_a[1] = prS_a[0] + NEXT_WORD_SIZE(N8_MAX_TLS_KEY_MATERIAL_LENGTH);
2176 prS_p[1] = prS_p[0] + NEXT_WORD_SIZE(N8_MAX_TLS_KEY_MATERIAL_LENGTH);
2177 msg_a = prS_a[1] + NEXT_WORD_SIZE(N8_MAX_TLS_KEY_MATERIAL_LENGTH);
2178 msg_p = prS_p[1] + NEXT_WORD_SIZE(N8_MAX_TLS_KEY_MATERIAL_LENGTH);
2179 /* copy the input key to the kernel memory area */
2180 memcpy(kKey_p, obj_p->key_p, obj_p->keyLength);
2182 memcpy(msg_p, label_p, labelLength);
2183 memcpy(msg_p + labelLength, seed_p, seedLength);
2185 memset(&resultStream_p[0], 0x0, N8_MAX_TLS_KEY_MATERIAL_LENGTH);
2186 memset(prS_p[0], 0x0, N8_MAX_TLS_KEY_MATERIAL_LENGTH);
2187 memset(prS_p[1], 0x0, N8_MAX_TLS_KEY_MATERIAL_LENGTH);
2189 secretHalves = (int) (obj_p->keyLength / 2);
2191 ret = cb_ea_TLSKeyMaterialHash(req_p,
2192 req_p->EA_CommandBlock_ptr,
2193 msg_p,
2194 msg_a,
2195 totalLength,
2196 kKey_p,
2197 kKey_a,
2198 secretHalves,
2199 outputLength,
2200 prS_a[0],
2201 prS_a[1],
2202 keyLen);
2203 CHECK_RETURN(ret);
2205 /* create a struct to carry results to the result handler */
2206 keyResultStruct_p = (N8_TLSKeyHashResults_t *)&req_p->postProcessBuffer;
2207 keyResultStruct_p->result_p = keyMaterial_p;
2208 keyResultStruct_p->prS_p[0] = prS_p[0];
2209 keyResultStruct_p->prS_p[1] = prS_p[1];
2210 keyResultStruct_p->outputLength = outputLength;
2212 req_p->postProcessingData_p = (void *) keyResultStruct_p;
2213 QUEUE_AND_CHECK(event_p, req_p, ret);
2214 HANDLE_EVENT(event_p, req_p, ret);
2216 } while (FALSE);
2217 /* clean up */
2218 if (ret != N8_STATUS_OK)
2220 freeRequest(req_p);
2222 return ret;
2223 } /* N8_TLSKeyMaterialHash */
2225 /*****************************************************************************
2226 * N8_IKEPrf
2227 ****************************************************************************/
2228 /** @ingroup n8_hash
2229 * @brief Computes the PRF/HMAC for the given message and key
2231 * Computes the IKE keyed pseudo-random-function (prf) of the specified Key
2232 * of length KeyLength and Message of length MessageLength and returns the
2233 * results in Result. As specified in Sec. 4 of RFC 2409 (see [IKE] in
2234 * Appendix B: Reference Documentation), the only current pseudo-random
2235 * functions are the HMAC version of the negotiated hash algorithm. The hash
2236 * algorithm to use, and by implication the length of Result, is indicated
2237 * by the enumeration value specified in the Algorithm element of HashInfo.
2238 * If the Algorithm element of HashInfo is N8_HMAC_MD5, Result is 16 bytes;
2239 * if Algorithm is N8_HMAC_SHA1, Result is 20 bytes.
2242 * @param alg RO: algorthim (MD5 or SHA-1)
2243 * @param hashInfo_p RO: pointer to hash info struct
2244 * @param msg_p RO: pointer to message buffer
2245 * @param msgLength RO: input message length in bytes
2246 * @param result_p RW: pointer where hardware should copy result
2247 * @param event_p RW: pointer to event N8 event structure
2249 * @par Externals:
2251 * @return
2252 * N8_STATUS_OK
2254 * @par Errors:
2255 * N8_INVALID_HASH - The hash algorithm specified in hashInfo is not one
2256 * of the constants N8_HMAC_MD5 or N8_HMAC_SHA1.
2257 * N8_INVALID_INPUT_SIZE - The value of msgLength is < 0 or > 18KB; no
2258 * operation is performed and no result is returned.
2259 * N8_INVALID_OBJECT - if any pointers are bad
2260 * N8_INVALID_KEY_SIZE - The value of hashInfo_p->keyLength is < 0 or > 64B
2261 * @par Locks:
2262 * None.
2264 * @par Assumptions:
2265 * The caller is responsible for ensuring that sufficient space is allocated
2266 * for Result. Hash info must contain valid key pointer and key length.
2267 * Key cannot be longer than 64 bytes!
2268 ****************************************************************************/
2269 N8_Status_t N8_IKEPrf(const N8_HashAlgorithm_t alg,
2270 const N8_HashInfo_t *hashInfo_p,
2271 const N8_Buffer_t *msg_p,
2272 const uint32_t msgLength,
2273 N8_Buffer_t *result_p,
2274 N8_Event_t *event_p)
2276 API_Request_t *req_p = NULL;
2277 N8_Status_t ret = N8_STATUS_OK;
2278 uint32_t nBytes;
2279 uint32_t kKey_a;
2280 N8_Buffer_t *kKey_p = NULL;
2281 uint32_t kRes_a;
2282 N8_Buffer_t *kRes_p = NULL;
2283 N8_Buffer_t *kMsg_p = NULL;
2284 uint32_t kMsg_a;
2288 ret = N8_preamble();
2289 CHECK_RETURN(ret);
2291 CHECK_OBJECT(hashInfo_p, ret);
2292 CHECK_OBJECT(hashInfo_p->key_p, ret);
2293 CHECK_OBJECT(msg_p, ret);
2294 CHECK_OBJECT(result_p, ret);
2296 /* Also, if the key length is less than 64 bytes we
2297 * need to post-pad the key with 0x00 up to 64 bytes.
2298 * The padding is performed by the lower command
2299 * block building routine.
2300 * If the key length is greater than 64 bytes we
2301 * need to hash the key (results in 64 bytes for MD5 or
2302 * SHA-1).
2305 /* TODO: handle the >64 byte key case:
2306 * key must be hashed and truncated
2307 * to 64 bytes
2309 /* check key length */
2310 #ifdef N8_64BYTE_IKE_KEY_LIMIT
2311 /* for now we will only accept up to 64 bytes of key */
2312 if (hashInfo_p->keyLength > EA_HMAC_Key_Length)
2313 #else
2314 if (hashInfo->keyLength > N8_MAX_KEY_LENGTH)
2315 #endif
2317 ret = N8_INVALID_KEY_SIZE;
2318 break;
2320 /* check msg length */
2321 if (msgLength > N8_MAX_HASH_LENGTH)
2323 ret = N8_INVALID_INPUT_SIZE;
2324 break;
2327 /* compute kernel memory size for the key and msg */
2328 /* SHA1 result length=20 is greater than MD5 result length */
2329 nBytes = (NEXT_WORD_SIZE(hashInfo_p->keyLength) +
2330 NEXT_WORD_SIZE(msgLength) +
2331 NEXT_WORD_SIZE(SHA1_HASH_RESULT_LENGTH));
2333 ret = createEARequestBuffer(&req_p,
2334 hashInfo_p->unitID,
2335 N8_CB_EA_IKEPRF_NUMCMDS,
2336 resultHandlerGeneric,
2337 nBytes);
2338 CHECK_RETURN(ret);
2340 /* set up pointers for key | msg | res */
2341 kKey_a = req_p->qr.physicalAddress + req_p->dataoffset;
2342 kKey_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
2343 memset(kKey_p, 0, nBytes);
2344 kMsg_a = kKey_a + NEXT_WORD_SIZE(hashInfo_p->keyLength);
2345 kMsg_p = kKey_p + NEXT_WORD_SIZE(hashInfo_p->keyLength);
2346 kRes_a = kMsg_a + NEXT_WORD_SIZE(msgLength);
2347 kRes_p = kMsg_p + NEXT_WORD_SIZE(msgLength);
2349 /* copy the input key to the kernel memory area */
2350 memcpy(kKey_p, hashInfo_p->key_p, hashInfo_p->keyLength);
2351 /* copy the input msg to the kernel memory area */
2352 memcpy(kMsg_p, msg_p, msgLength);
2354 ret = cb_ea_IKEPrf(req_p,
2355 req_p->EA_CommandBlock_ptr,
2356 alg,
2357 kMsg_a,
2358 msgLength,
2359 kKey_p,
2360 hashInfo_p->keyLength,
2361 kRes_a);
2362 CHECK_RETURN(ret);
2364 /* setup up post-processing info */
2365 req_p->copyBackFrom_p = kRes_p;
2366 req_p->copyBackTo_p = result_p;
2369 /* set copy back size based on alg */
2370 switch (alg)
2372 case N8_HMAC_SHA1:
2374 req_p->copyBackSize = SHA1_HASH_RESULT_LENGTH;
2375 break;
2377 case N8_HMAC_MD5:
2379 req_p->copyBackSize = MD5_HASH_RESULT_LENGTH;
2380 break;
2382 default:
2384 ret = N8_INVALID_HASH;
2385 break;
2389 CHECK_RETURN(ret);
2391 QUEUE_AND_CHECK(event_p, req_p, ret);
2392 HANDLE_EVENT(event_p, req_p, ret);
2393 } while (FALSE);
2394 /* clean up */
2395 if (ret != N8_STATUS_OK)
2397 freeRequest(req_p);
2399 return ret;
2400 } /* N8_IKEPrf */
2402 /*****************************************************************************
2403 * N8_IKESKEYIDExpand
2404 ****************************************************************************/
2405 /** @ingroup n8_hash
2406 * @brief Computes SKEYID_d,a,e for the given message and key
2408 * Computes key material from the specified Key of length KeyLength and
2409 * Message of length Message-Length, according to the IKE authenticated
2410 * keying material generating algorithm in Sec. 5 of RFC 2409 (see [IKE] in
2411 * Appendix B: Reference Documentation), returning the three results SKEYID_d,
2412 * SKEYID_a, and SKEYID_e.
2414 * The hash algorithm to use, and by implication the lengths of the three
2415 * results, is indicated by the enu-meration value specified in the Algorithm\
2416 * element of HashInfo. If Algorithm is N8_HMAC_MD5, each result is 16 bytes;
2417 * if Algorithm is N8_HMAC_SHA1 each result is 20 bytes. The caller is
2418 * responsible for ensuring that sufficient space is allocated for these
2419 * results. (Note that if these result values are shorter than the required
2420 * key material, IKE specifies how these results are expanded.)
2422 * @param alg RO: algorthim (MD5 or SHA-1)
2423 * @param hashInfo_p RO: a pointer to hashInfo struct
2424 * @param msg_p RO: pointer to input message
2425 * @param msgLength RO: input message length in bytes
2426 * @param SKEYIDd_p RW: pointer to SKEYID_d output buffer
2427 * @param SKEYIDa_p RW: pointer to SKEYID_a output buffer
2428 * @param SKEYIDe_p RW: pointer to SKEYID_e output buffer
2429 * @param event_p RW: pointer to N8 event structure
2431 * @par Externals:
2433 * @return
2434 * N8_STATUS_OK
2436 * @par Errors:
2437 * N8_INVALID_HASH - The hash algorithm specified in hashInfo is not one
2438 * of the constants N8_HMAC_MD5 or N8_HMAC_SHA1.
2439 * N8_INVALID_INPUT_SIZE - The value of msgLength is < 0 or > 18KB; no
2440 * operation is performed and no result is returned.
2441 * N8_INVALID_OBJECT - if any pointers are bad
2442 * N8_INVALID_KEY_SIZE - The value of hashInfo_p->keyLength is < 0 or > 64B
2444 * @par Locks:
2445 * None.
2447 * @par Assumptions:
2448 * The caller is responsible for ensuring that sufficient space is allocated
2449 * for Result. Hash info must contain valid key pointer and key length.
2450 * Key cannot be longer than 64 bytes!
2451 ****************************************************************************/
2452 N8_Status_t N8_IKESKEYIDExpand (const N8_HashAlgorithm_t alg,
2453 const N8_HashInfo_t *hashInfo_p,
2454 const N8_Buffer_t *msg_p,
2455 const uint32_t msgLength,
2456 N8_Buffer_t *SKEYIDd_p,
2457 N8_Buffer_t *SKEYIDa_p,
2458 N8_Buffer_t *SKEYIDe_p,
2459 N8_Event_t *event_p)
2461 API_Request_t *req_p = NULL;
2462 N8_Status_t ret = N8_STATUS_OK;
2463 uint32_t nBytes;
2464 uint32_t kKey_a;
2465 N8_Buffer_t *kKey_p = NULL;
2466 uint32_t kSKEYIDd_a;
2467 N8_Buffer_t *kSKEYIDd_p = NULL;
2468 N8_Buffer_t *kMsg_p = NULL;
2469 uint32_t kMsg_a;
2470 N8_IKESKEYIDExpandResults_t *keyResultStruct_p = NULL;
2474 ret = N8_preamble();
2475 CHECK_RETURN(ret);
2477 CHECK_OBJECT(hashInfo_p, ret);
2478 CHECK_OBJECT(hashInfo_p->key_p, ret);
2479 CHECK_OBJECT(msg_p, ret);
2480 CHECK_OBJECT(SKEYIDd_p, ret);
2481 CHECK_OBJECT(SKEYIDa_p, ret);
2482 CHECK_OBJECT(SKEYIDe_p, ret);
2484 /* Also, if the key length is less than 64 bytes we
2485 * need to post-pad the key with 0x00 up to 64 bytes.
2486 * The padding is performed by the lower command
2487 * block building routine.
2488 * If the key length is greater than 64 bytes we
2489 * need to hash the key (results in 64 bytes for MD5 or
2490 * SHA-1).
2493 /* TODO: handle the >64 byte key case:
2494 * key must be hashed and truncated
2495 * to 64 bytes
2497 /* check key length */
2498 #ifdef N8_64BYTE_IKE_KEY_LIMIT
2499 /* for now we will only accept up to 64 bytes of key */
2500 if (hashInfo_p->keyLength > EA_HMAC_Key_Length)
2501 #else
2502 if (hashInfo->keyLength > N8_MAX_KEY_LENGTH)
2503 #endif
2505 ret = N8_INVALID_KEY_SIZE;
2506 break;
2508 /* check msg length */
2509 if (msgLength > N8_MAX_HASH_LENGTH)
2511 ret = N8_INVALID_INPUT_SIZE;
2512 break;
2515 /* compute kernel memory size for the key and msg */
2516 /* SHA1 result length=20 is the max(sha1,md5)
2517 * result length
2519 nBytes =
2520 (NEXT_WORD_SIZE(hashInfo_p->keyLength) +
2521 NEXT_WORD_SIZE(msgLength) +
2522 NEXT_WORD_SIZE(N8_IKE_SKEYID_ITERATIONS*SHA1_HASH_RESULT_LENGTH));
2524 ret = createEARequestBuffer(&req_p,
2525 hashInfo_p->unitID,
2526 N8_CB_EA_IKESKEYIDEXPAND_NUMCMDS,
2527 resultHandlerIKESKEYIDExpand,
2528 nBytes);
2529 CHECK_RETURN(ret);
2531 /* set up pointers for key | msg | res */
2532 kKey_a = req_p->qr.physicalAddress + req_p->dataoffset;
2533 kKey_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
2534 memset(kKey_p, 0, nBytes);
2535 kMsg_a = kKey_a + NEXT_WORD_SIZE(hashInfo_p->keyLength);
2536 kMsg_p = kKey_p + NEXT_WORD_SIZE(hashInfo_p->keyLength);
2537 kSKEYIDd_a = kMsg_a + NEXT_WORD_SIZE(msgLength);
2538 kSKEYIDd_p = kMsg_p + NEXT_WORD_SIZE(msgLength);
2540 /* copy the input key to the kernel memory area */
2541 memcpy(kKey_p, hashInfo_p->key_p, hashInfo_p->keyLength);
2542 /* copy the input msg to the kernel memory area */
2543 memcpy(kMsg_p, msg_p, msgLength);
2545 ret = cb_ea_IKESKEYIDExpand(req_p,
2546 req_p->EA_CommandBlock_ptr,
2547 alg,
2548 kMsg_a,
2549 msgLength,
2550 kKey_p,
2551 hashInfo_p->keyLength,
2552 kSKEYIDd_a);
2553 CHECK_RETURN(ret);
2555 /* create a struct to carry results to the result handler */
2556 keyResultStruct_p = (N8_IKESKEYIDExpandResults_t *)&req_p->postProcessBuffer;
2557 keyResultStruct_p->result_p = kSKEYIDd_p;
2558 keyResultStruct_p->SKEYIDd_p = SKEYIDd_p;
2559 keyResultStruct_p->SKEYIDa_p = SKEYIDa_p;
2560 keyResultStruct_p->SKEYIDe_p = SKEYIDe_p;
2562 /* set output length based on alg */
2563 switch (alg)
2565 case N8_HMAC_SHA1:
2567 keyResultStruct_p->outputLength = SHA1_HASH_RESULT_LENGTH;
2568 break;
2570 case N8_HMAC_MD5:
2572 keyResultStruct_p->outputLength = MD5_HASH_RESULT_LENGTH;
2573 break;
2575 default:
2577 ret = N8_INVALID_HASH;
2578 break;
2582 CHECK_RETURN(ret);
2584 req_p->postProcessingData_p = (void *) keyResultStruct_p;
2585 QUEUE_AND_CHECK(event_p, req_p, ret);
2586 HANDLE_EVENT(event_p, req_p, ret);
2587 } while (FALSE);
2588 /* clean up */
2589 if (ret != N8_STATUS_OK)
2591 freeRequest(req_p);
2593 return ret;
2594 } /* N8_IKESKEYIDExpand */
2596 /*****************************************************************************
2597 * N8_IKEKeyMaterialExpand
2598 ****************************************************************************/
2599 /** @ingroup n8_hash
2600 * @brief Performs key expansion using the given message and key up to the
2601 * specfied length
2603 * Computes OutputLength bytes of key material from the specified Key of
2604 * length KeyLength and Mes-sage of length MessageLength using the hash
2605 * function specified by the Algorithm element of HashInfo. If
2606 * MessageLength is greater than 0, then it denotes the size of Message,
2607 * and Message is used to generate key material according to the IKE key
2608 * expansion algorithm in Sec. 5.5 of RFC 2409 (see [IKE] in Appendix B:
2609 * Reference Documentation).
2610 * The generated key material is returned in Output. Up to 240 bytes of key
2611 * material may be generated using HMAC-MD5, and up to 300 bytes using
2612 * HMAC-SHA-1. The requested number of returned Out-put bytes is specified
2613 * in OutputLength. The caller is responsible for ensuring that sufficient
2614 * space is allocated for Output. The hash algorithm used is indicated by
2615 * the enumeration value in the Algorithm element of HashInfo.
2617 * @param alg RO: algorthim (MD5 or SHA-1)
2618 * @param hashInfo_p RO: pointer to hashInfo struct
2619 * @param msg_p RO: pointer to input message
2620 * @param msgLength RO: input message length in bytes
2621 * @param result_p RO: pointer to output buffer
2622 * @param result_len RO: number of key expansion bytes requested by caller
2623 * @param event_p RW: pointer to N8 event structure
2625 * @par Externals:
2627 * @return
2628 * N8_STATUS_OK
2630 * @par Errors:
2631 * N8_INVALID_HASH - The hash algorithm specified in hashInfo is not one
2632 * of the constants N8_HMAC_MD5 or N8_HMAC_SHA1.
2633 * N8_INVALID_INPUT_SIZE - The value of msgLength is < 0 or > 18KB;
2634 * no operation is performed and no result is
2635 * returned.
2636 * N8_INVALID_OUTPUT_SIZE - The value of result_len > 240 when
2637 * alg is N8_HMAC_MD5, or > 300 when alg
2638 * is N8_HMAC_SHA1; no operation is performed
2639 * and no result is returned.
2640 * N8_INVALID_OBJECT - if any pointers are bad
2641 * N8_INVALID_KEY_SIZE - The value of hashInfo_p->keyLength is < 0 or > 64B
2643 * @par Locks:
2644 * None.
2646 * @par Assumptions:
2647 * The caller is responsible for ensuring that sufficient space is
2648 * allocated for Result. Hash info must contain valid key pointer
2649 * and key length.
2650 * Key cannot be longer than 64 bytes!
2651 ****************************************************************************/
2652 N8_Status_t N8_IKEKeyMaterialExpand(const N8_HashAlgorithm_t alg,
2653 const N8_HashInfo_t *hashInfo_p,
2654 const N8_Buffer_t *msg_p,
2655 const uint32_t msgLength,
2656 N8_Buffer_t *result_p,
2657 const uint32_t result_len,
2658 N8_Event_t *event_p)
2660 API_Request_t *req_p = NULL;
2661 N8_Status_t ret = N8_STATUS_OK;
2662 uint32_t nBytes;
2663 uint32_t kKey_a;
2664 N8_Buffer_t *kKey_p = NULL;
2665 N8_Buffer_t *kMsg_p = NULL;
2666 uint32_t kMsg_a;
2667 N8_Buffer_t *kRes_p = NULL;
2668 uint32_t kRes_a;
2669 uint32_t hash_len = 0;
2670 uint32_t i_count;
2674 ret = N8_preamble();
2675 CHECK_RETURN(ret);
2677 /* if result_len is 0 - no computing is done */
2678 if (result_len == 0)
2680 if (event_p != NULL)
2682 N8_SET_EVENT_FINISHED(event_p, N8_EA);
2684 break;
2686 CHECK_OBJECT(hashInfo_p, ret);
2687 CHECK_OBJECT(hashInfo_p->key_p, ret);
2688 CHECK_OBJECT(msg_p, ret);
2689 CHECK_OBJECT(result_p, ret);
2691 /* Also, if the key length is less than 64 bytes we
2692 * need to post-pad the key with 0x00 up to 64 bytes.
2693 * The padding is performed by the lower command
2694 * block building routine.
2695 * If the key length is greater than 64 bytes we
2696 * need to hash the key (results in 64 bytes for MD5 or
2697 * SHA-1).
2700 /* TODO: handle the >64 byte key case:
2701 * key must be hashed and truncated
2702 * to 64 bytes
2704 /* check key length */
2705 #ifdef N8_64BYTE_IKE_KEY_LIMIT
2706 /* for now we will only accept up to 64 bytes of key */
2707 if (hashInfo_p->keyLength > EA_HMAC_Key_Length)
2708 #else
2709 if (hashInfo_p->keyLength > N8_MAX_KEY_LENGTH)
2710 #endif
2712 ret = N8_INVALID_KEY_SIZE;
2713 break;
2715 /* check msg length */
2716 if (msgLength > N8_MAX_HASH_LENGTH)
2718 ret = N8_INVALID_INPUT_SIZE;
2719 break;
2722 /* set hash_len based on alg */
2723 switch (alg)
2725 case N8_HMAC_SHA1:
2727 hash_len = SHA1_HASH_RESULT_LENGTH;
2728 break;
2730 case N8_HMAC_MD5:
2732 hash_len = MD5_HASH_RESULT_LENGTH;
2733 break;
2735 default:
2737 ret = N8_INVALID_HASH;
2738 break;
2742 CHECK_RETURN(ret);
2744 /* check output length */
2745 if (result_len > N8_MAX_IKE_ITERATIONS*hash_len)
2747 ret = N8_INVALID_OUTPUT_SIZE;
2748 break;
2751 /* compute iteration count: we want the WHOLE number
2752 * of iterations we need to produce the requested
2753 * amount of data
2755 if ((result_len % hash_len) != 0)
2757 i_count = result_len/hash_len + 1;
2759 else
2761 i_count = result_len/hash_len;
2764 /* compute kernel memory size for the key and msg */
2765 nBytes = (NEXT_WORD_SIZE(hashInfo_p->keyLength) +
2766 NEXT_WORD_SIZE(msgLength) +
2767 NEXT_WORD_SIZE(i_count*hash_len)); /* for result */
2768 ret = createEARequestBuffer(&req_p,
2769 hashInfo_p->unitID,
2770 N8_CB_EA_IKEKEYMATERIALEXPAND_NUMCMDS,
2771 resultHandlerGeneric, nBytes);
2772 CHECK_RETURN(ret);
2774 /* set up pointers for key | msg | res */
2775 kKey_a = req_p->qr.physicalAddress + req_p->dataoffset;
2776 kKey_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
2777 memset(kKey_p, 0, nBytes);
2778 kMsg_a = kKey_a + NEXT_WORD_SIZE(hashInfo_p->keyLength);
2779 kMsg_p = kKey_p + NEXT_WORD_SIZE(hashInfo_p->keyLength);
2780 kRes_a = kMsg_a + NEXT_WORD_SIZE(msgLength);
2781 kRes_p = kMsg_p + NEXT_WORD_SIZE(msgLength);
2783 /* copy the input key to the kernel memory area */
2784 memcpy(kKey_p, hashInfo_p->key_p, hashInfo_p->keyLength);
2785 /* copy the input msg to the kernel memory area */
2786 memcpy(kMsg_p, msg_p, msgLength);
2788 ret = cb_ea_IKEKeyMaterialExpand(req_p,
2789 req_p->EA_CommandBlock_ptr,
2790 alg,
2791 kMsg_a,
2792 msgLength,
2793 kKey_p,
2794 hashInfo_p->keyLength,
2795 kRes_a,
2796 i_count);
2797 CHECK_RETURN(ret);
2799 /* setup up post-processing info */
2800 req_p->copyBackFrom_p = kRes_p;
2801 req_p->copyBackTo_p = result_p;
2802 req_p->copyBackSize = result_len;
2804 QUEUE_AND_CHECK(event_p, req_p, ret);
2805 HANDLE_EVENT(event_p, req_p, ret);
2806 } while (FALSE);
2807 /* clean up */
2808 if (ret != N8_STATUS_OK)
2810 freeRequest(req_p);
2812 return ret;
2814 } /* N8_IKEKeyMaterialExpand */
2817 /*****************************************************************************
2818 * N8_IKEEncryptKeyExpand
2819 ****************************************************************************/
2820 /** @ingroup n8_hash
2821 * @brief Performs key expansion using the given message and key up to the
2822 * specfied length
2824 * Computes OutputLength bytes of key material from the specified Key of
2825 * length KeyLength using the hash function specified in the Algorithm element
2826 * of HashInfo, according to the IKE key expansion algo-rithm in Sec. 5.3 of
2827 * RFC 2409. (See [IKE] in Appendix B: Reference Documentation.) The generated
2828 * key material is returned in Output.
2829 * Up to 240 bytes of key material may be generated using HMAC-MD5, and 300
2830 * bytes using HMAC-SHA-1. The caller is responsible for ensuring that
2831 * sufficient space is allocated for Output. The hash algorithm used is
2832 * indicated by the enumeration value in the Algorithm element of HashInfo.
2833 * Proper computation requires a msg of a single zero byte. This zero byte
2834 * is allocated by internally by the API.
2836 * @param alg RO: algorthim (MD5 or SHA-1)
2837 * @param hashInfo_p RO: pointer to hashInfo structure
2838 * @param result_p RW: pointer to result buffer
2839 * @param result_len RO: caller-specified output length in bytes
2840 * @param event_p RW: pointer to N8 event structure
2842 * @par Externals:
2844 * @return
2845 * N8_STATUS_OK
2847 * @par Errors:
2848 * N8_INVALID_HASH - The hash algorithm specified in hashInfo is not one
2849 * of the constants N8_HMAC_MD5 or N8_HMAC_SHA1.
2850 * N8_INVALID_OUTPUT_SIZE - The value of result_len is < 0 or > 240 when
2851 * alg is N8_HMAC_MD5, or < 0 or > 300 when alg
2852 * is N8_HMAC_SHA1; no operation is performed
2853 * and no result is returned.
2854 * N8_INVALID_OBJECT - if any pointers are bad
2855 * N8_INVALID_KEY_SIZE - The value of hashInfo_p->keyLength is < 0 or > 64B
2857 * @par Locks:
2858 * None.
2860 * @par Assumptions:
2861 * The caller is responsible for ensuring that sufficient space is allocated
2862 * for Result. Hash info must contain valid key pointer and key length.
2863 * Key cannot be longer than 64 bytes!
2864 ****************************************************************************/
2865 N8_Status_t N8_IKEEncryptKeyExpand(const N8_HashAlgorithm_t alg,
2866 const N8_HashInfo_t *hashInfo_p,
2867 N8_Buffer_t *result_p,
2868 const uint32_t result_len,
2869 N8_Event_t *event_p)
2871 API_Request_t *req_p = NULL;
2872 N8_Status_t ret = N8_STATUS_OK;
2873 uint32_t nBytes;
2874 uint32_t kKey_a;
2875 N8_Buffer_t *kKey_p = NULL;
2876 N8_Buffer_t *kMsg_p = NULL;
2877 uint32_t kMsg_a;
2878 N8_Buffer_t *kRes_p = NULL;
2879 uint32_t kRes_a;
2880 uint32_t hash_len = 0;
2881 uint32_t i_count;
2885 ret = N8_preamble();
2886 CHECK_RETURN(ret);
2888 /* if result_len is 0 - no computing is done */
2889 if (result_len == 0)
2891 if (event_p != NULL)
2893 N8_SET_EVENT_FINISHED(event_p, N8_EA);
2895 break;
2898 CHECK_OBJECT(hashInfo_p, ret);
2899 CHECK_OBJECT(hashInfo_p->key_p, ret);
2900 CHECK_OBJECT(result_p, ret);
2902 /* Also, if the key length is less than 64 bytes we
2903 * need to post-pad the key with 0x00 up to 64 bytes.
2904 * The padding is performed by the lower command
2905 * block building routine.
2906 * If the key length is greater than 64 bytes we
2907 * need to hash the key (results in 64 bytes for MD5 or
2908 * SHA-1).
2911 /* TODO: handle the >64 byte key case:
2912 * key must be hashed and truncated
2913 * to 64 bytes
2915 /* check key length */
2916 #ifdef N8_64BYTE_IKE_KEY_LIMIT
2917 /* for now we will only accept up to 64 bytes of key */
2918 if (hashInfo_p->keyLength > EA_HMAC_Key_Length)
2919 #else
2920 if (hashInfo_p->keyLength > N8_MAX_KEY_LENGTH)
2921 #endif
2923 ret = N8_INVALID_KEY_SIZE;
2924 break;
2927 /* set hash_len based on alg */
2928 switch (alg)
2930 case N8_HMAC_SHA1:
2932 hash_len = SHA1_HASH_RESULT_LENGTH;
2933 break;
2935 case N8_HMAC_MD5:
2937 hash_len = MD5_HASH_RESULT_LENGTH;
2938 break;
2940 default:
2942 ret = N8_INVALID_HASH;
2943 break;
2947 CHECK_RETURN(ret);
2949 /* check output length */
2950 if (result_len > N8_MAX_IKE_ITERATIONS*hash_len)
2952 ret = N8_INVALID_OUTPUT_SIZE;
2953 break;
2956 /* compute iteration count: we want the WHOLE number
2957 * of iterations we need to produce the requested
2958 * amount of data
2960 if ((result_len % hash_len) != 0)
2962 i_count = result_len/hash_len + 1;
2964 else
2966 i_count = result_len/hash_len;
2969 /* compute kernel memory size for the key and msg */
2970 /* there is a single zero byte message that
2971 * always required for this API call
2973 nBytes = (NEXT_WORD_SIZE(hashInfo_p->keyLength) +
2974 NEXT_WORD_SIZE(N8_IKE_ZERO_BYTE_LEN) + /* one zero byte message */
2975 NEXT_WORD_SIZE(i_count*hash_len)); /* for result */
2977 ret = createEARequestBuffer(&req_p,
2978 hashInfo_p->unitID,
2979 N8_CB_EA_IKEENCRYPTKEYEXPAND_NUMCMDS,
2980 resultHandlerGeneric, nBytes);
2981 CHECK_RETURN(ret);
2983 /* set up pointers for key | res | msg */
2984 kKey_a = req_p->qr.physicalAddress + req_p->dataoffset;
2985 kKey_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
2986 memset(kKey_p, 0, nBytes);
2987 kRes_a = kKey_a + NEXT_WORD_SIZE(hashInfo_p->keyLength);
2988 kRes_p = kKey_p + NEXT_WORD_SIZE(hashInfo_p->keyLength);
2989 kMsg_a = kRes_a + NEXT_WORD_SIZE(i_count*hash_len);
2990 kMsg_p = kRes_p + NEXT_WORD_SIZE(i_count*hash_len);
2992 /* copy the input key to the kernel memory area */
2993 memcpy(kKey_p, hashInfo_p->key_p, hashInfo_p->keyLength);
2995 ret = cb_ea_IKEEncryptKeyExpand(req_p,
2996 req_p->EA_CommandBlock_ptr,
2997 alg,
2998 kMsg_a,
2999 N8_IKE_ZERO_BYTE_LEN,
3000 kKey_p,
3001 hashInfo_p->keyLength,
3002 kRes_a,
3003 i_count);
3004 CHECK_RETURN(ret);
3006 /* setup up post-processing info */
3007 req_p->copyBackFrom_p = kRes_p;
3008 req_p->copyBackTo_p = result_p;
3009 req_p->copyBackSize = result_len;
3011 QUEUE_AND_CHECK(event_p, req_p, ret);
3012 HANDLE_EVENT(event_p, req_p, ret);
3014 } while (FALSE);
3015 /* clean up */
3016 if (ret != N8_STATUS_OK)
3018 freeRequest(req_p);
3020 return ret;
3022 } /* N8_IKEEncryptKeyExpand */
3025 /*****************************************************************************
3026 * n8_setInitialIVs
3027 *****************************************************************************/
3028 /** @ingroup n8_hash
3029 * @brief Determine the hash type and set the initial IV values for that type.
3031 * @param hashObj_p RW: Pointer to hash object to be initialized.
3032 * @param unit RO: Validated unit identifier.
3034 * @par Externals
3035 * None
3037 * @return
3038 * Status
3040 * @par Errors
3041 * N8_INVALID_HASH if the hash is not from the set of supported hashes.
3043 * @par Assumptions
3044 * The hash object has the type filed set correctly.
3045 *****************************************************************************/
3046 N8_Status_t n8_setInitialIVs(N8_HashObject_t *hashObj_p,
3047 const N8_HashAlgorithm_t alg,
3048 const N8_Unit_t unit)
3050 N8_Status_t ret = N8_STATUS_OK;
3051 switch (alg)
3053 case N8_MD5:
3054 case N8_HMAC_MD5:
3055 case N8_HMAC_MD5_96:
3056 ret = initMD5(hashObj_p, alg, unit);
3057 break;
3058 case N8_SHA1:
3059 case N8_HMAC_SHA1:
3060 case N8_HMAC_SHA1_96:
3061 ret = initSHA1(hashObj_p, alg, unit);
3062 break;
3063 case N8_HASH_NONE:
3064 break;
3065 default:
3066 ret = N8_INVALID_HASH;
3067 break;
3069 return ret;
3070 } /* n8_setInitialIVs */
3071 /*****************************************************************************
3072 * initMD5
3073 ****************************************************************************/
3074 /** @ingroup n8_hash
3075 * @brief Initialize MD5 hash
3077 * Initialize hash object for subsequent MD5 hashing
3079 * @param obj_p RW: object to be initialized
3080 * @param alg RO: algorithm to use (e.g. N8_MD5 or
3081 * N8_HMAC_MD5)
3083 * @par Externals
3084 * None
3086 * @return
3087 * Error code. No abnormal error conditions have been identified.
3089 * @par Errors
3090 * None
3092 * @par Assumptions
3093 * None
3094 ****************************************************************************/
3095 N8_Status_t initMD5(N8_HashObject_t *obj_p,
3096 const N8_HashAlgorithm_t alg,
3097 int unitID)
3099 N8_Status_t ret = N8_STATUS_OK;
3102 DBG(("In initMD5 SAPI Layer\n"));
3103 CHECK_OBJECT(obj_p, ret);
3104 CHECK_RETURN(ret);
3105 memset(obj_p, 0, sizeof(N8_HashObject_t));
3106 obj_p->iv[0] = MD5_INIT_A;
3107 obj_p->iv[1] = MD5_INIT_B;
3108 obj_p->iv[2] = MD5_INIT_C;
3109 obj_p->iv[3] = MD5_INIT_D;
3110 obj_p->type = alg;
3111 obj_p->hashSize = MD5_HASH_RESULT_LENGTH;
3112 obj_p->unitID = unitID;
3113 obj_p->structureID = N8_HASH_STRUCT_ID;
3114 } while (FALSE);
3116 DBG(("returning from initMD5 SAPI Layer\n"));
3117 return ret;
3118 } /* initMD5 */
3120 /*****************************************************************************
3121 * initSHA1
3122 ****************************************************************************/
3123 /** @ingroup n8_hash
3124 * @brief Initialize SHA-1 hash
3126 * Initialize hash object for subsequent MD5 hashing
3128 * @param obj_p RW: object to be initialized
3129 * @param alg RO: algorithm to use (e.g. N8_SHA1 or
3130 * N8_HMAC_SHA1)
3132 * @par Externals
3133 * None
3135 * @return
3136 * Error code. No abnormal error conditions have been identified.
3138 * @par Errors
3139 * None
3141 * @par Assumptions
3142 * None
3143 ****************************************************************************/
3144 N8_Status_t initSHA1(N8_HashObject_t *obj_p,
3145 const N8_HashAlgorithm_t alg,
3146 int unitID)
3148 N8_Status_t ret = N8_STATUS_OK;
3151 CHECK_OBJECT(obj_p, ret);
3152 CHECK_RETURN(ret);
3153 memset(obj_p, 0, sizeof(N8_HashObject_t));
3154 obj_p->iv[0] = SHA1_INIT_H0;
3155 obj_p->iv[1] = SHA1_INIT_H1;
3156 obj_p->iv[2] = SHA1_INIT_H2;
3157 obj_p->iv[3] = SHA1_INIT_H3;
3158 obj_p->iv[4] = SHA1_INIT_H4;
3159 obj_p->type = alg;
3160 obj_p->hashSize = SHA1_HASH_RESULT_LENGTH;
3161 obj_p->unitID = unitID;
3162 obj_p->structureID = N8_HASH_STRUCT_ID;
3163 } while (FALSE);
3164 return ret;
3165 } /* initSHA1 */
3168 * Static Functions
3171 /*****************************************************************************
3172 * getRoleString
3173 ****************************************************************************/
3174 /** @ingroup n8_hash
3175 * @brief Produce the correct role string for a given protocol and role.
3177 * Various protocols and roles require different constant strings to
3178 * be included in a hash. This routine returns the correct string for
3179 * a given protocol/role combination.
3181 * @param protocol RO: Protocol in use.
3182 * @param role RW: Role in use.
3184 * @par Externals
3185 * None
3187 * @return
3188 * String to use.
3190 * @par Errors
3191 * None
3193 * @par Assumptions
3194 * None
3195 ****************************************************************************/
3196 static char * getRoleString(const N8_HashProtocol_t protocol,
3197 const N8_HashRole_t role)
3199 char *string;
3200 switch (protocol)
3202 case N8_SSL_FINISH:
3203 if (role == N8_SERVER)
3205 string = n8_strdup("SRVR");
3207 else
3209 string = n8_strdup("CLNT");
3211 break;
3212 case N8_TLS_FINISH:
3213 if (role == N8_SERVER)
3215 string = n8_strdup("server finished");
3217 else
3219 string = n8_strdup("client finished");
3221 break;
3222 case N8_SSL_CERT:
3223 case N8_TLS_CERT:
3224 default:
3225 string = n8_strdup("");
3226 break;
3228 return string;
3229 } /* getRoleString */
3231 /*****************************************************************************
3232 * computeSSLHandshakeHash
3233 ****************************************************************************/
3234 /** @ingroup n8_hash
3235 * @brief Compute the SSL Hash
3237 * Do the work to compute the SSL handshake hash for one specified hash.
3239 * @param hObj_p RW: Hash object to use in performing
3240 * the hash.
3241 * @param roleString_p RW: String constant for role to be
3242 * used in the hash.
3243 * @param key_p RW: Key to be used in the hash.
3244 * @param keyLength RW: Length of the key.
3245 * @param result_p RW: Pointer to buffer for results.
3247 * @par Externals
3248 * None
3250 * @return
3251 * Status
3253 * @par Errors
3254 * Standard
3256 * @par Assumptions
3257 * result_p is a pointer to an allocated buffer of adequate size.
3258 ****************************************************************************/
3259 static N8_Status_t computeSSLHandshakeHash(N8_HashObject_t *hObjMD5_p,
3260 N8_HashObject_t *hObjSHA_p,
3261 const char *roleString_p,
3262 const N8_Buffer_t *key_p,
3263 const unsigned int keyLength,
3264 N8_Buffer_t *resultMD5_p,
3265 N8_Buffer_t *resultSHA_p,
3266 N8_Event_t *event_p)
3268 N8_Status_t ret = N8_STATUS_OK;
3270 API_Request_t *req_p = NULL;
3271 unsigned int nBytes;
3272 N8_HandshakeEndResults_t *callBackData_p = NULL;
3274 N8_Buffer_t *innerMsg_md5_p = NULL;
3275 uint32_t innerMsg_md5_a;
3276 N8_Buffer_t *innerResult_md5_p = NULL;
3277 uint32_t innerResult_md5_a;
3278 N8_Buffer_t *outerMsg_md5_p = NULL;
3279 uint32_t outerMsg_md5_a;
3280 N8_Buffer_t *endResult_md5_p = NULL;
3281 uint32_t endResult_md5_a;
3283 N8_Buffer_t *innerMsg_sha_p = NULL;
3284 uint32_t innerMsg_sha_a;
3285 N8_Buffer_t *innerResult_sha_p = NULL;
3286 uint32_t innerResult_sha_a;
3287 N8_Buffer_t *outerMsg_sha_p = NULL;
3288 uint32_t outerMsg_sha_a;
3289 N8_Buffer_t *endResult_sha_p = NULL;
3290 uint32_t endResult_sha_a;
3292 N8_Buffer_t *hashMsgMD5_p = NULL;
3293 uint32_t hashMsgMD5_a;
3295 N8_Buffer_t *hashMsgSHA_p = NULL;
3296 uint32_t hashMsgSHA_a;
3298 unsigned int roleStringLen = strlen(roleString_p);
3300 unsigned int hashingLength_md5 = 0; /* totalLength rounded down to the */
3301 unsigned int hashingLength_sha = 0; /* next multiple of N8_HASH_BLOCK_SIZE */
3303 unsigned int innerMsgLen_md5;
3304 unsigned int innerMsgLen_sha;
3305 unsigned int outerMsgLen_md5;
3306 unsigned int outerMsgLen_sha;
3307 unsigned int i;
3310 innerMsgLen_md5 = keyLength + MD5_PAD_LENGTH + roleStringLen;
3311 outerMsgLen_md5 = MD5_HASH_RESULT_LENGTH + keyLength + MD5_PAD_LENGTH;
3312 innerMsgLen_sha = keyLength + SHA1_PAD_LENGTH + roleStringLen;
3313 outerMsgLen_sha = SHA1_HASH_RESULT_LENGTH + keyLength + SHA1_PAD_LENGTH;
3315 /* compute size of the results and the incoming message */
3316 nBytes = NEXT_WORD_SIZE(innerMsgLen_md5) + /* innerMsg_md5 */
3317 NEXT_WORD_SIZE(outerMsgLen_md5) + /* outerMsg_md5 */
3318 NEXT_WORD_SIZE(hObjMD5_p->hashSize) + /* endResult_md5 */
3319 NEXT_WORD_SIZE(innerMsgLen_sha) + /* innerMsg_sha */
3320 NEXT_WORD_SIZE(outerMsgLen_sha) + /* outerMsg_sha */
3321 NEXT_WORD_SIZE(hObjSHA_p->hashSize) + /* endResult_sha */
3322 NEXT_WORD_SIZE(N8_MAX_RESIDUAL_LEN + innerMsgLen_md5) +
3323 /* hashMsgmd5 */
3324 NEXT_WORD_SIZE(N8_MAX_RESIDUAL_LEN + innerMsgLen_sha) ;
3325 /* hashMsgsha */
3327 ret = createEARequestBuffer(&req_p,
3328 hObjMD5_p->unitID,
3329 N8_CB_EA_SSLSHANDSHAKEHASH_NUMCMDS,
3330 resultHandlerHandshakeEnd, nBytes);
3332 /* setup the space for the chip to place the result */
3333 innerMsg_md5_a = req_p->qr.physicalAddress + req_p->dataoffset;
3334 innerMsg_md5_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
3335 memset(innerMsg_md5_p, 0, nBytes);
3337 outerMsg_md5_a = innerMsg_md5_a + NEXT_WORD_SIZE(innerMsgLen_md5);
3338 outerMsg_md5_p = innerMsg_md5_p + NEXT_WORD_SIZE(innerMsgLen_md5);
3340 /* the inner result must start EXACTLY (keyLength + MD5_PAD_LENGTH) bytes
3341 * from the beginning of outerMsg_md5. do not round up to the next word
3342 * size. */
3343 innerResult_md5_a = outerMsg_md5_a + (keyLength + MD5_PAD_LENGTH);
3344 innerResult_md5_p = outerMsg_md5_p + (keyLength + MD5_PAD_LENGTH);
3346 endResult_md5_a = outerMsg_md5_a + NEXT_WORD_SIZE(outerMsgLen_md5);
3347 endResult_md5_p = outerMsg_md5_p + NEXT_WORD_SIZE(outerMsgLen_md5);
3349 innerMsg_sha_a = endResult_md5_a + NEXT_WORD_SIZE(hObjMD5_p->hashSize);
3350 innerMsg_sha_p = endResult_md5_p + NEXT_WORD_SIZE(hObjMD5_p->hashSize);
3352 outerMsg_sha_a = innerMsg_sha_a + NEXT_WORD_SIZE(innerMsgLen_sha);
3353 outerMsg_sha_p = innerMsg_sha_p + NEXT_WORD_SIZE(innerMsgLen_sha);
3355 innerResult_sha_a = outerMsg_sha_a + (keyLength + SHA1_PAD_LENGTH);
3356 innerResult_sha_p = outerMsg_sha_p + (keyLength + SHA1_PAD_LENGTH);
3358 endResult_sha_a = outerMsg_sha_a + NEXT_WORD_SIZE(outerMsgLen_sha);
3359 endResult_sha_p = outerMsg_sha_p + NEXT_WORD_SIZE(outerMsgLen_sha);
3361 hashMsgMD5_a = endResult_sha_a + NEXT_WORD_SIZE(hObjSHA_p->hashSize);
3362 hashMsgMD5_p = endResult_sha_p + NEXT_WORD_SIZE(hObjSHA_p->hashSize);
3364 hashMsgSHA_a = hashMsgMD5_a + NEXT_WORD_SIZE(N8_MAX_RESIDUAL_LEN + innerMsgLen_md5);
3365 hashMsgSHA_p = hashMsgMD5_p + NEXT_WORD_SIZE(N8_MAX_RESIDUAL_LEN + innerMsgLen_md5);
3367 /* construct the remainder of the inner message to be hashed:
3368 * innerMsg_p = roleString_p + key_p + pad1_p
3369 * note that the hash of the message is already present in the
3370 * results of the hash object.
3372 /* construct the inner message:
3374 i = 0;
3375 memcpy(&(innerMsg_md5_p[i]), roleString_p, roleStringLen);
3376 i += roleStringLen;
3377 memcpy(&(innerMsg_md5_p[i]), key_p, keyLength);
3378 i += keyLength;
3379 memset(&(innerMsg_md5_p[i]), PAD1, MD5_PAD_LENGTH);
3381 i = 0;
3382 memcpy(&(innerMsg_sha_p[i]), roleString_p, roleStringLen);
3383 i += roleStringLen;
3384 memcpy(&(innerMsg_sha_p[i]), key_p, keyLength);
3385 i += keyLength;
3386 memset(&(innerMsg_sha_p[i]), PAD1, SHA1_PAD_LENGTH);
3388 /* prepend the residual, if any */
3389 if (hObjMD5_p->residualLength > 0)
3391 memcpy(hashMsgMD5_p, hObjMD5_p->residual, hObjMD5_p->residualLength);
3392 hashingLength_md5 = hObjMD5_p->residualLength;
3394 memcpy(&(hashMsgMD5_p[hObjMD5_p->residualLength]), innerMsg_md5_p, innerMsgLen_md5);
3395 hashingLength_md5 += innerMsgLen_md5;
3397 /* prepend the residual, if any */
3398 if (hObjSHA_p->residualLength > 0)
3400 memcpy(hashMsgSHA_p, hObjSHA_p->residual, hObjSHA_p->residualLength);
3401 hashingLength_sha = hObjSHA_p->residualLength;
3403 memcpy(&(hashMsgSHA_p[hObjSHA_p->residualLength]), innerMsg_sha_p, innerMsgLen_sha);
3404 hashingLength_sha += innerMsgLen_sha;
3407 /* construct the outer message:
3408 * outerMsg_p = key + pad2 + innerResult
3410 i = 0;
3411 memcpy(&(outerMsg_sha_p[i]), key_p, keyLength);
3412 i+= keyLength;
3413 memset(&(outerMsg_sha_p[i]), PAD2, SHA1_PAD_LENGTH);
3415 i = 0;
3416 memcpy(&(outerMsg_md5_p[i]), key_p, keyLength);
3417 i+= keyLength;
3418 memset(&(outerMsg_md5_p[i]), PAD2, MD5_PAD_LENGTH);
3420 /* create callback structure */
3421 callBackData_p = (N8_HandshakeEndResults_t *)&req_p->postProcessBuffer;
3423 callBackData_p->to_resultSHA_p = resultSHA_p;
3424 callBackData_p->from_end_resultSHA_p = endResult_sha_p;
3425 callBackData_p->to_objSHA_p = (void *) hObjSHA_p;
3426 callBackData_p->to_resultMD5_p = resultMD5_p;
3427 callBackData_p->from_end_resultMD5_p = endResult_md5_p;
3428 callBackData_p->to_objMD5_p = (void *) hObjMD5_p;
3430 req_p->postProcessingData_p = (void *) callBackData_p;
3432 ret = cb_ea_SSLHandshakeHash(req_p,
3433 req_p->EA_CommandBlock_ptr,
3434 hObjMD5_p,
3435 innerResult_md5_a,
3436 hashMsgMD5_a,
3437 hashingLength_md5,
3438 hObjSHA_p,
3439 innerResult_sha_a,
3440 hashMsgSHA_a,
3441 hashingLength_sha,
3442 endResult_md5_a,
3443 endResult_sha_a,
3444 outerMsg_md5_a,
3445 outerMsgLen_md5,
3446 outerMsg_sha_a,
3447 outerMsgLen_sha);
3449 CHECK_RETURN(ret);
3450 QUEUE_AND_CHECK(event_p, req_p, ret);
3451 HANDLE_EVENT(event_p, req_p, ret);
3453 while (FALSE);
3455 /* clean up resources */
3456 if (ret != N8_STATUS_OK)
3458 freeRequest(req_p);
3460 return ret;
3462 } /* computeSSLHandshakeHash */
3464 /*****************************************************************************
3465 * computeTLSHandshakeHash
3466 *****************************************************************************/
3467 /** @ingroup n8_hash
3468 * @brief Generate the command blocks and set up the result handler for
3469 * the TLS modes of the N8_HandshakeHashEnd command.
3471 * This function completes the N8_Handshake in either TLS_FINISH or TLS_CERT
3472 * mode. The TLS_FINISH calculation is done according to RFC 2246, section 5.
3474 * @param md5Obj_p RO: Contains the md5 partial result to complete.
3475 * @param sha1Obj_p RO: Contains the sha1 partial result to complete.
3476 * @param protocol RO: N8_TLS_CERT or N8_TLS_FINISH
3477 * @param roleString_p RO: Either "server finished" or "client finished"
3478 * @param key_p RO: The key (secret) for the TLS PRF.
3479 * @param md5Result_p RW: The md5 result pointer passed in from API.
3480 * @param sha1Result_p RW: The sha1 result pointer passed in from API.
3481 * @param event_p RO: The event pointer
3483 * @par Externals:
3484 * None.
3486 * @return
3487 * N8_STATUS_OK: The function has succeeded.
3489 * @par Errors:
3490 * N8_INVALID_OBJECT: One of the input parameters in invalid.
3492 * @par Locks:
3493 * None.
3495 * @par Assumptions:
3496 *****************************************************************************/
3498 N8_Status_t
3499 computeTLSHandshakeHash(N8_HashObject_t *md5Obj_p,
3500 N8_HashObject_t *sha1Obj_p,
3501 const N8_HashProtocol_t protocol,
3502 const char *roleString_p,
3503 const N8_Buffer_t *key_p,
3504 const unsigned int keyLength,
3505 N8_Buffer_t *md5Result_p,
3506 N8_Buffer_t *sha1Result_p,
3507 N8_Event_t *event_p)
3509 N8_Status_t ret = N8_STATUS_OK;
3510 N8_Buffer_t *hashMsgMD5_p = NULL;
3511 uint32_t hashMsgMD5_a;
3512 N8_Buffer_t *resMD5_p = NULL;
3513 uint32_t resMD5_a;
3514 N8_Buffer_t *hashMsgSHA1_p = NULL;
3515 uint32_t hashMsgSHA1_a;
3516 N8_Buffer_t *resSHA1_p = NULL;
3517 uint32_t resSHA1_a;
3518 N8_Buffer_t *resMD5PRF_p = NULL;
3519 uint32_t resMD5PRF_a;
3520 N8_Buffer_t *resSHA1PRF_p = NULL;
3521 uint32_t resSHA1PRF_a;
3522 N8_Buffer_t *roleStr_p = NULL;
3523 uint32_t roleStr_a;
3524 API_Request_t *req_p = NULL;
3525 int nBytes;
3526 N8_TLSHandshakeHashResults_t *hashResultStruct_p;
3527 int nCmdBlocks = 0;
3528 int roleSize;
3532 CHECK_OBJECT(md5Obj_p, ret);
3533 CHECK_OBJECT(sha1Obj_p, ret);
3534 CHECK_OBJECT(md5Result_p, ret);
3535 CHECK_OBJECT(sha1Result_p, ret);
3536 CHECK_OBJECT(roleString_p, ret);
3537 CHECK_OBJECT(key_p, ret);
3539 /* Note: If we are not doing TLS_FINISH or TLS_CERT we won't be in this
3540 function */
3541 if (protocol == N8_TLS_FINISH)
3543 nCmdBlocks = N8_CB_EA_FINISHTLSHANDSHAKE_NUMCMDS;
3545 else if (protocol == N8_TLS_CERT)
3547 nCmdBlocks = N8_CB_EA_CERTTLSHANDSHAKE_NUMCMDS;
3550 /* We need to allocate kernel space for the role string, but we
3551 don't want to include the null terminator */
3552 roleSize = strlen(roleString_p);
3554 /* allocate kernel memory for the keys and msgs */
3555 /* The number of bytes is derived as follows: We are going
3556 to complete the MD5 and SHA1 hashes (using opcodes 0x10 and 0x20).
3557 This requires the MD5 residual lengh, the SHA1 residual length and
3558 1 * hashSize for each of MD5 and SHA1. The additional 2 * hashSize
3559 for each of MD5 and SHA1 are used for the TLS Pseudo Random Function
3560 required for the N8_TLS_FINISH protocol (using opcodes 0x18 and 0x28).
3561 We are also allocating NEXT_WORD_SIZE(roleSize) bytes for the role
3562 string (either "client finished" or "server finished"). We use the
3563 NEXT_WORD_SIZE macro to add the extra bytes for the role string
3564 because we expect to need those extra bytes in the buffer when
3565 we restore word alignment. Of course, if we are doing a TLS_CERT
3566 instead of a TLS_FINISH, we could get by with less memory but this
3567 works fine and handles both cases correctly.
3569 nBytes = ((3 * NEXT_WORD_SIZE(md5Obj_p->hashSize)) +
3570 (3 * NEXT_WORD_SIZE(sha1Obj_p->hashSize)) +
3571 NEXT_WORD_SIZE(md5Obj_p->residualLength) +
3572 NEXT_WORD_SIZE(sha1Obj_p->residualLength)
3573 + NEXT_WORD_SIZE(roleSize));
3575 /* Notice that we are using the unit from the MD5 object. At some
3576 point in the future we might like to use different units for
3577 each of the requests, but that will require a more general
3578 solution */
3579 ret = createEARequestBuffer(&req_p,
3580 md5Obj_p->unitID,
3581 nCmdBlocks,
3582 resultHandlerTLSHandshakeHash,
3583 nBytes);
3584 CHECK_RETURN(ret);
3586 /* Set up the addresses. Note that we are setting this up so that
3587 after the first two command blocks the role string, the completed
3588 MD5 hash, and the completed SHA1 hash are contiguous in physical
3589 memory. This is because the last two steps of the TLS Finish
3590 protocol use this concatenation as an input. Also note that
3591 since the role strings are both 15 bytes, the MD5 and SHA1 result
3592 buffers are not word aligned.
3595 /* The role string */
3596 roleStr_a = req_p->qr.physicalAddress + req_p->dataoffset;
3597 roleStr_p = (N8_Buffer_t *) ((int)req_p + req_p->dataoffset);
3598 memset(roleStr_p, 0, nBytes);
3600 /* Results of MD5 hash */
3601 resMD5_a = roleStr_a + roleSize;
3602 resMD5_p = roleStr_p + roleSize;
3604 /* Results of SHA1 hash */
3605 resSHA1_a = resMD5_a + md5Obj_p->hashSize;
3606 resSHA1_p = resMD5_p + md5Obj_p->hashSize;
3608 /* Input for MD5 hash. The use of NEXT_WORD_SIZE on the resSHA1 ptrs
3609 is to restore word alignment. */
3610 hashMsgMD5_a = NEXT_WORD_SIZE(resSHA1_a) + NEXT_WORD_SIZE(sha1Obj_p->hashSize);
3611 hashMsgMD5_p = (N8_Buffer_t *) NEXT_WORD_SIZE((uint32_t) resSHA1_p) +
3612 NEXT_WORD_SIZE(sha1Obj_p->hashSize);
3614 /* Input for SHA1 hash */
3615 hashMsgSHA1_a = hashMsgMD5_a + NEXT_WORD_SIZE(md5Obj_p->residualLength);
3616 hashMsgSHA1_p = hashMsgMD5_p + NEXT_WORD_SIZE(md5Obj_p->residualLength);
3618 /* Results of MD5 PRF */
3619 resMD5PRF_a = hashMsgSHA1_a + NEXT_WORD_SIZE(sha1Obj_p->residualLength);
3620 resMD5PRF_p = hashMsgSHA1_p + NEXT_WORD_SIZE(sha1Obj_p->residualLength);
3622 /* Results of SHA1 PRF */
3623 resSHA1PRF_a = resMD5PRF_a + (2 * NEXT_WORD_SIZE(md5Obj_p->hashSize));
3624 resSHA1PRF_p = resMD5PRF_p + (2 * NEXT_WORD_SIZE(md5Obj_p->hashSize));
3626 /* Copy in the role string */
3627 memcpy(roleStr_p, roleString_p, roleSize);
3629 /* Copy in messages to hash */
3630 /* preappend the residual, if any */
3631 if (md5Obj_p->residualLength > 0)
3633 memcpy(hashMsgMD5_p, md5Obj_p->residual, md5Obj_p->residualLength);
3636 /* prepend the residual, if any */
3637 if (sha1Obj_p->residualLength > 0)
3639 memcpy(hashMsgSHA1_p, sha1Obj_p->residual, sha1Obj_p->residualLength);
3641 ret = cb_ea_TLSHandshakeHash(req_p,
3642 protocol,
3643 resMD5_a,
3644 hashMsgMD5_a,
3645 md5Obj_p,
3646 md5Obj_p->residualLength,
3647 resSHA1_a,
3648 hashMsgSHA1_a,
3649 sha1Obj_p,
3650 sha1Obj_p->residualLength,
3651 resMD5PRF_a,
3652 resSHA1PRF_a,
3653 key_p,
3654 keyLength,
3655 roleStr_a);
3657 CHECK_RETURN(ret);
3659 /* create a struct to carry results to the result handler */
3660 CREATE_UOBJECT(hashResultStruct_p, N8_TLSHandshakeHashResults_t,
3661 ret);
3662 hashResultStruct_p->protocol = protocol;
3663 hashResultStruct_p->MD5Result_p = md5Result_p;
3664 hashResultStruct_p->SHA1Result_p = sha1Result_p;
3665 hashResultStruct_p->resMD5_p = resMD5_p;
3666 hashResultStruct_p->resSHA1_p = resSHA1_p;
3667 hashResultStruct_p->resMD5PRF_p = resMD5PRF_p;
3668 hashResultStruct_p->resSHA1PRF_p = resSHA1PRF_p;
3670 req_p->postProcessingData_p = (void *) hashResultStruct_p;
3671 QUEUE_AND_CHECK(event_p, req_p, ret);
3672 HANDLE_EVENT(event_p, req_p, ret);
3673 } while (FALSE);
3675 /* clean up resources */
3676 if (ret != N8_STATUS_OK)
3678 freeRequest(req_p);
3680 return ret;
3683 /*****************************************************************************
3684 * n8_HashCompleteMessage_req
3685 *****************************************************************************/
3686 /** @ingroup n8_hash
3687 * @brief Generate the request for N8_HashCompleteMessage
3689 * @param obj_p RW: Hash object pointer.
3690 * @param msg_p RO: Message to be hashed.
3691 * @param msgLength RO: Length of message to be hashed.
3692 * @param result_p RW: Destination of hash results.
3693 * @param resultHandler RO: Pointer to callback function. If NULL
3694 * the default is used.
3695 * @param req_pp RW: Pointer to request pointer.
3697 * @par Externals
3698 * None
3700 * @return
3701 * Status
3703 * @par Errors
3704 * N8_INVALID_OBJECT if req_pp is NULL<br>
3705 * N8_INVALID_INPUT_SIZE if the msgLength is greater than N8_MAX_HASH_LENGTH
3707 * @par Assumptions
3708 * None
3709 *****************************************************************************/
3710 N8_Status_t n8_HashCompleteMessage_req(N8_HashObject_t *obj_p,
3711 const N8_Buffer_t *msg_p,
3712 const unsigned int msgLength,
3713 N8_Buffer_t *result_p,
3714 const void *resultHandler,
3715 API_Request_t **req_pp)
3717 N8_Status_t ret = N8_STATUS_OK;
3719 N8_Buffer_t *hashMsg_p = NULL;
3720 unsigned long hashMsg_a;
3721 uint32_t res_a;
3722 N8_Buffer_t *res_p = NULL;
3723 int nBytes;
3727 CHECK_OBJECT(req_pp, ret);
3728 *req_pp = NULL; /* set the return request to NULL in case we
3729 * have to bail out. */
3730 ret = N8_preamble();
3731 CHECK_RETURN(ret);
3733 if (resultHandler == NULL)
3735 resultHandler = resultHandlerGeneric;
3737 if (msgLength > N8_MAX_HASH_LENGTH)
3739 ret = N8_INVALID_INPUT_SIZE;
3740 break;
3742 CHECK_OBJECT(obj_p, ret);
3743 if (msgLength > 0)
3745 CHECK_OBJECT(msg_p, ret);
3747 CHECK_OBJECT(result_p, ret);
3748 CHECK_STRUCTURE(obj_p->structureID, N8_HASH_STRUCT_ID, ret);
3750 /* comput the size for the results and the incoming message. */
3751 nBytes = (NEXT_WORD_SIZE(obj_p->hashSize) +
3752 NEXT_WORD_SIZE(msgLength));
3754 /* create the command blocks and do the hash. */
3755 ret = createEARequestBuffer(req_pp,
3756 obj_p->unitID,
3757 N8_CB_EA_HASHCOMPLETEMESSAGE_NUMCMDS,
3758 resultHandler, nBytes);
3759 CHECK_RETURN(ret);
3761 /* allocate space for the chip to place the result */
3762 res_a = (*req_pp)->qr.physicalAddress + (*req_pp)->dataoffset;
3763 res_p = (N8_Buffer_t *) ((int)(*req_pp) + (*req_pp)->dataoffset);
3764 memset(res_p, 0, nBytes);
3766 hashMsg_a = res_a + NEXT_WORD_SIZE(obj_p->hashSize);
3767 hashMsg_p = res_p + NEXT_WORD_SIZE(obj_p->hashSize);
3769 /* Copy in message to hash */
3770 memcpy(hashMsg_p, msg_p, msgLength);
3772 DBG(("hash length: %d\n", msgLength));
3774 (*req_pp)->copyBackFrom_p = res_p;
3775 (*req_pp)->copyBackTo_p = (void *) result_p;
3776 (*req_pp)->copyBackSize = obj_p->hashSize;
3778 ret = cb_ea_hashCompleteMessage(*req_pp,
3779 (*req_pp)->EA_CommandBlock_ptr,
3780 obj_p,
3781 hashMsg_a,
3782 msgLength,
3783 res_a);
3784 CHECK_RETURN(ret);
3785 } while (FALSE);
3786 return ret;
3787 } /* n8_HashCompleteMessage_req */
3790 N8_Status_t n8_HashCompleteMessage_req_uio(N8_HashObject_t *obj_p,
3791 struct uio *msg_p,
3792 const unsigned int msgLength,
3793 N8_Buffer_t *result_p,
3794 const void *resultHandler,
3795 API_Request_t **req_pp)
3797 N8_Status_t ret = N8_STATUS_OK;
3799 N8_Buffer_t *hashMsg_p = NULL;
3800 unsigned long hashMsg_a;
3801 uint32_t res_a;
3802 N8_Buffer_t *res_p = NULL;
3803 int nBytes;
3807 CHECK_OBJECT(req_pp, ret);
3808 *req_pp = NULL; /* set the return request to NULL in case we
3809 * have to bail out. */
3810 ret = N8_preamble();
3811 CHECK_RETURN(ret);
3813 if (resultHandler == NULL)
3815 resultHandler = resultHandlerGeneric;
3817 if (msgLength > N8_MAX_HASH_LENGTH)
3819 ret = N8_INVALID_INPUT_SIZE;
3820 break;
3822 CHECK_OBJECT(obj_p, ret);
3823 if (msgLength > 0)
3825 CHECK_OBJECT(msg_p, ret);
3827 CHECK_OBJECT(result_p, ret);
3828 CHECK_STRUCTURE(obj_p->structureID, N8_HASH_STRUCT_ID, ret);
3830 /* comput the size for the results and the incoming message. */
3831 nBytes = (NEXT_WORD_SIZE(obj_p->hashSize) +
3832 NEXT_WORD_SIZE(msgLength));
3834 /* create the command blocks and do the hash. */
3835 ret = createEARequestBuffer(req_pp,
3836 obj_p->unitID,
3837 N8_CB_EA_HASHCOMPLETEMESSAGE_NUMCMDS,
3838 resultHandler, nBytes);
3839 CHECK_RETURN(ret);
3841 /* allocate space for the chip to place the result */
3842 res_a = (*req_pp)->qr.physicalAddress + (*req_pp)->dataoffset;
3843 res_p = (N8_Buffer_t *) ((int)(*req_pp) + (*req_pp)->dataoffset);
3844 memset(res_p, 0, nBytes);
3846 hashMsg_a = res_a + NEXT_WORD_SIZE(obj_p->hashSize);
3847 hashMsg_p = res_p + NEXT_WORD_SIZE(obj_p->hashSize);
3849 /* Copy in message to hash */
3850 cuio_copydata(msg_p, 0, msgLength, hashMsg_p);
3852 DBG(("hash length: %d\n", msgLength));
3853 DBG(("cleartext: %08x|%08x|%08x|%08x\n",
3854 *(((uint32_t *)hashMsg_p)),
3855 *(((uint32_t *)hashMsg_p)+1),
3856 *(((uint32_t *)hashMsg_p)+2),
3857 *(((uint32_t *)hashMsg_p)+3)));
3859 (*req_pp)->copyBackFrom_p = res_p;
3860 (*req_pp)->copyBackTo_p = result_p;
3861 (*req_pp)->copyBackTo_uio = NULL;
3862 (*req_pp)->copyBackSize = obj_p->hashSize;
3864 ret = cb_ea_hashCompleteMessage(*req_pp,
3865 (*req_pp)->EA_CommandBlock_ptr,
3866 obj_p,
3867 hashMsg_a,
3868 msgLength,
3869 res_a);
3870 CHECK_RETURN(ret);
3871 } while (FALSE);
3872 return ret;
3873 } /* n8_HashCompleteMessage_req */
3874 /*****************************************************************************
3875 * N8_HashCompleteMessage
3876 ****************************************************************************/
3877 /** @ingroup n8_hash
3878 * @brief Hash a complete message.
3880 * To hash a message under 18 K bytes long use this function. Any
3881 * hash greater than that should make multiple calls to
3882 * N8_HashPartial.
3884 * @param obj_p RW: Hash object to store intermediate results.
3885 * @param msg_p RO: Pointer to the message to be hashed.
3886 * @param msgLength RO: Length of message to be hashed.
3887 * @param result_p WO: Pointer to hashed message.
3888 * @param event_p RO: Pointer to event for async calls. Null for
3889 * synchronous call.
3890 * @par Externals:
3891 * None
3893 * @return
3894 * Status code of type N8_Status.
3896 * @par Errors:
3897 * N8_STATUS_OK: A-OK<br>
3898 * N8_INVALID_INPUT_SIZE: message passed was larger than allowed
3899 * limit of N8_MAX_HASH_LENGTH<br>
3900 * N8_INVALID_OBJECT Invalid or null input parameter.
3901 * @par Assumptions:
3902 * None
3903 ****************************************************************************/
3904 N8_Status_t N8_HashCompleteMessage(N8_HashObject_t *obj_p,
3905 const N8_Buffer_t *msg_p,
3906 const unsigned int msgLength,
3907 N8_Buffer_t *result_p,
3908 N8_Event_t *event_p)
3910 N8_Status_t ret = N8_STATUS_OK;
3911 API_Request_t *req_p = NULL;
3913 DBG(("N8_HashCompleteMessage\n"));
3916 /* generate the request */
3917 ret = n8_HashCompleteMessage_req(obj_p, msg_p, msgLength, result_p,
3918 NULL, /* result handler -- use default */
3919 &req_p);
3920 if (req_p == NULL)
3922 if (event_p != NULL)
3924 N8_SET_EVENT_FINISHED(event_p, N8_EA);
3926 break;
3928 QUEUE_AND_CHECK(event_p, req_p, ret);
3929 HANDLE_EVENT(event_p, req_p, ret);
3931 while (FALSE);
3932 /* clean up resources */
3933 if (ret != N8_STATUS_OK)
3935 freeRequest(req_p);
3937 DBG(("N8_HashCompleteMessage - OK\n"));
3938 return ret;
3939 } /* N8_HashCompleteMessage */
3942 /* same as above, but for uio iovec i/o */
3943 N8_Status_t N8_HashCompleteMessage_uio(N8_HashObject_t *obj_p,
3944 struct uio *msg_p,
3945 const unsigned int msgLength,
3946 N8_Buffer_t *result_p,
3947 N8_Event_t *event_p)
3949 N8_Status_t ret = N8_STATUS_OK;
3950 API_Request_t *req_p = NULL;
3952 DBG(("N8_HashCompleteMessage\n"));
3955 /* generate the request */
3956 ret = n8_HashCompleteMessage_req_uio(obj_p, msg_p, msgLength, result_p,
3957 NULL, /* result handler -- use default */
3958 &req_p);
3959 if (req_p == NULL)
3961 if (event_p != NULL)
3963 N8_SET_EVENT_FINISHED(event_p, N8_EA);
3965 break;
3967 QUEUE_AND_CHECK(event_p, req_p, ret);
3968 HANDLE_EVENT(event_p, req_p, ret);
3970 while (FALSE);
3971 /* clean up resources */
3972 if (ret != N8_STATUS_OK)
3974 freeRequest(req_p);
3976 DBG(("N8_HashCompleteMessage - OK\n"));
3977 return ret;
3978 } /* N8_HashCompleteMessage */