File: | utils/ssl_certs.c |
Warning: | line 194, column 7 Value stored to 'kvlen' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright 2020 Vincent Sanders <vince@netsurf-browser.org> |
3 | * |
4 | * This file is part of NetSurf, http://www.netsurf-browser.org/ |
5 | * |
6 | * NetSurf is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; version 2 of the License. |
9 | * |
10 | * NetSurf is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | /** |
20 | * \file |
21 | * helpers for X509 certificate chains |
22 | */ |
23 | |
24 | #include <stdlib.h> |
25 | #include <stdint.h> |
26 | #include <string.h> |
27 | #include <nsutils/base64.h> |
28 | |
29 | #include "utils/errors.h" |
30 | #include "utils/log.h" |
31 | #include "utils/nsurl.h" |
32 | |
33 | #include "netsurf/ssl_certs.h" |
34 | |
35 | /* |
36 | * create new certificate chain |
37 | * |
38 | * exported interface documented in netsurf/ssl_certs.h |
39 | */ |
40 | nserror |
41 | cert_chain_alloc(size_t depth, struct cert_chain **chain_out) |
42 | { |
43 | struct cert_chain* chain; |
44 | |
45 | chain = calloc(1, sizeof(struct cert_chain)); |
46 | if (chain == NULL((void*)0)) { |
47 | return NSERROR_NOMEM; |
48 | } |
49 | |
50 | chain->depth = depth; |
51 | |
52 | *chain_out = chain; |
53 | |
54 | return NSERROR_OK; |
55 | } |
56 | |
57 | |
58 | /* |
59 | * duplicate certificate chain into existing chain |
60 | * |
61 | * exported interface documented in netsurf/ssl_certs.h |
62 | */ |
63 | nserror |
64 | cert_chain_dup_into(const struct cert_chain *src, struct cert_chain *dst) |
65 | { |
66 | size_t depth; |
67 | for (depth = 0; depth < dst->depth; depth++) { |
68 | if (dst->certs[depth].der != NULL((void*)0)) { |
69 | free(dst->certs[depth].der); |
70 | dst->certs[depth].der = NULL((void*)0); |
71 | } |
72 | } |
73 | |
74 | dst->depth = src->depth; |
75 | |
76 | for (depth = 0; depth < src->depth; depth++) { |
77 | dst->certs[depth].err = src->certs[depth].err; |
78 | dst->certs[depth].der_length = src->certs[depth].der_length; |
79 | if (src->certs[depth].der != NULL((void*)0)) { |
80 | dst->certs[depth].der = malloc(src->certs[depth].der_length); |
81 | if (dst->certs[depth].der == NULL((void*)0)) { |
82 | return NSERROR_NOMEM; |
83 | } |
84 | memcpy(dst->certs[depth].der, |
85 | src->certs[depth].der, |
86 | src->certs[depth].der_length); |
87 | } |
88 | |
89 | } |
90 | |
91 | return NSERROR_OK; |
92 | } |
93 | |
94 | |
95 | /* |
96 | * duplicate certificate chain |
97 | * |
98 | * exported interface documented in netsurf/ssl_certs.h |
99 | */ |
100 | nserror |
101 | cert_chain_dup(const struct cert_chain *src, struct cert_chain **dst_out) |
102 | { |
103 | struct cert_chain* dst; |
104 | size_t depth; |
105 | nserror res; |
106 | |
107 | res = cert_chain_alloc(src->depth, &dst); |
108 | if (res != NSERROR_OK) { |
109 | return res; |
110 | } |
111 | |
112 | for (depth = 0; depth < src->depth; depth++) { |
113 | dst->certs[depth].err = src->certs[depth].err; |
114 | dst->certs[depth].der_length = src->certs[depth].der_length; |
115 | if (src->certs[depth].der != NULL((void*)0)) { |
116 | dst->certs[depth].der = malloc(src->certs[depth].der_length); |
117 | if (dst->certs[depth].der == NULL((void*)0)) { |
118 | cert_chain_free(dst); |
119 | return NSERROR_NOMEM; |
120 | } |
121 | memcpy(dst->certs[depth].der, |
122 | src->certs[depth].der, |
123 | src->certs[depth].der_length); |
124 | } |
125 | |
126 | } |
127 | |
128 | *dst_out = dst; |
129 | return NSERROR_OK; |
130 | } |
131 | |
132 | |
133 | #define MIN_CERT_LEN64 64 |
134 | |
135 | /** |
136 | * process a part of a query extracting the certificate of an error code |
137 | */ |
138 | static nserror |
139 | process_query_section(const char *str, size_t len, struct cert_chain* chain) |
140 | { |
141 | nsuerror nsures; |
142 | |
143 | if ((len > (5 + MIN_CERT_LEN64)) && |
144 | (strncmp(str, "cert=", 5) == 0)) { |
145 | /* possible certificate entry */ |
146 | nsures = nsu_base64_decode_alloc_url( |
147 | (const uint8_t *)str + 5, |
148 | len - 5, |
149 | &chain->certs[chain->depth].der, |
150 | &chain->certs[chain->depth].der_length); |
151 | if (nsures == NSUERROR_OK) { |
152 | chain->depth++; |
153 | } |
154 | } else if ((len > 8) && |
155 | (strncmp(str, "certerr=", 8) == 0)) { |
156 | /* certificate entry error code */ |
157 | if (chain->depth > 0) { |
158 | chain->certs[chain->depth - 1].err = strtoul(str + 8, NULL((void*)0), 10); |
159 | } |
160 | } |
161 | return NSERROR_OK; |
162 | } |
163 | |
164 | /* |
165 | * create a certificate chain from a fetch query string |
166 | * |
167 | * exported interface documented in netsurf/ssl_certs.h |
168 | */ |
169 | nserror cert_chain_from_query(struct nsurl *url, struct cert_chain **chain_out) |
170 | { |
171 | struct cert_chain* chain; |
172 | nserror res; |
173 | char *querystr; |
174 | size_t querylen; |
175 | size_t kvstart; |
176 | size_t kvlen; |
177 | |
178 | res = nsurl_get(url, NSURL_QUERY, &querystr, &querylen); |
179 | if (res != NSERROR_OK) { |
180 | return res; |
181 | } |
182 | |
183 | if (querylen < MIN_CERT_LEN64) { |
184 | free(querystr); |
185 | return NSERROR_NEED_DATA; |
186 | } |
187 | |
188 | res = cert_chain_alloc(0, &chain); |
189 | if (res != NSERROR_OK) { |
190 | free(querystr); |
191 | return res; |
192 | } |
193 | |
194 | for (kvlen = 0, kvstart = 0; kvstart < querylen; kvstart += kvlen) { |
Value stored to 'kvlen' is never read | |
195 | /* get query section length */ |
196 | kvlen = 0; |
197 | while (((kvstart + kvlen) < querylen) && |
198 | (querystr[kvstart + kvlen] != '&')) { |
199 | kvlen++; |
200 | } |
201 | |
202 | res = process_query_section(querystr + kvstart, kvlen, chain); |
203 | if (res != NSERROR_OK) { |
204 | break; |
205 | } |
206 | kvlen++; /* account for & separator */ |
207 | } |
208 | free(querystr); |
209 | |
210 | if (chain->depth > 0) { |
211 | *chain_out = chain; |
212 | } else { |
213 | free(chain); |
214 | return NSERROR_INVALID; |
215 | } |
216 | |
217 | return NSERROR_OK; |
218 | } |
219 | |
220 | |
221 | /* |
222 | * create a fetch query string from a certificate chain |
223 | * |
224 | * exported interface documented in netsurf/ssl_certs.h |
225 | */ |
226 | nserror cert_chain_to_query(struct cert_chain *chain, struct nsurl **url_out ) |
227 | { |
228 | nserror res; |
229 | nsurl *url; |
230 | size_t allocsize; |
231 | size_t urlstrlen; |
232 | uint8_t *urlstr; |
233 | size_t depth; |
234 | |
235 | allocsize = 20; |
236 | for (depth = 0; depth < chain->depth; depth++) { |
237 | allocsize += 7; /* allow for &cert= */ |
238 | allocsize += 4 * ((chain->certs[depth].der_length + 2) / 3); |
239 | if (chain->certs[depth].err != SSL_CERT_ERR_OK) { |
240 | allocsize += 20; /* allow for &certerr=4000000000 */ |
241 | } |
242 | } |
243 | |
244 | urlstr = malloc(allocsize); |
245 | if (urlstr == NULL((void*)0)) { |
246 | return NSERROR_NOMEM; |
247 | } |
248 | |
249 | urlstrlen = snprintf((char *)urlstr, allocsize, "about:certificate"); |
250 | for (depth = 0; depth < chain->depth; depth++) { |
251 | int written; |
252 | nsuerror nsures; |
253 | size_t output_length; |
254 | |
255 | written = snprintf((char *)urlstr + urlstrlen, |
256 | allocsize - urlstrlen, |
257 | "&cert="); |
258 | if (written < 0) { |
259 | free(urlstr); |
260 | return NSERROR_UNKNOWN; |
261 | } |
262 | if ((size_t)written >= allocsize - urlstrlen) { |
263 | free(urlstr); |
264 | return NSERROR_UNKNOWN; |
265 | } |
266 | |
267 | urlstrlen += (size_t)written; |
268 | |
269 | output_length = allocsize - urlstrlen; |
270 | nsures = nsu_base64_encode_url( |
271 | chain->certs[depth].der, |
272 | chain->certs[depth].der_length, |
273 | (uint8_t *)urlstr + urlstrlen, |
274 | &output_length); |
275 | if (nsures != NSUERROR_OK) { |
276 | free(urlstr); |
277 | return (nserror)nsures; |
278 | } |
279 | urlstrlen += output_length; |
280 | |
281 | if (chain->certs[depth].err != SSL_CERT_ERR_OK) { |
282 | written = snprintf((char *)urlstr + urlstrlen, |
283 | allocsize - urlstrlen, |
284 | "&certerr=%d", |
285 | chain->certs[depth].err); |
286 | if (written < 0) { |
287 | free(urlstr); |
288 | return NSERROR_UNKNOWN; |
289 | } |
290 | if ((size_t)written >= allocsize - urlstrlen) { |
291 | free(urlstr); |
292 | return NSERROR_UNKNOWN; |
293 | } |
294 | |
295 | urlstrlen += (size_t)written; |
296 | } |
297 | |
298 | } |
299 | urlstr[17] = '?'; |
300 | urlstr[urlstrlen] = 0; |
301 | |
302 | res = nsurl_create((const char *)urlstr, &url); |
303 | free(urlstr); |
304 | |
305 | if (res == NSERROR_OK) { |
306 | *url_out = url; |
307 | } |
308 | |
309 | return res; |
310 | } |
311 | |
312 | /* |
313 | * free certificate chain |
314 | * |
315 | * exported interface documented in netsurf/ssl_certs.h |
316 | */ |
317 | nserror cert_chain_free(struct cert_chain* chain) |
318 | { |
319 | size_t depth; |
320 | |
321 | if (chain != NULL((void*)0)) { |
322 | for (depth = 0; depth < chain->depth; depth++) { |
323 | if (chain->certs[depth].der != NULL((void*)0)) { |
324 | free(chain->certs[depth].der); |
325 | } |
326 | } |
327 | |
328 | free(chain); |
329 | } |
330 | |
331 | return NSERROR_OK; |
332 | } |
333 | |
334 | |
335 | /* |
336 | * calculate storage used of certificate chain |
337 | * |
338 | * exported interface documented in netsurf/ssl_certs.h |
339 | */ |
340 | size_t cert_chain_size(const struct cert_chain *chain) |
341 | { |
342 | size_t size = 0; |
343 | size_t depth; |
344 | |
345 | if (chain != NULL((void*)0)) { |
346 | size += sizeof(struct cert_chain); |
347 | |
348 | for (depth = 0; depth < chain->depth; depth++) { |
349 | if (chain->certs[depth].der != NULL((void*)0)) { |
350 | size += chain->certs[depth].der_length; |
351 | } |
352 | } |
353 | } |
354 | |
355 | return size; |
356 | } |