blob: 3d01d25a6cae48fef96aa262bb65f1acbdf29363 [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001/*
2 * rand_source.c
3 *
4 * implements a random source based on /dev/random
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#include "srtp_config.h"
46
47#if defined(DEV_URANDOM) || defined(PJ_DEV_URANDOM)
48# include <fcntl.h> /* for open() */
49# include <unistd.h> /* for close() */
50#elif (_MSC_VER >= 1400)
51#define _CRT_RAND_S
52# include <stdlib.h>
53# include <stdio.h>
54#else
55# include <stdio.h>
56#endif
57
58#include "rand_source.h"
59
60
61/*
62 * global dev_rand_fdes is file descriptor for /dev/random
63 *
64 * This variable is also used to indicate that the random source has
65 * been initialized. When this variable is set to the value of the
66 * #define RAND_SOURCE_NOT_READY, it indicates that the random source
67 * is not ready to be used. The value of the #define
68 * RAND_SOURCE_READY is for use whenever that variable is used as an
69 * indicator of the state of the random source, but not as a file
70 * descriptor.
71 */
72
73#define RAND_SOURCE_NOT_READY (-1)
74#define RAND_SOURCE_READY (17)
75
76static int dev_random_fdes = RAND_SOURCE_NOT_READY;
77
78
79err_status_t
80rand_source_init(void) {
81 if (dev_random_fdes >= 0) {
82 /* already open */
83 return err_status_ok;
84 }
85#ifdef DEV_URANDOM
86 /* open random source for reading */
87 dev_random_fdes = open(DEV_URANDOM, O_RDONLY);
88 if (dev_random_fdes < 0)
89 return err_status_init_fail;
90#elif defined(PJ_DEV_URANDOM)
91 /* open random source for reading */
92 dev_random_fdes = open(PJ_DEV_URANDOM, O_RDONLY);
93 if (dev_random_fdes < 0) {
94 err_report(3,"Ugh: /dev/urandom not present, using rand() instead");
95 return err_status_ok; /* it's ok, it'll fallback to using rand() */
96 }
97#elif (_MSC_VER >= 1400)
98 dev_random_fdes = RAND_SOURCE_READY;
99#else
100 /* no random source available; let the user know */
101 err_report(err_level_info, "WARNING: no real random source present!\n");
102 dev_random_fdes = RAND_SOURCE_READY;
103#endif
104 return err_status_ok;
105}
106
107err_status_t
108rand_source_get_octet_string(void *dest, uint32_t len) {
109
110 /*
111 * read len octets from /dev/random to dest, and
112 * check return value to make sure enough octets were
113 * written
114 */
115#ifdef DEV_URANDOM
116 if (read(dev_random_fdes, dest, len) != len)
117 return err_status_fail;
118#elif 0 && (_MSC_VER >= 1400) /* disabled rand_s, causing assertion 'rand_s not supported' in vs8 */
119 unsigned int *dst = dest;
120 while (len)
121 {
122 unsigned int val = 0;
123 errno_t err = rand_s(&val);
124 if (err != 0)
125 {
126 return err_status_fail;
127 }
128
129 *dst++ = val;
130 len--;
131 }
132#else
133 uint8_t *dst = (uint8_t *)dest;
134
135#ifdef PJ_DEV_URANDOM
136 /* First try with /dev/urandom, if it's opened */
137 if (dev_random_fdes >= 0) {
138 if (read(dev_random_fdes, dest, len) == len)
139 return err_status_ok; /* success */
140 }
141#endif
142
143 /* Generic C-library (rand()) version */
144 /* This is a random source of last resort */
145 while (len)
146 {
147 int val = rand();
148 /* rand() returns 0-32767 (ugh) */
149 /* Is this a good enough way to get random bytes?
150 It is if it passes FIPS-140... */
151 *dst++ = val & 0xff;
152 len--;
153 }
154#endif
155 return err_status_ok;
156}
157
158err_status_t
159rand_source_deinit(void) {
160#ifndef PJ_DEV_URANDOM
161 if (dev_random_fdes < 0)
162 return err_status_dealloc_fail; /* well, we haven't really failed, *
163 * but there is something wrong */
164#endif
165
166#if defined(DEV_URANDOM) || defined(PJ_DEV_URANDOM)
167 if (dev_random_fdes >= 0)
168 close(dev_random_fdes);
169
170 dev_random_fdes = RAND_SOURCE_NOT_READY;
171#endif
172
173 return err_status_ok;
174}
175