| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| /* |
| ** secutil.c - various functions used by security stuff |
| ** |
| */ |
| |
| #include "prtypes.h" |
| #include "prtime.h" |
| #include "prlong.h" |
| #include "prerror.h" |
| #include "prprf.h" |
| #include "plgetopt.h" |
| #include "prenv.h" |
| #include "prnetdb.h" |
| |
| #include "basicutil.h" |
| #include <stdarg.h> |
| #include <sys/stat.h> |
| #include <errno.h> |
| |
| #ifdef XP_UNIX |
| #include <unistd.h> |
| #endif |
| |
| #include "secoid.h" |
| |
| extern long DER_GetInteger(const SECItem *src); |
| |
| static PRBool wrapEnabled = PR_TRUE; |
| |
| void |
| SECU_EnableWrap(PRBool enable) |
| { |
| wrapEnabled = enable; |
| } |
| |
| PRBool |
| SECU_GetWrapEnabled(void) |
| { |
| return wrapEnabled; |
| } |
| |
| void |
| SECU_PrintErrMsg(FILE *out, int level, const char *progName, const char *msg, |
| ...) |
| { |
| va_list args; |
| PRErrorCode err = PORT_GetError(); |
| const char *errString = PORT_ErrorToString(err); |
| |
| va_start(args, msg); |
| |
| SECU_Indent(out, level); |
| fprintf(out, "%s: ", progName); |
| vfprintf(out, msg, args); |
| if (errString != NULL && PORT_Strlen(errString) > 0) |
| fprintf(out, ": %s\n", errString); |
| else |
| fprintf(out, ": error %d\n", (int)err); |
| |
| va_end(args); |
| } |
| |
| void |
| SECU_PrintError(const char *progName, const char *msg, ...) |
| { |
| va_list args; |
| PRErrorCode err = PORT_GetError(); |
| const char *errName = PR_ErrorToName(err); |
| const char *errString = PR_ErrorToString(err, 0); |
| |
| va_start(args, msg); |
| |
| fprintf(stderr, "%s: ", progName); |
| vfprintf(stderr, msg, args); |
| |
| if (errName != NULL) { |
| fprintf(stderr, ": %s", errName); |
| } else { |
| fprintf(stderr, ": error %d", (int)err); |
| } |
| |
| if (errString != NULL && PORT_Strlen(errString) > 0) |
| fprintf(stderr, ": %s\n", errString); |
| |
| va_end(args); |
| } |
| |
| void |
| SECU_PrintSystemError(const char *progName, const char *msg, ...) |
| { |
| va_list args; |
| |
| va_start(args, msg); |
| fprintf(stderr, "%s: ", progName); |
| vfprintf(stderr, msg, args); |
| fprintf(stderr, ": %s\n", strerror(errno)); |
| va_end(args); |
| } |
| |
| SECStatus |
| secu_StdinToItem(SECItem *dst) |
| { |
| unsigned char buf[1000]; |
| PRInt32 numBytes; |
| PRBool notDone = PR_TRUE; |
| |
| dst->len = 0; |
| dst->data = NULL; |
| |
| while (notDone) { |
| numBytes = PR_Read(PR_STDIN, buf, sizeof(buf)); |
| |
| if (numBytes < 0) { |
| return SECFailure; |
| } |
| |
| if (numBytes == 0) |
| break; |
| |
| if (dst->data) { |
| unsigned char *p = dst->data; |
| dst->data = (unsigned char *)PORT_Realloc(p, dst->len + numBytes); |
| if (!dst->data) { |
| PORT_Free(p); |
| } |
| } else { |
| dst->data = (unsigned char *)PORT_Alloc(numBytes); |
| } |
| if (!dst->data) { |
| return SECFailure; |
| } |
| PORT_Memcpy(dst->data + dst->len, buf, numBytes); |
| dst->len += numBytes; |
| } |
| |
| return SECSuccess; |
| } |
| |
| SECStatus |
| SECU_FileToItem(SECItem *dst, PRFileDesc *src) |
| { |
| PRFileInfo info; |
| PRInt32 numBytes; |
| PRStatus prStatus; |
| |
| if (src == PR_STDIN) |
| return secu_StdinToItem(dst); |
| |
| prStatus = PR_GetOpenFileInfo(src, &info); |
| |
| if (prStatus != PR_SUCCESS) { |
| PORT_SetError(SEC_ERROR_IO); |
| return SECFailure; |
| } |
| |
| /* XXX workaround for 3.1, not all utils zero dst before sending */ |
| dst->data = 0; |
| if (!SECITEM_AllocItem(NULL, dst, info.size)) |
| goto loser; |
| |
| numBytes = PR_Read(src, dst->data, info.size); |
| if (numBytes != info.size) { |
| PORT_SetError(SEC_ERROR_IO); |
| goto loser; |
| } |
| |
| return SECSuccess; |
| loser: |
| SECITEM_FreeItem(dst, PR_FALSE); |
| dst->data = NULL; |
| return SECFailure; |
| } |
| |
| SECStatus |
| SECU_TextFileToItem(SECItem *dst, PRFileDesc *src) |
| { |
| PRFileInfo info; |
| PRInt32 numBytes; |
| PRStatus prStatus; |
| unsigned char *buf; |
| |
| if (src == PR_STDIN) |
| return secu_StdinToItem(dst); |
| |
| prStatus = PR_GetOpenFileInfo(src, &info); |
| |
| if (prStatus != PR_SUCCESS) { |
| PORT_SetError(SEC_ERROR_IO); |
| return SECFailure; |
| } |
| |
| buf = (unsigned char *)PORT_Alloc(info.size); |
| if (!buf) |
| return SECFailure; |
| |
| numBytes = PR_Read(src, buf, info.size); |
| if (numBytes != info.size) { |
| PORT_SetError(SEC_ERROR_IO); |
| goto loser; |
| } |
| |
| if (buf[numBytes - 1] == '\n') |
| numBytes--; |
| #ifdef _WINDOWS |
| if (buf[numBytes - 1] == '\r') |
| numBytes--; |
| #endif |
| |
| /* XXX workaround for 3.1, not all utils zero dst before sending */ |
| dst->data = 0; |
| if (!SECITEM_AllocItem(NULL, dst, numBytes)) |
| goto loser; |
| |
| memcpy(dst->data, buf, numBytes); |
| |
| PORT_Free(buf); |
| return SECSuccess; |
| loser: |
| PORT_Free(buf); |
| return SECFailure; |
| } |
| |
| #define INDENT_MULT 4 |
| void |
| SECU_Indent(FILE *out, int level) |
| { |
| int i; |
| |
| for (i = 0; i < level; i++) { |
| fprintf(out, " "); |
| } |
| } |
| |
| void |
| SECU_Newline(FILE *out) |
| { |
| fprintf(out, "\n"); |
| } |
| |
| void |
| SECU_PrintAsHex(FILE *out, const SECItem *data, const char *m, int level) |
| { |
| unsigned i; |
| int column = 0; |
| PRBool isString = PR_TRUE; |
| PRBool isWhiteSpace = PR_TRUE; |
| PRBool printedHex = PR_FALSE; |
| unsigned int limit = 15; |
| |
| if (m) { |
| SECU_Indent(out, level); |
| fprintf(out, "%s:", m); |
| level++; |
| if (wrapEnabled) |
| fprintf(out, "\n"); |
| } |
| |
| if (wrapEnabled) { |
| SECU_Indent(out, level); |
| column = level * INDENT_MULT; |
| } |
| if (!data->len) { |
| fprintf(out, "(empty)\n"); |
| return; |
| } |
| /* take a pass to see if it's all printable. */ |
| for (i = 0; i < data->len; i++) { |
| unsigned char val = data->data[i]; |
| if (!val || !isprint(val)) { |
| isString = PR_FALSE; |
| break; |
| } |
| if (isWhiteSpace && !isspace(val)) { |
| isWhiteSpace = PR_FALSE; |
| } |
| } |
| |
| /* Short values, such as bit strings (which are printed with this |
| ** function) often look like strings, but we want to see the bits. |
| ** so this test assures that short values will be printed in hex, |
| ** perhaps in addition to being printed as strings. |
| ** The threshold size (4 bytes) is arbitrary. |
| */ |
| if (!isString || data->len <= 4) { |
| for (i = 0; i < data->len; i++) { |
| if (i != data->len - 1) { |
| fprintf(out, "%02x:", data->data[i]); |
| column += 3; |
| } else { |
| fprintf(out, "%02x", data->data[i]); |
| column += 2; |
| break; |
| } |
| if (wrapEnabled && |
| (column > 76 || (i % 16 == limit))) { |
| SECU_Newline(out); |
| SECU_Indent(out, level); |
| column = level * INDENT_MULT; |
| limit = i % 16; |
| } |
| } |
| printedHex = PR_TRUE; |
| } |
| if (isString && !isWhiteSpace) { |
| if (printedHex != PR_FALSE) { |
| SECU_Newline(out); |
| SECU_Indent(out, level); |
| column = level * INDENT_MULT; |
| } |
| for (i = 0; i < data->len; i++) { |
| unsigned char val = data->data[i]; |
| |
| if (val) { |
| fprintf(out, "%c", val); |
| column++; |
| } else { |
| column = 77; |
| } |
| if (wrapEnabled && column > 76) { |
| SECU_Newline(out); |
| SECU_Indent(out, level); |
| column = level * INDENT_MULT; |
| } |
| } |
| } |
| |
| if (column != level * INDENT_MULT) { |
| SECU_Newline(out); |
| } |
| } |
| |
| const char *hex = "0123456789abcdef"; |
| |
| const char printable[257] = { |
| "................" /* 0x */ |
| "................" /* 1x */ |
| " !\"#$%&'()*+,-./" /* 2x */ |
| "0123456789:;<=>?" /* 3x */ |
| "@ABCDEFGHIJKLMNO" /* 4x */ |
| "PQRSTUVWXYZ[\\]^_" /* 5x */ |
| "`abcdefghijklmno" /* 6x */ |
| "pqrstuvwxyz{|}~." /* 7x */ |
| "................" /* 8x */ |
| "................" /* 9x */ |
| "................" /* ax */ |
| "................" /* bx */ |
| "................" /* cx */ |
| "................" /* dx */ |
| "................" /* ex */ |
| "................" /* fx */ |
| }; |
| |
| void |
| SECU_PrintBuf(FILE *out, const char *msg, const void *vp, int len) |
| { |
| const unsigned char *cp = (const unsigned char *)vp; |
| char buf[80]; |
| char *bp; |
| char *ap; |
| |
| fprintf(out, "%s [Len: %d]\n", msg, len); |
| memset(buf, ' ', sizeof buf); |
| bp = buf; |
| ap = buf + 50; |
| while (--len >= 0) { |
| unsigned char ch = *cp++; |
| *bp++ = hex[(ch >> 4) & 0xf]; |
| *bp++ = hex[ch & 0xf]; |
| *bp++ = ' '; |
| *ap++ = printable[ch]; |
| if (ap - buf >= 66) { |
| *ap = 0; |
| fprintf(out, " %s\n", buf); |
| memset(buf, ' ', sizeof buf); |
| bp = buf; |
| ap = buf + 50; |
| } |
| } |
| if (bp > buf) { |
| *ap = 0; |
| fprintf(out, " %s\n", buf); |
| } |
| } |
| |
| /* This expents i->data[0] to be the MSB of the integer. |
| ** if you want to print a DER-encoded integer (with the tag and length) |
| ** call SECU_PrintEncodedInteger(); |
| */ |
| void |
| SECU_PrintInteger(FILE *out, const SECItem *i, const char *m, int level) |
| { |
| int iv; |
| |
| if (!i || !i->len || !i->data) { |
| SECU_Indent(out, level); |
| if (m) { |
| fprintf(out, "%s: (null)\n", m); |
| } else { |
| fprintf(out, "(null)\n"); |
| } |
| } else if (i->len > 4) { |
| SECU_PrintAsHex(out, i, m, level); |
| } else { |
| if (i->type == siUnsignedInteger && *i->data & 0x80) { |
| /* Make sure i->data has zero in the highest bite |
| * if i->data is an unsigned integer */ |
| SECItem tmpI; |
| char data[] = { 0, 0, 0, 0, 0 }; |
| |
| PORT_Memcpy(data + 1, i->data, i->len); |
| tmpI.len = i->len + 1; |
| tmpI.data = (void *)data; |
| |
| iv = DER_GetInteger(&tmpI); |
| } else { |
| iv = DER_GetInteger(i); |
| } |
| SECU_Indent(out, level); |
| if (m) { |
| fprintf(out, "%s: %d (0x%x)\n", m, iv, iv); |
| } else { |
| fprintf(out, "%d (0x%x)\n", iv, iv); |
| } |
| } |
| } |
| |
| #if defined(DEBUG) || defined(FORCE_PR_ASSERT) |
| /* Returns true iff a[i].flag has a duplicate in a[i+1 : count-1] */ |
| static PRBool |
| HasShortDuplicate(int i, secuCommandFlag *a, int count) |
| { |
| char target = a[i].flag; |
| int j; |
| |
| /* duplicate '\0' flags are okay, they are used with long forms */ |
| for (j = i + 1; j < count; j++) { |
| if (a[j].flag && a[j].flag == target) { |
| return PR_TRUE; |
| } |
| } |
| return PR_FALSE; |
| } |
| |
| /* Returns true iff a[i].longform has a duplicate in a[i+1 : count-1] */ |
| static PRBool |
| HasLongDuplicate(int i, secuCommandFlag *a, int count) |
| { |
| int j; |
| char *target = a[i].longform; |
| |
| if (!target) |
| return PR_FALSE; |
| |
| for (j = i + 1; j < count; j++) { |
| if (a[j].longform && strcmp(a[j].longform, target) == 0) { |
| return PR_TRUE; |
| } |
| } |
| return PR_FALSE; |
| } |
| |
| /* Returns true iff a has no short or long form duplicates |
| */ |
| PRBool |
| HasNoDuplicates(secuCommandFlag *a, int count) |
| { |
| int i; |
| |
| for (i = 0; i < count; i++) { |
| if (a[i].flag && HasShortDuplicate(i, a, count)) { |
| return PR_FALSE; |
| } |
| if (a[i].longform && HasLongDuplicate(i, a, count)) { |
| return PR_FALSE; |
| } |
| } |
| return PR_TRUE; |
| } |
| #endif |
| |
| SECStatus |
| SECU_ParseCommandLine(int argc, char **argv, char *progName, |
| const secuCommand *cmd) |
| { |
| PRBool found; |
| PLOptState *optstate; |
| PLOptStatus status; |
| char *optstring; |
| PLLongOpt *longopts = NULL; |
| int i, j; |
| int lcmd = 0, lopt = 0; |
| |
| PR_ASSERT(HasNoDuplicates(cmd->commands, cmd->numCommands)); |
| PR_ASSERT(HasNoDuplicates(cmd->options, cmd->numOptions)); |
| |
| optstring = (char *)PORT_Alloc(cmd->numCommands + 2 * cmd->numOptions + 1); |
| if (optstring == NULL) |
| return SECFailure; |
| |
| j = 0; |
| for (i = 0; i < cmd->numCommands; i++) { |
| if (cmd->commands[i].flag) /* single character option ? */ |
| optstring[j++] = cmd->commands[i].flag; |
| if (cmd->commands[i].longform) |
| lcmd++; |
| } |
| for (i = 0; i < cmd->numOptions; i++) { |
| if (cmd->options[i].flag) { |
| optstring[j++] = cmd->options[i].flag; |
| if (cmd->options[i].needsArg) |
| optstring[j++] = ':'; |
| } |
| if (cmd->options[i].longform) |
| lopt++; |
| } |
| |
| optstring[j] = '\0'; |
| |
| if (lcmd + lopt > 0) { |
| longopts = PORT_NewArray(PLLongOpt, lcmd + lopt + 1); |
| if (!longopts) { |
| PORT_Free(optstring); |
| return SECFailure; |
| } |
| |
| j = 0; |
| for (i = 0; j < lcmd && i < cmd->numCommands; i++) { |
| if (cmd->commands[i].longform) { |
| longopts[j].longOptName = cmd->commands[i].longform; |
| longopts[j].longOption = 0; |
| longopts[j++].valueRequired = cmd->commands[i].needsArg; |
| } |
| } |
| lopt += lcmd; |
| for (i = 0; j < lopt && i < cmd->numOptions; i++) { |
| if (cmd->options[i].longform) { |
| longopts[j].longOptName = cmd->options[i].longform; |
| longopts[j].longOption = 0; |
| longopts[j++].valueRequired = cmd->options[i].needsArg; |
| } |
| } |
| longopts[j].longOptName = NULL; |
| } |
| |
| optstate = PL_CreateLongOptState(argc, argv, optstring, longopts); |
| if (!optstate) { |
| PORT_Free(optstring); |
| PORT_Free(longopts); |
| return SECFailure; |
| } |
| /* Parse command line arguments */ |
| while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { |
| const char *optstatelong; |
| char option = optstate->option; |
| |
| /* positional parameter, single-char option or long opt? */ |
| if (optstate->longOptIndex == -1) { |
| /* not a long opt */ |
| if (option == '\0') |
| continue; /* it's a positional parameter */ |
| optstatelong = ""; |
| } else { |
| /* long opt */ |
| if (option == '\0') |
| option = '\377'; /* force unequal with all flags */ |
| optstatelong = longopts[optstate->longOptIndex].longOptName; |
| } |
| |
| found = PR_FALSE; |
| |
| for (i = 0; i < cmd->numCommands; i++) { |
| if (cmd->commands[i].flag == option || |
| cmd->commands[i].longform == optstatelong) { |
| cmd->commands[i].activated = PR_TRUE; |
| if (optstate->value) { |
| cmd->commands[i].arg = (char *)optstate->value; |
| } |
| found = PR_TRUE; |
| break; |
| } |
| } |
| |
| if (found) |
| continue; |
| |
| for (i = 0; i < cmd->numOptions; i++) { |
| if (cmd->options[i].flag == option || |
| cmd->options[i].longform == optstatelong) { |
| cmd->options[i].activated = PR_TRUE; |
| if (optstate->value) { |
| cmd->options[i].arg = (char *)optstate->value; |
| } else if (cmd->options[i].needsArg) { |
| status = PL_OPT_BAD; |
| goto loser; |
| } |
| found = PR_TRUE; |
| break; |
| } |
| } |
| |
| if (!found) { |
| status = PL_OPT_BAD; |
| break; |
| } |
| } |
| |
| loser: |
| PL_DestroyOptState(optstate); |
| PORT_Free(optstring); |
| if (longopts) |
| PORT_Free(longopts); |
| if (status == PL_OPT_BAD) |
| return SECFailure; |
| return SECSuccess; |
| } |
| |
| char * |
| SECU_GetOptionArg(const secuCommand *cmd, int optionNum) |
| { |
| if (optionNum < 0 || optionNum >= cmd->numOptions) |
| return NULL; |
| if (cmd->options[optionNum].activated) |
| return PL_strdup(cmd->options[optionNum].arg); |
| else |
| return NULL; |
| } |
| |
| void |
| SECU_PrintPRandOSError(const char *progName) |
| { |
| char buffer[513]; |
| PRInt32 errLen = PR_GetErrorTextLength(); |
| if (errLen > 0 && errLen < sizeof buffer) { |
| PR_GetErrorText(buffer); |
| } |
| SECU_PrintError(progName, "function failed"); |
| if (errLen > 0 && errLen < sizeof buffer) { |
| PR_fprintf(PR_STDERR, "\t%s\n", buffer); |
| } |
| } |
| |
| SECOidTag |
| SECU_StringToSignatureAlgTag(const char *alg) |
| { |
| SECOidTag hashAlgTag = SEC_OID_UNKNOWN; |
| |
| if (alg) { |
| if (!PL_strcmp(alg, "MD2")) { |
| hashAlgTag = SEC_OID_MD2; |
| } else if (!PL_strcmp(alg, "MD4")) { |
| hashAlgTag = SEC_OID_MD4; |
| } else if (!PL_strcmp(alg, "MD5")) { |
| hashAlgTag = SEC_OID_MD5; |
| } else if (!PL_strcmp(alg, "SHA1")) { |
| hashAlgTag = SEC_OID_SHA1; |
| } else if (!PL_strcmp(alg, "SHA224")) { |
| hashAlgTag = SEC_OID_SHA224; |
| } else if (!PL_strcmp(alg, "SHA256")) { |
| hashAlgTag = SEC_OID_SHA256; |
| } else if (!PL_strcmp(alg, "SHA384")) { |
| hashAlgTag = SEC_OID_SHA384; |
| } else if (!PL_strcmp(alg, "SHA512")) { |
| hashAlgTag = SEC_OID_SHA512; |
| } |
| } |
| return hashAlgTag; |
| } |
| |
| /* Caller ensures that dst is at least item->len*2+1 bytes long */ |
| void |
| SECU_SECItemToHex(const SECItem *item, char *dst) |
| { |
| if (dst && item && item->data) { |
| unsigned char *src = item->data; |
| unsigned int len = item->len; |
| for (; len > 0; --len, dst += 2) { |
| sprintf(dst, "%02x", *src++); |
| } |
| *dst = '\0'; |
| } |
| } |
| |
| static unsigned char |
| nibble(char c) |
| { |
| c = PORT_Tolower(c); |
| return (c >= '0' && c <= '9') ? c - '0' : (c >= 'a' && c <= 'f') ? c - 'a' + 10 : -1; |
| } |
| |
| SECStatus |
| SECU_SECItemHexStringToBinary(SECItem *srcdest) |
| { |
| unsigned int i; |
| |
| if (!srcdest) { |
| PORT_SetError(SEC_ERROR_INVALID_ARGS); |
| return SECFailure; |
| } |
| if (srcdest->len < 4 || (srcdest->len % 2)) { |
| /* too short to convert, or even number of characters */ |
| PORT_SetError(SEC_ERROR_BAD_DATA); |
| return SECFailure; |
| } |
| if (PORT_Strncasecmp((const char *)srcdest->data, "0x", 2)) { |
| /* wrong prefix */ |
| PORT_SetError(SEC_ERROR_BAD_DATA); |
| return SECFailure; |
| } |
| |
| /* 1st pass to check for hex characters */ |
| for (i = 2; i < srcdest->len; i++) { |
| char c = PORT_Tolower(srcdest->data[i]); |
| if (!((c >= '0' && c <= '9') || |
| (c >= 'a' && c <= 'f'))) { |
| PORT_SetError(SEC_ERROR_BAD_DATA); |
| return SECFailure; |
| } |
| } |
| |
| /* 2nd pass to convert */ |
| for (i = 2; i < srcdest->len; i += 2) { |
| srcdest->data[(i - 2) / 2] = (nibble(srcdest->data[i]) << 4) + |
| nibble(srcdest->data[i + 1]); |
| } |
| |
| /* adjust length */ |
| srcdest->len -= 2; |
| srcdest->len /= 2; |
| return SECSuccess; |
| } |
| |
| SECItem * |
| SECU_HexString2SECItem(PLArenaPool *arena, SECItem *item, const char *str) |
| { |
| int i = 0; |
| int byteval = 0; |
| int tmp = PORT_Strlen(str); |
| |
| PORT_Assert(arena); |
| PORT_Assert(item); |
| |
| if ((tmp % 2) != 0) { |
| PORT_SetError(SEC_ERROR_INVALID_ARGS); |
| return NULL; |
| } |
| |
| item = SECITEM_AllocItem(arena, item, tmp / 2); |
| if (item == NULL) { |
| return NULL; |
| } |
| |
| while (str[i]) { |
| if ((str[i] >= '0') && (str[i] <= '9')) { |
| tmp = str[i] - '0'; |
| } else if ((str[i] >= 'a') && (str[i] <= 'f')) { |
| tmp = str[i] - 'a' + 10; |
| } else if ((str[i] >= 'A') && (str[i] <= 'F')) { |
| tmp = str[i] - 'A' + 10; |
| } else { |
| /* item is in arena and gets freed by the caller */ |
| return NULL; |
| } |
| |
| byteval = byteval * 16 + tmp; |
| if ((i % 2) != 0) { |
| item->data[i / 2] = byteval; |
| byteval = 0; |
| } |
| i++; |
| } |
| |
| return item; |
| } |
| |
| /* mapping between ECCurveName enum and SECOidTags */ |
| static SECOidTag ecCurve_oid_map[] = { |
| SEC_OID_UNKNOWN, /* ECCurve_noName */ |
| SEC_OID_ANSIX962_EC_PRIME192V1, /* ECCurve_NIST_P192 */ |
| SEC_OID_SECG_EC_SECP224R1, /* ECCurve_NIST_P224 */ |
| SEC_OID_ANSIX962_EC_PRIME256V1, /* ECCurve_NIST_P256 */ |
| SEC_OID_SECG_EC_SECP384R1, /* ECCurve_NIST_P384 */ |
| SEC_OID_SECG_EC_SECP521R1, /* ECCurve_NIST_P521 */ |
| SEC_OID_SECG_EC_SECT163K1, /* ECCurve_NIST_K163 */ |
| SEC_OID_SECG_EC_SECT163R1, /* ECCurve_NIST_B163 */ |
| SEC_OID_SECG_EC_SECT233K1, /* ECCurve_NIST_K233 */ |
| SEC_OID_SECG_EC_SECT233R1, /* ECCurve_NIST_B233 */ |
| SEC_OID_SECG_EC_SECT283K1, /* ECCurve_NIST_K283 */ |
| SEC_OID_SECG_EC_SECT283R1, /* ECCurve_NIST_B283 */ |
| SEC_OID_SECG_EC_SECT409K1, /* ECCurve_NIST_K409 */ |
| SEC_OID_SECG_EC_SECT409R1, /* ECCurve_NIST_B409 */ |
| SEC_OID_SECG_EC_SECT571K1, /* ECCurve_NIST_K571 */ |
| SEC_OID_SECG_EC_SECT571R1, /* ECCurve_NIST_B571 */ |
| SEC_OID_ANSIX962_EC_PRIME192V2, |
| SEC_OID_ANSIX962_EC_PRIME192V3, |
| SEC_OID_ANSIX962_EC_PRIME239V1, |
| SEC_OID_ANSIX962_EC_PRIME239V2, |
| SEC_OID_ANSIX962_EC_PRIME239V3, |
| SEC_OID_ANSIX962_EC_C2PNB163V1, |
| SEC_OID_ANSIX962_EC_C2PNB163V2, |
| SEC_OID_ANSIX962_EC_C2PNB163V3, |
| SEC_OID_ANSIX962_EC_C2PNB176V1, |
| SEC_OID_ANSIX962_EC_C2TNB191V1, |
| SEC_OID_ANSIX962_EC_C2TNB191V2, |
| SEC_OID_ANSIX962_EC_C2TNB191V3, |
| SEC_OID_ANSIX962_EC_C2PNB208W1, |
| SEC_OID_ANSIX962_EC_C2TNB239V1, |
| SEC_OID_ANSIX962_EC_C2TNB239V2, |
| SEC_OID_ANSIX962_EC_C2TNB239V3, |
| SEC_OID_ANSIX962_EC_C2PNB272W1, |
| SEC_OID_ANSIX962_EC_C2PNB304W1, |
| SEC_OID_ANSIX962_EC_C2TNB359V1, |
| SEC_OID_ANSIX962_EC_C2PNB368W1, |
| SEC_OID_ANSIX962_EC_C2TNB431R1, |
| SEC_OID_SECG_EC_SECP112R1, |
| SEC_OID_SECG_EC_SECP112R2, |
| SEC_OID_SECG_EC_SECP128R1, |
| SEC_OID_SECG_EC_SECP128R2, |
| SEC_OID_SECG_EC_SECP160K1, |
| SEC_OID_SECG_EC_SECP160R1, |
| SEC_OID_SECG_EC_SECP160R2, |
| SEC_OID_SECG_EC_SECP192K1, |
| SEC_OID_SECG_EC_SECP224K1, |
| SEC_OID_SECG_EC_SECP256K1, |
| SEC_OID_SECG_EC_SECT113R1, |
| SEC_OID_SECG_EC_SECT113R2, |
| SEC_OID_SECG_EC_SECT131R1, |
| SEC_OID_SECG_EC_SECT131R2, |
| SEC_OID_SECG_EC_SECT163R1, |
| SEC_OID_SECG_EC_SECT193R1, |
| SEC_OID_SECG_EC_SECT193R2, |
| SEC_OID_SECG_EC_SECT239K1, |
| SEC_OID_UNKNOWN, /* ECCurve_WTLS_1 */ |
| SEC_OID_UNKNOWN, /* ECCurve_WTLS_8 */ |
| SEC_OID_UNKNOWN, /* ECCurve_WTLS_9 */ |
| SEC_OID_CURVE25519, |
| SEC_OID_UNKNOWN /* ECCurve_pastLastCurve */ |
| }; |
| |
| SECStatus |
| SECU_ecName2params(ECCurveName curve, SECItem *params) |
| { |
| SECOidData *oidData = NULL; |
| |
| if ((curve < ECCurve_noName) || (curve > ECCurve_pastLastCurve) || |
| ((oidData = SECOID_FindOIDByTag(ecCurve_oid_map[curve])) == NULL)) { |
| PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
| return SECFailure; |
| } |
| |
| if (SECITEM_AllocItem(NULL, params, (2 + oidData->oid.len)) == NULL) { |
| return SECFailure; |
| } |
| /* |
| * params->data needs to contain the ASN encoding of an object ID (OID) |
| * representing the named curve. The actual OID is in |
| * oidData->oid.data so we simply prepend 0x06 and OID length |
| */ |
| params->data[0] = SEC_ASN1_OBJECT_ID; |
| params->data[1] = oidData->oid.len; |
| memcpy(params->data + 2, oidData->oid.data, oidData->oid.len); |
| |
| return SECSuccess; |
| } |