/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * 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 the Initial Developer are Copyright (C) 1994-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include #include "secutil.h" #if defined(XP_UNIX) #include #include #include #endif #if defined(XP_WIN) || defined (XP_PC) #include #include #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; iarena = 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(const SECKEYPQGParams *params) { int primeBits = 0; if (params != NULL) { int i; for (i = 0; params->prime.data[i] == 0; i++) { /* empty */; } primeBits = (params->prime.len - i) * 8; } return primeBits; } static char * getPQGString(const char *filename) { unsigned char *buf = NULL; PRFileDesc *src; PRInt32 numBytes; PRStatus prStatus; PRFileInfo info; src = PR_Open(filename, PR_RDONLY, 0); if (!src) { fprintf(stderr, "Failed to open PQG file %s\n", filename); return NULL; } prStatus = PR_GetOpenFileInfo(src, &info); if (prStatus == PR_SUCCESS) { buf = (unsigned char*)PORT_Alloc(info.size + 1); } if (!buf) { PR_Close(src); fprintf(stderr, "Failed to read PQG file %s\n", filename); return NULL; } numBytes = PR_Read(src, buf, info.size); PR_Close(src); if (numBytes != info.size) { PORT_Free(buf); fprintf(stderr, "Failed to read PQG file %s\n", filename); PORT_SetError(SEC_ERROR_IO); return NULL; } if (buf[numBytes-1] == '\n') numBytes--; if (buf[numBytes-1] == '\r') numBytes--; buf[numBytes] = 0; return (char *)buf; } static SECKEYPQGParams* getpqgfromfile(int keyBits, const char *pqgFile) { char *end, *str, *pqgString; SECKEYPQGParams* params = NULL; str = pqgString = getPQGString(pqgFile); if (!str) return NULL; do { end = PORT_Strchr(str, ','); if (end) *end = '\0'; params = decode_pqg_params(str); if (params) { int primeBits = pqg_prime_bits(params); if (keyBits == primeBits) break; CERTUTIL_DestroyParamsPQG(params); params = NULL; } if (end) str = end + 1; } while (end); PORT_Free(pqgString); return params; } static SECStatus CERTUTIL_FileForRNG(const char *noise) { char buf[2048]; PRFileDesc *fd; PRInt32 count; fd = PR_Open(noise,PR_RDONLY,0); if (!fd) { fprintf(stderr, "failed to open noise file."); return SECFailure; } do { count = PR_Read(fd,buf,sizeof(buf)); if (count > 0) { PK11_RandomUpdate(buf,count); } } while (count > 0); PR_Close(fd); return SECSuccess; } #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(const 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, const char *noise, SECKEYPublicKey **pubkeyp, const char *pqgFile, secuPWData *pwdata) { CK_MECHANISM_TYPE mechanism; SECOidTag algtag; PK11RSAGenParams rsaparams; SECKEYPQGParams * dsaparams = NULL; void * params; SECKEYPrivateKey * privKey = NULL; if (slot == NULL) return NULL; if (PK11_Authenticate(slot, PR_TRUE, pwdata) != SECSuccess) return NULL; /* * Do some random-number initialization. */ if (noise) { SECStatus rv = CERTUTIL_FileForRNG(noise); if (rv != SECSuccess) { PORT_SetError(PR_END_OF_FILE_ERROR); /* XXX */ return NULL; } } 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); if (dsaparams == NULL) return NULL; params = dsaparams; } else { /* cast away const, and don't set dsaparams */ params = (void *)&default_pqg_params; } 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; } fprintf(stderr, "\n\n"); fprintf(stderr, "Generating key. This may take a few moments...\n\n"); privKey = PK11_GenerateKeyPair(slot, mechanism, params, pubkeyp, PR_TRUE /*isPerm*/, PR_TRUE /*isSensitive*/, pwdata /*wincx*/); /* free up the params */ switch (keytype) { case rsaKey: /* nothing to free */ break; case dsaKey: if (dsaparams) CERTUTIL_DestroyParamsPQG(dsaparams); break; #ifdef NSS_ENABLE_ECC case ecKey: SECITEM_FreeItem((SECItem *)params, PR_TRUE); break; #endif } return privKey; }