Mercurial > hg > nginx
comparison src/event/quic/ngx_event_quic_protection.c @ 9174:31702c53d2db
QUIC: reusing crypto contexts for header protection.
author | Sergey Kandaurov <pluknet@nginx.com> |
---|---|
date | Fri, 20 Oct 2023 18:05:07 +0400 |
parents | 904a54092d5b |
children | f7c9cd726298 |
comparison
equal
deleted
inserted
replaced
9173:904a54092d5b | 9174:31702c53d2db |
---|---|
30 u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log); | 30 u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log); |
31 #ifndef OPENSSL_IS_BORINGSSL | 31 #ifndef OPENSSL_IS_BORINGSSL |
32 static ngx_int_t ngx_quic_crypto_common(ngx_quic_secret_t *s, ngx_str_t *out, | 32 static ngx_int_t ngx_quic_crypto_common(ngx_quic_secret_t *s, ngx_str_t *out, |
33 u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log); | 33 u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log); |
34 #endif | 34 #endif |
35 static ngx_int_t ngx_quic_crypto_hp(ngx_log_t *log, const EVP_CIPHER *cipher, | 35 |
36 ngx_quic_secret_t *s, u_char *out, u_char *in); | 36 static ngx_int_t ngx_quic_crypto_hp_init(const EVP_CIPHER *cipher, |
37 ngx_quic_secret_t *s, ngx_log_t *log); | |
38 static ngx_int_t ngx_quic_crypto_hp(ngx_quic_secret_t *s, | |
39 u_char *out, u_char *in, ngx_log_t *log); | |
40 static void ngx_quic_crypto_hp_cleanup(ngx_quic_secret_t *s); | |
37 | 41 |
38 static ngx_int_t ngx_quic_create_packet(ngx_quic_header_t *pkt, | 42 static ngx_int_t ngx_quic_create_packet(ngx_quic_header_t *pkt, |
39 ngx_str_t *res); | 43 ngx_str_t *res); |
40 static ngx_int_t ngx_quic_create_retry_packet(ngx_quic_header_t *pkt, | 44 static ngx_int_t ngx_quic_create_retry_packet(ngx_quic_header_t *pkt, |
41 ngx_str_t *res); | 45 ngx_str_t *res); |
194 | 198 |
195 if (ngx_quic_crypto_init(ciphers.c, server, 1, log) == NGX_ERROR) { | 199 if (ngx_quic_crypto_init(ciphers.c, server, 1, log) == NGX_ERROR) { |
196 goto failed; | 200 goto failed; |
197 } | 201 } |
198 | 202 |
203 if (ngx_quic_crypto_hp_init(ciphers.hp, client, log) == NGX_ERROR) { | |
204 goto failed; | |
205 } | |
206 | |
207 if (ngx_quic_crypto_hp_init(ciphers.hp, server, log) == NGX_ERROR) { | |
208 goto failed; | |
209 } | |
210 | |
199 return NGX_OK; | 211 return NGX_OK; |
200 | 212 |
201 failed: | 213 failed: |
202 | 214 |
203 ngx_quic_keys_cleanup(keys); | 215 ngx_quic_keys_cleanup(keys); |
554 } | 566 } |
555 } | 567 } |
556 | 568 |
557 | 569 |
558 static ngx_int_t | 570 static ngx_int_t |
559 ngx_quic_crypto_hp(ngx_log_t *log, const EVP_CIPHER *cipher, | 571 ngx_quic_crypto_hp_init(const EVP_CIPHER *cipher, ngx_quic_secret_t *s, |
560 ngx_quic_secret_t *s, u_char *out, u_char *in) | 572 ngx_log_t *log) |
573 { | |
574 EVP_CIPHER_CTX *ctx; | |
575 | |
576 #ifdef OPENSSL_IS_BORINGSSL | |
577 if (cipher == (EVP_CIPHER *) EVP_aead_chacha20_poly1305()) { | |
578 /* no EVP interface */ | |
579 s->hp_ctx = NULL; | |
580 return NGX_OK; | |
581 } | |
582 #endif | |
583 | |
584 ctx = EVP_CIPHER_CTX_new(); | |
585 if (ctx == NULL) { | |
586 ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_CIPHER_CTX_new() failed"); | |
587 return NGX_ERROR; | |
588 } | |
589 | |
590 if (EVP_EncryptInit_ex(ctx, cipher, NULL, s->hp.data, NULL) != 1) { | |
591 EVP_CIPHER_CTX_free(ctx); | |
592 ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_EncryptInit_ex() failed"); | |
593 return NGX_ERROR; | |
594 } | |
595 | |
596 s->hp_ctx = ctx; | |
597 return NGX_OK; | |
598 } | |
599 | |
600 | |
601 static ngx_int_t | |
602 ngx_quic_crypto_hp(ngx_quic_secret_t *s, u_char *out, u_char *in, | |
603 ngx_log_t *log) | |
561 { | 604 { |
562 int outlen; | 605 int outlen; |
563 EVP_CIPHER_CTX *ctx; | 606 EVP_CIPHER_CTX *ctx; |
564 u_char zero[NGX_QUIC_HP_LEN] = {0}; | 607 u_char zero[NGX_QUIC_HP_LEN] = {0}; |
565 | 608 |
609 ctx = s->hp_ctx; | |
610 | |
566 #ifdef OPENSSL_IS_BORINGSSL | 611 #ifdef OPENSSL_IS_BORINGSSL |
567 uint32_t cnt; | 612 uint32_t cnt; |
568 | 613 |
569 ngx_memcpy(&cnt, in, sizeof(uint32_t)); | 614 if (ctx == NULL) { |
570 | 615 ngx_memcpy(&cnt, in, sizeof(uint32_t)); |
571 if (cipher == (const EVP_CIPHER *) EVP_aead_chacha20_poly1305()) { | |
572 CRYPTO_chacha_20(out, zero, NGX_QUIC_HP_LEN, s->hp.data, &in[4], cnt); | 616 CRYPTO_chacha_20(out, zero, NGX_QUIC_HP_LEN, s->hp.data, &in[4], cnt); |
573 return NGX_OK; | 617 return NGX_OK; |
574 } | 618 } |
575 #endif | 619 #endif |
576 | 620 |
577 ctx = EVP_CIPHER_CTX_new(); | 621 if (EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, in) != 1) { |
578 if (ctx == NULL) { | |
579 return NGX_ERROR; | |
580 } | |
581 | |
582 if (EVP_EncryptInit_ex(ctx, cipher, NULL, s->hp.data, in) != 1) { | |
583 ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_EncryptInit_ex() failed"); | 622 ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_EncryptInit_ex() failed"); |
584 goto failed; | 623 return NGX_ERROR; |
585 } | 624 } |
586 | 625 |
587 if (!EVP_EncryptUpdate(ctx, out, &outlen, zero, NGX_QUIC_HP_LEN)) { | 626 if (!EVP_EncryptUpdate(ctx, out, &outlen, zero, NGX_QUIC_HP_LEN)) { |
588 ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_EncryptUpdate() failed"); | 627 ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_EncryptUpdate() failed"); |
589 goto failed; | 628 return NGX_ERROR; |
590 } | 629 } |
591 | 630 |
592 if (!EVP_EncryptFinal_ex(ctx, out + NGX_QUIC_HP_LEN, &outlen)) { | 631 if (!EVP_EncryptFinal_ex(ctx, out + NGX_QUIC_HP_LEN, &outlen)) { |
593 ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_EncryptFinal_Ex() failed"); | 632 ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_EncryptFinal_Ex() failed"); |
594 goto failed; | 633 return NGX_ERROR; |
595 } | 634 } |
596 | 635 |
597 EVP_CIPHER_CTX_free(ctx); | 636 return NGX_OK; |
598 | 637 } |
599 return NGX_OK; | 638 |
600 | 639 |
601 failed: | 640 static void |
602 | 641 ngx_quic_crypto_hp_cleanup(ngx_quic_secret_t *s) |
603 EVP_CIPHER_CTX_free(ctx); | 642 { |
604 | 643 if (s->hp_ctx) { |
605 return NGX_ERROR; | 644 EVP_CIPHER_CTX_free(s->hp_ctx); |
645 s->hp_ctx = NULL; | |
646 } | |
606 } | 647 } |
607 | 648 |
608 | 649 |
609 ngx_int_t | 650 ngx_int_t |
610 ngx_quic_keys_set_encryption_secret(ngx_log_t *log, ngx_uint_t is_write, | 651 ngx_quic_keys_set_encryption_secret(ngx_log_t *log, ngx_uint_t is_write, |
661 == NGX_ERROR) | 702 == NGX_ERROR) |
662 { | 703 { |
663 return NGX_ERROR; | 704 return NGX_ERROR; |
664 } | 705 } |
665 | 706 |
707 if (ngx_quic_crypto_hp_init(ciphers.hp, peer_secret, log) == NGX_ERROR) { | |
708 return NGX_ERROR; | |
709 } | |
710 | |
666 return NGX_OK; | 711 return NGX_OK; |
667 } | 712 } |
668 | 713 |
669 | 714 |
670 ngx_uint_t | 715 ngx_uint_t |
688 client = &keys->secrets[level].client; | 733 client = &keys->secrets[level].client; |
689 server = &keys->secrets[level].server; | 734 server = &keys->secrets[level].server; |
690 | 735 |
691 ngx_quic_crypto_cleanup(client); | 736 ngx_quic_crypto_cleanup(client); |
692 ngx_quic_crypto_cleanup(server); | 737 ngx_quic_crypto_cleanup(server); |
738 | |
739 ngx_quic_crypto_hp_cleanup(client); | |
740 ngx_quic_crypto_hp_cleanup(server); | |
693 } | 741 } |
694 | 742 |
695 | 743 |
696 void | 744 void |
697 ngx_quic_keys_switch(ngx_connection_t *c, ngx_quic_keys_t *keys) | 745 ngx_quic_keys_switch(ngx_connection_t *c, ngx_quic_keys_t *keys) |
740 | 788 |
741 next->client.secret.len = current->client.secret.len; | 789 next->client.secret.len = current->client.secret.len; |
742 next->client.key.len = current->client.key.len; | 790 next->client.key.len = current->client.key.len; |
743 next->client.iv.len = NGX_QUIC_IV_LEN; | 791 next->client.iv.len = NGX_QUIC_IV_LEN; |
744 next->client.hp = current->client.hp; | 792 next->client.hp = current->client.hp; |
793 next->client.hp_ctx = current->client.hp_ctx; | |
745 | 794 |
746 next->server.secret.len = current->server.secret.len; | 795 next->server.secret.len = current->server.secret.len; |
747 next->server.key.len = current->server.key.len; | 796 next->server.key.len = current->server.key.len; |
748 next->server.iv.len = NGX_QUIC_IV_LEN; | 797 next->server.iv.len = NGX_QUIC_IV_LEN; |
749 next->server.hp = current->server.hp; | 798 next->server.hp = current->server.hp; |
799 next->server.hp_ctx = current->server.hp_ctx; | |
750 | 800 |
751 ngx_quic_hkdf_set(&seq[0], "tls13 quic ku", | 801 ngx_quic_hkdf_set(&seq[0], "tls13 quic ku", |
752 &next->client.secret, ¤t->client.secret); | 802 &next->client.secret, ¤t->client.secret); |
753 ngx_quic_hkdf_set(&seq[1], "tls13 quic key", | 803 ngx_quic_hkdf_set(&seq[1], "tls13 quic key", |
754 &next->client.key, &next->client.secret); | 804 &next->client.key, &next->client.secret); |
838 { | 888 { |
839 return NGX_ERROR; | 889 return NGX_ERROR; |
840 } | 890 } |
841 | 891 |
842 sample = &out.data[4 - pkt->num_len]; | 892 sample = &out.data[4 - pkt->num_len]; |
843 if (ngx_quic_crypto_hp(pkt->log, ciphers.hp, secret, mask, sample) | 893 if (ngx_quic_crypto_hp(secret, mask, sample, pkt->log) != NGX_OK) { |
844 != NGX_OK) | |
845 { | |
846 return NGX_ERROR; | 894 return NGX_ERROR; |
847 } | 895 } |
848 | 896 |
849 /* RFC 9001, 5.4.1. Header Protection Application */ | 897 /* RFC 9001, 5.4.1. Header Protection Application */ |
850 ad.data[0] ^= mask[0] & ngx_quic_pkt_hp_mask(pkt->flags); | 898 ad.data[0] ^= mask[0] & ngx_quic_pkt_hp_mask(pkt->flags); |
1068 | 1116 |
1069 sample = p + 4; | 1117 sample = p + 4; |
1070 | 1118 |
1071 /* header protection */ | 1119 /* header protection */ |
1072 | 1120 |
1073 if (ngx_quic_crypto_hp(pkt->log, ciphers.hp, secret, mask, sample) | 1121 if (ngx_quic_crypto_hp(secret, mask, sample, pkt->log) != NGX_OK) { |
1074 != NGX_OK) | |
1075 { | |
1076 return NGX_DECLINED; | 1122 return NGX_DECLINED; |
1077 } | 1123 } |
1078 | 1124 |
1079 pkt->flags ^= mask[0] & ngx_quic_pkt_hp_mask(pkt->flags); | 1125 pkt->flags ^= mask[0] & ngx_quic_pkt_hp_mask(pkt->flags); |
1080 | 1126 |