@@ -63,6 +63,7 @@ mod imp {
63
63
use std:: cast;
64
64
use std:: libc:: { c_ulong, DWORD , BYTE , LPCSTR , BOOL } ;
65
65
use std:: os;
66
+ use std:: rt:: stack;
66
67
67
68
type HCRYPTPROV = c_ulong ;
68
69
@@ -82,6 +83,7 @@ mod imp {
82
83
static PROV_RSA_FULL : DWORD = 1 ;
83
84
static CRYPT_SILENT : DWORD = 64 ;
84
85
static CRYPT_VERIFYCONTEXT : DWORD = 0xF0000000 ;
86
+ static NTE_BAD_SIGNATURE : DWORD = 0x80090006 ;
85
87
86
88
extern "system" {
87
89
fn CryptAcquireContextA ( phProv : * mut HCRYPTPROV ,
@@ -99,11 +101,47 @@ mod imp {
99
101
/// Create a new `OSRng`.
100
102
pub fn new ( ) -> OSRng {
101
103
let mut hcp = 0 ;
102
- let ret = unsafe {
104
+ let mut ret = unsafe {
103
105
CryptAcquireContextA ( & mut hcp, 0 as LPCSTR , 0 as LPCSTR ,
104
106
PROV_RSA_FULL ,
105
107
CRYPT_VERIFYCONTEXT | CRYPT_SILENT )
106
108
} ;
109
+
110
+ // It turns out that if we can't acquire a context with the
111
+ // NTE_BAD_SIGNATURE error code, the documentation states:
112
+ //
113
+ // The provider DLL signature could not be verified. Either the
114
+ // DLL or the digital signature has been tampered with.
115
+ //
116
+ // Sounds fishy, no? As it turns out, our signature can be bad
117
+ // because our Thread Information Block (TIB) isn't exactly what it
118
+ // expects. As to why, I have no idea. The only data we store in the
119
+ // TIB is the stack limit for each thread, but apparently that's
120
+ // enough to make the signature valid.
121
+ //
122
+ // Furthermore, this error only happens the *first* time we call
123
+ // CryptAcquireContext, so we don't have to worry about future
124
+ // calls.
125
+ //
126
+ // Anyway, the fix employed here is that if we see this error, we
127
+ // pray that we're not close to the end of the stack, temporarily
128
+ // set the stack limit to 0 (what the TIB originally was), acquire a
129
+ // context, and then reset the stack limit.
130
+ //
131
+ // Again, I'm not sure why this is the fix, nor why we're getting
132
+ // this error. All I can say is that this seems to allow libnative
133
+ // to progress where it otherwise would be hindered. Who knew?
134
+ if ret == 0 && os:: errno ( ) as DWORD == NTE_BAD_SIGNATURE {
135
+ unsafe {
136
+ let limit = stack:: get_sp_limit ( ) ;
137
+ stack:: record_sp_limit ( 0 ) ;
138
+ ret = CryptAcquireContextA ( & mut hcp, 0 as LPCSTR , 0 as LPCSTR ,
139
+ PROV_RSA_FULL ,
140
+ CRYPT_VERIFYCONTEXT | CRYPT_SILENT ) ;
141
+ stack:: record_sp_limit ( limit) ;
142
+ }
143
+ }
144
+
107
145
if ret == 0 {
108
146
fail ! ( "couldn't create context: {}" , os:: last_os_error( ) ) ;
109
147
}
0 commit comments