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.h>
23 
24 #ifdef XP_UNIX
25 #include <unistd.h>
26 #endif
27 
28 #include "secoid.h"
29 
30 extern long DER_GetInteger(const SECItem *src);
31 
32 static PRBool wrapEnabled = PR_TRUE;
33 
34 void
SECU_EnableWrap(PRBool enable)35 SECU_EnableWrap(PRBool enable)
36 {
37     wrapEnabled = enable;
38 }
39 
40 PRBool
SECU_GetWrapEnabled(void)41 SECU_GetWrapEnabled(void)
42 {
43     return wrapEnabled;
44 }
45 
46 void
SECU_PrintErrMsg(FILE * out,int level,const char * progName,const char * msg,...)47 SECU_PrintErrMsg(FILE *out, int level, const char *progName, const char *msg,
48                  ...)
49 {
50     va_list args;
51     PRErrorCode err = PORT_GetError();
52     const char *errString = PORT_ErrorToString(err);
53 
54     va_start(args, msg);
55 
56     SECU_Indent(out, level);
57     fprintf(out, "%s: ", progName);
58     vfprintf(out, msg, args);
59     if (errString != NULL && PORT_Strlen(errString) > 0)
60         fprintf(out, ": %s\n", errString);
61     else
62         fprintf(out, ": error %d\n", (int)err);
63 
64     va_end(args);
65 }
66 
67 void
SECU_PrintError(const char * progName,const char * msg,...)68 SECU_PrintError(const char *progName, const char *msg, ...)
69 {
70     va_list args;
71     PRErrorCode err = PORT_GetError();
72     const char *errName = PR_ErrorToName(err);
73     const char *errString = PR_ErrorToString(err, 0);
74 
75     va_start(args, msg);
76 
77     fprintf(stderr, "%s: ", progName);
78     vfprintf(stderr, msg, args);
79 
80     if (errName != NULL) {
81         fprintf(stderr, ": %s", errName);
82     } else {
83         fprintf(stderr, ": error %d", (int)err);
84     }
85 
86     if (errString != NULL && PORT_Strlen(errString) > 0)
87         fprintf(stderr, ": %s\n", errString);
88 
89     va_end(args);
90 }
91 
92 void
SECU_PrintSystemError(const char * progName,const char * msg,...)93 SECU_PrintSystemError(const char *progName, const char *msg, ...)
94 {
95     va_list args;
96 
97     va_start(args, msg);
98     fprintf(stderr, "%s: ", progName);
99     vfprintf(stderr, msg, args);
100     fprintf(stderr, ": %s\n", strerror(errno));
101     va_end(args);
102 }
103 
104 SECStatus
secu_StdinToItem(SECItem * dst)105 secu_StdinToItem(SECItem *dst)
106 {
107     unsigned char buf[1000];
108     PRInt32 numBytes;
109     PRBool notDone = PR_TRUE;
110 
111     dst->len = 0;
112     dst->data = NULL;
113 
114     while (notDone) {
115         numBytes = PR_Read(PR_STDIN, 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_Realloc(p, dst->len + numBytes);
127             if (!dst->data) {
128                 PORT_Free(p);
129             }
130         } else {
131             dst->data = (unsigned char *)PORT_Alloc(numBytes);
132         }
133         if (!dst->data) {
134             return SECFailure;
135         }
136         PORT_Memcpy(dst->data + dst->len, buf, numBytes);
137         dst->len += numBytes;
138     }
139 
140     return SECSuccess;
141 }
142 
143 SECStatus
SECU_FileToItem(SECItem * dst,PRFileDesc * src)144 SECU_FileToItem(SECItem *dst, PRFileDesc *src)
145 {
146     PRFileInfo info;
147     PRInt32 numBytes;
148     PRStatus prStatus;
149 
150     if (src == PR_STDIN)
151         return secu_StdinToItem(dst);
152 
153     prStatus = PR_GetOpenFileInfo(src, &info);
154 
155     if (prStatus != PR_SUCCESS) {
156         PORT_SetError(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_AllocItem(NULL, dst, info.size))
163         goto loser;
164 
165     numBytes = PR_Read(src, dst->data, info.size);
166     if (numBytes != info.size) {
167         PORT_SetError(SEC_ERROR_IO);
168         goto loser;
169     }
170 
171     return SECSuccess;
172 loser:
173     SECITEM_FreeItem(dst, PR_FALSE);
174     dst->data = NULL;
175     return SECFailure;
176 }
177 
178 SECStatus
SECU_TextFileToItem(SECItem * dst,PRFileDesc * src)179 SECU_TextFileToItem(SECItem *dst, PRFileDesc *src)
180 {
181     PRFileInfo info;
182     PRInt32 numBytes;
183     PRStatus prStatus;
184     unsigned char *buf;
185 
186     if (src == PR_STDIN)
187         return secu_StdinToItem(dst);
188 
189     prStatus = PR_GetOpenFileInfo(src, &info);
190 
191     if (prStatus != PR_SUCCESS) {
192         PORT_SetError(SEC_ERROR_IO);
193         return SECFailure;
194     }
195 
196     buf = (unsigned char *)PORT_Alloc(info.size);
197     if (!buf)
198         return SECFailure;
199 
200     numBytes = PR_Read(src, buf, info.size);
201     if (numBytes != info.size) {
202         PORT_SetError(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_AllocItem(NULL, dst, numBytes))
216         goto loser;
217 
218     memcpy(dst->data, buf, numBytes);
219 
220     PORT_Free(buf);
221     return SECSuccess;
222 loser:
223     PORT_Free(buf);
224     return SECFailure;
225 }
226 
227 #define INDENT_MULT 4
228 void
SECU_Indent(FILE * out,int level)229 SECU_Indent(FILE *out, int level)
230 {
231     int i;
232 
233     for (i = 0; i < level; i++) {
234         fprintf(out, "    ");
235     }
236 }
237 
238 void
SECU_Newline(FILE * out)239 SECU_Newline(FILE *out)
240 {
241     fprintf(out, "\n");
242 }
243 
244 void
SECU_PrintAsHex(FILE * out,const SECItem * data,const char * m,int level)245 SECU_PrintAsHex(FILE *out, const SECItem *data, const char *m, int level)
246 {
247     unsigned i;
248     int column = 0;
249     PRBool isString = PR_TRUE;
250     PRBool isWhiteSpace = PR_TRUE;
251     PRBool printedHex = PR_FALSE;
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_MULT;
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)) {
274             isString = PR_FALSE;
275             break;
276         }
277         if (isWhiteSpace && !isspace(val)) {
278             isWhiteSpace = PR_FALSE;
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_MULT;
303                 limit = i % 16;
304             }
305         }
306         printedHex = PR_TRUE;
307     }
308     if (isString && !isWhiteSpace) {
309         if (printedHex != PR_FALSE) {
310             SECU_Newline(out);
311             SECU_Indent(out, level);
312             column = level * INDENT_MULT;
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_MULT;
327             }
328         }
329     }
330 
331     if (column != level * INDENT_MULT) {
332         SECU_Newline(out);
333     }
334 }
335 
336 const char *hex = "0123456789abcdef";
337 
338 const 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 
357 void
SECU_PrintBuf(FILE * out,const char * msg,const void * vp,int len)358 SECU_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 */
393 void
SECU_PrintInteger(FILE * out,const SECItem * i,const char * m,int level)394 SECU_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_Memcpy(data + 1, i->data, i->len);
415             tmpI.len = i->len + 1;
416             tmpI.data = (void *)data;
417 
418             iv = DER_GetInteger(&tmpI);
419         } else {
420             iv = DER_GetInteger(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(DEBUG) || defined(FORCE_PR_ASSERT)
432 /* Returns true iff a[i].flag has a duplicate in a[i+1 : count-1]  */
433 static PRBool
HasShortDuplicate(int i,secuCommandFlag * a,int count)434 HasShortDuplicate(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_TRUE;
443         }
444     }
445     return PR_FALSE;
446 }
447 
448 /* Returns true iff a[i].longform has a duplicate in a[i+1 : count-1] */
449 static PRBool
HasLongDuplicate(int i,secuCommandFlag * a,int count)450 HasLongDuplicate(int i, secuCommandFlag *a, int count)
451 {
452     int j;
453     char *target = a[i].longform;
454 
455     if (!target)
456         return PR_FALSE;
457 
458     for (j = i + 1; j < count; j++) {
459         if (a[j].longform && strcmp(a[j].longform, target) == 0) {
460             return PR_TRUE;
461         }
462     }
463     return PR_FALSE;
464 }
465 
466 /* Returns true iff a has no short or long form duplicates
467  */
468 PRBool
HasNoDuplicates(secuCommandFlag * a,int count)469 HasNoDuplicates(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_FALSE;
476         }
477         if (a[i].longform && HasLongDuplicate(i, a, count)) {
478             return PR_FALSE;
479         }
480     }
481     return PR_TRUE;
482 }
483 #endif
484 
485 SECStatus
SECU_ParseCommandLine(int argc,char ** argv,char * progName,const secuCommand * cmd)486 SECU_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;
494     int i, j;
495     int lcmd = 0, lopt = 0;
496 
497     PR_ASSERT(HasNoDuplicates(cmd->commands, cmd->numCommands));
498     PR_ASSERT(HasNoDuplicates(cmd->options, cmd->numOptions));
499 
500     optstring = (char *)PORT_Alloc(cmd->numCommands + 2 * cmd->numOptions + 1);
501     if (optstring == NULL)
502         return SECFailure;
503 
504     j = 0;
505     for (i = 0; i < cmd->numCommands; i++) {
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++) {
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) {
524         longopts = PORT_NewArray(PLLongOpt, lcmd + lopt + 1);
525         if (!longopts) {
526             PORT_Free(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;
547     }
548 
549     optstate = PL_CreateLongOptState(argc, argv, optstring, longopts);
550     if (!optstate) {
551         PORT_Free(optstring);
552         PORT_Free(longopts);
553         return SECFailure;
554     }
555     /* Parse command line arguments */
556     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
557         const char *optstatelong;
558         char option = optstate->option;
559 
560         /*  positional parameter, single-char option or long opt? */
561         if (optstate->longOptIndex == -1) {
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')
569                 option = '\377'; /* force unequal with all flags */
570             optstatelong = longopts[optstate->longOptIndex].longOptName;
571         }
572 
573         found = PR_FALSE;
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_TRUE;
579                 if (optstate->value) {
580                     cmd->commands[i].arg = (char *)optstate->value;
581                 }
582                 found = PR_TRUE;
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_TRUE;
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_TRUE;
601                 break;
602             }
603         }
604 
605         if (!found) {
606             status = PL_OPT_BAD;
607             break;
608         }
609     }
610 
611 loser:
612     PL_DestroyOptState(optstate);
613     PORT_Free(optstring);
614     if (longopts)
615         PORT_Free(longopts);
616     if (status == PL_OPT_BAD)
617         return SECFailure;
618     return SECSuccess;
619 }
620 
621 char *
SECU_GetOptionArg(const secuCommand * cmd,int optionNum)622 SECU_GetOptionArg(const secuCommand *cmd, int optionNum)
623 {
624     if (optionNum < 0 || optionNum >= cmd->numOptions)
625         return NULL;
626     if (cmd->options[optionNum].activated)
627         return PL_strdup(cmd->options[optionNum].arg);
628     else
629         return NULL;
630 }
631 
632 void
SECU_PrintPRandOSError(const char * progName)633 SECU_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_STDERR, "\t%s\n", buffer);
644     }
645 }
646 
647 SECOidTag
SECU_StringToSignatureAlgTag(const char * alg)648 SECU_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 */
675 void
SECU_SECItemToHex(const SECItem * item,char * dst)676 SECU_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             sprintf(dst, "%02x", *src++);
683         }
684         *dst = '\0';
685     }
686 }
687 
688 static unsigned char
nibble(char c)689 nibble(char c)
690 {
691     c = PORT_Tolower(c);
692     return (c >= '0' && c <= '9') ? c - '0' : (c >= 'a' && c <= 'f') ? c - 'a' + 10 : -1;
693 }
694 
695 SECStatus
SECU_SECItemHexStringToBinary(SECItem * srcdest)696 SECU_SECItemHexStringToBinary(SECItem *srcdest)
697 {
698     unsigned int i;
699 
700     if (!srcdest) {
701         PORT_SetError(SEC_ERROR_INVALID_ARGS);
702         return SECFailure;
703     }
704     if (srcdest->len < 4 || (srcdest->len % 2)) {
705         /* too short to convert, or even number of characters */
706         PORT_SetError(SEC_ERROR_BAD_DATA);
707         return SECFailure;
708     }
709     if (PORT_Strncasecmp((const char *)srcdest->data, "0x", 2)) {
710         /* wrong prefix */
711         PORT_SetError(SEC_ERROR_BAD_DATA);
712         return SECFailure;
713     }
714 
715     /* 1st pass to check for hex characters */
716     for (i = 2; i < srcdest->len; i++) {
717         char c = PORT_Tolower(srcdest->data[i]);
718         if (!((c >= '0' && c <= '9') ||
719               (c >= 'a' && c <= 'f'))) {
720             PORT_SetError(SEC_ERROR_BAD_DATA);
721             return SECFailure;
722         }
723     }
724 
725     /* 2nd pass to convert */
726     for (i = 2; i < srcdest->len; i += 2) {
727         srcdest->data[(i - 2) / 2] = (nibble(srcdest->data[i]) << 4) +
728                                      nibble(srcdest->data[i + 1]);
729     }
730 
731     /* adjust length */
732     srcdest->len -= 2;
733     srcdest->len /= 2;
734     return SECSuccess;
735 }
736 
737 SECItem *
SECU_HexString2SECItem(PLArenaPool * arena,SECItem * item,const char * str)738 SECU_HexString2SECItem(PLArenaPool *arena, SECItem *item, const char *str)
739 {
740     int i = 0;
741     int byteval = 0;
742     int tmp = PORT_Strlen(str);
743 
744     PORT_Assert(item);
745 
746     if ((tmp % 2) != 0) {
747         PORT_SetError(SEC_ERROR_INVALID_ARGS);
748         return NULL;
749     }
750 
751     item = SECITEM_AllocItem(arena, item, tmp / 2);
752     if (item == NULL) {
753         return NULL;
754     }
755 
756     while (str[i]) {
757         if ((str[i] >= '0') && (str[i] <= '9')) {
758             tmp = str[i] - '0';
759         } else if ((str[i] >= 'a') && (str[i] <= 'f')) {
760             tmp = str[i] - 'a' + 10;
761         } else if ((str[i] >= 'A') && (str[i] <= 'F')) {
762             tmp = str[i] - 'A' + 10;
763         } else {
764             if (!arena) {
765                 SECITEM_FreeItem(item, PR_FALSE);
766             }
767             return NULL;
768         }
769 
770         byteval = byteval * 16 + tmp;
771         if ((i % 2) != 0) {
772             item->data[i / 2] = byteval;
773             byteval = 0;
774         }
775         i++;
776     }
777 
778     return item;
779 }
780 
781 /* mapping between ECCurveName enum and SECOidTags */
782 static SECOidTag ecCurve_oid_map[] = {
783     SEC_OID_UNKNOWN,                /* ECCurve_noName */
784     SEC_OID_ANSIX962_EC_PRIME192V1, /* ECCurve_NIST_P192 */
785     SEC_OID_SECG_EC_SECP224R1,      /* ECCurve_NIST_P224 */
786     SEC_OID_ANSIX962_EC_PRIME256V1, /* ECCurve_NIST_P256 */
787     SEC_OID_SECG_EC_SECP384R1,      /* ECCurve_NIST_P384 */
788     SEC_OID_SECG_EC_SECP521R1,      /* ECCurve_NIST_P521 */
789     SEC_OID_SECG_EC_SECT163K1,      /* ECCurve_NIST_K163 */
790     SEC_OID_SECG_EC_SECT163R1,      /* ECCurve_NIST_B163 */
791     SEC_OID_SECG_EC_SECT233K1,      /* ECCurve_NIST_K233 */
792     SEC_OID_SECG_EC_SECT233R1,      /* ECCurve_NIST_B233 */
793     SEC_OID_SECG_EC_SECT283K1,      /* ECCurve_NIST_K283 */
794     SEC_OID_SECG_EC_SECT283R1,      /* ECCurve_NIST_B283 */
795     SEC_OID_SECG_EC_SECT409K1,      /* ECCurve_NIST_K409 */
796     SEC_OID_SECG_EC_SECT409R1,      /* ECCurve_NIST_B409 */
797     SEC_OID_SECG_EC_SECT571K1,      /* ECCurve_NIST_K571 */
798     SEC_OID_SECG_EC_SECT571R1,      /* ECCurve_NIST_B571 */
799     SEC_OID_ANSIX962_EC_PRIME192V2,
800     SEC_OID_ANSIX962_EC_PRIME192V3,
801     SEC_OID_ANSIX962_EC_PRIME239V1,
802     SEC_OID_ANSIX962_EC_PRIME239V2,
803     SEC_OID_ANSIX962_EC_PRIME239V3,
804     SEC_OID_ANSIX962_EC_C2PNB163V1,
805     SEC_OID_ANSIX962_EC_C2PNB163V2,
806     SEC_OID_ANSIX962_EC_C2PNB163V3,
807     SEC_OID_ANSIX962_EC_C2PNB176V1,
808     SEC_OID_ANSIX962_EC_C2TNB191V1,
809     SEC_OID_ANSIX962_EC_C2TNB191V2,
810     SEC_OID_ANSIX962_EC_C2TNB191V3,
811     SEC_OID_ANSIX962_EC_C2PNB208W1,
812     SEC_OID_ANSIX962_EC_C2TNB239V1,
813     SEC_OID_ANSIX962_EC_C2TNB239V2,
814     SEC_OID_ANSIX962_EC_C2TNB239V3,
815     SEC_OID_ANSIX962_EC_C2PNB272W1,
816     SEC_OID_ANSIX962_EC_C2PNB304W1,
817     SEC_OID_ANSIX962_EC_C2TNB359V1,
818     SEC_OID_ANSIX962_EC_C2PNB368W1,
819     SEC_OID_ANSIX962_EC_C2TNB431R1,
820     SEC_OID_SECG_EC_SECP112R1,
821     SEC_OID_SECG_EC_SECP112R2,
822     SEC_OID_SECG_EC_SECP128R1,
823     SEC_OID_SECG_EC_SECP128R2,
824     SEC_OID_SECG_EC_SECP160K1,
825     SEC_OID_SECG_EC_SECP160R1,
826     SEC_OID_SECG_EC_SECP160R2,
827     SEC_OID_SECG_EC_SECP192K1,
828     SEC_OID_SECG_EC_SECP224K1,
829     SEC_OID_SECG_EC_SECP256K1,
830     SEC_OID_SECG_EC_SECT113R1,
831     SEC_OID_SECG_EC_SECT113R2,
832     SEC_OID_SECG_EC_SECT131R1,
833     SEC_OID_SECG_EC_SECT131R2,
834     SEC_OID_SECG_EC_SECT163R1,
835     SEC_OID_SECG_EC_SECT193R1,
836     SEC_OID_SECG_EC_SECT193R2,
837     SEC_OID_SECG_EC_SECT239K1,
838     SEC_OID_UNKNOWN, /* ECCurve_WTLS_1 */
839     SEC_OID_UNKNOWN, /* ECCurve_WTLS_8 */
840     SEC_OID_UNKNOWN, /* ECCurve_WTLS_9 */
841     SEC_OID_CURVE25519,
842     SEC_OID_UNKNOWN /* ECCurve_pastLastCurve */
843 };
844 
845 SECStatus
SECU_ecName2params(ECCurveName curve,SECItem * params)846 SECU_ecName2params(ECCurveName curve, SECItem *params)
847 {
848     SECOidData *oidData = NULL;
849 
850     if ((curve < ECCurve_noName) || (curve > ECCurve_pastLastCurve) ||
851         ((oidData = SECOID_FindOIDByTag(ecCurve_oid_map[curve])) == NULL)) {
852         PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
853         return SECFailure;
854     }
855 
856     if (SECITEM_AllocItem(NULL, params, (2 + oidData->oid.len)) == NULL) {
857         return SECFailure;
858     }
859     /*
860      * params->data needs to contain the ASN encoding of an object ID (OID)
861      * representing the named curve. The actual OID is in
862      * oidData->oid.data so we simply prepend 0x06 and OID length
863      */
864     params->data[0] = SEC_ASN1_OBJECT_ID;
865     params->data[1] = oidData->oid.len;
866     memcpy(params->data + 2, oidData->oid.data, oidData->oid.len);
867 
868     return SECSuccess;
869 }
870