@@ -63,6 +63,7 @@ mod imp {
6363 use std:: cast;
6464 use std:: libc:: { c_ulong, DWORD , BYTE , LPCSTR , BOOL } ;
6565 use std:: os;
66+ use std:: rt:: stack;
6667
6768 type HCRYPTPROV = c_ulong ;
6869
@@ -82,6 +83,7 @@ mod imp {
8283 static PROV_RSA_FULL : DWORD = 1 ;
8384 static CRYPT_SILENT : DWORD = 64 ;
8485 static CRYPT_VERIFYCONTEXT : DWORD = 0xF0000000 ;
86+ static NTE_BAD_SIGNATURE : DWORD = 0x80090006 ;
8587
8688 extern "system" {
8789 fn CryptAcquireContextA ( phProv : * mut HCRYPTPROV ,
@@ -99,11 +101,47 @@ mod imp {
99101 /// Create a new `OSRng`.
100102 pub fn new ( ) -> OSRng {
101103 let mut hcp = 0 ;
102- let ret = unsafe {
104+ let mut ret = unsafe {
103105 CryptAcquireContextA ( & mut hcp, 0 as LPCSTR , 0 as LPCSTR ,
104106 PROV_RSA_FULL ,
105107 CRYPT_VERIFYCONTEXT | CRYPT_SILENT )
106108 } ;
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+
107145 if ret == 0 {
108146 fail ! ( "couldn't create context: {}" , os:: last_os_error( ) ) ;
109147 }
0 commit comments