3
3
#include "proxy.h"
4
4
#include "proxy_tls.h"
5
5
#include <openssl/ssl.h>
6
+ #include <openssl/err.h>
7
+
8
+ /* Notes on ERR_clear_error() and friends:
9
+ * - Errors from SSL calls leave errors on a thread-local "error stack"
10
+ * - If an error is received from an SSL call, the stack needs to be inspected
11
+ * and cleared.
12
+ * - The error stack _must_ be clear before any SSL_get_error() calls, as it
13
+ * may return garbage.
14
+ * - There may be _multiple_ errors queued after one SSL call, so just
15
+ * checking the top level does not clear it.
16
+ * - ERR_clear_error() is not "free", so we would prefer to avoid calling it
17
+ * before hotpath calls. Thus, we should ensure it's called _after_ any
18
+ * hotpath call that receives any kind of error.
19
+ * - We should also call it _before_ any non-hotpath SSL calls (such as
20
+ * SSL_connect()) for defense against bugs in our code or OpenSSL.
21
+ */
6
22
7
23
int mcp_tls_init (proxy_ctx_t * ctx ) {
8
24
if (ctx -> tls_ctx ) {
@@ -47,8 +63,23 @@ int mcp_tls_connect(struct mcp_backendconn_s *be) {
47
63
// TODO: check return code. can fail if BIO fails to alloc.
48
64
SSL_set_fd (be -> ssl , mcmc_fd (be -> client ));
49
65
50
- // TODO: care about the error code.
51
- int ret = SSL_connect (be -> ssl );
66
+ ERR_clear_error ();
67
+ int n = SSL_connect (be -> ssl );
68
+ int ret = 1 ;
69
+ // TODO: complete error handling.
70
+ if (n == 1 ) {
71
+ // Successfully established and handshake complete.
72
+ } else if (n == 0 ) {
73
+ // Not successsful, but shut down normally.
74
+ ERR_clear_error ();
75
+ ret = -1 ;
76
+ } else if (n < 0 ) {
77
+ // Not successful. Check for temporary error.
78
+
79
+ // clear all errors in case of other junk.
80
+ ERR_clear_error ();
81
+ ret = -1 ;
82
+ }
52
83
53
84
return ret ;
54
85
}
@@ -58,6 +89,8 @@ int mcp_tls_handshake(struct mcp_backendconn_s *be) {
58
89
return 1 ;
59
90
}
60
91
92
+ // Non hot path, so clear errors before running.
93
+ ERR_clear_error ();
61
94
int n = SSL_do_handshake (be -> ssl );
62
95
if (n == 1 ) {
63
96
return 1 ;
@@ -69,20 +102,32 @@ int mcp_tls_handshake(struct mcp_backendconn_s *be) {
69
102
// leaving this note just in case.
70
103
if (err == SSL_ERROR_WANT_READ ||
71
104
err == SSL_ERROR_WANT_WRITE ) {
105
+ // So far as I can tell there would be an error on the queue here.
106
+ ERR_clear_error ();
72
107
return 0 ;
73
108
} else {
74
109
// TODO: can get the full error message and give to the caller to log
75
110
// to proxyevents?
111
+ ERR_clear_error ();
76
112
return -1 ;
77
113
}
78
114
}
79
115
80
- // TODO: error processing.
81
- void mcp_tls_send_validate (struct mcp_backendconn_s * be ) {
116
+ int mcp_tls_send_validate (struct mcp_backendconn_s * be ) {
82
117
const char * str = "version\r\n" ;
83
118
const size_t len = strlen (str );
84
119
85
- SSL_write (be -> ssl , str , len );
120
+ // Non hot path, clear errors.
121
+ ERR_clear_error ();
122
+ int n = SSL_write (be -> ssl , str , len );
123
+
124
+ // TODO: more detailed error checking.
125
+ if (n < 0 || n != len ) {
126
+ ERR_clear_error ();
127
+ return -1 ;
128
+ }
129
+
130
+ return 1 ;
86
131
}
87
132
88
133
int mcp_tls_read (struct mcp_backendconn_s * be ) {
@@ -92,8 +137,11 @@ int mcp_tls_read(struct mcp_backendconn_s *be) {
92
137
int err = SSL_get_error (be -> ssl , n );
93
138
if (err == SSL_ERROR_WANT_WRITE ||
94
139
err == SSL_ERROR_WANT_READ ) {
140
+ ERR_clear_error ();
95
141
return -1 ;
96
142
} else {
143
+ // TODO: log detailed error.
144
+ ERR_clear_error ();
97
145
return -2 ;
98
146
}
99
147
} else {
@@ -142,8 +190,10 @@ int mcp_tls_writev(struct mcp_backendconn_s *be, int iovcnt) {
142
190
int err = SSL_get_error (be -> ssl , n );
143
191
if (err == SSL_ERROR_WANT_WRITE ||
144
192
err == SSL_ERROR_WANT_READ ) {
193
+ ERR_clear_error ();
145
194
return -1 ;
146
195
}
196
+ ERR_clear_error ();
147
197
return -2 ;
148
198
}
149
199
0 commit comments