Mercurial > hg > nginx-quic
comparison src/event/ngx_event_openssl.c @ 7643:76e29ff31cd3 quic
AEAD routines, introduced ngx_quic_tls_open()/ngx_quic_tls_seal().
author | Sergey Kandaurov <pluknet@nginx.com> |
---|---|
date | Fri, 28 Feb 2020 13:09:52 +0300 |
parents | 72f632f90a17 |
children | a9ff4392ecde |
comparison
equal
deleted
inserted
replaced
7642:8964cc6ecc4a | 7643:76e29ff31cd3 |
---|---|
450 | 450 |
451 static int | 451 static int |
452 quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, | 452 quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, |
453 enum ssl_encryption_level_t level, const uint8_t *data, size_t len) | 453 enum ssl_encryption_level_t level, const uint8_t *data, size_t len) |
454 { | 454 { |
455 u_char buf[2048], *p, *ciphertext, *clear, *ad, *name; | 455 u_char buf[2048], *p, *name; |
456 size_t ad_len, clear_len; | 456 ngx_int_t m; |
457 ngx_int_t m; | 457 ngx_str_t in, out, ad; |
458 ngx_str_t *server_key, *server_iv, *server_hp; | 458 ngx_quic_secret_t *secret; |
459 #ifdef OPENSSL_IS_BORINGSSL | 459 ngx_connection_t *c; |
460 const EVP_AEAD *cipher; | 460 ngx_quic_connection_t *qc; |
461 #else | 461 const ngx_aead_cipher_t *cipher; |
462 const EVP_CIPHER *cipher; | |
463 #endif | |
464 ngx_connection_t *c; | |
465 ngx_quic_connection_t *qc; | |
466 static int pn = 0; | 462 static int pn = 0; |
467 | 463 |
468 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | 464 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); |
469 | 465 |
470 ngx_ssl_handshake_log(c); | 466 ngx_ssl_handshake_log(c); |
472 qc = c->quic; | 468 qc = c->quic; |
473 | 469 |
474 switch (level) { | 470 switch (level) { |
475 | 471 |
476 case ssl_encryption_initial: | 472 case ssl_encryption_initial: |
477 server_key = &qc->server_in.key; | 473 secret = &qc->server_in; |
478 server_iv = &qc->server_in.iv; | |
479 server_hp = &qc->server_in.hp; | |
480 break; | 474 break; |
481 | 475 |
482 case ssl_encryption_handshake: | 476 case ssl_encryption_handshake: |
483 server_key = &qc->server_hs.key; | 477 secret = &qc->server_hs; |
484 server_iv = &qc->server_hs.iv; | |
485 server_hp = &qc->server_hs.hp; | |
486 break; | 478 break; |
487 | 479 |
488 default: | 480 default: |
489 return 0; | 481 return 0; |
490 } | 482 } |
492 m = ngx_hex_dump(buf, (u_char *) data, ngx_min(len, 1024)) - buf; | 484 m = ngx_hex_dump(buf, (u_char *) data, ngx_min(len, 1024)) - buf; |
493 ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, | 485 ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, |
494 "quic_add_handshake_data: %*s%s, len: %uz, level:%d", | 486 "quic_add_handshake_data: %*s%s, len: %uz, level:%d", |
495 m, buf, len < 2048 ? "" : "...", len, (int) level); | 487 m, buf, len < 2048 ? "" : "...", len, (int) level); |
496 | 488 |
497 clear = ngx_alloc(4 + len + 5 /*minimal ACK*/, c->log); | 489 in.data = ngx_alloc(4 + len + 5 /*minimal ACK*/, c->log); |
498 if (clear == 0) { | 490 if (in.data == 0) { |
499 return 0; | 491 return 0; |
500 } | 492 } |
501 | 493 |
502 p = clear; | 494 p = in.data; |
503 ngx_quic_build_int(&p, 6); // crypto frame | 495 ngx_quic_build_int(&p, 6); // crypto frame |
504 ngx_quic_build_int(&p, 0); | 496 ngx_quic_build_int(&p, 0); |
505 ngx_quic_build_int(&p, len); | 497 ngx_quic_build_int(&p, len); |
506 p = ngx_cpymem(p, data, len); | 498 p = ngx_cpymem(p, data, len); |
507 | 499 |
511 ngx_quic_build_int(&p, 0); | 503 ngx_quic_build_int(&p, 0); |
512 ngx_quic_build_int(&p, 0); | 504 ngx_quic_build_int(&p, 0); |
513 ngx_quic_build_int(&p, 0); | 505 ngx_quic_build_int(&p, 0); |
514 } | 506 } |
515 | 507 |
516 clear_len = p - clear; | 508 in.len = p - in.data; |
517 size_t ciphertext_len = clear_len + 16 /*expansion*/; | 509 out.len = in.len + EVP_GCM_TLS_TAG_LEN; |
518 | 510 |
519 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 511 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
520 "quic_add_handshake_data: clear_len:%uz, ciphertext_len:%uz", | 512 "quic_add_handshake_data: clear_len:%uz, ciphertext_len:%uz", |
521 clear_len, ciphertext_len); | 513 in.len, out.len); |
522 | 514 |
523 ad = ngx_alloc(346 /*max header*/, c->log); | 515 ad.data = ngx_alloc(346 /*max header*/, c->log); |
524 if (ad == 0) { | 516 if (ad.data == 0) { |
525 return 0; | 517 return 0; |
526 } | 518 } |
527 | 519 |
528 p = ad; | 520 p = ad.data; |
529 if (level == ssl_encryption_initial) { | 521 if (level == ssl_encryption_initial) { |
530 *p++ = 0xc0; // initial, packet number len | 522 *p++ = 0xc0; // initial, packet number len |
531 } else if (level == ssl_encryption_handshake) { | 523 } else if (level == ssl_encryption_handshake) { |
532 *p++ = 0xe0; // handshake, packet number len | 524 *p++ = 0xe0; // handshake, packet number len |
533 } | 525 } |
540 *p++ = qc->dcid.len; | 532 *p++ = qc->dcid.len; |
541 p = ngx_cpymem(p, qc->dcid.data, qc->dcid.len); | 533 p = ngx_cpymem(p, qc->dcid.data, qc->dcid.len); |
542 if (level == ssl_encryption_initial) { | 534 if (level == ssl_encryption_initial) { |
543 ngx_quic_build_int(&p, 0); // token length | 535 ngx_quic_build_int(&p, 0); // token length |
544 } | 536 } |
545 ngx_quic_build_int(&p, ciphertext_len + 1); // length (inc. pnl) | 537 ngx_quic_build_int(&p, out.len + 1); // length (inc. pnl) |
546 u_char *pnp = p; | 538 u_char *pnp = p; |
547 | 539 |
548 if (level == ssl_encryption_initial) { | 540 if (level == ssl_encryption_initial) { |
549 *p++ = 0; // packet number 0 | 541 *p++ = 0; // packet number 0 |
550 | 542 |
551 } else if (level == ssl_encryption_handshake) { | 543 } else if (level == ssl_encryption_handshake) { |
552 *p++ = pn++; | 544 *p++ = pn++; |
553 } | 545 } |
554 | 546 |
555 ad_len = p - ad; | 547 ad.len = p - ad.data; |
556 | 548 |
557 m = ngx_hex_dump(buf, (u_char *) ad, ad_len) - buf; | 549 m = ngx_hex_dump(buf, ad.data, ad.len) - buf; |
558 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | 550 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, |
559 "quic_add_handshake_data ad: %*s, len: %uz", | 551 "quic_add_handshake_data ad: %*s, len: %uz", |
560 m, buf, ad_len); | 552 m, buf, ad.len); |
561 | 553 |
562 | 554 |
563 name = (u_char *) SSL_get_cipher(ssl_conn); | 555 name = (u_char *) SSL_get_cipher(ssl_conn); |
564 | 556 |
565 if (ngx_strcasecmp(name, (u_char *) "TLS_AES_128_GCM_SHA256") == 0 | 557 if (ngx_strcasecmp(name, (u_char *) "TLS_AES_128_GCM_SHA256") == 0 |
580 | 572 |
581 } else { | 573 } else { |
582 return 0; | 574 return 0; |
583 } | 575 } |
584 | 576 |
585 | 577 uint8_t *nonce = ngx_pstrdup(c->pool, &secret->iv); |
586 ciphertext = ngx_alloc(ciphertext_len, c->log); | |
587 if (ciphertext == 0) { | |
588 return 0; | |
589 } | |
590 | |
591 uint8_t *nonce = ngx_pstrdup(c->pool, server_iv); | |
592 if (level == ssl_encryption_handshake) { | 578 if (level == ssl_encryption_handshake) { |
593 nonce[11] ^= (pn - 1); | 579 nonce[11] ^= (pn - 1); |
594 } | 580 } |
595 | 581 |
596 m = ngx_hex_dump(buf, (u_char *) server_iv->data, 12) - buf; | 582 m = ngx_hex_dump(buf, (u_char *) secret->iv.data, 12) - buf; |
597 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 583 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
598 "quic_add_handshake_data sample: server_iv %*s", | 584 "quic_add_handshake_data sample: server_iv %*s", |
599 m, buf); | 585 m, buf); |
600 m = ngx_hex_dump(buf, (u_char *) nonce, 12) - buf; | 586 m = ngx_hex_dump(buf, (u_char *) nonce, 12) - buf; |
601 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | 587 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, |
602 "quic_add_handshake_data sample: n=%d nonce %*s", | 588 "quic_add_handshake_data sample: n=%d nonce %*s", |
603 pn - 1, m, buf); | 589 pn - 1, m, buf); |
604 | 590 |
605 | 591 if (ngx_quic_tls_seal(c, cipher, secret, &out, nonce, &in, &ad) != NGX_OK) |
606 #ifdef OPENSSL_IS_BORINGSSL | |
607 size_t out_len; | |
608 EVP_AEAD_CTX *aead = EVP_AEAD_CTX_new(cipher, | |
609 server_key->data, | |
610 server_key->len, | |
611 EVP_AEAD_DEFAULT_TAG_LENGTH); | |
612 | |
613 if (EVP_AEAD_CTX_seal(aead, ciphertext, &out_len, ciphertext_len, | |
614 nonce, server_iv->len, | |
615 clear, clear_len, ad, ad_len) | |
616 != 1) | |
617 { | 592 { |
618 EVP_AEAD_CTX_free(aead); | |
619 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, | |
620 "EVP_AEAD_CTX_seal() failed"); | |
621 return 0; | 593 return 0; |
622 } | 594 } |
623 | 595 |
624 EVP_AEAD_CTX_free(aead); | |
625 #else | |
626 int out_len; | |
627 EVP_CIPHER_CTX *aead; | |
628 | |
629 aead = EVP_CIPHER_CTX_new(); | |
630 if (aead == NULL) { | |
631 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_CIPHER_CTX_new() failed"); | |
632 return 0; | |
633 } | |
634 | |
635 if (EVP_EncryptInit_ex(aead, cipher, NULL, NULL, NULL) != 1) { | |
636 EVP_CIPHER_CTX_free(aead); | |
637 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_EncryptInit_ex() failed"); | |
638 return 0; | |
639 } | |
640 | |
641 if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_SET_IVLEN, server_iv->len, NULL) | |
642 == 0) | |
643 { | |
644 EVP_CIPHER_CTX_free(aead); | |
645 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, | |
646 "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_IVLEN) failed"); | |
647 return 0; | |
648 } | |
649 | |
650 if (EVP_EncryptInit_ex(aead, NULL, NULL, server_key->data, nonce) | |
651 != 1) | |
652 { | |
653 EVP_CIPHER_CTX_free(aead); | |
654 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_EncryptInit_ex() failed"); | |
655 return 0; | |
656 } | |
657 | |
658 if (EVP_EncryptUpdate(aead, NULL, &out_len, ad, ad_len) != 1) { | |
659 EVP_CIPHER_CTX_free(aead); | |
660 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_EncryptUpdate() failed"); | |
661 return 0; | |
662 } | |
663 | |
664 if (EVP_EncryptUpdate(aead, ciphertext, &out_len, clear, clear_len) != 1) { | |
665 EVP_CIPHER_CTX_free(aead); | |
666 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_EncryptUpdate() failed"); | |
667 return 0; | |
668 } | |
669 | |
670 ciphertext_len = out_len; | |
671 | |
672 if (EVP_EncryptFinal_ex(aead, ciphertext + out_len, &out_len) <= 0) { | |
673 EVP_CIPHER_CTX_free(aead); | |
674 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_EncryptFinal_ex failed"); | |
675 return 0; | |
676 } | |
677 | |
678 ciphertext_len += out_len; | |
679 | |
680 if (EVP_CIPHER_CTX_ctrl(aead, EVP_CTRL_GCM_GET_TAG, EVP_GCM_TLS_TAG_LEN, | |
681 ciphertext + clear_len) | |
682 == 0) | |
683 { | |
684 EVP_CIPHER_CTX_free(aead); | |
685 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, | |
686 "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_GET_TAG) failed"); | |
687 return 0; | |
688 } | |
689 | |
690 EVP_CIPHER_CTX_free(aead); | |
691 | |
692 out_len = ciphertext_len + EVP_GCM_TLS_TAG_LEN; | |
693 #endif | |
694 | |
695 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); | 596 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); |
696 u_char *sample = ciphertext + 3; // pnl=0 | 597 u_char *sample = &out.data[3]; // pnl=0 |
697 uint8_t mask[16]; | 598 uint8_t mask[16]; |
698 int outlen; | 599 int outlen; |
699 | 600 |
700 if (EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, server_hp->data, NULL) | 601 if (EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, secret->hp.data, NULL) |
701 != 1) | 602 != 1) |
702 { | 603 { |
703 EVP_CIPHER_CTX_free(ctx); | 604 EVP_CIPHER_CTX_free(ctx); |
704 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, | 605 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, |
705 "EVP_EncryptInit_ex() failed"); | 606 "EVP_EncryptInit_ex() failed"); |
723 m = ngx_hex_dump(buf, (u_char *) mask, 16) - buf; | 624 m = ngx_hex_dump(buf, (u_char *) mask, 16) - buf; |
724 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | 625 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, |
725 "quic_add_handshake_data mask: %*s, len: %uz", | 626 "quic_add_handshake_data mask: %*s, len: %uz", |
726 m, buf, 16); | 627 m, buf, 16); |
727 | 628 |
728 m = ngx_hex_dump(buf, (u_char *) server_hp->data, 16) - buf; | 629 m = ngx_hex_dump(buf, (u_char *) secret->hp.data, 16) - buf; |
729 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | 630 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, |
730 "quic_add_handshake_data hp_key: %*s, len: %uz", | 631 "quic_add_handshake_data hp_key: %*s, len: %uz", |
731 m, buf, 16); | 632 m, buf, 16); |
732 | 633 |
733 // header protection, pnl = 0 | 634 // header protection, pnl = 0 |
734 ad[0] ^= mask[0] & 0x0f; | 635 ad.data[0] ^= mask[0] & 0x0f; |
735 *pnp ^= mask[1]; | 636 *pnp ^= mask[1]; |
736 | 637 |
737 printf("clear_len %ld ciphertext_len %ld out_len %ld ad_len %ld\n", | 638 printf("clear_len %ld ciphertext_len %ld ad_len %ld\n", in.len, out.len, ad.len); |
738 clear_len, ciphertext_len, (size_t) out_len, ad_len); | 639 |
739 | 640 u_char *packet = ngx_alloc(ad.len + out.len, c->log); |
740 u_char *packet = ngx_alloc(ad_len + out_len, c->log); | |
741 if (packet == 0) { | 641 if (packet == 0) { |
742 return 0; | 642 return 0; |
743 } | 643 } |
744 | 644 |
745 p = ngx_cpymem(packet, ad, ad_len); | 645 p = ngx_cpymem(packet, ad.data, ad.len); |
746 p = ngx_cpymem(p, ciphertext, out_len); | 646 p = ngx_cpymem(p, out.data, out.len); |
747 | 647 |
748 m = ngx_hex_dump(buf, (u_char *) packet, ngx_min(1024, p - packet)) - buf; | 648 m = ngx_hex_dump(buf, (u_char *) packet, ngx_min(1024, p - packet)) - buf; |
749 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | 649 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, |
750 "quic_add_handshake_data packet: %*s%s, len: %uz", | 650 "quic_add_handshake_data packet: %*s%s, len: %uz", |
751 m, buf, len < 2048 ? "" : "...", p - packet); | 651 m, buf, len < 2048 ? "" : "...", p - packet); |