tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

basicutil.c (21371B)


      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
     35 SECU_EnableWrap(PRBool enable)
     36 {
     37    wrapEnabled = enable;
     38 }
     39 
     40 PRBool
     41 SECU_GetWrapEnabled(void)
     42 {
     43    return wrapEnabled;
     44 }
     45 
     46 void
     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
     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
     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
    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
    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
    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
    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
    239 SECU_Newline(FILE *out)
    240 {
    241    fprintf(out, "\n");
    242 }
    243 
    244 void
    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
    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
    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
    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
    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
    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
    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 *
    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
    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
    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
    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            snprintf(dst, 3, "%02x", *src++);
    683        }
    684    }
    685 }
    686 
    687 static unsigned char
    688 nibble(char c)
    689 {
    690    c = PORT_Tolower((unsigned char)c);
    691    return (c >= '0' && c <= '9') ? c - '0' : (c >= 'a' && c <= 'f') ? c - 'a' + 10
    692                                                                     : -1;
    693 }
    694 
    695 SECStatus
    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 *
    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 SECStatus
    782 SECU_ecName2params(ECCurveName curve, SECItem *params)
    783 {
    784    SECOidTag oidTag;
    785    SECOidData *oidData = NULL;
    786 
    787    switch (curve) {
    788        case ECCurve_NIST_P256:
    789            oidTag = SEC_OID_ANSIX962_EC_PRIME256V1;
    790            break;
    791        case ECCurve_NIST_P384:
    792            oidTag = SEC_OID_SECG_EC_SECP384R1;
    793            break;
    794        case ECCurve_NIST_P521:
    795            oidTag = SEC_OID_SECG_EC_SECP521R1;
    796            break;
    797        case ECCurve25519:
    798            oidTag = SEC_OID_CURVE25519;
    799            break;
    800        case ECCurve_Ed25519:
    801            oidTag = SEC_OID_ED25519_PUBLIC_KEY;
    802            break;
    803        default:
    804            PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    805            return SECFailure;
    806    }
    807 
    808    oidData = SECOID_FindOIDByTag(oidTag);
    809    if (oidData == NULL) {
    810        PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
    811        return SECFailure;
    812    }
    813 
    814    if (SECITEM_AllocItem(NULL, params, (2 + oidData->oid.len)) == NULL) {
    815        return SECFailure;
    816    }
    817    /*
    818     * params->data needs to contain the ASN encoding of an object ID (OID)
    819     * representing the named curve. The actual OID is in
    820     * oidData->oid.data so we simply prepend 0x06 and OID length
    821     */
    822    params->data[0] = SEC_ASN1_OBJECT_ID;
    823    params->data[1] = oidData->oid.len;
    824    memcpy(params->data + 2, oidData->oid.data, oidData->oid.len);
    825 
    826    return SECSuccess;
    827 }