diff options
Diffstat (limited to 'security/nss/cmd/certutil/keystuff.c')
-rw-r--r-- | security/nss/cmd/certutil/keystuff.c | 550 |
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*/); +} |