Bug Summary

File:s/cmd/lib/basicutil.c
Warning:line 570, column 28
Dereference of null pointer

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 basicutil.c -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 -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/cmd/lib -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/cmd/lib -resource-dir /usr/lib/llvm-18/lib/clang/18 -D HAVE_STRERROR -D LINUX -D linux -D XP_UNIX -D XP_UNIX -D NSPR20 -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D NSS_DISABLE_SSE3 -D NSS_NO_INIT_SUPPORT -D USE_UTIL_DIRECTLY -D NO_NSPR_10_SUPPORT -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -D NSS_USE_STATIC_LIBS -I ../../../dist/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/include -I ../../../dist/public/nss -I ../../../dist/private/nss -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-18-082241-28900-1 -x c basicutil.c
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4/*
5** secutil.c - various functions used by security stuff
6**
7*/
8
9#include "prtypes.h"
10#include "prtime.h"
11#include "prlong.h"
12#include "prerror.h"
13#include "prprf.h"
14#include "plgetopt.h"
15#include "prenv.h"
16#include "prnetdb.h"
17
18#include "basicutil.h"
19#include <stdarg.h>
20#include <stddef.h>
21#include <sys/stat.h>
22#include <errno(*__errno_location ()).h>
23
24#ifdef XP_UNIX1
25#include <unistd.h>
26#endif
27
28#include "secoid.h"
29
30extern long DER_GetIntegerDER_GetInteger_Util(const SECItem *src);
31
32static PRBool wrapEnabled = PR_TRUE1;
33
34void
35SECU_EnableWrap(PRBool enable)
36{
37 wrapEnabled = enable;
38}
39
40PRBool
41SECU_GetWrapEnabled(void)
42{
43 return wrapEnabled;
44}
45
46void
47SECU_PrintErrMsg(FILE *out, int level, const char *progName, const char *msg,
48 ...)
49{
50 va_list args;
51 PRErrorCode err = PORT_GetErrorPORT_GetError_Util();
52 const char *errString = PORT_ErrorToString(err)PR_ErrorToString((err), 0);
53
54 va_start(args, msg)__builtin_va_start(args, msg);
55
56 SECU_Indent(out, level);
57 fprintf(out, "%s: ", progName);
58 vfprintf(out, msg, args);
59 if (errString != NULL((void*)0) && PORT_Strlen(errString)strlen(errString) > 0)
60 fprintf(out, ": %s\n", errString);
61 else
62 fprintf(out, ": error %d\n", (int)err);
63
64 va_end(args)__builtin_va_end(args);
65}
66
67void
68SECU_PrintError(const char *progName, const char *msg, ...)
69{
70 va_list args;
71 PRErrorCode err = PORT_GetErrorPORT_GetError_Util();
72 const char *errName = PR_ErrorToName(err);
73 const char *errString = PR_ErrorToString(err, 0);
74
75 va_start(args, msg)__builtin_va_start(args, msg);
76
77 fprintf(stderrstderr, "%s: ", progName);
78 vfprintf(stderrstderr, msg, args);
79
80 if (errName != NULL((void*)0)) {
81 fprintf(stderrstderr, ": %s", errName);
82 } else {
83 fprintf(stderrstderr, ": error %d", (int)err);
84 }
85
86 if (errString != NULL((void*)0) && PORT_Strlen(errString)strlen(errString) > 0)
87 fprintf(stderrstderr, ": %s\n", errString);
88
89 va_end(args)__builtin_va_end(args);
90}
91
92void
93SECU_PrintSystemError(const char *progName, const char *msg, ...)
94{
95 va_list args;
96
97 va_start(args, msg)__builtin_va_start(args, msg);
98 fprintf(stderrstderr, "%s: ", progName);
99 vfprintf(stderrstderr, msg, args);
100 fprintf(stderrstderr, ": %s\n", strerror(errno(*__errno_location ())));
101 va_end(args)__builtin_va_end(args);
102}
103
104SECStatus
105secu_StdinToItem(SECItem *dst)
106{
107 unsigned char buf[1000];
108 PRInt32 numBytes;
109 PRBool notDone = PR_TRUE1;
110
111 dst->len = 0;
112 dst->data = NULL((void*)0);
113
114 while (notDone) {
115 numBytes = PR_Read(PR_STDINPR_GetSpecialFD(PR_StandardInput), buf, sizeof(buf));
116
117 if (numBytes < 0) {
118 return SECFailure;
119 }
120
121 if (numBytes == 0)
122 break;
123
124 if (dst->data) {
125 unsigned char *p = dst->data;
126 dst->data = (unsigned char *)PORT_ReallocPORT_Realloc_Util(p, dst->len + numBytes);
127 if (!dst->data) {
128 PORT_FreePORT_Free_Util(p);
129 }
130 } else {
131 dst->data = (unsigned char *)PORT_AllocPORT_Alloc_Util(numBytes);
132 }
133 if (!dst->data) {
134 return SECFailure;
135 }
136 PORT_Memcpymemcpy(dst->data + dst->len, buf, numBytes);
137 dst->len += numBytes;
138 }
139
140 return SECSuccess;
141}
142
143SECStatus
144SECU_FileToItem(SECItem *dst, PRFileDesc *src)
145{
146 PRFileInfo info;
147 PRInt32 numBytes;
148 PRStatus prStatus;
149
150 if (src == PR_STDINPR_GetSpecialFD(PR_StandardInput))
151 return secu_StdinToItem(dst);
152
153 prStatus = PR_GetOpenFileInfo(src, &info);
154
155 if (prStatus != PR_SUCCESS) {
156 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_IO);
157 return SECFailure;
158 }
159
160 /* XXX workaround for 3.1, not all utils zero dst before sending */
161 dst->data = 0;
162 if (!SECITEM_AllocItemSECITEM_AllocItem_Util(NULL((void*)0), dst, info.size))
163 goto loser;
164
165 numBytes = PR_Read(src, dst->data, info.size);
166 if (numBytes != info.size) {
167 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_IO);
168 goto loser;
169 }
170
171 return SECSuccess;
172loser:
173 SECITEM_FreeItemSECITEM_FreeItem_Util(dst, PR_FALSE0);
174 dst->data = NULL((void*)0);
175 return SECFailure;
176}
177
178SECStatus
179SECU_TextFileToItem(SECItem *dst, PRFileDesc *src)
180{
181 PRFileInfo info;
182 PRInt32 numBytes;
183 PRStatus prStatus;
184 unsigned char *buf;
185
186 if (src == PR_STDINPR_GetSpecialFD(PR_StandardInput))
187 return secu_StdinToItem(dst);
188
189 prStatus = PR_GetOpenFileInfo(src, &info);
190
191 if (prStatus != PR_SUCCESS) {
192 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_IO);
193 return SECFailure;
194 }
195
196 buf = (unsigned char *)PORT_AllocPORT_Alloc_Util(info.size);
197 if (!buf)
198 return SECFailure;
199
200 numBytes = PR_Read(src, buf, info.size);
201 if (numBytes != info.size) {
202 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_IO);
203 goto loser;
204 }
205
206 if (buf[numBytes - 1] == '\n')
207 numBytes--;
208#ifdef _WINDOWS
209 if (buf[numBytes - 1] == '\r')
210 numBytes--;
211#endif
212
213 /* XXX workaround for 3.1, not all utils zero dst before sending */
214 dst->data = 0;
215 if (!SECITEM_AllocItemSECITEM_AllocItem_Util(NULL((void*)0), dst, numBytes))
216 goto loser;
217
218 memcpy(dst->data, buf, numBytes);
219
220 PORT_FreePORT_Free_Util(buf);
221 return SECSuccess;
222loser:
223 PORT_FreePORT_Free_Util(buf);
224 return SECFailure;
225}
226
227#define INDENT_MULT4 4
228void
229SECU_Indent(FILE *out, int level)
230{
231 int i;
232
233 for (i = 0; i < level; i++) {
234 fprintf(out, " ");
235 }
236}
237
238void
239SECU_Newline(FILE *out)
240{
241 fprintf(out, "\n");
242}
243
244void
245SECU_PrintAsHex(FILE *out, const SECItem *data, const char *m, int level)
246{
247 unsigned i;
248 int column = 0;
249 PRBool isString = PR_TRUE1;
250 PRBool isWhiteSpace = PR_TRUE1;
251 PRBool printedHex = PR_FALSE0;
252 unsigned int limit = 15;
253
254 if (m) {
255 SECU_Indent(out, level);
256 fprintf(out, "%s:", m);
257 level++;
258 if (wrapEnabled)
259 fprintf(out, "\n");
260 }
261
262 if (wrapEnabled) {
263 SECU_Indent(out, level);
264 column = level * INDENT_MULT4;
265 }
266 if (!data->len) {
267 fprintf(out, "(empty)\n");
268 return;
269 }
270 /* take a pass to see if it's all printable. */
271 for (i = 0; i < data->len; i++) {
272 unsigned char val = data->data[i];
273 if (!val || !isprint(val)((*__ctype_b_loc ())[(int) ((val))] & (unsigned short int
) _ISprint)
) {
274 isString = PR_FALSE0;
275 break;
276 }
277 if (isWhiteSpace && !isspace(val)((*__ctype_b_loc ())[(int) ((val))] & (unsigned short int
) _ISspace)
) {
278 isWhiteSpace = PR_FALSE0;
279 }
280 }
281
282 /* Short values, such as bit strings (which are printed with this
283 ** function) often look like strings, but we want to see the bits.
284 ** so this test assures that short values will be printed in hex,
285 ** perhaps in addition to being printed as strings.
286 ** The threshold size (4 bytes) is arbitrary.
287 */
288 if (!isString || data->len <= 4) {
289 for (i = 0; i < data->len; i++) {
290 if (i != data->len - 1) {
291 fprintf(out, "%02x:", data->data[i]);
292 column += 3;
293 } else {
294 fprintf(out, "%02x", data->data[i]);
295 column += 2;
296 break;
297 }
298 if (wrapEnabled &&
299 (column > 76 || (i % 16 == limit))) {
300 SECU_Newline(out);
301 SECU_Indent(out, level);
302 column = level * INDENT_MULT4;
303 limit = i % 16;
304 }
305 }
306 printedHex = PR_TRUE1;
307 }
308 if (isString && !isWhiteSpace) {
309 if (printedHex != PR_FALSE0) {
310 SECU_Newline(out);
311 SECU_Indent(out, level);
312 column = level * INDENT_MULT4;
313 }
314 for (i = 0; i < data->len; i++) {
315 unsigned char val = data->data[i];
316
317 if (val) {
318 fprintf(out, "%c", val);
319 column++;
320 } else {
321 column = 77;
322 }
323 if (wrapEnabled && column > 76) {
324 SECU_Newline(out);
325 SECU_Indent(out, level);
326 column = level * INDENT_MULT4;
327 }
328 }
329 }
330
331 if (column != level * INDENT_MULT4) {
332 SECU_Newline(out);
333 }
334}
335
336const char *hex = "0123456789abcdef";
337
338const char printable[257] = {
339 "................" /* 0x */
340 "................" /* 1x */
341 " !\"#$%&'()*+,-./" /* 2x */
342 "0123456789:;<=>?" /* 3x */
343 "@ABCDEFGHIJKLMNO" /* 4x */
344 "PQRSTUVWXYZ[\\]^_" /* 5x */
345 "`abcdefghijklmno" /* 6x */
346 "pqrstuvwxyz{|}~." /* 7x */
347 "................" /* 8x */
348 "................" /* 9x */
349 "................" /* ax */
350 "................" /* bx */
351 "................" /* cx */
352 "................" /* dx */
353 "................" /* ex */
354 "................" /* fx */
355};
356
357void
358SECU_PrintBuf(FILE *out, const char *msg, const void *vp, int len)
359{
360 const unsigned char *cp = (const unsigned char *)vp;
361 char buf[80];
362 char *bp;
363 char *ap;
364
365 fprintf(out, "%s [Len: %d]\n", msg, len);
366 memset(buf, ' ', sizeof buf);
367 bp = buf;
368 ap = buf + 50;
369 while (--len >= 0) {
370 unsigned char ch = *cp++;
371 *bp++ = hex[(ch >> 4) & 0xf];
372 *bp++ = hex[ch & 0xf];
373 *bp++ = ' ';
374 *ap++ = printable[ch];
375 if (ap - buf >= 66) {
376 *ap = 0;
377 fprintf(out, " %s\n", buf);
378 memset(buf, ' ', sizeof buf);
379 bp = buf;
380 ap = buf + 50;
381 }
382 }
383 if (bp > buf) {
384 *ap = 0;
385 fprintf(out, " %s\n", buf);
386 }
387}
388
389/* This expents i->data[0] to be the MSB of the integer.
390** if you want to print a DER-encoded integer (with the tag and length)
391** call SECU_PrintEncodedInteger();
392*/
393void
394SECU_PrintInteger(FILE *out, const SECItem *i, const char *m, int level)
395{
396 int iv;
397
398 if (!i || !i->len || !i->data) {
399 SECU_Indent(out, level);
400 if (m) {
401 fprintf(out, "%s: (null)\n", m);
402 } else {
403 fprintf(out, "(null)\n");
404 }
405 } else if (i->len > 4) {
406 SECU_PrintAsHex(out, i, m, level);
407 } else {
408 if (i->type == siUnsignedInteger && *i->data & 0x80) {
409 /* Make sure i->data has zero in the highest bite
410 * if i->data is an unsigned integer */
411 SECItem tmpI;
412 char data[] = { 0, 0, 0, 0, 0 };
413
414 PORT_Memcpymemcpy(data + 1, i->data, i->len);
415 tmpI.len = i->len + 1;
416 tmpI.data = (void *)data;
417
418 iv = DER_GetIntegerDER_GetInteger_Util(&tmpI);
419 } else {
420 iv = DER_GetIntegerDER_GetInteger_Util(i);
421 }
422 SECU_Indent(out, level);
423 if (m) {
424 fprintf(out, "%s: %d (0x%x)\n", m, iv, iv);
425 } else {
426 fprintf(out, "%d (0x%x)\n", iv, iv);
427 }
428 }
429}
430
431#if defined(DEBUG1) || defined(FORCE_PR_ASSERT)
432/* Returns true iff a[i].flag has a duplicate in a[i+1 : count-1] */
433static PRBool
434HasShortDuplicate(int i, secuCommandFlag *a, int count)
435{
436 char target = a[i].flag;
437 int j;
438
439 /* duplicate '\0' flags are okay, they are used with long forms */
440 for (j = i + 1; j < count; j++) {
441 if (a[j].flag && a[j].flag == target) {
442 return PR_TRUE1;
443 }
444 }
445 return PR_FALSE0;
446}
447
448/* Returns true iff a[i].longform has a duplicate in a[i+1 : count-1] */
449static PRBool
450HasLongDuplicate(int i, secuCommandFlag *a, int count)
451{
452 int j;
453 char *target = a[i].longform;
454
455 if (!target)
456 return PR_FALSE0;
457
458 for (j = i + 1; j < count; j++) {
459 if (a[j].longform && strcmp(a[j].longform, target) == 0) {
460 return PR_TRUE1;
461 }
462 }
463 return PR_FALSE0;
464}
465
466/* Returns true iff a has no short or long form duplicates
467 */
468PRBool
469HasNoDuplicates(secuCommandFlag *a, int count)
470{
471 int i;
472
473 for (i = 0; i < count; i++) {
474 if (a[i].flag && HasShortDuplicate(i, a, count)) {
475 return PR_FALSE0;
476 }
477 if (a[i].longform && HasLongDuplicate(i, a, count)) {
478 return PR_FALSE0;
479 }
480 }
481 return PR_TRUE1;
482}
483#endif
484
485SECStatus
486SECU_ParseCommandLine(int argc, char **argv, char *progName,
487 const secuCommand *cmd)
488{
489 PRBool found;
490 PLOptState *optstate;
491 PLOptStatus status;
492 char *optstring;
493 PLLongOpt *longopts = NULL((void*)0);
1
'longopts' initialized to a null pointer value
494 int i, j;
495 int lcmd = 0, lopt = 0;
496
497 PR_ASSERT(HasNoDuplicates(cmd->commands, cmd->numCommands))((HasNoDuplicates(cmd->commands, cmd->numCommands))?((void
)0):PR_Assert("HasNoDuplicates(cmd->commands, cmd->numCommands)"
,"basicutil.c",497))
;
2
Assuming the condition is true
3
'?' condition is true
498 PR_ASSERT(HasNoDuplicates(cmd->options, cmd->numOptions))((HasNoDuplicates(cmd->options, cmd->numOptions))?((void
)0):PR_Assert("HasNoDuplicates(cmd->options, cmd->numOptions)"
,"basicutil.c",498))
;
4
Assuming the condition is true
5
'?' condition is true
499
500 optstring = (char *)PORT_AllocPORT_Alloc_Util(cmd->numCommands + 2 * cmd->numOptions + 1);
501 if (optstring == NULL((void*)0))
6
Assuming 'optstring' is not equal to NULL
7
Taking false branch
502 return SECFailure;
503
504 j = 0;
505 for (i = 0; i < cmd->numCommands; i++) {
8
Assuming 'i' is >= field 'numCommands'
9
Loop condition is false. Execution continues on line 511
506 if (cmd->commands[i].flag) /* single character option ? */
507 optstring[j++] = cmd->commands[i].flag;
508 if (cmd->commands[i].longform)
509 lcmd++;
510 }
511 for (i = 0; i < cmd->numOptions; i++) {
10
Assuming 'i' is >= field 'numOptions'
11
Loop condition is false. Execution continues on line 521
512 if (cmd->options[i].flag) {
513 optstring[j++] = cmd->options[i].flag;
514 if (cmd->options[i].needsArg)
515 optstring[j++] = ':';
516 }
517 if (cmd->options[i].longform)
518 lopt++;
519 }
520
521 optstring[j] = '\0';
522
523 if (lcmd + lopt > 0) {
12
Taking false branch
524 longopts = PORT_NewArray(PLLongOpt, lcmd + lopt + 1)(PLLongOpt *)PORT_Alloc_Util(sizeof(PLLongOpt) * (lcmd + lopt
+ 1))
;
525 if (!longopts) {
526 PORT_FreePORT_Free_Util(optstring);
527 return SECFailure;
528 }
529
530 j = 0;
531 for (i = 0; j < lcmd && i < cmd->numCommands; i++) {
532 if (cmd->commands[i].longform) {
533 longopts[j].longOptName = cmd->commands[i].longform;
534 longopts[j].longOption = 0;
535 longopts[j++].valueRequired = cmd->commands[i].needsArg;
536 }
537 }
538 lopt += lcmd;
539 for (i = 0; j < lopt && i < cmd->numOptions; i++) {
540 if (cmd->options[i].longform) {
541 longopts[j].longOptName = cmd->options[i].longform;
542 longopts[j].longOption = 0;
543 longopts[j++].valueRequired = cmd->options[i].needsArg;
544 }
545 }
546 longopts[j].longOptName = NULL((void*)0);
547 }
548
549 optstate = PL_CreateLongOptState(argc, argv, optstring, longopts);
550 if (!optstate) {
13
Assuming 'optstate' is non-null
14
Taking false branch
551 PORT_FreePORT_Free_Util(optstring);
552 PORT_FreePORT_Free_Util(longopts);
553 return SECFailure;
554 }
555 /* Parse command line arguments */
556 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
15
Assuming the condition is true
16
Loop condition is true. Entering loop body
557 const char *optstatelong;
558 char option = optstate->option;
559
560 /* positional parameter, single-char option or long opt? */
561 if (optstate->longOptIndex == -1) {
17
Assuming the condition is false
18
Taking false branch
562 /* not a long opt */
563 if (option == '\0')
564 continue; /* it's a positional parameter */
565 optstatelong = "";
566 } else {
567 /* long opt */
568 if (option == '\0')
19
Assuming the condition is false
20
Taking false branch
569 option = '\377'; /* force unequal with all flags */
570 optstatelong = longopts[optstate->longOptIndex].longOptName;
21
Dereference of null pointer
571 }
572
573 found = PR_FALSE0;
574
575 for (i = 0; i < cmd->numCommands; i++) {
576 if (cmd->commands[i].flag == option ||
577 cmd->commands[i].longform == optstatelong) {
578 cmd->commands[i].activated = PR_TRUE1;
579 if (optstate->value) {
580 cmd->commands[i].arg = (char *)optstate->value;
581 }
582 found = PR_TRUE1;
583 break;
584 }
585 }
586
587 if (found)
588 continue;
589
590 for (i = 0; i < cmd->numOptions; i++) {
591 if (cmd->options[i].flag == option ||
592 cmd->options[i].longform == optstatelong) {
593 cmd->options[i].activated = PR_TRUE1;
594 if (optstate->value) {
595 cmd->options[i].arg = (char *)optstate->value;
596 } else if (cmd->options[i].needsArg) {
597 status = PL_OPT_BAD;
598 goto loser;
599 }
600 found = PR_TRUE1;
601 break;
602 }
603 }
604
605 if (!found) {
606 status = PL_OPT_BAD;
607 break;
608 }
609 }
610
611loser:
612 PL_DestroyOptState(optstate);
613 PORT_FreePORT_Free_Util(optstring);
614 if (longopts)
615 PORT_FreePORT_Free_Util(longopts);
616 if (status == PL_OPT_BAD)
617 return SECFailure;
618 return SECSuccess;
619}
620
621char *
622SECU_GetOptionArg(const secuCommand *cmd, int optionNum)
623{
624 if (optionNum < 0 || optionNum >= cmd->numOptions)
625 return NULL((void*)0);
626 if (cmd->options[optionNum].activated)
627 return PL_strdup(cmd->options[optionNum].arg);
628 else
629 return NULL((void*)0);
630}
631
632void
633SECU_PrintPRandOSError(const char *progName)
634{
635 char buffer[513];
636 PRInt32 errLenInt = PR_GetErrorTextLength();
637 size_t errLen = errLenInt < 0 ? 0 : (size_t)errLenInt;
638 if (errLen > 0 && errLen < sizeof buffer) {
639 PR_GetErrorText(buffer);
640 }
641 SECU_PrintError(progName, "function failed");
642 if (errLen > 0 && errLen < sizeof buffer) {
643 PR_fprintf(PR_STDERRPR_GetSpecialFD(PR_StandardError), "\t%s\n", buffer);
644 }
645}
646
647SECOidTag
648SECU_StringToSignatureAlgTag(const char *alg)
649{
650 SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
651
652 if (alg) {
653 if (!PL_strcmp(alg, "MD2")) {
654 hashAlgTag = SEC_OID_MD2;
655 } else if (!PL_strcmp(alg, "MD4")) {
656 hashAlgTag = SEC_OID_MD4;
657 } else if (!PL_strcmp(alg, "MD5")) {
658 hashAlgTag = SEC_OID_MD5;
659 } else if (!PL_strcmp(alg, "SHA1")) {
660 hashAlgTag = SEC_OID_SHA1;
661 } else if (!PL_strcmp(alg, "SHA224")) {
662 hashAlgTag = SEC_OID_SHA224;
663 } else if (!PL_strcmp(alg, "SHA256")) {
664 hashAlgTag = SEC_OID_SHA256;
665 } else if (!PL_strcmp(alg, "SHA384")) {
666 hashAlgTag = SEC_OID_SHA384;
667 } else if (!PL_strcmp(alg, "SHA512")) {
668 hashAlgTag = SEC_OID_SHA512;
669 }
670 }
671 return hashAlgTag;
672}
673
674/* Caller ensures that dst is at least item->len*2+1 bytes long */
675void
676SECU_SECItemToHex(const SECItem *item, char *dst)
677{
678 if (dst && item && item->data) {
679 unsigned char *src = item->data;
680 unsigned int len = item->len;
681 for (; len > 0; --len, dst += 2) {
682 snprintf(dst, 3, "%02x", *src++);
683 }
684 }
685}
686
687static unsigned char
688nibble(char c)
689{
690 c = PORT_Tolowertolower(c);
691 return (c >= '0' && c <= '9') ? c - '0' : (c >= 'a' && c <= 'f') ? c - 'a' + 10 : -1;
692}
693
694SECStatus
695SECU_SECItemHexStringToBinary(SECItem *srcdest)
696{
697 unsigned int i;
698
699 if (!srcdest) {
700 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
701 return SECFailure;
702 }
703 if (srcdest->len < 4 || (srcdest->len % 2)) {
704 /* too short to convert, or even number of characters */
705 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATA);
706 return SECFailure;
707 }
708 if (PORT_StrncasecmpPL_strncasecmp((const char *)srcdest->data, "0x", 2)) {
709 /* wrong prefix */
710 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATA);
711 return SECFailure;
712 }
713
714 /* 1st pass to check for hex characters */
715 for (i = 2; i < srcdest->len; i++) {
716 char c = PORT_Tolowertolower(srcdest->data[i]);
717 if (!((c >= '0' && c <= '9') ||
718 (c >= 'a' && c <= 'f'))) {
719 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DATA);
720 return SECFailure;
721 }
722 }
723
724 /* 2nd pass to convert */
725 for (i = 2; i < srcdest->len; i += 2) {
726 srcdest->data[(i - 2) / 2] = (nibble(srcdest->data[i]) << 4) +
727 nibble(srcdest->data[i + 1]);
728 }
729
730 /* adjust length */
731 srcdest->len -= 2;
732 srcdest->len /= 2;
733 return SECSuccess;
734}
735
736SECItem *
737SECU_HexString2SECItem(PLArenaPool *arena, SECItem *item, const char *str)
738{
739 int i = 0;
740 int byteval = 0;
741 int tmp = PORT_Strlen(str)strlen(str);
742
743 PORT_Assert(item)((item)?((void)0):PR_Assert("item","basicutil.c",743));
744
745 if ((tmp % 2) != 0) {
746 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
747 return NULL((void*)0);
748 }
749
750 item = SECITEM_AllocItemSECITEM_AllocItem_Util(arena, item, tmp / 2);
751 if (item == NULL((void*)0)) {
752 return NULL((void*)0);
753 }
754
755 while (str[i]) {
756 if ((str[i] >= '0') && (str[i] <= '9')) {
757 tmp = str[i] - '0';
758 } else if ((str[i] >= 'a') && (str[i] <= 'f')) {
759 tmp = str[i] - 'a' + 10;
760 } else if ((str[i] >= 'A') && (str[i] <= 'F')) {
761 tmp = str[i] - 'A' + 10;
762 } else {
763 if (!arena) {
764 SECITEM_FreeItemSECITEM_FreeItem_Util(item, PR_FALSE0);
765 }
766 return NULL((void*)0);
767 }
768
769 byteval = byteval * 16 + tmp;
770 if ((i % 2) != 0) {
771 item->data[i / 2] = byteval;
772 byteval = 0;
773 }
774 i++;
775 }
776
777 return item;
778}
779
780SECStatus
781SECU_ecName2params(ECCurveName curve, SECItem *params)
782{
783 SECOidTag oidTag;
784 SECOidData *oidData = NULL((void*)0);
785
786 switch (curve) {
787 case ECCurve_NIST_P256:
788 oidTag = SEC_OID_ANSIX962_EC_PRIME256V1;
789 break;
790 case ECCurve_NIST_P384:
791 oidTag = SEC_OID_SECG_EC_SECP384R1;
792 break;
793 case ECCurve_NIST_P521:
794 oidTag = SEC_OID_SECG_EC_SECP521R1;
795 break;
796 case ECCurve25519:
797 oidTag = SEC_OID_CURVE25519;
798 break;
799 case ECCurve_Ed25519:
800 oidTag = SEC_OID_ED25519_PUBLIC_KEY;
801 break;
802 default:
803 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
804 return SECFailure;
805 }
806
807 oidData = SECOID_FindOIDByTagSECOID_FindOIDByTag_Util(oidTag);
808 if (oidData == NULL((void*)0)) {
809 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
810 return SECFailure;
811 }
812
813 if (SECITEM_AllocItemSECITEM_AllocItem_Util(NULL((void*)0), params, (2 + oidData->oid.len)) == NULL((void*)0)) {
814 return SECFailure;
815 }
816 /*
817 * params->data needs to contain the ASN encoding of an object ID (OID)
818 * representing the named curve. The actual OID is in
819 * oidData->oid.data so we simply prepend 0x06 and OID length
820 */
821 params->data[0] = SEC_ASN1_OBJECT_ID0x06;
822 params->data[1] = oidData->oid.len;
823 memcpy(params->data + 2, oidData->oid.data, oidData->oid.len);
824
825 return SECSuccess;
826}