1/*
2 * crypto_kernel.c
3 *
4 * header for the cryptographic kernel
5 *
6 * David A. McGrew
7 * Cisco Systems, Inc.
8 */
9/*
10 *
11 * Copyright(c) 2001-2006 Cisco Systems, Inc.
12 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 *
18 *   Redistributions of source code must retain the above copyright
19 *   notice, this list of conditions and the following disclaimer.
20 *
21 *   Redistributions in binary form must reproduce the above
22 *   copyright notice, this list of conditions and the following
23 *   disclaimer in the documentation and/or other materials provided
24 *   with the distribution.
25 *
26 *   Neither the name of the Cisco Systems, Inc. nor the names of its
27 *   contributors may be used to endorse or promote products derived
28 *   from this software without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
33 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
34 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
35 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
37 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
41 * OF THE POSSIBILITY OF SUCH DAMAGE.
42 *
43 */
44
45
46#include "alloc.h"
47
48#include "crypto_kernel.h"
49
50/* the debug module for the crypto_kernel */
51
52debug_module_t mod_crypto_kernel = {
53  0,                  /* debugging is off by default */
54  "crypto kernel"     /* printable name for module   */
55};
56
57/*
58 * other debug modules that can be included in the kernel
59 */
60
61extern debug_module_t mod_auth;
62extern debug_module_t mod_cipher;
63extern debug_module_t mod_stat;
64extern debug_module_t mod_alloc;
65
66/*
67 * cipher types that can be included in the kernel
68 */
69
70extern cipher_type_t null_cipher;
71extern cipher_type_t aes_icm;
72extern cipher_type_t aes_cbc;
73
74
75/*
76 * auth func types that can be included in the kernel
77 */
78
79extern auth_type_t null_auth;
80extern auth_type_t hmac;
81
82/* crypto_kernel is a global variable, the only one of its datatype */
83
84crypto_kernel_t
85crypto_kernel = {
86  crypto_kernel_state_insecure,    /* start off in insecure state */
87  NULL,                            /* no cipher types yet         */
88  NULL,                            /* no auth types yet           */
89  NULL                             /* no debug modules yet        */
90};
91
92#define MAX_RNG_TRIALS 25
93
94err_status_t
95crypto_kernel_init() {
96  err_status_t status;
97
98  /* check the security state */
99  if (crypto_kernel.state == crypto_kernel_state_secure) {
100
101    /*
102     * we're already in the secure state, but we've been asked to
103     * re-initialize, so we just re-run the self-tests and then return
104     */
105    return crypto_kernel_status();
106  }
107
108  /* initialize error reporting system */
109  status = err_reporting_init("crypto");
110  if (status)
111    return status;
112
113  /* load debug modules */
114  status = crypto_kernel_load_debug_module(&mod_crypto_kernel);
115  if (status)
116    return status;
117  status = crypto_kernel_load_debug_module(&mod_auth);
118  if (status)
119    return status;
120  status = crypto_kernel_load_debug_module(&mod_cipher);
121  if (status)
122    return status;
123  status = crypto_kernel_load_debug_module(&mod_stat);
124  if (status)
125    return status;
126  status = crypto_kernel_load_debug_module(&mod_alloc);
127  if (status)
128    return status;
129
130  /* initialize random number generator */
131  status = rand_source_init();
132  if (status)
133    return status;
134
135  /* run FIPS-140 statistical tests on rand_source */
136  status = stat_test_rand_source_with_repetition(rand_source_get_octet_string, MAX_RNG_TRIALS);
137  if (status)
138    return status;
139
140  /* initialize pseudorandom number generator */
141  status = ctr_prng_init(rand_source_get_octet_string);
142  if (status)
143    return status;
144
145  /* run FIPS-140 statistical tests on ctr_prng */
146  status = stat_test_rand_source_with_repetition(ctr_prng_get_octet_string, MAX_RNG_TRIALS);
147  if (status)
148    return status;
149
150  /* load cipher types */
151  status = crypto_kernel_load_cipher_type(&null_cipher, NULL_CIPHER);
152  if (status)
153    return status;
154  status = crypto_kernel_load_cipher_type(&aes_icm, AES_ICM);
155  if (status)
156    return status;
157  status = crypto_kernel_load_cipher_type(&aes_cbc, AES_CBC);
158  if (status)
159    return status;
160
161  /* load auth func types */
162  status = crypto_kernel_load_auth_type(&null_auth, NULL_AUTH);
163  if (status)
164    return status;
165  status = crypto_kernel_load_auth_type(&hmac, HMAC_SHA1);
166  if (status)
167    return status;
168
169  /* change state to secure */
170  crypto_kernel.state = crypto_kernel_state_secure;
171
172  return err_status_ok;
173}
174
175err_status_t
176crypto_kernel_status() {
177  err_status_t status;
178  kernel_cipher_type_t  *ctype = crypto_kernel.cipher_type_list;
179  kernel_auth_type_t    *atype = crypto_kernel.auth_type_list;
180  kernel_debug_module_t *dm    = crypto_kernel.debug_module_list;
181
182  /* run FIPS-140 statistical tests on rand_source */
183  printf("testing rand_source...");
184  status = stat_test_rand_source_with_repetition(rand_source_get_octet_string, MAX_RNG_TRIALS);
185  if (status) {
186    printf("failed\n");
187    crypto_kernel.state = crypto_kernel_state_insecure;
188    return status;
189  }
190  printf("passed\n");
191
192  /* for each cipher type, describe and test */
193  while(ctype != NULL) {
194    printf("cipher: %s\n", ctype->cipher_type->description);
195    printf("  instance count: %d\n", ctype->cipher_type->ref_count);
196    printf("  self-test: ");
197    status = cipher_type_self_test(ctype->cipher_type);
198    if (status) {
199      printf("failed with error code %d\n", status);
200      exit(status);
201    }
202    printf("passed\n");
203    ctype = ctype->next;
204  }
205
206  /* for each auth type, describe and test */
207  while(atype != NULL) {
208    printf("auth func: %s\n", atype->auth_type->description);
209    printf("  instance count: %d\n", atype->auth_type->ref_count);
210    printf("  self-test: ");
211    status = auth_type_self_test(atype->auth_type);
212    if (status) {
213      printf("failed with error code %d\n", status);
214      exit(status);
215    }
216    printf("passed\n");
217    atype = atype->next;
218  }
219
220  /* describe each debug module */
221  printf("debug modules loaded:\n");
222  while (dm != NULL) {
223    printf("  %s ", dm->mod->name);
224    if (dm->mod->on)
225      printf("(on)\n");
226    else
227      printf("(off)\n");
228    dm = dm->next;
229  }
230
231  return err_status_ok;
232}
233
234err_status_t
235crypto_kernel_list_debug_modules() {
236  kernel_debug_module_t *dm = crypto_kernel.debug_module_list;
237
238  /* describe each debug module */
239  printf("debug modules loaded:\n");
240  while (dm != NULL) {
241    printf("  %s ", dm->mod->name);
242    if (dm->mod->on)
243      printf("(on)\n");
244    else
245      printf("(off)\n");
246    dm = dm->next;
247  }
248
249  return err_status_ok;
250}
251
252err_status_t
253crypto_kernel_shutdown() {
254  err_status_t status;
255
256  /*
257   * free dynamic memory used in crypto_kernel at present
258   */
259
260  /* walk down cipher type list, freeing memory */
261  while (crypto_kernel.cipher_type_list != NULL) {
262    kernel_cipher_type_t *ctype = crypto_kernel.cipher_type_list;
263    crypto_kernel.cipher_type_list = ctype->next;
264    debug_print(mod_crypto_kernel,
265		"freeing memory for cipher %s",
266		ctype->cipher_type->description);
267    crypto_free(ctype);
268  }
269
270  /* walk down authetication module list, freeing memory */
271  while (crypto_kernel.auth_type_list != NULL) {
272     kernel_auth_type_t *atype = crypto_kernel.auth_type_list;
273     crypto_kernel.auth_type_list = atype->next;
274     debug_print(mod_crypto_kernel,
275		"freeing memory for authentication %s",
276		atype->auth_type->description);
277     crypto_free(atype);
278  }
279
280  /* walk down debug module list, freeing memory */
281  while (crypto_kernel.debug_module_list != NULL) {
282    kernel_debug_module_t *kdm = crypto_kernel.debug_module_list;
283    crypto_kernel.debug_module_list = kdm->next;
284    debug_print(mod_crypto_kernel,
285		"freeing memory for debug module %s",
286		kdm->mod->name);
287    crypto_free(kdm);
288  }
289
290  /* de-initialize random number generator */  status = rand_source_deinit();
291  if (status)
292    return status;
293
294  /* return to insecure state */
295  crypto_kernel.state = crypto_kernel_state_insecure;
296
297  return err_status_ok;
298}
299
300static INLINE err_status_t
301crypto_kernel_do_load_cipher_type(cipher_type_t *new_ct, cipher_type_id_t id,
302				  int replace) {
303  kernel_cipher_type_t *ctype, *new_ctype;
304  err_status_t status;
305
306  /* defensive coding */
307  if (new_ct == NULL)
308    return err_status_bad_param;
309
310  if (new_ct->id != id)
311    return err_status_bad_param;
312
313  /* check cipher type by running self-test */
314  status = cipher_type_self_test(new_ct);
315  if (status) {
316    return status;
317  }
318
319  /* walk down list, checking if this type is in the list already  */
320  ctype = crypto_kernel.cipher_type_list;
321  while (ctype != NULL) {
322    if (id == ctype->id) {
323      if (!replace)
324	return err_status_bad_param;
325      status = cipher_type_test(new_ct, ctype->cipher_type->test_data);
326      if (status)
327	return status;
328      new_ctype = ctype;
329      break;
330    }
331    else if (new_ct == ctype->cipher_type)
332      return err_status_bad_param;
333    ctype = ctype->next;
334  }
335
336  /* if not found, put new_ct at the head of the list */
337  if (ctype == NULL) {
338  /* allocate memory */
339    new_ctype = (kernel_cipher_type_t *) crypto_alloc(sizeof(kernel_cipher_type_t));
340    if (new_ctype == NULL)
341      return err_status_alloc_fail;
342    new_ctype->next = crypto_kernel.cipher_type_list;
343
344    /* set head of list to new cipher type */
345    crypto_kernel.cipher_type_list = new_ctype;
346  }
347
348  /* set fields */
349  new_ctype->cipher_type = new_ct;
350  new_ctype->id = id;
351
352  /* load debug module, if there is one present */
353  if (new_ct->debug != NULL)
354    crypto_kernel_load_debug_module(new_ct->debug);
355  /* we could check for errors here */
356
357  return err_status_ok;
358}
359
360err_status_t
361crypto_kernel_load_cipher_type(cipher_type_t *new_ct, cipher_type_id_t id) {
362  return crypto_kernel_do_load_cipher_type(new_ct, id, 0);
363}
364
365err_status_t
366crypto_kernel_replace_cipher_type(cipher_type_t *new_ct, cipher_type_id_t id) {
367  return crypto_kernel_do_load_cipher_type(new_ct, id, 1);
368}
369
370err_status_t
371crypto_kernel_do_load_auth_type(auth_type_t *new_at, auth_type_id_t id,
372				int replace) {
373  kernel_auth_type_t *atype, *new_atype;
374  err_status_t status;
375
376  /* defensive coding */
377  if (new_at == NULL)
378    return err_status_bad_param;
379
380  if (new_at->id != id)
381    return err_status_bad_param;
382
383  /* check auth type by running self-test */
384  status = auth_type_self_test(new_at);
385  if (status) {
386    return status;
387  }
388
389  /* walk down list, checking if this type is in the list already  */
390  atype = crypto_kernel.auth_type_list;
391  while (atype != NULL) {
392    if (id == atype->id) {
393      if (!replace)
394	return err_status_bad_param;
395      status = auth_type_test(new_at, atype->auth_type->test_data);
396      if (status)
397	return status;
398      new_atype = atype;
399      break;
400    }
401    else if (new_at == atype->auth_type)
402      return err_status_bad_param;
403    atype = atype->next;
404  }
405
406  /* if not found, put new_at at the head of the list */
407  if (atype == NULL) {
408    /* allocate memory */
409    new_atype = (kernel_auth_type_t *)crypto_alloc(sizeof(kernel_auth_type_t));
410    if (new_atype == NULL)
411      return err_status_alloc_fail;
412
413    new_atype->next = crypto_kernel.auth_type_list;
414    /* set head of list to new auth type */
415    crypto_kernel.auth_type_list = new_atype;
416  }
417
418  /* set fields */
419  new_atype->auth_type = new_at;
420  new_atype->id = id;
421
422  /* load debug module, if there is one present */
423  if (new_at->debug != NULL)
424    crypto_kernel_load_debug_module(new_at->debug);
425  /* we could check for errors here */
426
427  return err_status_ok;
428
429}
430
431err_status_t
432crypto_kernel_load_auth_type(auth_type_t *new_at, auth_type_id_t id) {
433  return crypto_kernel_do_load_auth_type(new_at, id, 0);
434}
435
436err_status_t
437crypto_kernel_replace_auth_type(auth_type_t *new_at, auth_type_id_t id) {
438  return crypto_kernel_do_load_auth_type(new_at, id, 1);
439}
440
441
442cipher_type_t *
443crypto_kernel_get_cipher_type(cipher_type_id_t id) {
444  kernel_cipher_type_t *ctype;
445
446  /* walk down list, looking for id  */
447  ctype = crypto_kernel.cipher_type_list;
448  while (ctype != NULL) {
449    if (id == ctype->id)
450      return ctype->cipher_type;
451    ctype = ctype->next;
452  }
453
454  /* haven't found the right one, indicate failure by returning NULL */
455  return NULL;
456}
457
458
459err_status_t
460crypto_kernel_alloc_cipher(cipher_type_id_t id,
461			      cipher_pointer_t *cp,
462			      int key_len) {
463  cipher_type_t *ct;
464
465  /*
466   * if the crypto_kernel is not yet initialized, we refuse to allocate
467   * any ciphers - this is a bit extra-paranoid
468   */
469  if (crypto_kernel.state != crypto_kernel_state_secure)
470    return err_status_init_fail;
471
472  ct = crypto_kernel_get_cipher_type(id);
473  if (!ct)
474    return err_status_fail;
475
476  return ((ct)->alloc(cp, key_len));
477}
478
479
480
481auth_type_t *
482crypto_kernel_get_auth_type(auth_type_id_t id) {
483  kernel_auth_type_t *atype;
484
485  /* walk down list, looking for id  */
486  atype = crypto_kernel.auth_type_list;
487  while (atype != NULL) {
488    if (id == atype->id)
489      return atype->auth_type;
490    atype = atype->next;
491  }
492
493  /* haven't found the right one, indicate failure by returning NULL */
494  return NULL;
495}
496
497err_status_t
498crypto_kernel_alloc_auth(auth_type_id_t id,
499			 auth_pointer_t *ap,
500			 int key_len,
501			 int tag_len) {
502  auth_type_t *at;
503
504  /*
505   * if the crypto_kernel is not yet initialized, we refuse to allocate
506   * any auth functions - this is a bit extra-paranoid
507   */
508  if (crypto_kernel.state != crypto_kernel_state_secure)
509    return err_status_init_fail;
510
511  at = crypto_kernel_get_auth_type(id);
512  if (!at)
513    return err_status_fail;
514
515  return ((at)->alloc(ap, key_len, tag_len));
516}
517
518err_status_t
519crypto_kernel_load_debug_module(debug_module_t *new_dm) {
520  kernel_debug_module_t *kdm, *new;
521
522  /* defensive coding */
523  if (new_dm == NULL)
524    return err_status_bad_param;
525
526  /* walk down list, checking if this type is in the list already  */
527  kdm = crypto_kernel.debug_module_list;
528  while (kdm != NULL) {
529    if (strncmp(new_dm->name, kdm->mod->name, 64) == 0)
530      return err_status_bad_param;
531    kdm = kdm->next;
532  }
533
534  /* put new_dm at the head of the list */
535  /* allocate memory */
536  new = (kernel_debug_module_t *)crypto_alloc(sizeof(kernel_debug_module_t));
537  if (new == NULL)
538    return err_status_alloc_fail;
539
540  /* set fields */
541  new->mod = new_dm;
542  new->next = crypto_kernel.debug_module_list;
543
544  /* set head of list to new cipher type */
545  crypto_kernel.debug_module_list = new;
546
547  return err_status_ok;
548}
549
550err_status_t
551crypto_kernel_set_debug_module(char *name, int on) {
552  kernel_debug_module_t *kdm;
553
554  /* walk down list, checking if this type is in the list already  */
555  kdm = crypto_kernel.debug_module_list;
556  while (kdm != NULL) {
557    if (strncmp(name, kdm->mod->name, 64) == 0) {
558      kdm->mod->on = on;
559      return err_status_ok;
560    }
561    kdm = kdm->next;
562  }
563
564  return err_status_fail;
565}
566
567err_status_t
568crypto_get_random(unsigned char *buffer, unsigned int length) {
569  if (crypto_kernel.state == crypto_kernel_state_secure)
570    return ctr_prng_get_octet_string(buffer, length);
571  else
572    return err_status_fail;
573}
574