diff options
Diffstat (limited to 'networking/tls.c')
| -rw-r--r-- | networking/tls.c | 530 |
1 files changed, 516 insertions, 14 deletions
diff --git a/networking/tls.c b/networking/tls.c index ac6f0767f..97217f435 100644 --- a/networking/tls.c +++ b/networking/tls.c | |||
| @@ -10,18 +10,19 @@ | |||
| 10 | //Config.src also defines FEATURE_TLS_SHA1 option | 10 | //Config.src also defines FEATURE_TLS_SHA1 option |
| 11 | 11 | ||
| 12 | //kbuild:lib-$(CONFIG_TLS) += tls.o | 12 | //kbuild:lib-$(CONFIG_TLS) += tls.o |
| 13 | //kbuild:lib-$(CONFIG_TLS) += tls_pstm.o | 13 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm.o |
| 14 | //kbuild:lib-$(CONFIG_TLS) += tls_pstm_montgomery_reduce.o | 14 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm_montgomery_reduce.o |
| 15 | //kbuild:lib-$(CONFIG_TLS) += tls_pstm_mul_comba.o | 15 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm_mul_comba.o |
| 16 | //kbuild:lib-$(CONFIG_TLS) += tls_pstm_sqr_comba.o | 16 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm_sqr_comba.o |
| 17 | //kbuild:lib-$(CONFIG_TLS) += tls_aes.o | 17 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_aes.o |
| 18 | //kbuild:lib-$(CONFIG_TLS) += tls_aesgcm.o | 18 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_aesgcm.o |
| 19 | //kbuild:lib-$(CONFIG_TLS) += tls_rsa.o | 19 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_rsa.o |
| 20 | //kbuild:lib-$(CONFIG_TLS) += tls_fe.o | 20 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_fe.o |
| 21 | //kbuild:lib-$(CONFIG_TLS) += tls_sp_c32.o | 21 | //kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_sp_c32.o |
| 22 | 22 | ||
| 23 | #include "tls.h" | 23 | #include "tls.h" |
| 24 | 24 | ||
| 25 | #if !ENABLE_FEATURE_TLS_SCHANNEL | ||
| 25 | // Usually enabled. You can disable some of them to force only | 26 | // Usually enabled. You can disable some of them to force only |
| 26 | // specific ciphers to be advertized to server. | 27 | // specific ciphers to be advertized to server. |
| 27 | // (this would not exclude code to handle disabled ciphers, no code size win) | 28 | // (this would not exclude code to handle disabled ciphers, no code size win) |
| @@ -329,7 +330,7 @@ static void dump_tls_record(const void *vp, int len) | |||
| 329 | 330 | ||
| 330 | void FAST_FUNC tls_get_random(void *buf, unsigned len) | 331 | void FAST_FUNC tls_get_random(void *buf, unsigned len) |
| 331 | { | 332 | { |
| 332 | if (len != open_read_close("/dev/urandom", buf, len)) | 333 | if (len != MINGW_SPECIAL(open_read_close)("/dev/urandom", buf, len)) |
| 333 | xfunc_die(); | 334 | xfunc_die(); |
| 334 | } | 335 | } |
| 335 | 336 | ||
| @@ -417,7 +418,7 @@ static void prf_hmac_sha256(/*tls_state_t *tls,*/ | |||
| 417 | #define SEED label, label_size, seed, seed_size | 418 | #define SEED label, label_size, seed, seed_size |
| 418 | #define A a, MAC_size | 419 | #define A a, MAC_size |
| 419 | 420 | ||
| 420 | hmac_begin(&ctx, secret, secret_size, sha256_begin); | 421 | hmac_begin(&ctx, secret, secret_size, sha256_begin_hmac); |
| 421 | 422 | ||
| 422 | /* A(1) = HMAC_hash(secret, seed) */ | 423 | /* A(1) = HMAC_hash(secret, seed) */ |
| 423 | hmac_peek_hash(&ctx, a, SEED, NULL); | 424 | hmac_peek_hash(&ctx, a, SEED, NULL); |
| @@ -429,6 +430,7 @@ static void prf_hmac_sha256(/*tls_state_t *tls,*/ | |||
| 429 | /* (use a[] as temp buffer) */ | 430 | /* (use a[] as temp buffer) */ |
| 430 | hmac_peek_hash(&ctx, a, A, SEED, NULL); | 431 | hmac_peek_hash(&ctx, a, A, SEED, NULL); |
| 431 | memcpy(out_p, a, outbuf_size); | 432 | memcpy(out_p, a, outbuf_size); |
| 433 | hmac_uninit(&ctx); | ||
| 432 | return; | 434 | return; |
| 433 | } | 435 | } |
| 434 | /* Not last block. Store directly to result buffer */ | 436 | /* Not last block. Store directly to result buffer */ |
| @@ -512,18 +514,21 @@ static unsigned hmac_blocks(tls_state_t *tls, uint8_t *out, uint8_t *key, unsign | |||
| 512 | { | 514 | { |
| 513 | hmac_ctx_t ctx; | 515 | hmac_ctx_t ctx; |
| 514 | va_list va; | 516 | va_list va; |
| 517 | unsigned len; | ||
| 515 | 518 | ||
| 516 | hmac_begin(&ctx, key, key_size, | 519 | hmac_begin(&ctx, key, key_size, |
| 517 | (ENABLE_FEATURE_TLS_SHA1 && tls->MAC_size == SHA1_OUTSIZE) | 520 | (ENABLE_FEATURE_TLS_SHA1 && tls->MAC_size == SHA1_OUTSIZE) |
| 518 | ? sha1_begin | 521 | ? sha1_begin_hmac |
| 519 | : sha256_begin | 522 | : sha256_begin_hmac |
| 520 | ); | 523 | ); |
| 521 | 524 | ||
| 522 | va_start(va, key_size); | 525 | va_start(va, key_size); |
| 523 | hmac_hash_v(&ctx, va); | 526 | hmac_hash_v(&ctx, va); |
| 524 | va_end(va); | 527 | va_end(va); |
| 525 | 528 | ||
| 526 | return hmac_end(&ctx, out); | 529 | len = hmac_end(&ctx, out); |
| 530 | hmac_uninit(&ctx); | ||
| 531 | return len; | ||
| 527 | } | 532 | } |
| 528 | 533 | ||
| 529 | static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type) | 534 | static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type) |
| @@ -2357,3 +2362,500 @@ void FAST_FUNC tls_run_copy_loop(tls_state_t *tls, unsigned flags) | |||
| 2357 | } | 2362 | } |
| 2358 | } | 2363 | } |
| 2359 | } | 2364 | } |
| 2365 | #else | ||
| 2366 | #include <stdbool.h> | ||
| 2367 | |||
| 2368 | #if ENABLE_FEATURE_TLS_SCHANNEL_1_3 | ||
| 2369 | #include <subauth.h> | ||
| 2370 | #endif | ||
| 2371 | |||
| 2372 | #define SCHANNEL_USE_BLACKLISTS | ||
| 2373 | |||
| 2374 | #include <security.h> | ||
| 2375 | #include <schannel.h> | ||
| 2376 | |||
| 2377 | #ifndef SECBUFFER_ALERT | ||
| 2378 | # define SECBUFFER_ALERT 17 | ||
| 2379 | #endif | ||
| 2380 | |||
| 2381 | #ifndef SP_PROT_TLS1_0_CLIENT | ||
| 2382 | # define SP_PROT_TLS1_0_CLIENT 0x00000080 | ||
| 2383 | # define SP_PROT_TLS1_1_CLIENT 0x00000200 | ||
| 2384 | # define SP_PROT_TLS1_2_CLIENT 0x00000800 | ||
| 2385 | # define SCH_USE_STRONG_CRYPTO 0x00400000 | ||
| 2386 | #endif | ||
| 2387 | |||
| 2388 | #define BB_SCHANNEL_ISC_FLAGS \ | ||
| 2389 | (ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY | ISC_REQ_REPLAY_DETECT | \ | ||
| 2390 | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS) | ||
| 2391 | |||
| 2392 | #define SEC_STATUS_FAIL(status) ((status) != SEC_E_OK) | ||
| 2393 | |||
| 2394 | static char *hresult_to_error_string(HRESULT result) { | ||
| 2395 | char *output = NULL; | ||
| 2396 | |||
| 2397 | FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | ||
| 2398 | | FORMAT_MESSAGE_IGNORE_INSERTS | | ||
| 2399 | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, result, | ||
| 2400 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||
| 2401 | (char *) &output, 0, NULL); | ||
| 2402 | return output; | ||
| 2403 | } | ||
| 2404 | |||
| 2405 | static void init_sec_buffer(SecBuffer *buffer, void *pvBuffer, unsigned long cbBuffer, unsigned long BufferType) { | ||
| 2406 | buffer->BufferType = BufferType; | ||
| 2407 | buffer->cbBuffer = cbBuffer; | ||
| 2408 | buffer->pvBuffer = pvBuffer; | ||
| 2409 | } | ||
| 2410 | |||
| 2411 | #define init_sec_buffer_empty(buffer, BufferType) init_sec_buffer(buffer, NULL, 0, BufferType) | ||
| 2412 | |||
| 2413 | static void init_sec_buffer_desc(SecBufferDesc *desc, SecBuffer *buffers, unsigned long buffer_count) { | ||
| 2414 | desc->ulVersion = SECBUFFER_VERSION; | ||
| 2415 | desc->cBuffers = buffer_count; | ||
| 2416 | desc->pBuffers = buffers; | ||
| 2417 | } | ||
| 2418 | |||
| 2419 | static ssize_t tls_read(tls_state_t *state, char *buf, ssize_t len) { | ||
| 2420 | ssize_t amount_read = 0; | ||
| 2421 | |||
| 2422 | if (state->connection_state > BB_SCHANNEL_OPEN) { | ||
| 2423 | goto Success; | ||
| 2424 | } | ||
| 2425 | |||
| 2426 | while (len > 0) { | ||
| 2427 | if (state->out_buffer) { | ||
| 2428 | unsigned long copy_amount = | ||
| 2429 | min(len, (ssize_t)state->out_buffer_length); | ||
| 2430 | memcpy(buf, state->out_buffer, copy_amount); | ||
| 2431 | |||
| 2432 | amount_read += copy_amount; | ||
| 2433 | buf += copy_amount; | ||
| 2434 | len -= copy_amount; | ||
| 2435 | |||
| 2436 | if (copy_amount == state->out_buffer_length) { | ||
| 2437 | if (state->out_buffer_extra > 0) { | ||
| 2438 | memmove( | ||
| 2439 | state->in_buffer, | ||
| 2440 | state->in_buffer + | ||
| 2441 | (state->in_buffer_offset - state->out_buffer_extra), | ||
| 2442 | state->in_buffer_offset - (state->in_buffer_offset - | ||
| 2443 | state->out_buffer_extra)); | ||
| 2444 | state->in_buffer_offset = state->out_buffer_extra; | ||
| 2445 | } else { | ||
| 2446 | state->in_buffer_offset = 0; | ||
| 2447 | } | ||
| 2448 | |||
| 2449 | state->out_buffer = NULL; | ||
| 2450 | state->out_buffer_length = 0; | ||
| 2451 | state->out_buffer_extra = 0; | ||
| 2452 | |||
| 2453 | } else { | ||
| 2454 | state->out_buffer_length -= copy_amount; | ||
| 2455 | state->out_buffer += copy_amount; | ||
| 2456 | } | ||
| 2457 | } else { | ||
| 2458 | SecBuffer buffers[4]; | ||
| 2459 | SecBufferDesc desc; | ||
| 2460 | SECURITY_STATUS status; | ||
| 2461 | |||
| 2462 | init_sec_buffer(&buffers[0], | ||
| 2463 | state->in_buffer, | ||
| 2464 | state->in_buffer_offset, | ||
| 2465 | SECBUFFER_DATA); | ||
| 2466 | init_sec_buffer_empty(&buffers[1], SECBUFFER_EMPTY); | ||
| 2467 | init_sec_buffer_empty(&buffers[2], SECBUFFER_EMPTY); | ||
| 2468 | init_sec_buffer_empty(&buffers[3], SECBUFFER_EMPTY); | ||
| 2469 | |||
| 2470 | init_sec_buffer_desc(&desc, buffers, _countof(buffers)); | ||
| 2471 | |||
| 2472 | status = DecryptMessage(&state->ctx_handle, &desc, 0, NULL); | ||
| 2473 | |||
| 2474 | switch (status) { | ||
| 2475 | case SEC_E_OK: { | ||
| 2476 | state->out_buffer = buffers[1].pvBuffer; | ||
| 2477 | state->out_buffer_length = buffers[1].cbBuffer; | ||
| 2478 | state->out_buffer_extra = state->in_buffer_offset; | ||
| 2479 | |||
| 2480 | if (buffers[3].BufferType == SECBUFFER_EXTRA) { | ||
| 2481 | state->out_buffer_extra = buffers[3].cbBuffer; | ||
| 2482 | } else { | ||
| 2483 | state->out_buffer_extra = 0; | ||
| 2484 | } | ||
| 2485 | |||
| 2486 | continue; | ||
| 2487 | } | ||
| 2488 | case SEC_I_CONTEXT_EXPIRED: { | ||
| 2489 | // Shut down the connection | ||
| 2490 | state->connection_state = BB_SCHANNEL_CLOSED; | ||
| 2491 | goto Success; | ||
| 2492 | } | ||
| 2493 | case SEC_E_INCOMPLETE_MESSAGE: { | ||
| 2494 | int result = safe_read(state->ifd, | ||
| 2495 | state->in_buffer + state->in_buffer_offset, | ||
| 2496 | sizeof(state->in_buffer) - state->in_buffer_offset); | ||
| 2497 | if (result == 0) { | ||
| 2498 | state->connection_state = BB_SCHANNEL_CLOSED; | ||
| 2499 | goto Success; | ||
| 2500 | } else if (result < 0) { | ||
| 2501 | bb_error_msg_and_die("schannel: read() failed"); | ||
| 2502 | } | ||
| 2503 | |||
| 2504 | state->in_buffer_offset += result; | ||
| 2505 | continue; | ||
| 2506 | } | ||
| 2507 | case SEC_I_RENEGOTIATE: { | ||
| 2508 | DWORD flags = BB_SCHANNEL_ISC_FLAGS; | ||
| 2509 | |||
| 2510 | SecBuffer in_buffers[2]; | ||
| 2511 | SecBufferDesc in_buffers_desc; | ||
| 2512 | |||
| 2513 | SecBuffer out_buffers[2]; | ||
| 2514 | SecBufferDesc out_buffers_desc; | ||
| 2515 | |||
| 2516 | init_sec_buffer(&in_buffers[0], | ||
| 2517 | buffers[3].pvBuffer, | ||
| 2518 | buffers[3].cbBuffer, | ||
| 2519 | SECBUFFER_TOKEN); | ||
| 2520 | init_sec_buffer_empty(&in_buffers[1], SECBUFFER_EMPTY); | ||
| 2521 | |||
| 2522 | init_sec_buffer_empty(&out_buffers[0], SECBUFFER_TOKEN); | ||
| 2523 | init_sec_buffer_empty(&out_buffers[1], SECBUFFER_ALERT); | ||
| 2524 | |||
| 2525 | init_sec_buffer_desc( | ||
| 2526 | &in_buffers_desc, in_buffers, _countof(in_buffers)); | ||
| 2527 | init_sec_buffer_desc( | ||
| 2528 | &out_buffers_desc, out_buffers, _countof(out_buffers)); | ||
| 2529 | |||
| 2530 | status = InitializeSecurityContextA(&state->cred_handle, | ||
| 2531 | &state->ctx_handle, | ||
| 2532 | state->hostname, | ||
| 2533 | flags, | ||
| 2534 | 0, | ||
| 2535 | 0, | ||
| 2536 | &in_buffers_desc, | ||
| 2537 | 0, | ||
| 2538 | &state->ctx_handle, | ||
| 2539 | &out_buffers_desc, | ||
| 2540 | &flags, | ||
| 2541 | 0); | ||
| 2542 | |||
| 2543 | if (SEC_STATUS_FAIL(status)) { | ||
| 2544 | bb_error_msg_and_die("schannel: renegotiate failed: (0x%08lx): %s", | ||
| 2545 | status, hresult_to_error_string(status)); | ||
| 2546 | } | ||
| 2547 | |||
| 2548 | if (in_buffers[1].BufferType == SECBUFFER_EXTRA) { | ||
| 2549 | memmove(state->in_buffer, | ||
| 2550 | state->in_buffer + (state->in_buffer_offset - | ||
| 2551 | in_buffers[1].cbBuffer), | ||
| 2552 | in_buffers[1].cbBuffer); | ||
| 2553 | state->in_buffer_offset = in_buffers[1].cbBuffer; | ||
| 2554 | } else { | ||
| 2555 | state->in_buffer_offset = 0; | ||
| 2556 | } | ||
| 2557 | |||
| 2558 | continue; | ||
| 2559 | } | ||
| 2560 | default: { | ||
| 2561 | bb_error_msg_and_die("schannel: DecryptMessage failed: (0x%08lx): %s", | ||
| 2562 | status, hresult_to_error_string(status)); | ||
| 2563 | } | ||
| 2564 | } | ||
| 2565 | } | ||
| 2566 | } | ||
| 2567 | |||
| 2568 | Success: | ||
| 2569 | return amount_read; | ||
| 2570 | } | ||
| 2571 | |||
| 2572 | static void tls_write(tls_state_t *state, char *buf, size_t len) { | ||
| 2573 | if (state->connection_state > BB_SCHANNEL_OPEN) { | ||
| 2574 | bb_error_msg_and_die("schannel: attempted to write to a closed connection"); | ||
| 2575 | } | ||
| 2576 | |||
| 2577 | while (len > 0) { | ||
| 2578 | SECURITY_STATUS status; | ||
| 2579 | unsigned long copy_amount = | ||
| 2580 | min(len, (size_t)state->stream_sizes.cbMaximumMessage); | ||
| 2581 | char *write_buffer = _alloca(sizeof(state->in_buffer)); | ||
| 2582 | |||
| 2583 | SecBuffer buffers[4]; | ||
| 2584 | SecBufferDesc desc; | ||
| 2585 | |||
| 2586 | init_sec_buffer(&buffers[0], | ||
| 2587 | write_buffer, | ||
| 2588 | state->stream_sizes.cbHeader, | ||
| 2589 | SECBUFFER_STREAM_HEADER); | ||
| 2590 | init_sec_buffer(&buffers[1], | ||
| 2591 | write_buffer + state->stream_sizes.cbHeader, | ||
| 2592 | copy_amount, | ||
| 2593 | SECBUFFER_DATA); | ||
| 2594 | init_sec_buffer(&buffers[2], | ||
| 2595 | write_buffer + state->stream_sizes.cbHeader + | ||
| 2596 | copy_amount, | ||
| 2597 | state->stream_sizes.cbTrailer, | ||
| 2598 | SECBUFFER_STREAM_TRAILER); | ||
| 2599 | init_sec_buffer_empty(&buffers[3], SECBUFFER_EMPTY); | ||
| 2600 | |||
| 2601 | init_sec_buffer_desc(&desc, buffers, _countof(buffers)); | ||
| 2602 | |||
| 2603 | memcpy(buffers[1].pvBuffer, buf, copy_amount); | ||
| 2604 | |||
| 2605 | status = EncryptMessage(&state->ctx_handle, 0, &desc, 0); | ||
| 2606 | if (SEC_STATUS_FAIL(status)) { | ||
| 2607 | bb_error_msg_and_die("schannel: EncryptMessage failed: (0x%08lx): %s", | ||
| 2608 | status, hresult_to_error_string(status)); | ||
| 2609 | } | ||
| 2610 | |||
| 2611 | xwrite(state->ofd, write_buffer, | ||
| 2612 | buffers[0].cbBuffer + buffers[1].cbBuffer + | ||
| 2613 | buffers[2].cbBuffer); | ||
| 2614 | |||
| 2615 | len -= copy_amount; | ||
| 2616 | } | ||
| 2617 | } | ||
| 2618 | |||
| 2619 | static void tls_disconnect(tls_state_t * state) { | ||
| 2620 | SECURITY_STATUS status; | ||
| 2621 | |||
| 2622 | DWORD token = SCHANNEL_SHUTDOWN; | ||
| 2623 | DWORD flags = BB_SCHANNEL_ISC_FLAGS; | ||
| 2624 | |||
| 2625 | SecBuffer buf_token; | ||
| 2626 | SecBufferDesc buf_token_desc; | ||
| 2627 | |||
| 2628 | SecBuffer out_buffer; | ||
| 2629 | SecBufferDesc out_buffer_desc; | ||
| 2630 | |||
| 2631 | if (state->connection_state == BB_SCHANNEL_CLOSED_AND_FREED) | ||
| 2632 | return; | ||
| 2633 | state->connection_state = BB_SCHANNEL_CLOSED_AND_FREED; | ||
| 2634 | |||
| 2635 | init_sec_buffer(&buf_token, &token, sizeof(token), SECBUFFER_TOKEN); | ||
| 2636 | init_sec_buffer_desc(&buf_token_desc, &buf_token, 1); | ||
| 2637 | |||
| 2638 | ApplyControlToken(&state->ctx_handle, &buf_token_desc); | ||
| 2639 | |||
| 2640 | init_sec_buffer_empty(&out_buffer, SECBUFFER_TOKEN); | ||
| 2641 | init_sec_buffer_desc(&out_buffer_desc, &out_buffer, 1); | ||
| 2642 | |||
| 2643 | status = InitializeSecurityContextA(&state->cred_handle, | ||
| 2644 | &state->ctx_handle, | ||
| 2645 | state->hostname, | ||
| 2646 | flags, | ||
| 2647 | 0, | ||
| 2648 | 0, | ||
| 2649 | NULL, | ||
| 2650 | 0, | ||
| 2651 | &state->ctx_handle, | ||
| 2652 | &out_buffer_desc, | ||
| 2653 | &flags, | ||
| 2654 | 0); | ||
| 2655 | |||
| 2656 | if ((status == SEC_E_OK) || (status == SEC_I_CONTEXT_EXPIRED)) { | ||
| 2657 | write(state->ofd, out_buffer.pvBuffer, out_buffer.cbBuffer); | ||
| 2658 | FreeContextBuffer(out_buffer.pvBuffer); | ||
| 2659 | } | ||
| 2660 | |||
| 2661 | DeleteSecurityContext(&state->ctx_handle); | ||
| 2662 | FreeCredentialsHandle(&state->cred_handle); | ||
| 2663 | free(state->hostname); | ||
| 2664 | } | ||
| 2665 | |||
| 2666 | |||
| 2667 | void FAST_FUNC tls_handshake(tls_state_t *state, const char *hostname) { | ||
| 2668 | SECURITY_STATUS status; | ||
| 2669 | |||
| 2670 | #if ENABLE_FEATURE_TLS_SCHANNEL_1_3 | ||
| 2671 | SCH_CREDENTIALS credential = {.dwVersion = SCH_CREDENTIALS_VERSION, | ||
| 2672 | .dwCredFormat = 0, | ||
| 2673 | .cCreds = 0, | ||
| 2674 | .paCred = NULL, | ||
| 2675 | .hRootStore = NULL, | ||
| 2676 | .cMappers = 0, | ||
| 2677 | .aphMappers = NULL, | ||
| 2678 | .dwSessionLifespan = 0, | ||
| 2679 | .dwFlags = | ||
| 2680 | SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS | | ||
| 2681 | SCH_USE_STRONG_CRYPTO, | ||
| 2682 | .cTlsParameters = 0, | ||
| 2683 | .pTlsParameters = NULL | ||
| 2684 | }; | ||
| 2685 | #else | ||
| 2686 | SCHANNEL_CRED credential = {.dwVersion = SCHANNEL_CRED_VERSION, | ||
| 2687 | .cCreds = 0, | ||
| 2688 | .paCred = NULL, | ||
| 2689 | .hRootStore = NULL, | ||
| 2690 | .cMappers = 0, | ||
| 2691 | .aphMappers = NULL, | ||
| 2692 | .cSupportedAlgs = 0, | ||
| 2693 | .palgSupportedAlgs = NULL, | ||
| 2694 | .grbitEnabledProtocols = | ||
| 2695 | SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_1_CLIENT | | ||
| 2696 | SP_PROT_TLS1_2_CLIENT, | ||
| 2697 | .dwMinimumCipherStrength = 0, | ||
| 2698 | .dwMaximumCipherStrength = 0, | ||
| 2699 | .dwSessionLifespan = 0, | ||
| 2700 | .dwFlags = | ||
| 2701 | SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS | | ||
| 2702 | SCH_USE_STRONG_CRYPTO, | ||
| 2703 | .dwCredFormat = 0 | ||
| 2704 | }; | ||
| 2705 | #endif | ||
| 2706 | |||
| 2707 | state->in_buffer_offset = 0; | ||
| 2708 | |||
| 2709 | state->out_buffer = NULL; | ||
| 2710 | state->out_buffer_length = 0; | ||
| 2711 | state->out_buffer_extra = 0; | ||
| 2712 | |||
| 2713 | state->hostname = xstrdup(hostname); | ||
| 2714 | state->initialized = false; | ||
| 2715 | state->connection_state = BB_SCHANNEL_OPEN; | ||
| 2716 | |||
| 2717 | if (SEC_STATUS_FAIL(status = AcquireCredentialsHandleA(NULL, | ||
| 2718 | (SEC_CHAR *)UNISP_NAME_A, | ||
| 2719 | SECPKG_CRED_OUTBOUND, | ||
| 2720 | NULL, | ||
| 2721 | &credential, | ||
| 2722 | NULL, | ||
| 2723 | NULL, | ||
| 2724 | &state->cred_handle, | ||
| 2725 | NULL))) { | ||
| 2726 | bb_error_msg_and_die("schannel: AcquireCredentialsHandleA failed: (0x%08lx): %s", | ||
| 2727 | status, hresult_to_error_string(status)); | ||
| 2728 | } | ||
| 2729 | |||
| 2730 | // InitializeSecurityContext loop | ||
| 2731 | while (true) { | ||
| 2732 | DWORD flags = BB_SCHANNEL_ISC_FLAGS; | ||
| 2733 | |||
| 2734 | SecBuffer in_buffers[2]; | ||
| 2735 | SecBufferDesc in_buffers_desc; | ||
| 2736 | |||
| 2737 | SecBuffer out_buffers[2]; | ||
| 2738 | SecBufferDesc out_buffers_desc; | ||
| 2739 | |||
| 2740 | init_sec_buffer(&in_buffers[0], | ||
| 2741 | state->in_buffer, | ||
| 2742 | state->in_buffer_offset, | ||
| 2743 | SECBUFFER_TOKEN); | ||
| 2744 | init_sec_buffer_empty(&in_buffers[1], SECBUFFER_EMPTY); | ||
| 2745 | |||
| 2746 | init_sec_buffer_empty(&out_buffers[0], SECBUFFER_TOKEN); | ||
| 2747 | init_sec_buffer_empty(&out_buffers[1], SECBUFFER_ALERT); | ||
| 2748 | |||
| 2749 | init_sec_buffer_desc( | ||
| 2750 | &in_buffers_desc, in_buffers, _countof(in_buffers)); | ||
| 2751 | init_sec_buffer_desc( | ||
| 2752 | &out_buffers_desc, out_buffers, _countof(out_buffers)); | ||
| 2753 | |||
| 2754 | status = InitializeSecurityContextA( | ||
| 2755 | &state->cred_handle, | ||
| 2756 | state->initialized ? &state->ctx_handle : NULL, | ||
| 2757 | state->hostname, | ||
| 2758 | flags, | ||
| 2759 | 0, | ||
| 2760 | 0, | ||
| 2761 | state->initialized ? &in_buffers_desc : NULL, | ||
| 2762 | 0, | ||
| 2763 | &state->ctx_handle, | ||
| 2764 | &out_buffers_desc, | ||
| 2765 | &flags, | ||
| 2766 | 0); | ||
| 2767 | |||
| 2768 | state->initialized = true; | ||
| 2769 | |||
| 2770 | if (in_buffers[1].BufferType == SECBUFFER_EXTRA) { | ||
| 2771 | memmove(state->in_buffer, | ||
| 2772 | state->in_buffer + | ||
| 2773 | (state->in_buffer_offset - in_buffers[1].cbBuffer), | ||
| 2774 | in_buffers[1].cbBuffer); | ||
| 2775 | state->in_buffer_offset = in_buffers[1].cbBuffer; | ||
| 2776 | } | ||
| 2777 | |||
| 2778 | switch (status) { | ||
| 2779 | case SEC_E_OK: { | ||
| 2780 | state->in_buffer_offset = | ||
| 2781 | (in_buffers[1].BufferType == SECBUFFER_EXTRA) | ||
| 2782 | ? in_buffers[1].cbBuffer | ||
| 2783 | : 0; | ||
| 2784 | |||
| 2785 | if (out_buffers[0].cbBuffer > 0) { | ||
| 2786 | xwrite(state->ifd, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer); | ||
| 2787 | FreeContextBuffer(out_buffers[0].pvBuffer); | ||
| 2788 | } | ||
| 2789 | |||
| 2790 | goto Success; | ||
| 2791 | } | ||
| 2792 | case SEC_I_CONTINUE_NEEDED: { | ||
| 2793 | xwrite(state->ofd, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer); | ||
| 2794 | FreeContextBuffer(out_buffers[0].pvBuffer); | ||
| 2795 | if (in_buffers[1].BufferType != SECBUFFER_EXTRA) { | ||
| 2796 | state->in_buffer_offset = 0; | ||
| 2797 | } | ||
| 2798 | break; | ||
| 2799 | } | ||
| 2800 | case SEC_E_INCOMPLETE_MESSAGE: { | ||
| 2801 | int amount_read = | ||
| 2802 | safe_read(state->ifd, state->in_buffer + state->in_buffer_offset, | ||
| 2803 | sizeof(state->in_buffer) - state->in_buffer_offset); | ||
| 2804 | if (amount_read <= 0) { | ||
| 2805 | bb_error_msg_and_die("schannel: handshake read() failed"); | ||
| 2806 | } | ||
| 2807 | |||
| 2808 | state->in_buffer_offset += amount_read; | ||
| 2809 | continue; | ||
| 2810 | } | ||
| 2811 | default: { | ||
| 2812 | bb_error_msg_and_die("schannel: handshake failed: (0x%08lx): %s", | ||
| 2813 | status, hresult_to_error_string(status)); | ||
| 2814 | } | ||
| 2815 | } | ||
| 2816 | } | ||
| 2817 | |||
| 2818 | Success: | ||
| 2819 | QueryContextAttributes( | ||
| 2820 | &state->ctx_handle, SECPKG_ATTR_STREAM_SIZES, &state->stream_sizes); | ||
| 2821 | return; | ||
| 2822 | } | ||
| 2823 | |||
| 2824 | void FAST_FUNC tls_run_copy_loop(tls_state_t *tls, unsigned flags) { | ||
| 2825 | char buffer[65536]; | ||
| 2826 | |||
| 2827 | struct pollfd pfds[2]; | ||
| 2828 | |||
| 2829 | pfds[0].fd = STDIN_FILENO; | ||
| 2830 | pfds[0].events = POLLIN; | ||
| 2831 | pfds[1].fd = tls->ifd; | ||
| 2832 | pfds[1].events = POLLIN; | ||
| 2833 | |||
| 2834 | for (;;) { | ||
| 2835 | int nread; | ||
| 2836 | |||
| 2837 | if (safe_poll(pfds, 2, -1) < 0) | ||
| 2838 | bb_simple_perror_msg_and_die("poll"); | ||
| 2839 | |||
| 2840 | if (pfds[0].revents) { | ||
| 2841 | nread = safe_read(STDIN_FILENO, buffer, sizeof(buffer)); | ||
| 2842 | if (nread < 1) { | ||
| 2843 | pfds[0].fd = -1; | ||
| 2844 | tls_disconnect(tls); | ||
| 2845 | if (flags & TLSLOOP_EXIT_ON_LOCAL_EOF) | ||
| 2846 | break; | ||
| 2847 | } else { | ||
| 2848 | tls_write(tls, buffer, nread); | ||
| 2849 | } | ||
| 2850 | } | ||
| 2851 | if (pfds[1].revents) { | ||
| 2852 | nread = tls_read(tls, buffer, sizeof(buffer)); | ||
| 2853 | if (nread < 1) { | ||
| 2854 | tls_disconnect(tls); | ||
| 2855 | break; | ||
| 2856 | } | ||
| 2857 | xwrite(STDOUT_FILENO, buffer, nread); | ||
| 2858 | } | ||
| 2859 | } | ||
| 2860 | } | ||
| 2861 | #endif | ||
