comparison src/event/ngx_event_quic_protection.c @ 8621:9c3be23ddbe7 quic

QUIC: refactored key handling. All key handling functionality is moved into ngx_quic_protection.c. Public structures from ngx_quic_protection.h are now private and new methods are available to manipulate keys. A negotiated cipher is cached in QUIC connection from the set secret callback to avoid calling SSL_get_current_cipher() on each encrypt/decrypt operation. This also reduces the number of unwanted c->ssl->connection occurrences.
author Sergey Kandaurov <pluknet@nginx.com>
date Mon, 02 Nov 2020 18:21:34 +0300
parents f32740ddd484
children 05b1ee464350
comparison
equal deleted inserted replaced
8620:d10118e38943 8621:9c3be23ddbe7
22 #define ngx_quic_cipher_t EVP_AEAD 22 #define ngx_quic_cipher_t EVP_AEAD
23 #else 23 #else
24 #define ngx_quic_cipher_t EVP_CIPHER 24 #define ngx_quic_cipher_t EVP_CIPHER
25 #endif 25 #endif
26 26
27
27 typedef struct { 28 typedef struct {
28 const ngx_quic_cipher_t *c; 29 const ngx_quic_cipher_t *c;
29 const EVP_CIPHER *hp; 30 const EVP_CIPHER *hp;
30 const EVP_MD *d; 31 const EVP_MD *d;
31 } ngx_quic_ciphers_t; 32 } ngx_quic_ciphers_t;
33
34
35 typedef struct ngx_quic_secret_s {
36 ngx_str_t secret;
37 ngx_str_t key;
38 ngx_str_t iv;
39 ngx_str_t hp;
40 } ngx_quic_secret_t;
41
42
43 typedef struct {
44 ngx_quic_secret_t client;
45 ngx_quic_secret_t server;
46 } ngx_quic_secrets_t;
47
48
49 struct ngx_quic_keys_s {
50 ngx_quic_secrets_t secrets[NGX_QUIC_ENCRYPTION_LAST];
51 ngx_quic_secrets_t next_key;
52 ngx_uint_t cipher;
53 };
32 54
33 55
34 static ngx_int_t ngx_hkdf_expand(u_char *out_key, size_t out_len, 56 static ngx_int_t ngx_hkdf_expand(u_char *out_key, size_t out_len,
35 const EVP_MD *digest, const u_char *prk, size_t prk_len, 57 const EVP_MD *digest, const u_char *prk, size_t prk_len,
36 const u_char *info, size_t info_len); 58 const u_char *info, size_t info_len);
39 const u_char *salt, size_t salt_len); 61 const u_char *salt, size_t salt_len);
40 62
41 static uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask, 63 static uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask,
42 uint64_t *largest_pn); 64 uint64_t *largest_pn);
43 static void ngx_quic_compute_nonce(u_char *nonce, size_t len, uint64_t pn); 65 static void ngx_quic_compute_nonce(u_char *nonce, size_t len, uint64_t pn);
44 static ngx_int_t ngx_quic_ciphers(ngx_ssl_conn_t *ssl_conn, 66 static ngx_int_t ngx_quic_ciphers(ngx_uint_t id,
45 ngx_quic_ciphers_t *ciphers, enum ssl_encryption_level_t level); 67 ngx_quic_ciphers_t *ciphers, enum ssl_encryption_level_t level);
46 68
47 static ngx_int_t ngx_quic_tls_open(const ngx_quic_cipher_t *cipher, 69 static ngx_int_t ngx_quic_tls_open(const ngx_quic_cipher_t *cipher,
48 ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce, ngx_str_t *in, 70 ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce, ngx_str_t *in,
49 ngx_str_t *ad, ngx_log_t *log); 71 ngx_str_t *ad, ngx_log_t *log);
54 ngx_quic_secret_t *s, u_char *out, u_char *in); 76 ngx_quic_secret_t *s, u_char *out, u_char *in);
55 static ngx_int_t ngx_quic_hkdf_expand(ngx_pool_t *pool, const EVP_MD *digest, 77 static ngx_int_t ngx_quic_hkdf_expand(ngx_pool_t *pool, const EVP_MD *digest,
56 ngx_str_t *out, ngx_str_t *label, const uint8_t *prk, size_t prk_len); 78 ngx_str_t *out, ngx_str_t *label, const uint8_t *prk, size_t prk_len);
57 79
58 static ngx_int_t ngx_quic_create_long_packet(ngx_quic_header_t *pkt, 80 static ngx_int_t ngx_quic_create_long_packet(ngx_quic_header_t *pkt,
59 ngx_ssl_conn_t *ssl_conn, ngx_str_t *res); 81 ngx_str_t *res);
60 static ngx_int_t ngx_quic_create_short_packet(ngx_quic_header_t *pkt, 82 static ngx_int_t ngx_quic_create_short_packet(ngx_quic_header_t *pkt,
61 ngx_ssl_conn_t *ssl_conn, ngx_str_t *res); 83 ngx_str_t *res);
62 static ngx_int_t ngx_quic_create_retry_packet(ngx_quic_header_t *pkt, 84 static ngx_int_t ngx_quic_create_retry_packet(ngx_quic_header_t *pkt,
63 ngx_str_t *res); 85 ngx_str_t *res);
64 86
65 87
66 static ngx_int_t 88 static ngx_int_t
67 ngx_quic_ciphers(ngx_ssl_conn_t *ssl_conn, ngx_quic_ciphers_t *ciphers, 89 ngx_quic_ciphers(ngx_uint_t id, ngx_quic_ciphers_t *ciphers,
68 enum ssl_encryption_level_t level) 90 enum ssl_encryption_level_t level)
69 { 91 {
70 ngx_int_t id, len; 92 ngx_int_t len;
71 const SSL_CIPHER *cipher;
72 93
73 if (level == ssl_encryption_initial) { 94 if (level == ssl_encryption_initial) {
74 id = NGX_AES_128_GCM_SHA256; 95 id = NGX_AES_128_GCM_SHA256;
75
76 } else {
77 cipher = SSL_get_current_cipher(ssl_conn);
78 if (cipher == NULL) {
79 return NGX_ERROR;
80 }
81
82 id = SSL_CIPHER_get_id(cipher) & 0xffff;
83 } 96 }
84 97
85 switch (id) { 98 switch (id) {
86 99
87 case NGX_AES_128_GCM_SHA256: 100 case NGX_AES_128_GCM_SHA256:
128 return len; 141 return len;
129 } 142 }
130 143
131 144
132 ngx_int_t 145 ngx_int_t
133 ngx_quic_set_initial_secret(ngx_pool_t *pool, ngx_quic_secret_t *client, 146 ngx_quic_keys_set_initial_secret(ngx_pool_t *pool, ngx_quic_keys_t *keys,
134 ngx_quic_secret_t *server, ngx_str_t *secret) 147 ngx_str_t *secret)
135 { 148 {
136 size_t is_len; 149 size_t is_len;
137 uint8_t is[SHA256_DIGEST_LENGTH]; 150 uint8_t is[SHA256_DIGEST_LENGTH];
138 ngx_uint_t i; 151 ngx_uint_t i;
139 const EVP_MD *digest; 152 const EVP_MD *digest;
140 const EVP_CIPHER *cipher; 153 const EVP_CIPHER *cipher;
154 ngx_quic_secret_t *client, *server;
141 155
142 static const uint8_t salt[20] = 156 static const uint8_t salt[20] =
143 #if (NGX_QUIC_DRAFT_VERSION >= 29) 157 #if (NGX_QUIC_DRAFT_VERSION >= 29)
144 "\xaf\xbf\xec\x28\x99\x93\xd2\x4c\x9e\x97" 158 "\xaf\xbf\xec\x28\x99\x93\xd2\x4c\x9e\x97"
145 "\x86\xf1\x9c\x61\x11\xe0\x43\x90\xa8\x99"; 159 "\x86\xf1\x9c\x61\x11\xe0\x43\x90\xa8\x99";
146 #else 160 #else
147 "\xc3\xee\xf7\x12\xc7\x2e\xbb\x5a\x11\xa7" 161 "\xc3\xee\xf7\x12\xc7\x2e\xbb\x5a\x11\xa7"
148 "\xd2\x43\x2b\xb4\x63\x65\xbe\xf9\xf5\x02"; 162 "\xd2\x43\x2b\xb4\x63\x65\xbe\xf9\xf5\x02";
149 #endif 163 #endif
150 164
165 client = &keys->secrets[ssl_encryption_initial].client;
166 server = &keys->secrets[ssl_encryption_initial].server;
167
151 /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */ 168 /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */
152 169
153 cipher = EVP_aes_128_gcm(); 170 cipher = EVP_aes_128_gcm();
154 digest = EVP_sha256(); 171 digest = EVP_sha256();
155 172
624 641
625 return NGX_ERROR; 642 return NGX_ERROR;
626 } 643 }
627 644
628 645
629 int 646 int ngx_quic_keys_set_encryption_secret(ngx_pool_t *pool, ngx_uint_t is_write,
630 ngx_quic_set_encryption_secret(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn, 647 ngx_quic_keys_t *keys, enum ssl_encryption_level_t level,
631 enum ssl_encryption_level_t level, const uint8_t *secret, 648 const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len)
632 size_t secret_len, ngx_quic_secret_t *peer_secret) 649 {
633 { 650 ngx_int_t key_len;
634 ngx_int_t key_len; 651 ngx_uint_t i;
635 ngx_uint_t i; 652 ngx_quic_secret_t *peer_secret;
636 ngx_quic_ciphers_t ciphers; 653 ngx_quic_ciphers_t ciphers;
637 654
638 key_len = ngx_quic_ciphers(ssl_conn, &ciphers, level); 655 peer_secret = is_write ? &keys->secrets[level].server
656 : &keys->secrets[level].client;
657
658 /*
659 * SSL_CIPHER_get_protocol_id() is not universally available,
660 * casting to uint16_t works for both OpenSSL and BoringSSL
661 */
662 keys->cipher = (uint16_t) SSL_CIPHER_get_id(cipher);
663
664 key_len = ngx_quic_ciphers(keys->cipher, &ciphers, level);
639 665
640 if (key_len == NGX_ERROR) { 666 if (key_len == NGX_ERROR) {
641 ngx_ssl_error(NGX_LOG_INFO, pool->log, 0, "unexpected cipher"); 667 ngx_ssl_error(NGX_LOG_INFO, pool->log, 0, "unexpected cipher");
642 return 0; 668 return 0;
643 } 669 }
680 706
681 return 1; 707 return 1;
682 } 708 }
683 709
684 710
711 ngx_quic_keys_t *
712 ngx_quic_keys_new(ngx_pool_t *pool)
713 {
714 return ngx_pcalloc(pool, sizeof(ngx_quic_keys_t));
715 }
716
717
718 ngx_uint_t
719 ngx_quic_keys_available(ngx_quic_keys_t *keys,
720 enum ssl_encryption_level_t level)
721 {
722 return keys->secrets[level].client.key.len != 0;
723 }
724
725
726 void
727 ngx_quic_keys_discard(ngx_quic_keys_t *keys,
728 enum ssl_encryption_level_t level)
729 {
730 keys->secrets[level].client.key.len = 0;
731 }
732
733
734 void
735 ngx_quic_keys_switch(ngx_connection_t *c, ngx_quic_keys_t *keys)
736 {
737 ngx_quic_secrets_t *current, *next, tmp;
738
739 current = &keys->secrets[ssl_encryption_application];
740 next = &keys->next_key;
741
742 tmp = *current;
743 *current = *next;
744 *next = tmp;
745 }
746
747
685 ngx_int_t 748 ngx_int_t
686 ngx_quic_key_update(ngx_connection_t *c, ngx_quic_secrets_t *current, 749 ngx_quic_keys_update(ngx_connection_t *c, ngx_quic_keys_t *keys)
687 ngx_quic_secrets_t *next) 750 {
688 { 751 ngx_uint_t i;
689 ngx_uint_t i; 752 ngx_quic_ciphers_t ciphers;
690 ngx_quic_ciphers_t ciphers; 753 ngx_quic_secrets_t *current, *next;
754
755 current = &keys->secrets[ssl_encryption_application];
756 next = &keys->next_key;
691 757
692 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic key update"); 758 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic key update");
693 759
694 if (ngx_quic_ciphers(c->ssl->connection, &ciphers, 760 if (ngx_quic_ciphers(keys->cipher, &ciphers, ssl_encryption_application)
695 ssl_encryption_application)
696 == NGX_ERROR) 761 == NGX_ERROR)
697 { 762 {
698 return NGX_ERROR; 763 return NGX_ERROR;
699 } 764 }
700 765
758 return NGX_OK; 823 return NGX_OK;
759 } 824 }
760 825
761 826
762 static ngx_int_t 827 static ngx_int_t
763 ngx_quic_create_long_packet(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn, 828 ngx_quic_create_long_packet(ngx_quic_header_t *pkt, ngx_str_t *res)
764 ngx_str_t *res)
765 { 829 {
766 u_char *pnp, *sample; 830 u_char *pnp, *sample;
767 ngx_str_t ad, out; 831 ngx_str_t ad, out;
768 ngx_uint_t i; 832 ngx_uint_t i;
833 ngx_quic_secret_t *secret;
769 ngx_quic_ciphers_t ciphers; 834 ngx_quic_ciphers_t ciphers;
770 u_char nonce[12], mask[16]; 835 u_char nonce[12], mask[16];
771 836
772 out.len = pkt->payload.len + EVP_GCM_TLS_TAG_LEN; 837 out.len = pkt->payload.len + EVP_GCM_TLS_TAG_LEN;
773 838
778 843
779 #ifdef NGX_QUIC_DEBUG_CRYPTO 844 #ifdef NGX_QUIC_DEBUG_CRYPTO
780 ngx_quic_hexdump(pkt->log, "quic ad", ad.data, ad.len); 845 ngx_quic_hexdump(pkt->log, "quic ad", ad.data, ad.len);
781 #endif 846 #endif
782 847
783 if (ngx_quic_ciphers(ssl_conn, &ciphers, pkt->level) == NGX_ERROR) { 848 if (ngx_quic_ciphers(pkt->keys->cipher, &ciphers, pkt->level) == NGX_ERROR)
784 return NGX_ERROR; 849 {
785 } 850 return NGX_ERROR;
786 851 }
787 ngx_memcpy(nonce, pkt->secret->iv.data, pkt->secret->iv.len); 852
853 secret = &pkt->keys->secrets[pkt->level].server;
854
855 ngx_memcpy(nonce, secret->iv.data, secret->iv.len);
788 ngx_quic_compute_nonce(nonce, sizeof(nonce), pkt->number); 856 ngx_quic_compute_nonce(nonce, sizeof(nonce), pkt->number);
789 857
790 if (ngx_quic_tls_seal(ciphers.c, pkt->secret, &out, 858 if (ngx_quic_tls_seal(ciphers.c, secret, &out,
791 nonce, &pkt->payload, &ad, pkt->log) 859 nonce, &pkt->payload, &ad, pkt->log)
792 != NGX_OK) 860 != NGX_OK)
793 { 861 {
794 return NGX_ERROR; 862 return NGX_ERROR;
795 } 863 }
796 864
797 sample = &out.data[4 - pkt->num_len]; 865 sample = &out.data[4 - pkt->num_len];
798 if (ngx_quic_tls_hp(pkt->log, ciphers.hp, pkt->secret, mask, sample) 866 if (ngx_quic_tls_hp(pkt->log, ciphers.hp, secret, mask, sample)
799 != NGX_OK) 867 != NGX_OK)
800 { 868 {
801 return NGX_ERROR; 869 return NGX_ERROR;
802 } 870 }
803 871
813 return NGX_OK; 881 return NGX_OK;
814 } 882 }
815 883
816 884
817 static ngx_int_t 885 static ngx_int_t
818 ngx_quic_create_short_packet(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn, 886 ngx_quic_create_short_packet(ngx_quic_header_t *pkt, ngx_str_t *res)
819 ngx_str_t *res)
820 { 887 {
821 u_char *pnp, *sample; 888 u_char *pnp, *sample;
822 ngx_str_t ad, out; 889 ngx_str_t ad, out;
823 ngx_uint_t i; 890 ngx_uint_t i;
891 ngx_quic_secret_t *secret;
824 ngx_quic_ciphers_t ciphers; 892 ngx_quic_ciphers_t ciphers;
825 u_char nonce[12], mask[16]; 893 u_char nonce[12], mask[16];
826 894
827 out.len = pkt->payload.len + EVP_GCM_TLS_TAG_LEN; 895 out.len = pkt->payload.len + EVP_GCM_TLS_TAG_LEN;
828 896
833 901
834 #ifdef NGX_QUIC_DEBUG_CRYPTO 902 #ifdef NGX_QUIC_DEBUG_CRYPTO
835 ngx_quic_hexdump(pkt->log, "quic ad", ad.data, ad.len); 903 ngx_quic_hexdump(pkt->log, "quic ad", ad.data, ad.len);
836 #endif 904 #endif
837 905
838 if (ngx_quic_ciphers(ssl_conn, &ciphers, pkt->level) == NGX_ERROR) { 906 if (ngx_quic_ciphers(pkt->keys->cipher, &ciphers, pkt->level) == NGX_ERROR)
839 return NGX_ERROR; 907 {
840 } 908 return NGX_ERROR;
841 909 }
842 ngx_memcpy(nonce, pkt->secret->iv.data, pkt->secret->iv.len); 910
911 secret = &pkt->keys->secrets[pkt->level].server;
912
913 ngx_memcpy(nonce, secret->iv.data, secret->iv.len);
843 ngx_quic_compute_nonce(nonce, sizeof(nonce), pkt->number); 914 ngx_quic_compute_nonce(nonce, sizeof(nonce), pkt->number);
844 915
845 if (ngx_quic_tls_seal(ciphers.c, pkt->secret, &out, 916 if (ngx_quic_tls_seal(ciphers.c, secret, &out,
846 nonce, &pkt->payload, &ad, pkt->log) 917 nonce, &pkt->payload, &ad, pkt->log)
847 != NGX_OK) 918 != NGX_OK)
848 { 919 {
849 return NGX_ERROR; 920 return NGX_ERROR;
850 } 921 }
851 922
852 sample = &out.data[4 - pkt->num_len]; 923 sample = &out.data[4 - pkt->num_len];
853 if (ngx_quic_tls_hp(pkt->log, ciphers.hp, pkt->secret, mask, sample) 924 if (ngx_quic_tls_hp(pkt->log, ciphers.hp, secret, mask, sample)
854 != NGX_OK) 925 != NGX_OK)
855 { 926 {
856 return NGX_ERROR; 927 return NGX_ERROR;
857 } 928 }
858 929
900 971
901 #ifdef NGX_QUIC_DEBUG_CRYPTO 972 #ifdef NGX_QUIC_DEBUG_CRYPTO
902 ngx_quic_hexdump(pkt->log, "quic retry itag", ad.data, ad.len); 973 ngx_quic_hexdump(pkt->log, "quic retry itag", ad.data, ad.len);
903 #endif 974 #endif
904 975
905 if (ngx_quic_ciphers(NULL, &ciphers, pkt->level) == NGX_ERROR) { 976 if (ngx_quic_ciphers(0, &ciphers, pkt->level) == NGX_ERROR) {
906 return NGX_ERROR; 977 return NGX_ERROR;
907 } 978 }
908 979
909 secret.key.len = sizeof(key); 980 secret.key.len = sizeof(key);
910 secret.key.data = key; 981 secret.key.data = key;
1031 nonce[len - 1] ^= (pn & 0x000000ff); 1102 nonce[len - 1] ^= (pn & 0x000000ff);
1032 } 1103 }
1033 1104
1034 1105
1035 ngx_int_t 1106 ngx_int_t
1036 ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn, 1107 ngx_quic_encrypt(ngx_quic_header_t *pkt, ngx_str_t *res)
1037 ngx_str_t *res)
1038 { 1108 {
1039 if (ngx_quic_short_pkt(pkt->flags)) { 1109 if (ngx_quic_short_pkt(pkt->flags)) {
1040 return ngx_quic_create_short_packet(pkt, ssl_conn, res); 1110 return ngx_quic_create_short_packet(pkt, res);
1041 } 1111 }
1042 1112
1043 if (ngx_quic_pkt_retry(pkt->flags)) { 1113 if (ngx_quic_pkt_retry(pkt->flags)) {
1044 return ngx_quic_create_retry_packet(pkt, res); 1114 return ngx_quic_create_retry_packet(pkt, res);
1045 } 1115 }
1046 1116
1047 return ngx_quic_create_long_packet(pkt, ssl_conn, res); 1117 return ngx_quic_create_long_packet(pkt, res);
1048 } 1118 }
1049 1119
1050 1120
1051 ngx_int_t 1121 ngx_int_t
1052 ngx_quic_decrypt(ngx_quic_header_t *pkt, ngx_ssl_conn_t *ssl_conn, 1122 ngx_quic_decrypt(ngx_quic_header_t *pkt, uint64_t *largest_pn)
1053 uint64_t *largest_pn)
1054 { 1123 {
1055 u_char clearflags, *p, *sample; 1124 u_char clearflags, *p, *sample;
1056 size_t len; 1125 size_t len;
1057 uint8_t badflags; 1126 uint8_t badflags;
1058 uint64_t pn, lpn; 1127 uint64_t pn, lpn;
1060 ngx_str_t in, ad; 1129 ngx_str_t in, ad;
1061 ngx_quic_secret_t *secret; 1130 ngx_quic_secret_t *secret;
1062 ngx_quic_ciphers_t ciphers; 1131 ngx_quic_ciphers_t ciphers;
1063 uint8_t mask[16], nonce[12]; 1132 uint8_t mask[16], nonce[12];
1064 1133
1065 if (ngx_quic_ciphers(ssl_conn, &ciphers, pkt->level) == NGX_ERROR) { 1134 if (ngx_quic_ciphers(pkt->keys->cipher, &ciphers, pkt->level) == NGX_ERROR)
1066 return NGX_ERROR; 1135 {
1067 } 1136 return NGX_ERROR;
1068 1137 }
1069 secret = pkt->secret; 1138
1139 secret = &pkt->keys->secrets[pkt->level].client;
1070 1140
1071 p = pkt->raw->pos; 1141 p = pkt->raw->pos;
1072 len = pkt->data + pkt->len - p; 1142 len = pkt->data + pkt->len - p;
1073 1143
1074 /* draft-ietf-quic-tls-23#section-5.4.2: 1144 /* draft-ietf-quic-tls-23#section-5.4.2:
1097 } else { 1167 } else {
1098 clearflags = pkt->flags ^ (mask[0] & 0x1f); 1168 clearflags = pkt->flags ^ (mask[0] & 0x1f);
1099 key_phase = (clearflags & NGX_QUIC_PKT_KPHASE) != 0; 1169 key_phase = (clearflags & NGX_QUIC_PKT_KPHASE) != 0;
1100 1170
1101 if (key_phase != pkt->key_phase) { 1171 if (key_phase != pkt->key_phase) {
1102 secret = pkt->next; 1172 secret = &pkt->keys->next_key.client;
1103 pkt->key_update = 1; 1173 pkt->key_update = 1;
1104 } 1174 }
1105 } 1175 }
1106 1176
1107 lpn = *largest_pn; 1177 lpn = *largest_pn;