1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : /*
8 : * NaCl Service Runtime. Secure RNG implementation.
9 : */
10 :
11 : #include <errno.h>
12 : #include <string.h>
13 :
14 : #include <unistd.h>
15 : #include <sys/types.h>
16 : #include <sys/stat.h>
17 : #include <fcntl.h>
18 :
19 : #include "native_client/src/shared/platform/nacl_check.h"
20 : #include "native_client/src/shared/platform/nacl_log.h"
21 : #include "native_client/src/shared/platform/nacl_secure_random.h"
22 :
23 : #ifndef NACL_SECURE_RANDOM_SYSTEM_RANDOM_SOURCE
24 : # define NACL_SECURE_RANDOM_SYSTEM_RANDOM_SOURCE "/dev/urandom"
25 : #endif
26 :
27 : static struct NaClSecureRngIfVtbl const kNaClSecureRngVtbl;
28 :
29 : /* use -1 to ensure a fast failure if module initializer is not called */
30 : static int urandom_d = -1;
31 :
32 : /*
33 : * This sets a /dev/urandom file descriptor for this module to use.
34 : * This is for use inside outer sandboxes where opening /dev/urandom
35 : * with open() does not work.
36 : *
37 : * This function should be called before NaClSecureRngModuleInit() so
38 : * that we do not attempt to use open() inside the outer sandbox.
39 : *
40 : * This takes ownership of the file descriptor.
41 : */
42 0 : void NaClSecureRngModuleSetUrandomFd(int fd) {
43 0 : CHECK(urandom_d == -1);
44 0 : urandom_d = fd;
45 0 : }
46 :
47 349 : void NaClSecureRngModuleInit(void) {
48 : /*
49 : * Check whether we have already been initialised via
50 : * NaClSecureRngModuleSetUrandomFd().
51 : */
52 349 : if (urandom_d != -1) {
53 350 : return;
54 : }
55 :
56 348 : urandom_d = open(NACL_SECURE_RANDOM_SYSTEM_RANDOM_SOURCE, O_RDONLY, 0);
57 348 : if (-1 == urandom_d) {
58 0 : NaClLog(LOG_FATAL, "Cannot open system random source %s\n",
59 : NACL_SECURE_RANDOM_SYSTEM_RANDOM_SOURCE);
60 : }
61 : }
62 :
63 52 : void NaClSecureRngModuleFini(void) {
64 52 : if (urandom_d != -1) {
65 52 : if (close(urandom_d) != 0) {
66 0 : NaClLog(LOG_FATAL,
67 : "NaClSecureRngModuleFini: close() failed with errno %d\n",
68 0 : errno);
69 : }
70 52 : urandom_d = -1;
71 : }
72 52 : }
73 :
74 349 : int NaClSecureRngCtor(struct NaClSecureRng *self) {
75 349 : self->base.vtbl = &kNaClSecureRngVtbl;
76 349 : self->nvalid = 0;
77 349 : return 1;
78 : }
79 :
80 0 : int NaClSecureRngTestingCtor(struct NaClSecureRng *self,
81 : uint8_t *seed_material,
82 : size_t seed_bytes) {
83 : UNREFERENCED_PARAMETER(self);
84 : UNREFERENCED_PARAMETER(seed_material);
85 : UNREFERENCED_PARAMETER(seed_bytes);
86 0 : return 0;
87 : }
88 :
89 52 : static void NaClSecureRngDtor(struct NaClSecureRngIf *vself) {
90 52 : struct NaClSecureRng *self = (struct NaClSecureRng *) vself;
91 52 : memset(self->buf, 0, sizeof self->buf);
92 52 : vself->vtbl = NULL;
93 52 : return;
94 : }
95 :
96 323 : static void NaClSecureRngFilbuf(struct NaClSecureRng *self) {
97 323 : VCHECK(-1 != urandom_d,
98 : ("NaClSecureRngCtor: random descriptor invalid;"
99 : " module initialization failed?\n"));
100 323 : self->nvalid = read(urandom_d, self->buf, sizeof self->buf);
101 323 : if (self->nvalid <= 0) {
102 0 : NaClLog(LOG_FATAL, "NaClSecureRngFilbuf failed, read returned %d\n",
103 : self->nvalid);
104 : }
105 323 : }
106 :
107 30810 : static uint8_t NaClSecureRngGenByte(struct NaClSecureRngIf *vself) {
108 30810 : struct NaClSecureRng *self = (struct NaClSecureRng *) vself;
109 :
110 30810 : if (0 > self->nvalid) {
111 0 : NaClLog(LOG_FATAL,
112 : "NaClSecureRngGenByte: illegal buffer state, nvalid = %d\n",
113 : self->nvalid);
114 : }
115 30810 : if (0 == self->nvalid) {
116 323 : NaClSecureRngFilbuf(self);
117 : }
118 : /* 0 < self->nvalid <= sizeof self->buf */
119 30810 : return self->buf[--self->nvalid];
120 : }
121 :
122 : static struct NaClSecureRngIfVtbl const kNaClSecureRngVtbl = {
123 : NaClSecureRngDtor,
124 : NaClSecureRngGenByte,
125 : NaClSecureRngDefaultGenUint32,
126 : NaClSecureRngDefaultGenBytes,
127 : NaClSecureRngDefaultUniform,
128 : };
|