|
Line 0
Link Here
|
|
|
1 |
--- net/netssltransport.cc.orig 2018-10-28 00:15:23 UTC |
| 2 |
+++ net/netssltransport.cc |
| 3 |
@@ -112,11 +112,37 @@ unsigned long sCompileVersion = OPENSSL |
| 4 |
unsigned long sVersion1_0_0 = 0x1000000f; |
| 5 |
const char *sVerStr1_0_0 = "1.0.0"; |
| 6 |
# ifdef OS_NT |
| 7 |
-static HANDLE *mutexArray = NULL; |
| 8 |
+static HANDLE mutexArray[ CRYPTO_NUM_LOCKS ]; |
| 9 |
# else |
| 10 |
-static pthread_mutex_t *mutexArray = NULL; |
| 11 |
+static pthread_mutex_t mutexArray[ CRYPTO_NUM_LOCKS ]; |
| 12 |
# endif |
| 13 |
|
| 14 |
+typedef struct { |
| 15 |
+ int value; |
| 16 |
+ const char *name; |
| 17 |
+} SslErrorNames; |
| 18 |
+ |
| 19 |
+SslErrorNames sslErrorNames[] = { |
| 20 |
+ {SSL_ERROR_NONE, " (None)"}, // 0 |
| 21 |
+ {SSL_ERROR_SSL, " (SSL)"}, // 1 |
| 22 |
+ {SSL_ERROR_WANT_READ, " (Want_Read)"}, // 2 |
| 23 |
+ {SSL_ERROR_WANT_WRITE, " (Want_Write)"}, // 3 |
| 24 |
+ {SSL_ERROR_WANT_X509_LOOKUP, " (Want_X509_Lookup)"}, // 4 |
| 25 |
+ {SSL_ERROR_SYSCALL, " (Syscall)"}, // 5 |
| 26 |
+ {SSL_ERROR_ZERO_RETURN, " (Zero_Return)"}, // 6 |
| 27 |
+ {SSL_ERROR_WANT_CONNECT, " (Want_Connect)"}, // 7 |
| 28 |
+ {SSL_ERROR_WANT_ACCEPT, " (Want_Accept)"} // 8 |
| 29 |
+}; |
| 30 |
+ |
| 31 |
+const char * |
| 32 |
+GetSslErrorName(int err) |
| 33 |
+{ |
| 34 |
+ if( err < SSL_ERROR_NONE || err > SSL_ERROR_WANT_ACCEPT ) |
| 35 |
+ return ""; |
| 36 |
+ |
| 37 |
+ return sslErrorNames[err].name; |
| 38 |
+} |
| 39 |
+ |
| 40 |
//////////////////////////////////////////////////////////////////////////// |
| 41 |
// MutexLocker // |
| 42 |
//////////////////////////////////////////////////////////////////////////// |
| 43 |
@@ -220,6 +246,147 @@ NetSslTransport::~NetSslTransport() |
| 44 |
Close(); |
| 45 |
} |
| 46 |
|
| 47 |
+// MS Visual Studio didn't implement snprintf until VS 2015. Sigh. |
| 48 |
+# ifdef _MSC_VER |
| 49 |
+ #define SNPRINTF1(buf, len, msg, arg1) sprintf(buf, msg, arg1) |
| 50 |
+ #define SNPRINTF2(buf, len, msg, arg1, arg2) sprintf(buf, msg, arg1, arg2) |
| 51 |
+# else |
| 52 |
+ #define SNPRINTF1(buf, len, msg, arg1) snprintf(buf, len, msg, arg1) |
| 53 |
+ #define SNPRINTF2(buf, len, msg, arg1, arg2) snprintf(buf, len, msg, arg1, arg2) |
| 54 |
+# endif |
| 55 |
+ |
| 56 |
+SSL_CTX * |
| 57 |
+NetSslTransport::CreateAndInitializeSslContext(const char *conntypename) |
| 58 |
+{ |
| 59 |
+ char msgbuf[128]; |
| 60 |
+ size_t bufsize = sizeof(msgbuf) - 1; |
| 61 |
+ |
| 62 |
+ SNPRINTF1( msgbuf, bufsize, |
| 63 |
+ "NetSslTransport::Ssl%sInit - Initializing CTX structure.", |
| 64 |
+ conntypename ); |
| 65 |
+ TRANSPORT_PRINT_VAR( SSLDEBUG_FUNCTION, msgbuf ); |
| 66 |
+ |
| 67 |
+ /* |
| 68 |
+ * In OpenSSL v1.1.0 we can use |
| 69 |
+ * TLS_method() |
| 70 |
+ * SSL_CTX_set_min_proto_version() |
| 71 |
+ * SSL_CTX_set_max_proto_version() |
| 72 |
+ * instead of the deprecated |
| 73 |
+ * SSLv23_method() |
| 74 |
+ * and the not-recommended |
| 75 |
+ * SSL_CTX_set_options( SSL_OP_NO_xxx ) |
| 76 |
+ * but we still build with OpenSSL v1.0.x, so for now we'll stay |
| 77 |
+ * with the old way of doing things. |
| 78 |
+ * |
| 79 |
+ * See https://www.openssl.org/docs/man1.1.0/ssl/SSLv23_method.html |
| 80 |
+ * Note: |
| 81 |
+ * "Clients should avoid creating "holes" in the set of protocols they support. |
| 82 |
+ * When disabling a protocol, make sure that you also disable either all |
| 83 |
+ * previous or all subsequent protocol versions. In clients, when a protocol |
| 84 |
+ * version is disabled without disabling all previous protocol versions, |
| 85 |
+ * the effect is to also disable all subsequent protocol versions." |
| 86 |
+ */ |
| 87 |
+ |
| 88 |
+ /* |
| 89 |
+ * Start by allowing all protocol versions |
| 90 |
+ */ |
| 91 |
+ |
| 92 |
+ SSL_CTX *ctxp = SSL_CTX_new( SSLv23_method() ); |
| 93 |
+ SNPRINTF1( msgbuf, bufsize, "NetSslTransport::Ssl%sInit SSL_CTX_new", conntypename ); |
| 94 |
+ TRANSPORT_PRINT_VAR( SSLDEBUG_FUNCTION, msgbuf ); |
| 95 |
+ |
| 96 |
+ SSL_CTX_set_mode( |
| 97 |
+ ctxp, |
| 98 |
+ SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER ); |
| 99 |
+ SNPRINTF1( msgbuf, bufsize, "NetSslTransport::Ssl%sInit SSL_CTX_set_mode", conntypename ); |
| 100 |
+ SSLLOGFUNCTION( msgbuf ); |
| 101 |
+ |
| 102 |
+ /* |
| 103 |
+ * Now disable SSLv2 and SSLv3 (but still allow TLSv1.0 and later) |
| 104 |
+ */ |
| 105 |
+ |
| 106 |
+ SSL_CTX_set_options( ctxp, SSL_OP_NO_SSLv2 ); |
| 107 |
+ SNPRINTF1( msgbuf, bufsize, "NetSslTransport::Ssl%sInit SSL_CTX_set_options(NO_SSLv2)", conntypename ); |
| 108 |
+ SSLLOGFUNCTION( msgbuf ); |
| 109 |
+ |
| 110 |
+ SSL_CTX_set_options( ctxp, SSL_OP_NO_SSLv3 ); |
| 111 |
+ SNPRINTF1( msgbuf, bufsize, "NetSslTransport::Ssl%sInit SSL_CTX_set_options(NO_SSLv3)", conntypename ); |
| 112 |
+ SSLLOGFUNCTION( msgbuf ); |
| 113 |
+ |
| 114 |
+ /* |
| 115 |
+ * Let the customer disable any protocols they don't want. |
| 116 |
+ * Allow only TLS versions in the (closed) range [tlsmin, tlsmax]. |
| 117 |
+ */ |
| 118 |
+ int tlsmin = p4tunable.Get( P4TUNE_SSL_TLS_VERSION_MIN ); |
| 119 |
+ int tlsmax = p4tunable.Get( P4TUNE_SSL_TLS_VERSION_MAX ); |
| 120 |
+ |
| 121 |
+ struct TlsVersion { |
| 122 |
+ int value; // tunable value |
| 123 |
+ int proto; // OpenSSL protocol version value |
| 124 |
+ const char *name; // OpenSSL protocol version name |
| 125 |
+ }; |
| 126 |
+ |
| 127 |
+ /* |
| 128 |
+ * Expand this table if and when new TLS protocol versions are available. |
| 129 |
+ * This table *must* be ordered by the "value" field |
| 130 |
+ * and terminated by a "value" of 0. |
| 131 |
+ */ |
| 132 |
+ static TlsVersion tlsVersions[] = { |
| 133 |
+ { 10, SSL_OP_NO_TLSv1, "NO_TLSv1.0" }, |
| 134 |
+ { 11, SSL_OP_NO_TLSv1_1, "NO_TLSv1.1" }, |
| 135 |
+ { 12, SSL_OP_NO_TLSv1_2, "NO_TLSv1.2" }, |
| 136 |
+ { 0, 0, NULL} |
| 137 |
+ }; |
| 138 |
+ |
| 139 |
+ /* |
| 140 |
+ * Pin the value to the legal range. |
| 141 |
+ * Update this code if new values are added to tlsVersions[]. |
| 142 |
+ */ |
| 143 |
+ if( tlsmin < 10 ) |
| 144 |
+ tlsmin = 10; |
| 145 |
+ if( tlsmin > 12 ) |
| 146 |
+ tlsmin = 12; |
| 147 |
+ |
| 148 |
+ if( tlsmax < 10 ) |
| 149 |
+ tlsmax = 10; |
| 150 |
+ if( tlsmax > 12 ) |
| 151 |
+ tlsmax = 12; |
| 152 |
+ |
| 153 |
+ if( SSLDEBUG_FUNCTION ) |
| 154 |
+ { |
| 155 |
+ p4debug.printf( "NetSslTransport::Ssl%sInit tlsmin=%d, tlsmax=%d\n", |
| 156 |
+ conntypename, tlsmin, tlsmax ); |
| 157 |
+ } |
| 158 |
+ |
| 159 |
+ // disallow protocols below the requested minimum |
| 160 |
+ for( TlsVersion *vp = tlsVersions; vp->value; vp++ ) |
| 161 |
+ { |
| 162 |
+ if( vp->value < tlsmin ) |
| 163 |
+ { |
| 164 |
+ SSL_CTX_set_options( ctxp, vp->proto ); |
| 165 |
+ SNPRINTF2( msgbuf, bufsize, |
| 166 |
+ "NetSslTransport::Ssl%sInit SSL_CTX_set_options(%s)", |
| 167 |
+ conntypename, vp->name ); |
| 168 |
+ SSLLOGFUNCTION( msgbuf ); |
| 169 |
+ } |
| 170 |
+ } |
| 171 |
+ |
| 172 |
+ // disallow protocols above the requested maximum |
| 173 |
+ for( TlsVersion *vp = tlsVersions; vp->value; vp++ ) |
| 174 |
+ { |
| 175 |
+ if( vp->value > tlsmax ) |
| 176 |
+ { |
| 177 |
+ SSL_CTX_set_options( ctxp, vp->proto ); |
| 178 |
+ SNPRINTF2( msgbuf, bufsize, |
| 179 |
+ "NetSslTransport::Ssl%sInit SSL_CTX_set_options(%s)", |
| 180 |
+ conntypename, vp->name ); |
| 181 |
+ SSLLOGFUNCTION( msgbuf ); |
| 182 |
+ } |
| 183 |
+ } |
| 184 |
+ |
| 185 |
+ return ctxp; |
| 186 |
+} |
| 187 |
+ |
| 188 |
/** |
| 189 |
* NetSslTransport::SslClientInit |
| 190 |
* |
| 191 |
@@ -255,10 +422,6 @@ NetSslTransport::SslClientInit(Error *e) |
| 192 |
return; |
| 193 |
#endif // OS_NT |
| 194 |
|
| 195 |
- TRANSPORT_PRINT( SSLDEBUG_FUNCTION, |
| 196 |
- "NetSslTransport::SslClientInit - Initializing client CTX structure." ); |
| 197 |
- |
| 198 |
- |
| 199 |
ValidateRuntimeVsCompiletimeSSLVersion( e ); |
| 200 |
if( e->Test() ) |
| 201 |
{ |
| 202 |
@@ -298,15 +461,12 @@ NetSslTransport::SslClientInit(Error *e) |
| 203 |
|
| 204 |
// WSAstartup code in NetTcpEndPoint constructor |
| 205 |
|
| 206 |
- sClientCtx = SSL_CTX_new( TLSv1_method() ); |
| 207 |
- SSLNULLHANDLER( sClientCtx, e, |
| 208 |
- "NetSslTransport::SslClientInit SSL_CTX_new", |
| 209 |
- fail ); |
| 210 |
- |
| 211 |
- SSL_CTX_set_mode( |
| 212 |
- sClientCtx, |
| 213 |
- SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER ); |
| 214 |
- SSLLOGFUNCTION( "NetSslTransport::SslClientInit SSL_CTX_set_mode" ); |
| 215 |
+ /* |
| 216 |
+ * Allow TLSv1.0 and later but disable SSLv2 and SSLv3 |
| 217 |
+ * - Allow customers to further filter TLS protocol versions |
| 218 |
+ */ |
| 219 |
+ if( (sClientCtx = CreateAndInitializeSslContext("Client")) == NULL ) |
| 220 |
+ goto fail; |
| 221 |
} |
| 222 |
return; |
| 223 |
|
| 224 |
@@ -362,9 +522,6 @@ NetSslTransport::SslServerInit(StrPtr *h |
| 225 |
return; |
| 226 |
#endif // OS_NT |
| 227 |
|
| 228 |
- TRANSPORT_PRINT( SSLDEBUG_FUNCTION, |
| 229 |
- "NetSslTransport::SslServerInit - Initializing server CTX structure." ); |
| 230 |
- |
| 231 |
/* |
| 232 |
* Added due to job084753: Swarm is a web app that reuses client processes. |
| 233 |
* See the SslClientInit code for more info. |
| 234 |
@@ -407,17 +564,12 @@ NetSslTransport::SslServerInit(StrPtr *h |
| 235 |
credentials.ReadCredentials(e); |
| 236 |
P4CHECKERROR( e, "NetSslTransport::SslServerInit ReadCredentials", fail ); |
| 237 |
|
| 238 |
- |
| 239 |
- sServerCtx = SSL_CTX_new( TLSv1_method() ); |
| 240 |
- SSLNULLHANDLER( sServerCtx, e, |
| 241 |
- "NetSslTransport::SslServerInit SSL_CTX_new", |
| 242 |
- fail ); |
| 243 |
- |
| 244 |
- SSL_CTX_set_mode( |
| 245 |
- sServerCtx, |
| 246 |
- SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER ); |
| 247 |
- SSLLOGFUNCTION( "NetSslTransport::SslServerInit SSL_CTX_set_mode" ); |
| 248 |
- |
| 249 |
+ /* |
| 250 |
+ * Allow TLSv1.0 and later but disable SSLv2 and SSLv3 |
| 251 |
+ * - Allow customers to further filter TLS protocol versions |
| 252 |
+ */ |
| 253 |
+ if( (sServerCtx = CreateAndInitializeSslContext("Server")) == NULL ) |
| 254 |
+ goto fail; |
| 255 |
|
| 256 |
SSL_CTX_use_PrivateKey( sServerCtx, credentials.GetPrivateKey() ); |
| 257 |
SSLLOGFUNCTION( |
| 258 |
@@ -471,8 +623,6 @@ fail: |
| 259 |
void |
| 260 |
NetSslTransport::DoHandshake( Error *e ) |
| 261 |
{ |
| 262 |
- int sslRetval; |
| 263 |
- |
| 264 |
if(ssl) |
| 265 |
return; |
| 266 |
|
| 267 |
@@ -624,8 +774,8 @@ bool |
| 268 |
NetSslTransport::SslHandshake( Error *e ) |
| 269 |
{ |
| 270 |
bool done = false; |
| 271 |
- int readable = isAccepted? 1 : 0; |
| 272 |
- int writable = isAccepted? 0 : 1; |
| 273 |
+ int readable; |
| 274 |
+ int writable; |
| 275 |
int counter = 0; |
| 276 |
/* select timeout */ |
| 277 |
const int tv = HALF_SECOND; |
| 278 |
@@ -651,6 +801,8 @@ NetSslTransport::SslHandshake( Error *e |
| 279 |
{ |
| 280 |
case SSL_ERROR_NONE: |
| 281 |
done = true; |
| 282 |
+ TRANSPORT_PRINTF( SSLDEBUG_CONNECT, |
| 283 |
+ "NetSslTransport::SslHandshake protocol=%s", SSL_get_version(ssl) ); |
| 284 |
break; |
| 285 |
|
| 286 |
case SSL_ERROR_WANT_READ: |
| 287 |
@@ -730,10 +882,12 @@ NetSslTransport::SslHandshake( Error *e |
| 288 |
/* underlying protocol error dump error to |
| 289 |
* debug output |
| 290 |
*/ |
| 291 |
- char sslError[256]; |
| 292 |
- ERR_error_string( ERR_get_error(), sslError ); |
| 293 |
- TRANSPORT_PRINTF( SSLDEBUG_ERROR, "Handshake Failed: %s", sslError ); |
| 294 |
- e->Net( "ssl handshake", sslError); |
| 295 |
+ |
| 296 |
+ // buffer for ssl protocol errors |
| 297 |
+ char sslErrorBuf[256]; |
| 298 |
+ ERR_error_string( ERR_get_error(), sslErrorBuf ); |
| 299 |
+ TRANSPORT_PRINTF( SSLDEBUG_ERROR, "Handshake Failed: %s", sslErrorBuf ); |
| 300 |
+ e->Set( MsgRpc::SslProtocolError ) << sslErrorBuf; |
| 301 |
return false; |
| 302 |
break; |
| 303 |
default: |
| 304 |
@@ -746,18 +900,26 @@ NetSslTransport::SslHandshake( Error *e |
| 305 |
errBuf.Append( &tmp ); |
| 306 |
errBuf.Append( ")" ); |
| 307 |
} |
| 308 |
+ else |
| 309 |
+ { |
| 310 |
+ StrBuf tmp; |
| 311 |
+ Error::StrError( tmp ); |
| 312 |
+ errBuf.Set( " (" ); |
| 313 |
+ errBuf.Append( &tmp ); |
| 314 |
+ errBuf.Append( ")" ); |
| 315 |
+ } |
| 316 |
if( isAccepted ) |
| 317 |
{ |
| 318 |
TRANSPORT_PRINTF( SSLDEBUG_ERROR, |
| 319 |
- "NetSslTransport::SslHandshake failed on server side: %d", |
| 320 |
- errorRet ); |
| 321 |
+ "NetSslTransport::SslHandshake failed on server side: %d%s", |
| 322 |
+ errorRet, GetSslErrorName(errorRet) ); |
| 323 |
e->Set( MsgRpc::SslAccept) << errBuf; |
| 324 |
} |
| 325 |
else |
| 326 |
{ |
| 327 |
TRANSPORT_PRINTF( SSLDEBUG_ERROR, |
| 328 |
- "NetSslTransport::SslHandshake failed on client side: %d", |
| 329 |
- errorRet); |
| 330 |
+ "NetSslTransport::SslHandshake failed on client side: %d%s", |
| 331 |
+ errorRet, GetSslErrorName(errorRet) ); |
| 332 |
e->Set( MsgRpc::SslConnect) << GetPortParser().String() << errBuf; |
| 333 |
} |
| 334 |
return false; |
| 335 |
@@ -819,10 +981,6 @@ NetSslTransport::SendOrReceive( NetIoPtr |
| 336 |
int readable = 0; |
| 337 |
int writable = 0; |
| 338 |
|
| 339 |
- /* flags set by check_availability( ) that poll for I/O status */ |
| 340 |
- bool can_read = false; |
| 341 |
- bool can_write = false; |
| 342 |
- |
| 343 |
/* flags to mark all the combinations of why we're blocking */ |
| 344 |
bool read_waiton_write = false; |
| 345 |
bool read_waiton_read = false; |
| 346 |
@@ -843,17 +1001,13 @@ NetSslTransport::SendOrReceive( NetIoPtr |
| 347 |
{ |
| 348 |
DoHandshake( se ); |
| 349 |
if( se->Test() ) |
| 350 |
- { |
| 351 |
- re = se; |
| 352 |
goto end; |
| 353 |
- } |
| 354 |
} |
| 355 |
|
| 356 |
for ( ;; ) |
| 357 |
{ |
| 358 |
doRead = io.recvPtr != io.recvEnd && !re->Test(); |
| 359 |
doWrite = io.sendPtr != io.sendEnd && !se->Test(); |
| 360 |
- sslPending = 0; |
| 361 |
|
| 362 |
if( !doRead && !doWrite ) |
| 363 |
{ |
| 364 |
@@ -892,7 +1046,15 @@ NetSslTransport::SendOrReceive( NetIoPtr |
| 365 |
if (readable && sslPending) |
| 366 |
tv = 0; |
| 367 |
else if( (readable && breakCallback) || maxwait ) |
| 368 |
+ { |
| 369 |
tv = HALF_SECOND; |
| 370 |
+ if( breakCallback ) |
| 371 |
+ { |
| 372 |
+ int p = breakCallback->PollMs(); |
| 373 |
+ if( p >= 1 ) |
| 374 |
+ tv = p; |
| 375 |
+ } |
| 376 |
+ } |
| 377 |
else |
| 378 |
tv = -1; |
| 379 |
|
| 380 |
@@ -1222,7 +1384,6 @@ end: |
| 381 |
void |
| 382 |
NetSslTransport::Close( void ) |
| 383 |
{ |
| 384 |
- int ret; |
| 385 |
if( t < 0 ) |
| 386 |
return; |
| 387 |
|
| 388 |
@@ -1476,23 +1637,7 @@ static void DynDestroyFunction( |
| 389 |
|
| 390 |
static int InitLockCallbacks( Error *e ) |
| 391 |
{ |
| 392 |
- int i; |
| 393 |
- int numlocks = CRYPTO_num_locks(); |
| 394 |
- |
| 395 |
- /* static locks area */ |
| 396 |
-# ifdef OS_NT |
| 397 |
- mutexArray = (HANDLE *) malloc( CRYPTO_num_locks() * sizeof(HANDLE) ); |
| 398 |
-# else |
| 399 |
- mutexArray = (pthread_mutex_t *) malloc( CRYPTO_num_locks() * sizeof(pthread_mutex_t) ); |
| 400 |
-# endif // OS_NT |
| 401 |
- |
| 402 |
- if( mutexArray == NULL ) |
| 403 |
- { |
| 404 |
- e->Set(MsgRpc::Operat) << "malloc"; |
| 405 |
- return -1; |
| 406 |
- } |
| 407 |
- |
| 408 |
- for ( i = 0; i < numlocks; i++ ) |
| 409 |
+ for ( int i = 0; i < CRYPTO_num_locks(); i++ ) |
| 410 |
{ |
| 411 |
# ifdef OS_NT |
| 412 |
mutexArray[i] = CreateMutex( NULL, FALSE, NULL ); |
| 413 |
@@ -1516,16 +1661,8 @@ static int InitLockCallbacks( Error *e ) |
| 414 |
* |
| 415 |
* @return 0 |
| 416 |
*/ |
| 417 |
-static int ShudownLockCallbacks( void ) |
| 418 |
+static int ShutdownLockCallbacks( void ) |
| 419 |
{ |
| 420 |
- int i; |
| 421 |
- int numlocks = CRYPTO_num_locks(); |
| 422 |
- |
| 423 |
- if( mutexArray == NULL ) |
| 424 |
- { |
| 425 |
- return (0); |
| 426 |
- } |
| 427 |
- |
| 428 |
CRYPTO_set_dynlock_create_callback( NULL ); |
| 429 |
CRYPTO_set_dynlock_lock_callback( NULL ); |
| 430 |
CRYPTO_set_dynlock_destroy_callback( NULL ); |
| 431 |
@@ -1533,7 +1670,7 @@ static int ShudownLockCallbacks( void ) |
| 432 |
CRYPTO_set_locking_callback( NULL ); |
| 433 |
CRYPTO_set_id_callback( NULL ); |
| 434 |
|
| 435 |
- for ( i = 0; i < numlocks; i++ ) |
| 436 |
+ for ( int i = 0; i < CRYPTO_num_locks(); i++ ) |
| 437 |
{ |
| 438 |
# ifdef OS_NT |
| 439 |
CloseHandle( mutexArray[i] ); |