16
16
17
17
#![ allow( unsafe_code) ]
18
18
19
- #[ cfg( unix) ]
20
- extern crate std;
21
-
22
19
use c;
23
20
use core;
24
21
@@ -31,16 +28,27 @@ pub trait SecureRandom {
31
28
/// A secure random number generator where the random values come directly
32
29
/// from the operating system.
33
30
///
34
- /// On "unix"-ish platforms, this is currently done by reading from
35
- /// `/dev/urandom`. A new file handle for `/dev/urandom/` is opened each time a
36
- /// `SystemRandom` is constructed and the file handle is closed each time.
31
+ /// On non-Linux Unix-/Posix-ish platforms, `fill()` is currently always
32
+ /// implemented by reading from `/dev/urandom`. (This is something that should
33
+ /// be improved, at least for platforms that offer something better.)
34
+ ///
35
+ /// On Linux, `fill()` will use the
36
+ /// [`getrandom`](man7.org/linux/man-pages/man2/getrandom.2.html) syscall. If
37
+ /// the kernel is too old to support `getrandom` then by default `fill()` falls
38
+ /// back to reading from `/dev/urandom`. This decision is made the first time
39
+ /// `fill` *succeeds*. The fallback to `/dev/urandom` can be disabled by
40
+ /// disabling by enabling the *ring* crate's `disable_dev_urandom_fallback`
41
+ /// feature; this should be done whenever the target system is known to support
42
+ /// `getrandom`. Note that only application (binary) crates, and not library
43
+ /// crates, should enable the `disable_dev_urandom_fallback` feature.
37
44
///
38
- /// On other platforms, this is done using the platform's API for secure random
39
- /// number generation.
45
+ /// On Windows, `fill` is implemented done using the platform's API for secure
46
+ /// random number generation.
40
47
///
41
- /// For efficiency's sake, it is recommend to create a single SystemRandom and
42
- /// then use it for all randomness generation, especially if the
43
- /// /dev/urandom-based `SystemRandom` implementation may be used.
48
+ /// On Linux, to properly implement seccomp filtering when the
49
+ /// `disable_dev_urandom_fallback` feature is enabled, allow `getrandom`
50
+ /// through. Otherwise, allow file opening, `getrandom`, and `read` up until
51
+ /// `fill()` succeeds. After that, allow `getrandom` and `read`.
44
52
pub struct SystemRandom {
45
53
impl_ : Impl ,
46
54
}
@@ -60,13 +68,19 @@ impl SecureRandom for SystemRandom {
60
68
}
61
69
}
62
70
63
- #[ cfg( unix ) ]
71
+ #[ cfg( not ( any ( target_os = "linux" , windows ) ) ) ]
64
72
type Impl = self :: urandom:: DevURandom ;
65
73
66
- #[ cfg( windows) ]
74
+ #[ cfg( any( all( target_os = "linux" , feature = "disable_dev_urandom_fallback" ) ,
75
+ windows) ) ]
67
76
type Impl = self :: sysrand:: Sysrand ;
68
77
69
- #[ cfg( unix) ]
78
+ #[ cfg( all( target_os = "linux" , not( feature = "disable_dev_urandom_fallback" ) ) ) ]
79
+ type Impl = self :: sysrand_or_urandom:: SysRandOrDevURandom ;
80
+
81
+ #[ cfg( all( unix,
82
+ not( all( target_os = "linux" ,
83
+ feature = "disable_dev_urandom_fallback" ) ) ) ) ]
70
84
mod urandom {
71
85
extern crate std;
72
86
@@ -92,9 +106,9 @@ mod urandom {
92
106
}
93
107
}
94
108
95
- #[ cfg( windows) ]
109
+ #[ cfg( any ( target_os = "linux" , windows) ) ]
96
110
mod sysrand {
97
- use { bssl, c } ;
111
+ use bssl;
98
112
99
113
pub struct Sysrand ;
100
114
@@ -107,14 +121,70 @@ mod sysrand {
107
121
impl super :: SecureRandom for Sysrand {
108
122
#[ allow( unsafe_code) ]
109
123
fn fill ( & mut self , dest : & mut [ u8 ] ) -> Result < ( ) , ( ) > {
110
- bssl:: map_result ( unsafe {
111
- CRYPTO_sysrand ( dest. as_mut_ptr ( ) , dest. len ( ) )
112
- } )
124
+ for mut chunk in
125
+ dest. chunks_mut ( super :: CRYPTO_sysrand_chunk_max_len ) {
126
+ try!( bssl:: map_result ( unsafe {
127
+ super :: CRYPTO_sysrand_chunk ( chunk. as_mut_ptr ( ) , chunk. len ( ) )
128
+ } ) ) ;
129
+ }
130
+ Ok ( ( ) )
131
+ }
132
+ }
133
+ }
134
+
135
+ #[ cfg( all( target_os = "linux" , not( feature = "disable_dev_urandom_fallback" ) ) ) ]
136
+ mod sysrand_or_urandom {
137
+ use core;
138
+ use super :: { sysrand, urandom} ;
139
+
140
+ pub enum SysRandOrDevURandom {
141
+ Undecided ,
142
+ Sysrand ( sysrand:: Sysrand ) ,
143
+ DevURandom ( urandom:: DevURandom ) ,
144
+ }
145
+
146
+ impl SysRandOrDevURandom {
147
+ pub fn new ( ) -> Result < SysRandOrDevURandom , ( ) > {
148
+ Ok ( SysRandOrDevURandom :: Undecided )
113
149
}
114
150
}
115
151
116
- extern {
117
- fn CRYPTO_sysrand ( buf : * mut u8 , len : c:: size_t ) -> c:: int ;
152
+ impl super :: SecureRandom for SysRandOrDevURandom {
153
+ fn fill ( & mut self , dest : & mut [ u8 ] ) -> Result < ( ) , ( ) > {
154
+ match self {
155
+ & mut SysRandOrDevURandom :: Sysrand ( ref mut i) => i. fill ( dest) ,
156
+ & mut SysRandOrDevURandom :: DevURandom ( ref mut i) => i. fill ( dest) ,
157
+ & mut SysRandOrDevURandom :: Undecided => {
158
+ let first_chunk_len =
159
+ core:: cmp:: min ( dest. len ( ) ,
160
+ super :: CRYPTO_sysrand_chunk_max_len ) ;
161
+ match unsafe {
162
+ super :: CRYPTO_sysrand_chunk ( dest. as_mut_ptr ( ) ,
163
+ first_chunk_len)
164
+ } {
165
+ 1 => {
166
+ let _ = core:: mem:: replace ( self ,
167
+ SysRandOrDevURandom :: Sysrand (
168
+ try!( sysrand:: Sysrand :: new ( ) ) ) ) ;
169
+ if first_chunk_len < dest. len ( ) {
170
+ self . fill ( & mut dest[ first_chunk_len..] )
171
+ } else {
172
+ Ok ( ( ) )
173
+ }
174
+ } ,
175
+ -1 => {
176
+ let _ = core:: mem:: replace ( self ,
177
+ SysRandOrDevURandom :: DevURandom (
178
+ try!( urandom:: DevURandom :: new ( ) ) ) ) ;
179
+ self . fill ( dest)
180
+ } ,
181
+ _ => {
182
+ Err ( ( ) )
183
+ }
184
+ }
185
+ }
186
+ }
187
+ }
118
188
}
119
189
}
120
190
@@ -138,3 +208,10 @@ pub unsafe extern fn RAND_bytes(rng: *mut RAND, dest: *mut u8,
138
208
_ => 0
139
209
}
140
210
}
211
+
212
+
213
+ #[ cfg( any( target_os = "linux" , windows) ) ]
214
+ extern {
215
+ pub static CRYPTO_sysrand_chunk_max_len : c:: size_t ;
216
+ pub fn CRYPTO_sysrand_chunk ( buf : * mut u8 , len : c:: size_t ) -> c:: int ;
217
+ }
0 commit comments