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, &current->client.secret); 802 &next->client.secret, &current->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