Bug Summary

File:utils/ssl_certs.c
Warning:line 194, column 7
Value stored to 'kvlen' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ssl_certs.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -I . -I include -I build/Linux-monkey -I frontends -I content/handlers -D WITH_JPEG -U WITH_PDF_EXPORT -D LIBICONV_PLUG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /usr/include/x86_64-linux-gnu -D WITH_CURL -D WITH_OPENSSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D UTF8PROC_EXPORTS -D WITH_UTF8PROC -D WITH_WEBP -I /usr/include/libpng16 -D WITH_PNG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include/ -D WITH_BMP -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_GIF -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSPSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSLOG -D NETSURF_UA_FORMAT_STRING="Mozilla/5.0 (%s) NetSurf/%d.%d" -D NETSURF_HOMEPAGE="about:welcome" -D NETSURF_LOG_LEVEL=VERBOSE -D NETSURF_BUILTIN_LOG_FILTER="(level:WARNING || cat:jserrors)" -D NETSURF_BUILTIN_VERBOSE_FILTER="(level:VERBOSE || cat:jserrors)" -D STMTEXPR=1 -D monkey -D nsmonkey -D MONKEY_RESPATH="/var/lib/jenkins/artifacts-x86_64-linux-gnu/share/netsurf/" -D _POSIX_C_SOURCE=200809L -D _XOPEN_SOURCE=700 -D _BSD_SOURCE -D _DEFAULT_SOURCE -D _NETBSD_SOURCE -D DUK_OPT_HAVE_CUSTOM_H -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wwrite-strings -Wno-unused-parameter -Wno-unused-but-set-variable -std=c99 -fconst-strings -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-netsurf/clangScanBuildReports/2024-10-17-140254-391015-1 -x c utils/ssl_certs.c
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 */
40nserror
41cert_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 */
63nserror
64cert_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 */
100nserror
101cert_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 */
138static nserror
139process_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 */
169nserror 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 */
226nserror 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 */
317nserror 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 */
340size_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}