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_rng.c,v 1.1 2008/10/30 12:02:15 darran Exp $";
36 /*****************************************************************************/
38 * @brief Contains Random Number Generator interface functions
41 * N8_SetRNGParameters - Sets the operating parameters for the
42 * Random Number Generator.
43 * N8_GetRNGParameters - Gets the operating parameters for the
44 * Random Number Generator.
45 * N8_GetRandomBytes - Gets requested number of random bytes.
47 *****************************************************************************/
49 /*****************************************************************************
51 * 07/28/03 brr Removed obsolete #ifdefs. (Bug 918)
52 * 05/19/03 brr Clean up include files.
53 * 05/15/03 brr Eliminated obsolete n8_rng.h & updated constants.
54 * 11/25/02 brr Use new define N8_RNG_UNIT to set/get RNG parameters.
55 * 05/15/02 brr Rework RNG queue such that ioctl returns the bytes requested.
56 * 04/04/02 msz Fix for BUG 685 (INCONSISTANT not INVALID OBJECT)
57 * 04/02/02 msz Fix for BUG 503 (not catching weak key of all zeros - check
58 * key after setting parity.)
59 * 03/26/02 msz Fix for BUG 506 (external clock w/o seed source external)
60 * Fix for BUG 507 (check seed source)
61 * Fix for BUG 509 (null pointer on get random bytes)
62 * 03/20/02 msz Fix for BUG 508 (check for request of 0 bytes.)
63 * 03/08/02 msz Request Handler callback is optional.
64 * 02/28/02 msz Request Handler callback is back.
65 * 02/28/02 brr Do not include any QMgr include files.
66 * 02/18/02 msz No longer need Request Handler callback. No longer need
67 * references to the queue control structure. No longer need
68 * current_RNGparms_gp. No longer need initRNGParameters
69 * 02/15/02 brr Correct DBG print for requestStatus.
70 * 02/06/02 bac Added error checking to functions even in the temporary
71 * USE_OS_RNG path so that QA tests behave as expected.
72 * 01/29/02 bac Changed Get/Set parameters to do nothing if using
74 * 01/29/02 bac Changed N8_GetRandomBytes to use rand() instead of the
75 * behavioral model. This is a temporary measure until the
76 * NSP2000 hardware fix is effected.
77 * 11/13/01 brr Removed references to shared_resource.
78 * 11/10/01 brr Modified to support static allocations of persistant data
80 * 11/07/01 mel Fixed Bugs #187 , #188 , #189 - cosmetic changes
81 * 10/05/01 msz Added slightly more protection around current_RNGparms_gp.
82 * 10/05/01 msz Added support for mulitple RNG execution units.
83 * 10/04/01 msz Added internal initRNGParameters.
84 * 10/02/01 msz Continued merging, use n8_get_shared_resource
85 * 09/25/01 msz Removed bufferLen_log2 from N8_RNG_Parameter_t.
86 * Ask QMgr if hardware has been already initialized before
87 * initializing it. Put current parameters in shared memory.
88 * 09/20/01 bac Changed Key_cblock to key_cblock_t to follow coding stds.
89 * 09/17/01 bac Removed occurence of buffer_source in a DBG statement.
90 * 09/14/01 bac Removed buffer_source from RNG parameters. It will always be
91 * X917. Also removed reference to enums for seed source and use
92 * the new bit-pattern macros instead.
93 * 09/07/01 bac Changed the return code to N8_INVALID_OBJECT if
94 * N8_SetRNGParameters includes a buffer size that is too large
95 * -- as listed in the API Programmer Reference. (BUG #157)
96 * 09/07/01 bac Added a return code check after calling set parameters.
98 * 09/11/01 msz Adjusted N8_RNG_Parameter_t parameters
99 * 09/04/01 bac Fixed BUG #56 by editting comments.
100 * 08/27/01 msz Renamed fcnToCallbackWhenRequestIsFilled to callback
101 * 08/08/01 msz Use internal seed, external does not work on FPGA.
102 * 08/08/01 msz Include n8_semaphore.h directly.
103 * 08/07/01 hml Added Locks section to appropriate comment block.
104 * 08/07/01 hml Added protection of globals with a process level semaphore.
105 * 08/03/01 msz Added a test for request_p not zero before de-referencing
106 * it in N8_GetRandomBytes.
107 * 08/02/01 bac Changed the default to set seed source to internal. Also
108 * fixed a bug when freeing a request.
109 * 07/31/01 bac Added call to N8_preamble for all public interfaces.
110 * 07/31/01 bac Check to ensure a request to get random bytes is not for more
111 * than RNG_MAX_REQUEST as required by the specification.
112 * 07/30/01 bac Set the queue pointer in the request.
113 * 07/12/01 bac Deleted unused variables.
114 * 06/28/01 bac Changes to hook-up callback function and get event handling to
116 * 06/25/01 bac Substantial changes to support QMgr v 1.0.1 and new kernel
117 * memory management. Added event to the GetRandomBytes call.
118 * 06/20/01 mel Corrected use of kernel memory.
119 * 05/30/01 mel Deleted checkKeyForWeakness and checkKeyParity.
120 * Added forcing parity on key.
121 * 05/21/01 bac Converted to use N8_ContextHandle_t.
122 * 05/18/01 bac Memory management macros.
123 * 05/03/01 bac Replaced integer use of NULL with 0.
124 * 04/30/01 bac Fixed problem with resultHandler to eliminate compiler
125 * warnings. Warning that resultHandler is defined but not
126 * used still exists as this problem needs to be resolved.
127 * 04/12/01 mel Original version.
128 ****************************************************************************/
129 /** @defgroup RNG Random Number Methods
131 #include "n8_common.h" /* common definitions */
132 #include "n8_pub_errors.h" /* Errors definition */
133 #include "n8_pub_types.h" /* Some type definitions. */
134 #include "n8_enqueue_common.h" /* common definitions for enqueue */
135 #include "n8_util.h" /* definitions for CHECK_RETURN and other macros */
136 #include "n8_key_works.h" /* definitions for functions that work with key */
137 #include "n8_API_Initialize.h"
138 #include "n8_semaphore.h"
141 /*****************************************************************************
142 * N8_SetRNGParameters
143 *****************************************************************************/
145 * @brief Sets the operating parameters for Random Number Generator.
147 * Sets the operating parameters for the Random Number Generator to the
148 * values contained in the N8_RNG_Parameter_t object. These parameters
149 * include the base address of the host memory buffer into which the RNG
150 * will write random values, the size of this buffer (in terms of entries,
151 * where each entry is a 64-bit random value), the seed source to use, etc.
152 * as defined in the RNG specification. Once this call returns, all values
153 * returned by N8_GetRandomBytes will be values generated using the parameters
154 * specified in this call (up until a subsequent call to N8_SetRNGParameters).
155 * A call to N8_SetRNGParameters must be made before N8_GetRandomBytes can
156 * return any random values.
158 * Currently this code will set parameters on all RNG units the same way.
159 * Thus, when we go to set parameters, we will tell RN code to set parameters
162 * @param p RO: Pointer to N8_RNG_Parameter_t
166 * ret - returns N8_STATUS_OK if successful or Error value.
169 * N8_INVALID_OBJECT - one or more values specified in
170 * N8_RNG_Parameter_t are outside its
171 * permitted range <BR>
172 * N8_INCONSISTENT - the values specified in
173 * N8_RNG_Parameter_t are not
174 * consistent with one another <BR>
175 * N8_WEAK_KEY - key1 or key2 or both - weak key(s) <BR>
176 * N8_INVALID_ENUM - buffer/seed type is invalid <BR>
177 * N8_INVALID_INPUT_SIZE - invalid size of the kernel-space
179 * N8_INVALID_KEY - key's parity check failed
187 *****************************************************************************/
191 N8_Status_t
N8_SetRNGParameters(N8_RNG_Parameter_t
*p
)
193 N8_Status_t ret
= N8_STATUS_OK
;
194 key_cblock_t key1
, key2
; /* Keys to be checked */
197 DBG(("N8_SetRNGParameters(N8_RNG_Parameter_t *p)\n"));
204 /* verify RNG parameter object */
205 CHECK_OBJECT(p
, ret
);
208 * 1. verify parameters for range and consistency
212 /* verify the consistency of the Time of the Day parameters */
213 if ((p
->set_TOD_counter
== N8_TRUE
) && (p
->TOD_prescale
< TOD_MIN
))
215 DBG(("TOD_prescale is out of range: %d\n", p
->TOD_prescale
));
216 DBG(("N8_SetRNGParameters - return Error\n"));
217 ret
= N8_INCONSISTENT
;
221 /* build keys for weakness and parity verification */
222 for ( i
= 0; i
< N8_DES_KEY_LENGTH
; i
++ )
224 key1
[i
] = p
->key1
[i
];
225 key2
[i
] = p
->key2
[i
];
229 /* check key1 and key2 for parity and force parity if needed*/
230 if (checkKeyParity(&key1
) == N8_FALSE
)
233 for ( i
= 0; i
< N8_DES_KEY_LENGTH
; i
++ )
235 p
->key1
[i
] = key1
[i
];
239 if(checkKeyParity(&key2
) == N8_FALSE
)
242 for ( i
= 0; i
< N8_DES_KEY_LENGTH
; i
++ )
244 p
->key2
[i
] = key2
[i
];
248 /* check key1 and key2 for weakness */
249 if (checkKeyForWeakness(&key1
) == N8_TRUE
||
250 checkKeyForWeakness(&key2
) == N8_TRUE
)
252 DBG(("Weak key\nN8_SetRNGParameters - return Error\n"));
260 /* verify iteration_count. */
261 if ((p
->iteration_count
< 1) || (p
->iteration_count
> 256))
263 DBG(("Iteration count is out of range\n"));
264 DBG(("N8_SetRNGParameters - return Error\n"));
265 /* iteration count is out of range */
266 ret
= N8_INVALID_OBJECT
;
271 /* Check seed souce */
272 if ( (p
->seed_source
!= N8_RNG_SEED_INTERNAL
) /* &&
273 (p->seed_source != N8_RNG_SEED_EXTERNAL) &&
274 (p->seed_source != N8_RNG_SEED_HOST) */ )
276 DBG(("Invalid seed source\n"));
277 DBG(("N8_SetRNGParameters - return Error\n"));
278 ret
= N8_INVALID_VALUE
;
282 /* Check for use of external clock without seed being seed external */
283 if ((p
->use_external_clock
== N8_TRUE
) &&
284 (p
->seed_source
!= N8_RNG_SEED_EXTERNAL
))
286 DBG(("External clock set without seed source external\n"));
287 DBG(("N8_SetRNGParameters - return Error\n"));
288 ret
= N8_INCONSISTENT
;
294 * 2. set parameters in queue manager
297 /* Initialize parameters in queue manager. All RNG units are */
298 /* initialized the same way. */
299 /* if queue was not able to set parameters return invalid object error */
300 ret
= RN_SetParameters(p
, N8_RNG_UNIT
);
301 if (ret
!= N8_STATUS_OK
)
303 DBG(("Queue was not able to set parameters\n"));
304 DBG(("N8_SetRNGParameters - return Error\n"));
305 N8_PRINT("N8_SetRNGParameters - return %d\n", ret
);
306 ret
= N8_INVALID_OBJECT
;
311 DBG(("N8_SetRNGParameters - FINISHED\n"));
317 } /* N8_SetRNGParameters */
319 /*****************************************************************************
320 * N8_GetRNGParameters
321 *****************************************************************************/
323 * @brief Gets the current operating parameters for RNG.
325 * Gets the current operating parameters for the Random Number Generator and
326 * returns their values in the N8_RNG_Parameter_t object. These parameters
327 * include the size of this buffer (in terms of entries, where each entry is a
328 * 64-bit random value), the seed source to use, etc. as defined in the RNG
329 * specification. This call has no effect on the operation of the RNG. A call
330 * to N8_GetRNGParameters made before any call to N8_SetRNGParameters will
331 * return whatever values are in the RNG's registers at the time of the call.
333 * We currently set all RNG units up the same way. So for the most part
334 * all parameters are the same on each unit. However, when we look at
335 * hardware specific parameters, we need to tell RN code to get parameters
336 * from all units. The RN code will handle any specific manipulation of
337 * the individual units to present one overall view.
339 * @param p WO: Pointer to N8_RNG_Parameter_t
342 * ret - returns N8_STATUS_OK if successful or Error value.
345 * N8_INVALID_OBJECT - Pointer to N8_RNG_Parameter_t is NULL<BR>
346 * N8_NOT_INITIALIZED - RNG wasn't initialized<BR>
352 * Assumes hardware is or will be initialized.
353 *****************************************************************************/
354 N8_Status_t
N8_GetRNGParameters(N8_RNG_Parameter_t
*p
)
357 N8_Status_t ret
= N8_STATUS_OK
; /* the return status: OK or ERROR */
359 DBG(("N8_GetRNGParameters(N8_RNG_Parameter_t *p)\n"));
366 /* verify RNG parameter object */
367 CHECK_OBJECT(p
, ret
);
369 /* QMgr keeps the copy of what the RNG Parameters look like. It */
370 /* will fill in the parameters */
371 ret
= RN_GetParameters(p
, N8_RNG_UNIT
);
372 if (ret
!= N8_STATUS_OK
)
374 DBG(("Queue was not able to get parameters\n"));
375 DBG(("N8_GetRNGParameters - return Error\n"));
376 ret
= N8_INVALID_OBJECT
;
380 /* Set set_TOD_counter to N8_FALSE, as that is what is claimed to */
381 /* be done in n8_rn_common.h's documentation. */
382 p
->set_TOD_counter
= N8_FALSE
;
384 DBG(("todEnable = %s\n",
385 (p
->todEnable
== N8_TRUE
) ? "N8_TRUE" : "N8_FALSE"));
386 DBG(("use_external_clock = %s\n",
387 (p
->use_external_clock
== N8_TRUE
) ? "N8_TRUE" : "N8_FALSE"));
388 DBG(("seed_source = %d\n", p
->seed_source
));
389 DBG(("iteration_count = %d\n", p
->iteration_count
));
390 DBG(("TOD_prescale = %x\n", p
->TOD_prescale
));
391 DBG(("set_TOD_counter = %s\n",
392 (p
->set_TOD_counter
== N8_TRUE
) ? "N8_TRUE" : "N8_FALSE"));
394 /* Note - These DBG lines assume N8_DES_KEY_LENGTH is 8 */
395 DBG(("key1 = %02x%02x%02x%02x%02x%02x%02x%02x\n",
396 p
->key1
[0],p
->key1
[1],p
->key1
[2],p
->key1
[3],
397 p
->key1
[4],p
->key1
[5],p
->key1
[6],p
->key1
[7]));
398 DBG(("key1 = %02x%02x%02x%02x%02x%02x%02x%02x\n",
399 p
->key2
[0],p
->key2
[1],p
->key2
[2],p
->key2
[3],
400 p
->key2
[4],p
->key2
[5],p
->key2
[6],p
->key2
[7]));
401 DBG(("hostSeed = %02x%02x%02x%02x%02x%02x%02x%02x\n",
402 p
->hostSeed
[0],p
->hostSeed
[1],p
->hostSeed
[2],p
->hostSeed
[3],
403 p
->hostSeed
[4],p
->hostSeed
[5],p
->hostSeed
[6],p
->hostSeed
[7]));
405 DBG(("initial_TOD_seconds = %x\n", p
->initial_TOD_seconds
));
406 DBG(("externalClockScaler = %x\n", p
->externalClockScaler
));
407 DBG(("hostSeedValid = %s\n",
408 (p
->hostSeedValid
== N8_TRUE
) ? "N8_TRUE" : "N8_FALSE"));
409 DBG(("seedErrorFlag = %s\n",
410 (p
->seedErrorFlag
== N8_TRUE
) ? "N8_TRUE" : "N8_FALSE"));
411 DBG(("x9_17_errorFlag = %s\n",
412 (p
->x9_17_errorFlag
== N8_TRUE
) ? "N8_TRUE" : "N8_FALSE"));
413 DBG(("seedValue_ms = %08x\n", p
->seedValue_ms
));
414 DBG(("seedValue_ls = %08x\n", p
->seedValue_ls
));
416 DBG(("N8_GetRNGParameters - FINISHED\n"));
421 } /* N8_GetRNGParameters */
423 /*****************************************************************************
425 *****************************************************************************/
427 * @brief Gets random bytes generated by the RNG.
429 * Gets reqvested number of random bytes generated by the RNG and returns
430 * them in the buffer, which must be at least as big as number of random bytes
431 * reqvested. Up to 8 K random bytes can be returned in a single call. A call
432 * to N8_SetRNGParameters must be made before N8_GetRandomBytes can return
435 * We currently pick a unit (next available) to get the parameters.
436 * This is ok, as all RNG units are set up the same way.
438 * @param num_bytes RO: The number of random bytes desired
439 * @param buf WO: The buffer for returned random bytes
440 * @param event_p RW: On input, if null the call is synchronous
441 * and no event is returned. The operation
442 * is complete when the call returns. If
443 * non-null, then the call is asynchronous;
444 * an event is returned that can be used to
445 * determine when the operation completes.
449 * ret - returns N8_STATUS_OK if successful or Error value.
450 * buf - the returned random bytes<BR>
453 * N8_NOT_INITIALIZED - the RNG has not been initialized<BR>
454 * N8_INVALID_INPUT_SIZE - num_bytes is less than 0
455 * or more than 8 KBytes<BR>
458 * Buffer is pre-allocated and is large enough.
459 *****************************************************************************/
461 N8_Status_t
N8_GetRandomBytes(int num_bytes
, char *buf_p
, N8_Event_t
*event_p
)
463 RN_Request_t rn_request
; /* RNG request structure */
465 DBG(("N8_GetRandomBytes\n"));
469 /* check the buffer */
470 CHECK_OBJECT(buf_p
, ret
);
472 /* check the number of bytes requested
473 it can't be less or equal to 0 or more than N8_RNG_MAX_REQUEST. */
474 if ((num_bytes
<= 0) || (num_bytes
> N8_RNG_MAX_REQUEST
))
476 DBG(("Number of bytes requested is out of range : %d\n", num_bytes
));
477 DBG(("N8_GetRandomBytes - return Error\n"));
478 ret
= N8_INVALID_INPUT_SIZE
;
485 rn_request
.userRequest
= N8_FALSE
;
486 rn_request
.userBuffer_p
= buf_p
;
487 rn_request
.numBytesRequested
= num_bytes
;
489 /* we have a valid request. queue it up. */
490 ret
= Queue_RN_request(&rn_request
);
495 N8_SET_EVENT_FINISHED(event_p
, N8_RNG
);
501 } /* N8_GetRandomBytes */