/src/samba/third_party/ngtcp2/lib/ngtcp2_ppe.c
Line | Count | Source |
1 | | /* |
2 | | * ngtcp2 |
3 | | * |
4 | | * Copyright (c) 2017 ngtcp2 contributors |
5 | | * |
6 | | * Permission is hereby granted, free of charge, to any person obtaining |
7 | | * a copy of this software and associated documentation files (the |
8 | | * "Software"), to deal in the Software without restriction, including |
9 | | * without limitation the rights to use, copy, modify, merge, publish, |
10 | | * distribute, sublicense, and/or sell copies of the Software, and to |
11 | | * permit persons to whom the Software is furnished to do so, subject to |
12 | | * the following conditions: |
13 | | * |
14 | | * The above copyright notice and this permission notice shall be |
15 | | * included in all copies or substantial portions of the Software. |
16 | | * |
17 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
18 | | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
19 | | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
20 | | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
21 | | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
22 | | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
23 | | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
24 | | */ |
25 | | #include "ngtcp2_ppe.h" |
26 | | |
27 | | #include <string.h> |
28 | | #include <assert.h> |
29 | | |
30 | | #include "ngtcp2_str.h" |
31 | | #include "ngtcp2_conv.h" |
32 | | #include "ngtcp2_macro.h" |
33 | | |
34 | | void ngtcp2_ppe_init(ngtcp2_ppe *ppe, uint8_t *out, size_t outlen, |
35 | 0 | size_t dgram_offset, ngtcp2_crypto_cc *cc) { |
36 | 0 | ngtcp2_buf_init(&ppe->buf, out, outlen); |
37 | |
|
38 | 0 | ppe->dgram_offset = dgram_offset; |
39 | 0 | ppe->hdlen = 0; |
40 | 0 | ppe->len_offset = 0; |
41 | 0 | ppe->pkt_num_offset = 0; |
42 | 0 | ppe->pkt_numlen = 0; |
43 | 0 | ppe->pkt_num = 0; |
44 | 0 | ppe->cc = cc; |
45 | 0 | } |
46 | | |
47 | 0 | int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd) { |
48 | 0 | ngtcp2_ssize rv; |
49 | 0 | ngtcp2_buf *buf = &ppe->buf; |
50 | 0 | size_t buf_left = ngtcp2_buf_left(buf); |
51 | 0 | ngtcp2_crypto_cc *cc = ppe->cc; |
52 | |
|
53 | 0 | if (buf_left <= cc->aead.max_overhead) { |
54 | 0 | return NGTCP2_ERR_NOBUF; |
55 | 0 | } |
56 | | |
57 | 0 | if (hd->flags & NGTCP2_PKT_FLAG_LONG_FORM) { |
58 | 0 | ppe->len_offset = 1 + 4 + 1 + hd->dcid.datalen + 1 + hd->scid.datalen; |
59 | |
|
60 | 0 | if (hd->type == NGTCP2_PKT_INITIAL) { |
61 | 0 | ppe->len_offset += ngtcp2_put_uvarintlen(hd->tokenlen) + hd->tokenlen; |
62 | 0 | } |
63 | |
|
64 | 0 | ppe->pkt_num_offset = ppe->len_offset + NGTCP2_PKT_LENGTHLEN; |
65 | |
|
66 | 0 | rv = ngtcp2_pkt_encode_hd_long(buf->last, buf_left - cc->aead.max_overhead, |
67 | 0 | hd); |
68 | 0 | } else { |
69 | 0 | ppe->pkt_num_offset = 1 + hd->dcid.datalen; |
70 | |
|
71 | 0 | rv = ngtcp2_pkt_encode_hd_short(buf->last, buf_left - cc->aead.max_overhead, |
72 | 0 | hd); |
73 | 0 | } |
74 | |
|
75 | 0 | if (rv < 0) { |
76 | 0 | return (int)rv; |
77 | 0 | } |
78 | | |
79 | 0 | buf->last += rv; |
80 | |
|
81 | 0 | ppe->pkt_numlen = hd->pkt_numlen; |
82 | 0 | ppe->hdlen = (size_t)rv; |
83 | 0 | ppe->pkt_num = hd->pkt_num; |
84 | |
|
85 | 0 | return 0; |
86 | 0 | } |
87 | | |
88 | 0 | int ngtcp2_ppe_encode_frame(ngtcp2_ppe *ppe, ngtcp2_frame *fr) { |
89 | 0 | ngtcp2_ssize rv; |
90 | 0 | ngtcp2_buf *buf = &ppe->buf; |
91 | 0 | size_t buf_left = ngtcp2_buf_left(buf); |
92 | 0 | ngtcp2_crypto_cc *cc = ppe->cc; |
93 | |
|
94 | 0 | if (buf_left <= cc->aead.max_overhead) { |
95 | 0 | return NGTCP2_ERR_NOBUF; |
96 | 0 | } |
97 | | |
98 | 0 | rv = ngtcp2_pkt_encode_frame(buf->last, buf_left - cc->aead.max_overhead, fr); |
99 | 0 | if (rv < 0) { |
100 | 0 | return (int)rv; |
101 | 0 | } |
102 | | |
103 | 0 | buf->last += rv; |
104 | |
|
105 | 0 | return 0; |
106 | 0 | } |
107 | | |
108 | | /* |
109 | | * ppe_sample_offset returns the offset to sample for packet number |
110 | | * encryption. |
111 | | */ |
112 | 0 | static size_t ppe_sample_offset(ngtcp2_ppe *ppe) { |
113 | 0 | return ppe->pkt_num_offset + 4; |
114 | 0 | } |
115 | | |
116 | 0 | ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt) { |
117 | 0 | ngtcp2_buf *buf = &ppe->buf; |
118 | 0 | ngtcp2_crypto_cc *cc = ppe->cc; |
119 | 0 | uint8_t *payload = buf->begin + ppe->hdlen; |
120 | 0 | size_t payloadlen = ngtcp2_buf_len(buf) - ppe->hdlen; |
121 | 0 | uint8_t mask[NGTCP2_HP_SAMPLELEN]; |
122 | 0 | uint8_t *p; |
123 | 0 | size_t i; |
124 | 0 | int rv; |
125 | |
|
126 | 0 | assert(cc->encrypt); |
127 | 0 | assert(cc->hp_mask); |
128 | |
|
129 | 0 | if (ppe->len_offset) { |
130 | 0 | ngtcp2_put_uvarint30( |
131 | 0 | buf->begin + ppe->len_offset, |
132 | 0 | (uint16_t)(payloadlen + ppe->pkt_numlen + cc->aead.max_overhead)); |
133 | 0 | } |
134 | |
|
135 | 0 | ngtcp2_crypto_create_nonce(ppe->nonce, cc->ckm->iv.base, cc->ckm->iv.len, |
136 | 0 | ppe->pkt_num); |
137 | |
|
138 | 0 | rv = cc->encrypt(payload, &cc->aead, &cc->ckm->aead_ctx, payload, payloadlen, |
139 | 0 | ppe->nonce, cc->ckm->iv.len, buf->begin, ppe->hdlen); |
140 | 0 | if (rv != 0) { |
141 | 0 | return NGTCP2_ERR_CALLBACK_FAILURE; |
142 | 0 | } |
143 | | |
144 | 0 | buf->last = payload + payloadlen + cc->aead.max_overhead; |
145 | | |
146 | | /* Make sure that we have enough space to get sample */ |
147 | 0 | assert(ppe_sample_offset(ppe) + NGTCP2_HP_SAMPLELEN <= ngtcp2_buf_len(buf)); |
148 | |
|
149 | 0 | rv = cc->hp_mask(mask, &cc->hp, &cc->hp_ctx, |
150 | 0 | buf->begin + ppe_sample_offset(ppe)); |
151 | 0 | if (rv != 0) { |
152 | 0 | return NGTCP2_ERR_CALLBACK_FAILURE; |
153 | 0 | } |
154 | | |
155 | 0 | p = buf->begin; |
156 | 0 | if (*p & NGTCP2_HEADER_FORM_BIT) { |
157 | 0 | *p = (uint8_t)(*p ^ (mask[0] & 0x0F)); |
158 | 0 | } else { |
159 | 0 | *p = (uint8_t)(*p ^ (mask[0] & 0x1F)); |
160 | 0 | } |
161 | |
|
162 | 0 | p = buf->begin + ppe->pkt_num_offset; |
163 | 0 | for (i = 0; i < ppe->pkt_numlen; ++i) { |
164 | 0 | *(p + i) ^= mask[i + 1]; |
165 | 0 | } |
166 | |
|
167 | 0 | if (ppkt != NULL) { |
168 | 0 | *ppkt = buf->begin; |
169 | 0 | } |
170 | |
|
171 | 0 | return (ngtcp2_ssize)ngtcp2_buf_len(buf); |
172 | 0 | } |
173 | | |
174 | 0 | size_t ngtcp2_ppe_left(const ngtcp2_ppe *ppe) { |
175 | 0 | ngtcp2_crypto_cc *cc = ppe->cc; |
176 | 0 | size_t buf_left = ngtcp2_buf_left(&ppe->buf); |
177 | |
|
178 | 0 | if (buf_left <= cc->aead.max_overhead) { |
179 | 0 | return 0; |
180 | 0 | } |
181 | | |
182 | 0 | return buf_left - cc->aead.max_overhead; |
183 | 0 | } |
184 | | |
185 | 0 | size_t ngtcp2_ppe_padding_size(ngtcp2_ppe *ppe, size_t n) { |
186 | 0 | ngtcp2_crypto_cc *cc = ppe->cc; |
187 | 0 | ngtcp2_buf *buf = &ppe->buf; |
188 | 0 | size_t pktlen = ngtcp2_buf_len(buf) + cc->aead.max_overhead; |
189 | 0 | size_t len = 0; |
190 | 0 | size_t max_samplelen; |
191 | |
|
192 | 0 | n = ngtcp2_min_size(n, ngtcp2_buf_cap(buf)); |
193 | 0 | if (pktlen < n) { |
194 | 0 | len = n - pktlen; |
195 | 0 | } |
196 | | |
197 | | /* Ensure header protection sample */ |
198 | 0 | max_samplelen = |
199 | 0 | ngtcp2_buf_len(buf) + cc->aead.max_overhead - ppe_sample_offset(ppe); |
200 | |
|
201 | 0 | if (max_samplelen < NGTCP2_HP_SAMPLELEN) { |
202 | 0 | len = ngtcp2_max_size(len, NGTCP2_HP_SAMPLELEN - max_samplelen); |
203 | 0 | } |
204 | |
|
205 | 0 | assert(ngtcp2_buf_left(buf) >= len + cc->aead.max_overhead); |
206 | |
|
207 | 0 | if (len == 0) { |
208 | 0 | return 0; |
209 | 0 | } |
210 | | |
211 | 0 | buf->last = ngtcp2_setmem(buf->last, 0, len); |
212 | |
|
213 | 0 | return len; |
214 | 0 | } |
215 | | |
216 | 0 | size_t ngtcp2_ppe_dgram_padding(ngtcp2_ppe *ppe) { |
217 | 0 | return ngtcp2_ppe_dgram_padding_size(ppe, NGTCP2_MAX_UDP_PAYLOAD_SIZE); |
218 | 0 | } |
219 | | |
220 | 0 | size_t ngtcp2_ppe_dgram_padding_size(ngtcp2_ppe *ppe, size_t n) { |
221 | 0 | ngtcp2_crypto_cc *cc = ppe->cc; |
222 | 0 | ngtcp2_buf *buf = &ppe->buf; |
223 | 0 | size_t dgramlen = |
224 | 0 | ppe->dgram_offset + ngtcp2_buf_len(buf) + cc->aead.max_overhead; |
225 | 0 | size_t len; |
226 | |
|
227 | 0 | n = ngtcp2_min_size(n, ppe->dgram_offset + ngtcp2_buf_cap(buf)); |
228 | |
|
229 | 0 | if (dgramlen >= n) { |
230 | 0 | return 0; |
231 | 0 | } |
232 | | |
233 | 0 | len = n - dgramlen; |
234 | 0 | buf->last = ngtcp2_setmem(buf->last, 0, len); |
235 | |
|
236 | 0 | return len; |
237 | 0 | } |
238 | | |
239 | 0 | int ngtcp2_ppe_ensure_hp_sample(ngtcp2_ppe *ppe) { |
240 | 0 | ngtcp2_buf *buf = &ppe->buf; |
241 | |
|
242 | 0 | return ngtcp2_buf_left(buf) >= (4 - ppe->pkt_numlen) + NGTCP2_HP_SAMPLELEN; |
243 | 0 | } |