summaryrefslogtreecommitdiff
path: root/security/nss/cmd/certutil/keystuff.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/cmd/certutil/keystuff.c')
-rw-r--r--security/nss/cmd/certutil/keystuff.c550
1 files changed, 550 insertions, 0 deletions
diff --git a/security/nss/cmd/certutil/keystuff.c b/security/nss/cmd/certutil/keystuff.c
new file mode 100644
index 000000000..66661c7bc
--- /dev/null
+++ b/security/nss/cmd/certutil/keystuff.c
@@ -0,0 +1,550 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
+ * Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "secutil.h"
+
+#if defined(XP_UNIX)
+#include <unistd.h>
+#include <sys/time.h>
+#include <termios.h>
+#endif
+
+#if defined(XP_WIN) || defined (XP_PC)
+#include <time.h>
+#include <conio.h>
+#endif
+
+#if defined(__sun) && !defined(SVR4)
+extern int fclose(FILE*);
+extern int fprintf(FILE *, char *, ...);
+extern int isatty(int);
+extern char *sys_errlist[];
+#define strerror(errno) sys_errlist[errno]
+#endif
+
+#include "nspr.h"
+#include "prtypes.h"
+#include "prtime.h"
+#include "prlong.h"
+
+#include "pk11func.h"
+
+#define NUM_KEYSTROKES 120
+#define RAND_BUF_SIZE 60
+
+#define ERROR_BREAK rv = SECFailure;break;
+
+const SEC_ASN1Template SECKEY_PQGParamsTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPQGParams) },
+ { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,prime) },
+ { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,subPrime) },
+ { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,base) },
+ { 0, }
+};
+
+/* returns 0 for success, -1 for failure (EOF encountered) */
+static int
+UpdateRNG(void)
+{
+ char * randbuf;
+ int fd, i, count;
+ int c;
+ int rv = 0;
+#ifdef XP_UNIX
+ cc_t orig_cc_min;
+ cc_t orig_cc_time;
+ tcflag_t orig_lflag;
+ struct termios tio;
+#endif
+
+#define FPS fprintf(stderr,
+ FPS "\n");
+ FPS "A random seed must be generated that will be used in the\n");
+ FPS "creation of your key. One of the easiest ways to create a\n");
+ FPS "random seed is to use the timing of keystrokes on a keyboard.\n");
+ FPS "\n");
+ FPS "To begin, type keys on the keyboard until this progress meter\n");
+ FPS "is full. DO NOT USE THE AUTOREPEAT FUNCTION ON YOUR KEYBOARD!\n");
+ FPS "\n");
+ FPS "\n");
+ FPS "Continue typing until the progress meter is full:\n\n");
+ FPS "| |\r");
+
+ /* turn off echo on stdin & return on 1 char instead of NL */
+ fd = fileno(stdin);
+
+#if defined(XP_UNIX) && !defined(VMS)
+ tcgetattr(fd, &tio);
+ orig_lflag = tio.c_lflag;
+ orig_cc_min = tio.c_cc[VMIN];
+ orig_cc_time = tio.c_cc[VTIME];
+ tio.c_lflag &= ~ECHO;
+ tio.c_lflag &= ~ICANON;
+ tio.c_cc[VMIN] = 1;
+ tio.c_cc[VTIME] = 0;
+ tcsetattr(fd, TCSAFLUSH, &tio);
+#endif
+
+ /* Get random noise from keyboard strokes */
+ randbuf = (char *) PORT_Alloc(RAND_BUF_SIZE);
+ count = 0;
+ while (count < NUM_KEYSTROKES+1) {
+#ifdef VMS
+ c = GENERIC_GETCHAR_NOECHO();
+#elif XP_UNIX
+ c = getc(stdin);
+#else
+ c = getch();
+#endif
+ if (c == EOF) {
+ rv = -1;
+ break;
+ }
+ PK11_RandomUpdate(randbuf, sizeof(randbuf));
+ if (c != randbuf[0]) {
+ randbuf[0] = c;
+ FPS "\r|");
+ for (i=0; i<count/(NUM_KEYSTROKES/RAND_BUF_SIZE); i++) {
+ FPS "*");
+ }
+ if (count%(NUM_KEYSTROKES/RAND_BUF_SIZE) == 1)
+ FPS "/");
+ count++;
+ }
+ }
+ free(randbuf);
+
+ FPS "\n\n");
+ FPS "Finished. Press enter to continue: ");
+#if defined(VMS)
+ while((c = GENERIC_GETCHAR_NO_ECHO()) != '\r' && c != EOF)
+ ;
+#else
+ while ((c = getc(stdin)) != '\n' && c != EOF)
+ ;
+#endif
+ if (c == EOF)
+ rv = -1;
+ FPS "\n");
+
+#undef FPS
+
+#if defined(XP_UNIX) && !defined(VMS)
+ /* set back termio the way it was */
+ tio.c_lflag = orig_lflag;
+ tio.c_cc[VMIN] = orig_cc_min;
+ tio.c_cc[VTIME] = orig_cc_time;
+ tcsetattr(fd, TCSAFLUSH, &tio);
+#endif
+ return rv;
+}
+
+
+static unsigned char P[] = { 0x00, 0x8d, 0xf2, 0xa4, 0x94, 0x49, 0x22, 0x76,
+ 0xaa, 0x3d, 0x25, 0x75, 0x9b, 0xb0, 0x68, 0x69,
+ 0xcb, 0xea, 0xc0, 0xd8, 0x3a, 0xfb, 0x8d, 0x0c,
+ 0xf7, 0xcb, 0xb8, 0x32, 0x4f, 0x0d, 0x78, 0x82,
+ 0xe5, 0xd0, 0x76, 0x2f, 0xc5, 0xb7, 0x21, 0x0e,
+ 0xaf, 0xc2, 0xe9, 0xad, 0xac, 0x32, 0xab, 0x7a,
+ 0xac, 0x49, 0x69, 0x3d, 0xfb, 0xf8, 0x37, 0x24,
+ 0xc2, 0xec, 0x07, 0x36, 0xee, 0x31, 0xc8, 0x02,
+ 0x91 };
+static unsigned char Q[] = { 0x00, 0xc7, 0x73, 0x21, 0x8c, 0x73, 0x7e, 0xc8,
+ 0xee, 0x99, 0x3b, 0x4f, 0x2d, 0xed, 0x30, 0xf4,
+ 0x8e, 0xda, 0xce, 0x91, 0x5f };
+static unsigned char G[] = { 0x00, 0x62, 0x6d, 0x02, 0x78, 0x39, 0xea, 0x0a,
+ 0x13, 0x41, 0x31, 0x63, 0xa5, 0x5b, 0x4c, 0xb5,
+ 0x00, 0x29, 0x9d, 0x55, 0x22, 0x95, 0x6c, 0xef,
+ 0xcb, 0x3b, 0xff, 0x10, 0xf3, 0x99, 0xce, 0x2c,
+ 0x2e, 0x71, 0xcb, 0x9d, 0xe5, 0xfa, 0x24, 0xba,
+ 0xbf, 0x58, 0xe5, 0xb7, 0x95, 0x21, 0x92, 0x5c,
+ 0x9c, 0xc4, 0x2e, 0x9f, 0x6f, 0x46, 0x4b, 0x08,
+ 0x8c, 0xc5, 0x72, 0xaf, 0x53, 0xe6, 0xd7, 0x88,
+ 0x02 };
+
+static SECKEYPQGParams default_pqg_params = {
+ NULL,
+ { 0, P, sizeof(P) },
+ { 0, Q, sizeof(Q) },
+ { 0, G, sizeof(G) }
+};
+
+static SECKEYPQGParams *
+decode_pqg_params(char *str)
+{
+ char *buf;
+ unsigned int len;
+ PRArenaPool *arena;
+ SECKEYPQGParams *params;
+ SECStatus status;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL)
+ return NULL;
+
+ params = PORT_ArenaZAlloc(arena, sizeof(SECKEYPQGParams));
+ if (params == NULL)
+ goto loser;
+ params->arena = arena;
+
+ buf = (char *)ATOB_AsciiToData(str, &len);
+ if ((buf == NULL) || (len == 0))
+ goto loser;
+
+ status = SEC_ASN1Decode(arena, params, SECKEY_PQGParamsTemplate, buf, len);
+ if (status != SECSuccess)
+ goto loser;
+
+ return params;
+
+loser:
+ if (arena != NULL)
+ PORT_FreeArena(arena, PR_FALSE);
+ return NULL;
+}
+
+void
+CERTUTIL_DestroyParamsPQG(SECKEYPQGParams *params)
+{
+ if (params->arena) {
+ PORT_FreeArena(params->arena, PR_FALSE);
+ }
+}
+
+static int
+pqg_prime_bits(char *str)
+{
+ SECKEYPQGParams *params = NULL;
+ int primeBits = 0, i;
+
+ params = decode_pqg_params(str);
+ if (params == NULL)
+ goto done; /* lose */
+
+ for (i = 0; params->prime.data[i] == 0; i++)
+ /* empty */;
+ primeBits = (params->prime.len - i) * 8;
+
+done:
+ if (params != NULL)
+ CERTUTIL_DestroyParamsPQG(params);
+ return primeBits;
+}
+
+static char *
+SECU_GetpqgString(char *filename)
+{
+ char phrase[400];
+ FILE *fh;
+ char *rv;
+
+ fh = fopen(filename,"r");
+ rv = fgets (phrase, sizeof(phrase), fh);
+
+ fclose(fh);
+ if (phrase[strlen(phrase)-1] == '\n')
+ phrase[strlen(phrase)-1] = '\0';
+ if (rv) {
+ return (char*) PORT_Strdup(phrase);
+ }
+ fprintf(stderr,"pqg file contain no data\n");
+ return NULL;
+}
+
+SECKEYPQGParams*
+getpqgfromfile(int keyBits, char *pqgFile)
+{
+ char *end, *str, *pqgString;
+ int primeBits;
+
+ pqgString = SECU_GetpqgString(pqgFile);
+ if (pqgString)
+ str = PORT_Strdup(pqgString);
+ else
+ return NULL;
+
+ do {
+ end = PORT_Strchr(str, ',');
+ if (end)
+ *end = '\0';
+ primeBits = pqg_prime_bits(str);
+ if (keyBits == primeBits)
+ goto found_match;
+ str = end + 1;
+ } while (end);
+
+ PORT_Free(pqgString);
+ PORT_Free(str);
+ return NULL;
+
+found_match:
+ PORT_Free(pqgString);
+ PORT_Free(str);
+ return decode_pqg_params(str);
+}
+
+void CERTUTIL_FileForRNG(char *noise)
+{
+ char buf[2048];
+ PRFileDesc *fd;
+ PRInt32 count;
+
+ fd = PR_OpenFile(noise,PR_RDONLY,0666);
+ if (!fd) return;
+
+ do {
+ count = PR_Read(fd,buf,sizeof(buf));
+ if (count > 0) {
+ PK11_RandomUpdate(buf,count);
+ }
+ } while (count > 0);
+
+ PR_Close(fd);
+
+}
+
+#ifdef NSS_ENABLE_ECC
+typedef struct curveNameTagPairStr {
+ char *curveName;
+ SECOidTag curveOidTag;
+} CurveNameTagPair;
+
+#define DEFAULT_CURVE_OID_TAG SEC_OID_SECG_EC_SECP192R1
+/* #define DEFAULT_CURVE_OID_TAG SEC_OID_SECG_EC_SECP160R1 */
+
+static CurveNameTagPair nameTagPair[] =
+{
+ { "sect163k1", SEC_OID_SECG_EC_SECT163K1},
+ { "nistk163", SEC_OID_SECG_EC_SECT163K1},
+ { "sect163r1", SEC_OID_SECG_EC_SECT163R1},
+ { "sect163r2", SEC_OID_SECG_EC_SECT163R2},
+ { "nistb163", SEC_OID_SECG_EC_SECT163R2},
+ { "sect193r1", SEC_OID_SECG_EC_SECT193R1},
+ { "sect193r2", SEC_OID_SECG_EC_SECT193R2},
+ { "sect233k1", SEC_OID_SECG_EC_SECT233K1},
+ { "nistk233", SEC_OID_SECG_EC_SECT233K1},
+ { "sect233r1", SEC_OID_SECG_EC_SECT233R1},
+ { "nistb233", SEC_OID_SECG_EC_SECT233R1},
+ { "sect239k1", SEC_OID_SECG_EC_SECT239K1},
+ { "sect283k1", SEC_OID_SECG_EC_SECT283K1},
+ { "nistk283", SEC_OID_SECG_EC_SECT283K1},
+ { "sect283r1", SEC_OID_SECG_EC_SECT283R1},
+ { "nistb283", SEC_OID_SECG_EC_SECT283R1},
+ { "sect409k1", SEC_OID_SECG_EC_SECT409K1},
+ { "nistk409", SEC_OID_SECG_EC_SECT409K1},
+ { "sect409r1", SEC_OID_SECG_EC_SECT409R1},
+ { "nistb409", SEC_OID_SECG_EC_SECT409R1},
+ { "sect571k1", SEC_OID_SECG_EC_SECT571K1},
+ { "nistk571", SEC_OID_SECG_EC_SECT571K1},
+ { "sect571r1", SEC_OID_SECG_EC_SECT571R1},
+ { "nistb571", SEC_OID_SECG_EC_SECT571R1},
+ { "secp160k1", SEC_OID_SECG_EC_SECP160K1},
+ { "secp160r1", SEC_OID_SECG_EC_SECP160R1},
+ { "secp160r2", SEC_OID_SECG_EC_SECP160R2},
+ { "secp192k1", SEC_OID_SECG_EC_SECP192K1},
+ { "secp192r1", SEC_OID_SECG_EC_SECP192R1},
+ { "nistp192", SEC_OID_SECG_EC_SECP192R1},
+ { "secp224k1", SEC_OID_SECG_EC_SECP224K1},
+ { "secp224r1", SEC_OID_SECG_EC_SECP224R1},
+ { "nistp224", SEC_OID_SECG_EC_SECP224R1},
+ { "secp256k1", SEC_OID_SECG_EC_SECP256K1},
+ { "secp256r1", SEC_OID_SECG_EC_SECP256R1},
+ { "nistp256", SEC_OID_SECG_EC_SECP256R1},
+ { "secp384r1", SEC_OID_SECG_EC_SECP384R1},
+ { "nistp384", SEC_OID_SECG_EC_SECP384R1},
+ { "secp521r1", SEC_OID_SECG_EC_SECP521R1},
+ { "nistp521", SEC_OID_SECG_EC_SECP521R1},
+
+ { "prime192v1", SEC_OID_ANSIX962_EC_PRIME192V1 },
+ { "prime192v2", SEC_OID_ANSIX962_EC_PRIME192V2 },
+ { "prime192v3", SEC_OID_ANSIX962_EC_PRIME192V3 },
+ { "prime239v1", SEC_OID_ANSIX962_EC_PRIME239V1 },
+ { "prime239v2", SEC_OID_ANSIX962_EC_PRIME239V2 },
+ { "prime239v3", SEC_OID_ANSIX962_EC_PRIME239V3 },
+
+ { "c2pnb163v1", SEC_OID_ANSIX962_EC_C2PNB163V1 },
+ { "c2pnb163v2", SEC_OID_ANSIX962_EC_C2PNB163V2 },
+ { "c2pnb163v3", SEC_OID_ANSIX962_EC_C2PNB163V3 },
+ { "c2pnb176v1", SEC_OID_ANSIX962_EC_C2PNB176V1 },
+ { "c2tnb191v1", SEC_OID_ANSIX962_EC_C2TNB191V1 },
+ { "c2tnb191v2", SEC_OID_ANSIX962_EC_C2TNB191V2 },
+ { "c2tnb191v3", SEC_OID_ANSIX962_EC_C2TNB191V3 },
+ { "c2onb191v4", SEC_OID_ANSIX962_EC_C2ONB191V4 },
+ { "c2onb191v5", SEC_OID_ANSIX962_EC_C2ONB191V5 },
+ { "c2pnb208w1", SEC_OID_ANSIX962_EC_C2PNB208W1 },
+ { "c2tnb239v1", SEC_OID_ANSIX962_EC_C2TNB239V1 },
+ { "c2tnb239v2", SEC_OID_ANSIX962_EC_C2TNB239V2 },
+ { "c2tnb239v3", SEC_OID_ANSIX962_EC_C2TNB239V3 },
+ { "c2onb239v4", SEC_OID_ANSIX962_EC_C2ONB239V4 },
+ { "c2onb239v5", SEC_OID_ANSIX962_EC_C2ONB239V5 },
+ { "c2pnb272w1", SEC_OID_ANSIX962_EC_C2PNB272W1 },
+ { "c2pnb304w1", SEC_OID_ANSIX962_EC_C2PNB304W1 },
+ { "c2tnb359v1", SEC_OID_ANSIX962_EC_C2TNB359V1 },
+ { "c2pnb368w1", SEC_OID_ANSIX962_EC_C2PNB368W1 },
+ { "c2tnb431r1", SEC_OID_ANSIX962_EC_C2TNB431R1 },
+
+ { "secp112r1", SEC_OID_SECG_EC_SECP112R1},
+ { "secp112r2", SEC_OID_SECG_EC_SECP112R2},
+ { "secp128r1", SEC_OID_SECG_EC_SECP128R1},
+ { "secp128r2", SEC_OID_SECG_EC_SECP128R2},
+
+ { "sect113r1", SEC_OID_SECG_EC_SECT113R1},
+ { "sect113r2", SEC_OID_SECG_EC_SECT113R2},
+ { "sect131r1", SEC_OID_SECG_EC_SECT131R1},
+ { "sect131r2", SEC_OID_SECG_EC_SECT131R2},
+};
+
+static SECKEYECParams *
+getECParams(char *curve)
+{
+ SECKEYECParams *ecparams;
+ SECOidData *oidData = NULL;
+ SECOidTag curveOidTag = SEC_OID_UNKNOWN; /* default */
+ int i, numCurves;
+
+ if (curve != NULL) {
+ numCurves = sizeof(nameTagPair)/sizeof(CurveNameTagPair);
+ for (i = 0; ((i < numCurves) && (curveOidTag == SEC_OID_UNKNOWN));
+ i++) {
+ if (PL_strcmp(curve, nameTagPair[i].curveName) == 0)
+ curveOidTag = nameTagPair[i].curveOidTag;
+ }
+ }
+
+ /* Return NULL if curve name is not recognized */
+ if ((curveOidTag == SEC_OID_UNKNOWN) ||
+ (oidData = SECOID_FindOIDByTag(curveOidTag)) == NULL) {
+ fprintf(stderr, "Unrecognized elliptic curve %s\n", curve);
+ return NULL;
+ }
+
+ ecparams = SECITEM_AllocItem(NULL, NULL, (2 + oidData->oid.len));
+
+ /*
+ * ecparams->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
+ */
+ ecparams->data[0] = SEC_ASN1_OBJECT_ID;
+ ecparams->data[1] = oidData->oid.len;
+ memcpy(ecparams->data + 2, oidData->oid.data, oidData->oid.len);
+
+ return ecparams;
+}
+#endif /* NSS_ENABLE_ECC */
+
+SECKEYPrivateKey *
+CERTUTIL_GeneratePrivateKey(KeyType keytype, PK11SlotInfo *slot, int size,
+ int publicExponent, char *noise,
+ SECKEYPublicKey **pubkeyp, char *pqgFile,
+ secuPWData *pwdata)
+{
+ CK_MECHANISM_TYPE mechanism;
+ SECOidTag algtag;
+ PK11RSAGenParams rsaparams;
+ SECKEYPQGParams *dsaparams = NULL;
+ void *params;
+ PRArenaPool *dsaparena;
+
+ /*
+ * Do some random-number initialization.
+ */
+
+ if (noise) {
+ CERTUTIL_FileForRNG(noise);
+ } else {
+ int rv = UpdateRNG();
+ if (rv) {
+ PORT_SetError(PR_END_OF_FILE_ERROR);
+ return NULL;
+ }
+ }
+
+ switch (keytype) {
+ case rsaKey:
+ rsaparams.keySizeInBits = size;
+ rsaparams.pe = publicExponent;
+ mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
+ algtag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
+ params = &rsaparams;
+ break;
+ case dsaKey:
+ mechanism = CKM_DSA_KEY_PAIR_GEN;
+ algtag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
+ if (pqgFile) {
+ dsaparams = getpqgfromfile(size, pqgFile);
+ } else {
+ dsaparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (dsaparena == NULL) return NULL;
+ dsaparams = PORT_ArenaZAlloc(dsaparena, sizeof(SECKEYPQGParams));
+ if (dsaparams == NULL) return NULL;
+ dsaparams->arena = dsaparena;
+ SECITEM_AllocItem(dsaparena, &dsaparams->prime, sizeof P);
+ SECITEM_AllocItem(dsaparena, &dsaparams->subPrime, sizeof Q);
+ SECITEM_AllocItem(dsaparena, &dsaparams->base, sizeof G);
+ PORT_Memcpy(dsaparams->prime.data, P, dsaparams->prime.len);
+ PORT_Memcpy(dsaparams->subPrime.data, Q, dsaparams->subPrime.len);
+ PORT_Memcpy(dsaparams->base.data, G, dsaparams->base.len);
+ }
+ params = dsaparams;
+ break;
+#ifdef NSS_ENABLE_ECC
+ case ecKey:
+ mechanism = CKM_EC_KEY_PAIR_GEN;
+ /* For EC keys, PQGFile determines EC parameters */
+ if ((params = (void *) getECParams(pqgFile)) == NULL)
+ return NULL;
+ break;
+#endif /* NSS_ENABLE_ECC */
+ default:
+ return NULL;
+ }
+
+ if (slot == NULL)
+ return NULL;
+ if (PK11_Authenticate(slot, PR_TRUE, pwdata) != SECSuccess)
+ return NULL;
+
+ fprintf(stderr, "\n\n");
+ fprintf(stderr, "Generating key. This may take a few moments...\n\n");
+
+ return PK11_GenerateKeyPair(slot, mechanism, params, pubkeyp,
+ PR_TRUE /*isPerm*/, PR_TRUE /*isSensitive*/,
+ pwdata /*wincx*/);
+}