@@ -32,26 +32,48 @@ internal static Exception CreateOpenSslCryptographicException()
32
32
const uint ReasonMask = 0x0FFF ;
33
33
const uint ERR_R_MALLOC_FAILURE = 64 | 1 ;
34
34
35
+ // The Windows cryptography library reports error codes through
36
+ // Marshal.GetLastWin32Error, which has a single value when the
37
+ // function exits, last writer wins.
38
+ //
39
+ // OpenSSL maintains an error queue. Calls to ERR_get_error read
40
+ // values out of the queue in the order that ERR_set_error wrote
41
+ // them. Nothing enforces that a single call into an OpenSSL
42
+ // function will guarantee at-most one error being set.
43
+ //
44
+ // In order to maintain parity in how error flows look between the
45
+ // Windows code and the OpenSSL-calling code, drain the queue
46
+ // whenever an Exception is desired, and report the exception
47
+ // related to the last value in the queue.
35
48
uint error = ERR_get_error ( ) ;
36
- uint last = error ;
49
+ uint lastRead = error ;
37
50
38
- while ( last != 0 )
51
+ // 0 (there's no named constant) is only returned when the calls
52
+ // to ERR_get_error exceed the calls to ERR_set_error.
53
+ while ( lastRead != 0 )
39
54
{
40
- last = ERR_get_error ( ) ;
55
+ error = lastRead ;
56
+ lastRead = ERR_get_error ( ) ;
41
57
}
42
58
59
+ // If we're in an error flow which results in an Exception, but
60
+ // no calls to ERR_set_error were made, throw the unadorned
61
+ // CryptographicException.
43
62
if ( error == 0 )
44
63
{
45
64
return new CryptographicException ( ) ;
46
65
}
47
66
67
+ // Inline version of the ERR_GET_REASON macro.
48
68
uint reason = error & ReasonMask ;
49
69
50
70
if ( reason == ERR_R_MALLOC_FAILURE )
51
71
{
52
72
return new OutOfMemoryException ( ) ;
53
73
}
54
74
75
+ // If there was an error code, and it wasn't something handled specially,
76
+ // use the OpenSSL error string as the message to a CryptographicException.
55
77
return new CryptographicException ( ERR_error_string_n ( error ) ) ;
56
78
}
57
79
0 commit comments