2 * Copyright (C) 2001-2003 by NBMK Encryption Technologies.
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>.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are
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 /*****************************************************************************/
38 * @brief Hashing functionality.
40 * Implementation of all public functions dealing with management of
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,
47 * HMAC: RFC2104 "HMAC: Keyed-Hashing for Message Authentication", H. Krawczyk,
50 *****************************************************************************/
52 /*****************************************************************************
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
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
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
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
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
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.
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
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"
215 #include "n8_ea_common.h"
216 #include "n8_cb_ea.h"
217 #include "n8_enqueue_common.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
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
271 N8_Buffer_t
*result_p
;
274 } N8_SSLKeyHashResults_t
;
279 N8_Buffer_t
*result_p
;
280 N8_Buffer_t
*prS_p
[2];
281 } N8_TLSKeyHashResults_t
;
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
;
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
;
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
;
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
;
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
;
323 } N8_HandshakeEndResults_t
;
327 N8_Buffer_t
*result1_p
;
328 N8_Buffer_t
*result2_p
;
335 static void n8_setHashedHMACKey(N8_HashObject_t
*obj_p
,
337 unsigned int keyLength
)
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
);
353 } /* n8_setHashedHMACKey */
355 /**********************************************************************
356 * resultHandlerHashPartial
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
369 **********************************************************************/
370 static void resultHandlerHashPartial(API_Request_t
* req_p
)
373 N8_HashObject_t
*obj_p
;
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
;
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
]));
391 for (i
= 0; i
< obj_p
->hashSize
/ sizeof(uint32_t); i
++)
393 obj_p
->iv
[i
] = BE_to_uint32(iv_p
);
399 RESULT_HANDLER_WARNING(title
, req_p
);
401 /* freeRequest(req_p); */
402 } /* resultHandlerHashPartial */
405 /**********************************************************************
406 * resultHandlerTLSKeyHash
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
419 **********************************************************************/
420 static void resultHandlerTLSKeyHash(API_Request_t
* req_p
)
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
));
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
435 keyResults_p
->result_p
[i
] = (keyResults_p
->prS_p
[0][i
] ^
436 keyResults_p
->prS_p
[1][i
]);
441 RESULT_HANDLER_WARNING(title
, req_p
);
443 } /* resultHandlerTLSKeyHash */
445 /*****************************************************************************
446 * resultHandlerIKESKEYIDExpand
447 *****************************************************************************/
449 * @brief Handles result for N8_IKESKEYIDExpand
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
461 * @param req_p RW: pointer to API request structure
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
));
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
);
498 RESULT_HANDLER_WARNING(title
, req_p
);
501 } /* resultHandlerIKESKEYIDExpand */
503 /*****************************************************************************
504 * resultHandlerTLSHandshakeHash
505 *****************************************************************************/
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.
532 *****************************************************************************/
534 static void resultHandlerTLSHandshakeHash(API_Request_t
* req_p
)
536 N8_TLSHandshakeHashResults_t
*data_p
= NULL
;
538 unsigned int dataBuffer
[NUM_WORDS_TLS_RESULT
];
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
,
553 MD5_HASH_RESULT_LENGTH
);
555 memcpy(data_p
->SHA1Result_p
,
557 SHA1_HASH_RESULT_LENGTH
);
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
567 (unsigned int *) (data_p
->resMD5PRF_p
+ MD5_HASH_RESULT_LENGTH
);
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
);
579 memcpy(data_p
->MD5Result_p
, dataBuffer
, MD5_HASH_RESULT_LENGTH
);
586 RESULT_HANDLER_WARNING(title
, req_p
);
589 N8_UFREE(req_p
->postProcessingData_p
);
590 /* freeRequest(req_p); */
592 } /* resultHandlerTLSHandshakeHash */
595 /*****************************************************************************
596 * resultHandlerHandshakePartial
597 ****************************************************************************/
599 * @brief Handles the result for the HandshakePartial
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
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
;
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
));
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
);
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
);
659 RESULT_HANDLER_WARNING(title
, req_p
);
661 /* DO NOT free request (req_p) here */
662 } /* resultHandlerHandshakePartial */
664 /**********************************************************************
665 * resultHandlerHandshakeEnd
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
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
);
708 RESULT_HANDLER_WARNING(title
, req_p
);
710 } /* resultHandlerHandshakeEnd */
712 /*****************************************************************************
714 ****************************************************************************/
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
727 * Status code of type N8_Status.
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>
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
));
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
,
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
]),
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"));
791 } /* computeResidual */
794 /*****************************************************************************
795 * n8_initializeHMAC_req
796 ****************************************************************************/
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
805 * @param req_pp RW: Pointer to request pointer.
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.
815 ****************************************************************************/
816 N8_Status_t
n8_initializeHMAC_req(N8_Buffer_t
*HMACKey
,
817 uint32_t HMACKeyLength
,
818 N8_HashObject_t
*hashObj_p
,
820 N8_Buffer_t
**ctx_pp
,
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
,
838 hashObj_p
->ipadHMAC_iv
,
839 hashObj_p
->opadHMAC_iv
);
840 memcpy(hashObj_p
->iv
, hashObj_p
->ipadHMAC_iv
, 20);
844 N8_CipherInfo_t
*obj_p
= (N8_CipherInfo_t
*) result_p
;
845 ret
= n8_precompute_tls_ipad_opad(hashObj_p
->type
,
849 obj_p
->key
.IPsecKeyDES
.ipad
,
850 obj_p
->key
.IPsecKeyDES
.opad
);
853 hashObj_p
->opad_Nl
= 64;
855 n8_setHashedHMACKey(hashObj_p
, hashedKey
, HMACKeyLength
);
860 } /* n8_initializeHMAC_req */
862 /*****************************************************************************
864 ****************************************************************************/
866 * @brief Compute HMAC for future hashing and store results in context memory
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.
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.
882 ****************************************************************************/
883 N8_Status_t
n8_initializeHMAC(N8_Buffer_t
*HMACKey
,
884 uint32_t HMACKeyLength
,
885 N8_HashObject_t
*hashObj_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
,
907 N8_SET_EVENT_FINISHED(event_p
, N8_EA
);
911 QUEUE_AND_CHECK(event_p
, req_p
, ret
);
912 HANDLE_EVENT(event_p
, req_p
, ret
);
915 /* clean up resources */
916 if (ret
!= N8_STATUS_OK
)
921 } /* n8_initializeHMAC */
922 /*****************************************************************************
924 ****************************************************************************/
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.
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.
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
,
956 N8_Status_t ret
= N8_STATUS_OK
;
958 DBG(("N8_HashInitialize\n"));
964 CHECK_OBJECT(hashObj_p
, ret
);
966 hashObj_p
->unitID
= hashInfo_p
->unitID
;
967 ret
= n8_setInitialIVs(hashObj_p
, alg
, hashObj_p
->unitID
);
969 switch (hashObj_p
->type
)
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
;
981 CHECK_OBJECT(hashInfo_p
, ret
);
982 ret
= n8_initializeHMAC(hashInfo_p
->key_p
,
983 hashInfo_p
->keyLength
,
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"));
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
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
;
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();
1061 /* this is legal but has no effect. do not change any state
1062 * and return successfully.
1067 /* only after verifying that the message length is non-zero, test for
1069 CHECK_OBJECT(msg_p
, ret
);
1071 if (msgLength
> N8_MAX_HASH_LENGTH
)
1073 ret
= N8_INVALID_INPUT_SIZE
;
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
,
1084 N8_CB_EA_HASHPARTIAL_NUMCMDS
,
1085 resultHandlerHashPartial
, nBytes
);
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
,
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
);
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
,
1133 NULL
/* next command block */,
1138 } /* n8_HashPartial_req */
1140 /*****************************************************************************
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
1159 * Status code of type N8_Status.
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>
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
);
1184 if (event_p
!= NULL
)
1186 N8_SET_EVENT_FINISHED(event_p
, N8_EA
);
1190 QUEUE_AND_CHECK(event_p
, req_p
, ret
);
1191 HANDLE_EVENT(event_p
, req_p
, ret
);
1194 /* clean up resources */
1195 if (ret
!= N8_STATUS_OK
)
1199 DBG(("N8_HashPartial - OK\n"));
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
1224 * @param req_pp RW: Pointer to request pointer.
1233 * N8_INVALID_OBJECT, N8_INVALID_HASH
1236 * The object algorithm has been pre-screened to be one of the supported HMAC
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
;
1245 N8_Buffer_t
*hashMsg_p
= NULL
;
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
;
1257 ret
= N8_preamble();
1259 CHECK_OBJECT(req_pp
, ret
);
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
,
1282 2 * N8_CB_EA_HASHEND_NUMCMDS
,
1283 resultHandlerGeneric
, nBytes
);
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
));
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
1316 hashMsg_a
, /* message to hash */
1317 hashingLength
, /* length of message */
1318 tempResults_a
, /* results physical address */
1319 &nextCommandBlock_p
, /* next command block pointer */
1323 /* next, create a command request to hash the results that were just
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 */
1336 req_p
->copyBackSize
= obj_p
->hashSize
;
1337 req_p
->copyBackFrom_p
= kResults_p
;
1338 req_p
->copyBackTo_p
= result_p
;
1344 } /* n8_HMACHashEnd_req */
1346 /*****************************************************************************
1348 *****************************************************************************/
1349 /** @ingroup n8_hash
1350 * @brief Generate the request for a Hash End operation for non-HMAC
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
1361 * <description of return value>
1364 * <description of possible errors><br>
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
;
1376 N8_Buffer_t
*hashMsg_p
= NULL
;
1378 unsigned long pAddr
;
1380 N8_Buffer_t
*kResults_p
= NULL
;
1381 uint32_t kResults_a
;
1382 API_Request_t
*req_p
;
1387 ret
= N8_preamble();
1389 CHECK_OBJECT(req_pp
, ret
);
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
,
1416 N8_CB_EA_HASHEND_NUMCMDS
,
1417 resultHandlerGeneric
, nBytes
);
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
);
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
;
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
));
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
1447 DBG(("hash length: %d\n", hashingLength
));
1448 DBG(("msg to hash: none\n"));
1452 ret
= cb_ea_hashEnd(req_p
,
1453 req_p
->EA_CommandBlock_ptr
,
1455 N8_IV
, /* get the IV from the
1460 NULL
, /* next command block */
1464 req_p
->copyBackSize
= obj_p
->hashSize
;
1465 req_p
->copyBackFrom_p
= kResults_p
;
1466 req_p
->copyBackTo_p
= result_p
;
1473 } /* n8_HashEnd_req */
1474 /*****************************************************************************
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
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
1496 * N8_INVALID_OBJECT<br>
1497 * N8_MALLOC_FAILED<br>
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
)
1515 case N8_HMAC_MD5_96
:
1517 case N8_HMAC_SHA1_96
:
1518 ret
= n8_HMACHashEnd_req(obj_p
, result_p
, &req_p
);
1522 ret
= n8_HashEnd_req(obj_p
, result_p
, &req_p
);
1525 ret
= N8_INVALID_HASH
;
1529 QUEUE_AND_CHECK(event_p
, req_p
, ret
);
1530 HANDLE_EVENT(event_p
, req_p
, ret
);
1533 /* clean up resources */
1534 if (ret
!= N8_STATUS_OK
)
1539 DBG(("N8_HashEnd - OK\n"));
1543 /*****************************************************************************
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.
1558 * Error condition if raised.
1564 * Values in the original are unchecked. Only a copy is
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();
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
));
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
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
1602 * @param msgLength RW: Length of message portion to be hashed.
1603 * @param event_p RW: Asynchronous event
1609 * Error code if encountered.
1614 * N8_INVALID_INPUT_SIZE
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
;
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
;
1637 EA_CMD_BLOCK_t
*nextCommandBlock
= NULL
;
1638 N8_HandshakePartialResults_t
*callBackData_p
= NULL
;
1641 ret
= N8_preamble();
1646 /* legal but has no effect or side-effects */
1649 if (msgLength
> N8_MAX_HASH_LENGTH
)
1651 ret
= N8_INVALID_INPUT_SIZE
;
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
;
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
,
1676 2 * N8_CB_EA_HASHPARTIAL_NUMCMDS
,
1677 resultHandlerHandshakePartial
, nBytes
);
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
,
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
);
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
,
1751 ret
= cb_ea_hashPartial(req_p
,
1762 DBG(("command block:\n"));
1764 QUEUE_AND_CHECK(event_p
, req_p
, ret
);
1765 HANDLE_EVENT(event_p
, req_p
, ret
);
1769 /* clean up resources */
1770 if (ret
!= N8_STATUS_OK
)
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
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
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
1798 * @param sha1Result_p RW: Pointer to pre-allocated space for
1800 * @param event_p RW: Async event. NULL for blocking.
1806 * Error condition if met.
1809 * N8_MALLOC_FAILED<br>
1810 * N8_INVALID_HASH<br>
1811 * N8_INVALID_PROTOCOL
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();
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
;
1841 if (md5Obj_p
->type
!= N8_MD5
|| sha1Obj_p
->type
!= N8_SHA1
)
1843 ret
= N8_INVALID_HASH
;
1846 roleString_p
= getRoleString(protocol
, role
);
1852 ret
= computeTLSHandshakeHash(md5Obj_p
,
1864 ret
= computeSSLHandshakeHash(md5Obj_p
,
1873 ret
= N8_INVALID_PROTOCOL
;
1881 N8_UFREE(roleString_p
);
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.
1905 * Error condition if raised.
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.
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
;
1931 ret
= N8_preamble();
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
;
1944 /* check key length */
1945 if (obj_p
->keyLength
> N8_MAX_KEY_LENGTH
)
1947 ret
= N8_INVALID_KEY_SIZE
;
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
1956 nBytes
= NEXT_WORD_SIZE(N8_MAX_SSL_KEY_MATERIAL_LENGTH
) +
1957 NEXT_WORD_SIZE(obj_p
->keyLength
);
1959 ret
= createEARequestBuffer(&req_p
,
1961 N8_CB_EA_SSLKEYMATERIALHASH_NUMCMDS
,
1962 resultHandlerGeneric
, nBytes
);
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
,
1989 QUEUE_AND_CHECK(event_p
, req_p
, ret
);
1990 HANDLE_EVENT(event_p
, req_p
, ret
);
1994 if (ret
!= N8_STATUS_OK
)
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
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
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
2032 * @param labelLength RO: The length of Label, from 0 to 18 KBytes
2034 * A length of 0 is legal;
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.
2041 * are defined in [TLS].
2042 * @param seedLength RO: The length of Seed, from 0 to 18 KBytes
2044 * A length of 0 is legal;
2045 * the result is computed with a
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
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
2062 * an event is returned that can be used to
2063 * determine when the operation completes.
2066 * Error condition if raised.
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>
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
;
2089 N8_Buffer_t
*kKey_p
= NULL
;
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
;
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();
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
;
2120 /* check label length */
2121 if (labelLength
> N8_MAX_KEY_LENGTH
)
2123 ret
= N8_INVALID_KEY_SIZE
;
2127 /* check seed length */
2128 if (seedLength
> N8_MAX_KEY_LENGTH
)
2130 ret
= N8_INVALID_KEY_SIZE
;
2134 if ((obj_p
->keyLength
+ labelLength
+ seedLength
) > N8_MAX_KEY_LENGTH
)
2136 ret
= N8_INVALID_KEY_SIZE
;
2140 /* check output buffer length */
2141 if (outputLength
> N8_MAX_TLS_KEY_MATERIAL_LENGTH
)
2143 ret
= N8_INVALID_KEY_SIZE
;
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
,
2166 resultHandlerTLSKeyHash
,
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
,
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
);
2218 if (ret
!= N8_STATUS_OK
)
2223 } /* N8_TLSKeyMaterialHash */
2225 /*****************************************************************************
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
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
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
;
2280 N8_Buffer_t
*kKey_p
= NULL
;
2282 N8_Buffer_t
*kRes_p
= NULL
;
2283 N8_Buffer_t
*kMsg_p
= NULL
;
2288 ret
= N8_preamble();
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
2305 /* TODO: handle the >64 byte key case:
2306 * key must be hashed and truncated
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
)
2314 if (hashInfo
->keyLength
> N8_MAX_KEY_LENGTH
)
2317 ret
= N8_INVALID_KEY_SIZE
;
2320 /* check msg length */
2321 if (msgLength
> N8_MAX_HASH_LENGTH
)
2323 ret
= N8_INVALID_INPUT_SIZE
;
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
,
2335 N8_CB_EA_IKEPRF_NUMCMDS
,
2336 resultHandlerGeneric
,
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
,
2360 hashInfo_p
->keyLength
,
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 */
2374 req_p
->copyBackSize
= SHA1_HASH_RESULT_LENGTH
;
2379 req_p
->copyBackSize
= MD5_HASH_RESULT_LENGTH
;
2384 ret
= N8_INVALID_HASH
;
2391 QUEUE_AND_CHECK(event_p
, req_p
, ret
);
2392 HANDLE_EVENT(event_p
, req_p
, ret
);
2395 if (ret
!= N8_STATUS_OK
)
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
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
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
;
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
;
2470 N8_IKESKEYIDExpandResults_t
*keyResultStruct_p
= NULL
;
2474 ret
= N8_preamble();
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
2493 /* TODO: handle the >64 byte key case:
2494 * key must be hashed and truncated
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
)
2502 if (hashInfo
->keyLength
> N8_MAX_KEY_LENGTH
)
2505 ret
= N8_INVALID_KEY_SIZE
;
2508 /* check msg length */
2509 if (msgLength
> N8_MAX_HASH_LENGTH
)
2511 ret
= N8_INVALID_INPUT_SIZE
;
2515 /* compute kernel memory size for the key and msg */
2516 /* SHA1 result length=20 is the max(sha1,md5)
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
,
2526 N8_CB_EA_IKESKEYIDEXPAND_NUMCMDS
,
2527 resultHandlerIKESKEYIDExpand
,
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
,
2551 hashInfo_p
->keyLength
,
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 */
2567 keyResultStruct_p
->outputLength
= SHA1_HASH_RESULT_LENGTH
;
2572 keyResultStruct_p
->outputLength
= MD5_HASH_RESULT_LENGTH
;
2577 ret
= N8_INVALID_HASH
;
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
);
2589 if (ret
!= N8_STATUS_OK
)
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
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
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
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
2647 * The caller is responsible for ensuring that sufficient space is
2648 * allocated for Result. Hash info must contain valid key pointer
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
;
2664 N8_Buffer_t
*kKey_p
= NULL
;
2665 N8_Buffer_t
*kMsg_p
= NULL
;
2667 N8_Buffer_t
*kRes_p
= NULL
;
2669 uint32_t hash_len
= 0;
2674 ret
= N8_preamble();
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
);
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
2700 /* TODO: handle the >64 byte key case:
2701 * key must be hashed and truncated
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
)
2709 if (hashInfo_p
->keyLength
> N8_MAX_KEY_LENGTH
)
2712 ret
= N8_INVALID_KEY_SIZE
;
2715 /* check msg length */
2716 if (msgLength
> N8_MAX_HASH_LENGTH
)
2718 ret
= N8_INVALID_INPUT_SIZE
;
2722 /* set hash_len based on alg */
2727 hash_len
= SHA1_HASH_RESULT_LENGTH
;
2732 hash_len
= MD5_HASH_RESULT_LENGTH
;
2737 ret
= N8_INVALID_HASH
;
2744 /* check output length */
2745 if (result_len
> N8_MAX_IKE_ITERATIONS
*hash_len
)
2747 ret
= N8_INVALID_OUTPUT_SIZE
;
2751 /* compute iteration count: we want the WHOLE number
2752 * of iterations we need to produce the requested
2755 if ((result_len
% hash_len
) != 0)
2757 i_count
= result_len
/hash_len
+ 1;
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
,
2770 N8_CB_EA_IKEKEYMATERIALEXPAND_NUMCMDS
,
2771 resultHandlerGeneric
, nBytes
);
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
,
2794 hashInfo_p
->keyLength
,
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
);
2808 if (ret
!= N8_STATUS_OK
)
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
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
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
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
;
2875 N8_Buffer_t
*kKey_p
= NULL
;
2876 N8_Buffer_t
*kMsg_p
= NULL
;
2878 N8_Buffer_t
*kRes_p
= NULL
;
2880 uint32_t hash_len
= 0;
2885 ret
= N8_preamble();
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
);
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
2911 /* TODO: handle the >64 byte key case:
2912 * key must be hashed and truncated
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
)
2920 if (hashInfo_p
->keyLength
> N8_MAX_KEY_LENGTH
)
2923 ret
= N8_INVALID_KEY_SIZE
;
2927 /* set hash_len based on alg */
2932 hash_len
= SHA1_HASH_RESULT_LENGTH
;
2937 hash_len
= MD5_HASH_RESULT_LENGTH
;
2942 ret
= N8_INVALID_HASH
;
2949 /* check output length */
2950 if (result_len
> N8_MAX_IKE_ITERATIONS
*hash_len
)
2952 ret
= N8_INVALID_OUTPUT_SIZE
;
2956 /* compute iteration count: we want the WHOLE number
2957 * of iterations we need to produce the requested
2960 if ((result_len
% hash_len
) != 0)
2962 i_count
= result_len
/hash_len
+ 1;
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
,
2979 N8_CB_EA_IKEENCRYPTKEYEXPAND_NUMCMDS
,
2980 resultHandlerGeneric
, nBytes
);
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
,
2999 N8_IKE_ZERO_BYTE_LEN
,
3001 hashInfo_p
->keyLength
,
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
);
3016 if (ret
!= N8_STATUS_OK
)
3022 } /* N8_IKEEncryptKeyExpand */
3025 /*****************************************************************************
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.
3041 * N8_INVALID_HASH if the hash is not from the set of supported hashes.
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
;
3055 case N8_HMAC_MD5_96
:
3056 ret
= initMD5(hashObj_p
, alg
, unit
);
3060 case N8_HMAC_SHA1_96
:
3061 ret
= initSHA1(hashObj_p
, alg
, unit
);
3066 ret
= N8_INVALID_HASH
;
3070 } /* n8_setInitialIVs */
3071 /*****************************************************************************
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
3087 * Error code. No abnormal error conditions have been identified.
3094 ****************************************************************************/
3095 N8_Status_t
initMD5(N8_HashObject_t
*obj_p
,
3096 const N8_HashAlgorithm_t alg
,
3099 N8_Status_t ret
= N8_STATUS_OK
;
3102 DBG(("In initMD5 SAPI Layer\n"));
3103 CHECK_OBJECT(obj_p
, 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
;
3111 obj_p
->hashSize
= MD5_HASH_RESULT_LENGTH
;
3112 obj_p
->unitID
= unitID
;
3113 obj_p
->structureID
= N8_HASH_STRUCT_ID
;
3116 DBG(("returning from initMD5 SAPI Layer\n"));
3120 /*****************************************************************************
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
3136 * Error code. No abnormal error conditions have been identified.
3143 ****************************************************************************/
3144 N8_Status_t
initSHA1(N8_HashObject_t
*obj_p
,
3145 const N8_HashAlgorithm_t alg
,
3148 N8_Status_t ret
= N8_STATUS_OK
;
3151 CHECK_OBJECT(obj_p
, 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
;
3160 obj_p
->hashSize
= SHA1_HASH_RESULT_LENGTH
;
3161 obj_p
->unitID
= unitID
;
3162 obj_p
->structureID
= N8_HASH_STRUCT_ID
;
3171 /*****************************************************************************
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.
3195 ****************************************************************************/
3196 static char * getRoleString(const N8_HashProtocol_t protocol
,
3197 const N8_HashRole_t role
)
3203 if (role
== N8_SERVER
)
3205 string
= n8_strdup("SRVR");
3209 string
= n8_strdup("CLNT");
3213 if (role
== N8_SERVER
)
3215 string
= n8_strdup("server finished");
3219 string
= n8_strdup("client finished");
3225 string
= n8_strdup("");
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
3241 * @param roleString_p RW: String constant for role to be
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.
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
;
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
) +
3324 NEXT_WORD_SIZE(N8_MAX_RESIDUAL_LEN
+ innerMsgLen_sha
) ;
3327 ret
= createEARequestBuffer(&req_p
,
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
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:
3375 memcpy(&(innerMsg_md5_p
[i
]), roleString_p
, roleStringLen
);
3377 memcpy(&(innerMsg_md5_p
[i
]), key_p
, keyLength
);
3379 memset(&(innerMsg_md5_p
[i
]), PAD1
, MD5_PAD_LENGTH
);
3382 memcpy(&(innerMsg_sha_p
[i
]), roleString_p
, roleStringLen
);
3384 memcpy(&(innerMsg_sha_p
[i
]), key_p
, 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
3411 memcpy(&(outerMsg_sha_p
[i
]), key_p
, keyLength
);
3413 memset(&(outerMsg_sha_p
[i
]), PAD2
, SHA1_PAD_LENGTH
);
3416 memcpy(&(outerMsg_md5_p
[i
]), key_p
, 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
,
3450 QUEUE_AND_CHECK(event_p
, req_p
, ret
);
3451 HANDLE_EVENT(event_p
, req_p
, ret
);
3455 /* clean up resources */
3456 if (ret
!= N8_STATUS_OK
)
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
3487 * N8_STATUS_OK: The function has succeeded.
3490 * N8_INVALID_OBJECT: One of the input parameters in invalid.
3496 *****************************************************************************/
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
;
3514 N8_Buffer_t
*hashMsgSHA1_p
= NULL
;
3515 uint32_t hashMsgSHA1_a
;
3516 N8_Buffer_t
*resSHA1_p
= NULL
;
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
;
3524 API_Request_t
*req_p
= NULL
;
3526 N8_TLSHandshakeHashResults_t
*hashResultStruct_p
;
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
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
3579 ret
= createEARequestBuffer(&req_p
,
3582 resultHandlerTLSHandshakeHash
,
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
,
3646 md5Obj_p
->residualLength
,
3650 sha1Obj_p
->residualLength
,
3659 /* create a struct to carry results to the result handler */
3660 CREATE_UOBJECT(hashResultStruct_p
, N8_TLSHandshakeHashResults_t
,
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
);
3675 /* clean up resources */
3676 if (ret
!= N8_STATUS_OK
)
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.
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
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
;
3722 N8_Buffer_t
*res_p
= NULL
;
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();
3733 if (resultHandler
== NULL
)
3735 resultHandler
= resultHandlerGeneric
;
3737 if (msgLength
> N8_MAX_HASH_LENGTH
)
3739 ret
= N8_INVALID_INPUT_SIZE
;
3742 CHECK_OBJECT(obj_p
, ret
);
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
,
3757 N8_CB_EA_HASHCOMPLETEMESSAGE_NUMCMDS
,
3758 resultHandler
, nBytes
);
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
,
3787 } /* n8_HashCompleteMessage_req */
3790 N8_Status_t
n8_HashCompleteMessage_req_uio(N8_HashObject_t
*obj_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
;
3802 N8_Buffer_t
*res_p
= NULL
;
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();
3813 if (resultHandler
== NULL
)
3815 resultHandler
= resultHandlerGeneric
;
3817 if (msgLength
> N8_MAX_HASH_LENGTH
)
3819 ret
= N8_INVALID_INPUT_SIZE
;
3822 CHECK_OBJECT(obj_p
, ret
);
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
,
3837 N8_CB_EA_HASHCOMPLETEMESSAGE_NUMCMDS
,
3838 resultHandler
, nBytes
);
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
,
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
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
3894 * Status code of type N8_Status.
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.
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 */
3922 if (event_p
!= NULL
)
3924 N8_SET_EVENT_FINISHED(event_p
, N8_EA
);
3928 QUEUE_AND_CHECK(event_p
, req_p
, ret
);
3929 HANDLE_EVENT(event_p
, req_p
, ret
);
3932 /* clean up resources */
3933 if (ret
!= N8_STATUS_OK
)
3937 DBG(("N8_HashCompleteMessage - OK\n"));
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
,
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 */
3961 if (event_p
!= NULL
)
3963 N8_SET_EVENT_FINISHED(event_p
, N8_EA
);
3967 QUEUE_AND_CHECK(event_p
, req_p
, ret
);
3968 HANDLE_EVENT(event_p
, req_p
, ret
);
3971 /* clean up resources */
3972 if (ret
!= N8_STATUS_OK
)
3976 DBG(("N8_HashCompleteMessage - OK\n"));
3978 } /* N8_HashCompleteMessage */