/* * 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. * * Contributor(s): * * 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 #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" #include "secrng.h" #include "pqgutil.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(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); } 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; 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*/); }