michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "prtypes.h" michael@0: #include "prtime.h" michael@0: #include "prlong.h" michael@0: michael@0: #include "nss.h" michael@0: #include "secutil.h" michael@0: #include "secitem.h" michael@0: #include "pk11func.h" michael@0: #include "pk11pqg.h" michael@0: michael@0: #if defined(XP_UNIX) michael@0: #include michael@0: #endif michael@0: michael@0: #include "plgetopt.h" michael@0: michael@0: #define BPB 8 /* bits per byte. */ michael@0: michael@0: char *progName; michael@0: michael@0: michael@0: const SEC_ASN1Template seckey_PQGParamsTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPQGParams) }, michael@0: { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,prime) }, michael@0: { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,subPrime) }, michael@0: { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,base) }, michael@0: { 0, } michael@0: }; michael@0: michael@0: michael@0: michael@0: void michael@0: Usage(void) michael@0: { michael@0: fprintf(stderr, "Usage: %s\n", progName); michael@0: fprintf(stderr, michael@0: "-a Output DER-encoded PQG params, BTOA encoded.\n" michael@0: "-b Output DER-encoded PQG params in binary\n" michael@0: "-r Output P, Q and G in ASCII hexadecimal. \n" michael@0: " -l prime-length Length of prime in bits (1024 is default)\n" michael@0: " -n subprime-length Length of subprime in bits\n" michael@0: " -o file Output to this file (default is stdout)\n" michael@0: " -g bits Generate SEED this many bits long.\n" michael@0: ); michael@0: exit(-1); michael@0: michael@0: } michael@0: michael@0: SECStatus michael@0: outputPQGParams(PQGParams * pqgParams, PRBool output_binary, PRBool output_raw, michael@0: FILE * outFile) michael@0: { michael@0: PLArenaPool * arena = NULL; michael@0: char * PQG; michael@0: SECItem * pItem; michael@0: int cc; michael@0: SECStatus rv; michael@0: SECItem encodedParams; michael@0: michael@0: if (output_raw) { michael@0: SECItem item; michael@0: michael@0: rv = PK11_PQG_GetPrimeFromParams(pqgParams, &item); michael@0: if (rv) { michael@0: SECU_PrintError(progName, "PK11_PQG_GetPrimeFromParams"); michael@0: return rv; michael@0: } michael@0: SECU_PrintInteger(outFile, &item, "Prime", 1); michael@0: SECITEM_FreeItem(&item, PR_FALSE); michael@0: michael@0: rv = PK11_PQG_GetSubPrimeFromParams(pqgParams, &item); michael@0: if (rv) { michael@0: SECU_PrintError(progName, "PK11_PQG_GetPrimeFromParams"); michael@0: return rv; michael@0: } michael@0: SECU_PrintInteger(outFile, &item, "Subprime", 1); michael@0: SECITEM_FreeItem(&item, PR_FALSE); michael@0: michael@0: rv = PK11_PQG_GetBaseFromParams(pqgParams, &item); michael@0: if (rv) { michael@0: SECU_PrintError(progName, "PK11_PQG_GetPrimeFromParams"); michael@0: return rv; michael@0: } michael@0: SECU_PrintInteger(outFile, &item, "Base", 1); michael@0: SECITEM_FreeItem(&item, PR_FALSE); michael@0: michael@0: fprintf(outFile, "\n"); michael@0: return SECSuccess; michael@0: } michael@0: michael@0: encodedParams.data = NULL; michael@0: encodedParams.len = 0; michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (!arena) { michael@0: SECU_PrintError(progName, "PORT_NewArena"); michael@0: return SECFailure; michael@0: } michael@0: pItem = SEC_ASN1EncodeItem(arena, &encodedParams, pqgParams, michael@0: seckey_PQGParamsTemplate); michael@0: if (!pItem) { michael@0: SECU_PrintError(progName, "SEC_ASN1EncodeItem"); michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: return SECFailure; michael@0: } michael@0: if (output_binary) { michael@0: size_t len; michael@0: len = fwrite(encodedParams.data, 1, encodedParams.len, outFile); michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: if (len != encodedParams.len) { michael@0: fprintf(stderr, "%s: fwrite failed\n", progName); michael@0: return SECFailure; michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: /* must be output ASCII */ michael@0: PQG = BTOA_DataToAscii(encodedParams.data, encodedParams.len); michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: if (!PQG) { michael@0: SECU_PrintError(progName, "BTOA_DataToAscii"); michael@0: return SECFailure; michael@0: } michael@0: michael@0: cc = fprintf(outFile,"%s\n",PQG); michael@0: PORT_Free(PQG); michael@0: if (cc <= 0) { michael@0: fprintf(stderr, "%s: fprintf failed\n", progName); michael@0: return SECFailure; michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: SECStatus michael@0: outputPQGVerify(PQGVerify * pqgVerify, PRBool output_binary, PRBool output_raw, michael@0: FILE * outFile) michael@0: { michael@0: SECStatus rv = SECSuccess; michael@0: if (output_raw) { michael@0: SECItem item; michael@0: unsigned int counter; michael@0: michael@0: rv = PK11_PQG_GetHFromVerify(pqgVerify, &item); michael@0: if (rv) { michael@0: SECU_PrintError(progName, "PK11_PQG_GetHFromVerify"); michael@0: return rv; michael@0: } michael@0: SECU_PrintInteger(outFile, &item, "h", 1); michael@0: SECITEM_FreeItem(&item, PR_FALSE); michael@0: michael@0: rv = PK11_PQG_GetSeedFromVerify(pqgVerify, &item); michael@0: if (rv) { michael@0: SECU_PrintError(progName, "PK11_PQG_GetSeedFromVerify"); michael@0: return rv; michael@0: } michael@0: SECU_PrintInteger(outFile, &item, "SEED", 1); michael@0: fprintf(outFile, " g: %d\n", item.len * BPB); michael@0: SECITEM_FreeItem(&item, PR_FALSE); michael@0: michael@0: counter = PK11_PQG_GetCounterFromVerify(pqgVerify); michael@0: fprintf(outFile, " counter: %d\n", counter); michael@0: fprintf(outFile, "\n"); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: int michael@0: main(int argc, char **argv) michael@0: { michael@0: FILE * outFile = NULL; michael@0: char * outFileName = NULL; michael@0: PQGParams * pqgParams = NULL; michael@0: PQGVerify * pqgVerify = NULL; michael@0: int keySizeInBits = 1024; michael@0: int j = 8; michael@0: int g = 0; michael@0: int gMax = 0; michael@0: int qSizeInBits = 0; michael@0: SECStatus rv = 0; michael@0: SECStatus passed = 0; michael@0: PRBool output_ascii = PR_FALSE; michael@0: PRBool output_binary = PR_FALSE; michael@0: PRBool output_raw = PR_FALSE; michael@0: PLOptState *optstate; michael@0: PLOptStatus status; michael@0: michael@0: michael@0: progName = strrchr(argv[0], '/'); michael@0: if (!progName) michael@0: progName = strrchr(argv[0], '\\'); michael@0: progName = progName ? progName+1 : argv[0]; michael@0: michael@0: /* Parse command line arguments */ michael@0: optstate = PL_CreateOptState(argc, argv, "?abg:l:n:o:r" ); michael@0: while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { michael@0: switch (optstate->option) { michael@0: michael@0: case 'l': michael@0: keySizeInBits = atoi(optstate->value); michael@0: break; michael@0: michael@0: case 'n': michael@0: qSizeInBits = atoi(optstate->value); michael@0: break; michael@0: michael@0: case 'a': michael@0: output_ascii = PR_TRUE; michael@0: break; michael@0: michael@0: case 'b': michael@0: output_binary = PR_TRUE; michael@0: break; michael@0: michael@0: case 'r': michael@0: output_raw = PR_TRUE; michael@0: break; michael@0: michael@0: case 'o': michael@0: if (outFileName) { michael@0: PORT_Free(outFileName); michael@0: } michael@0: outFileName = PORT_Strdup(optstate->value); michael@0: if (!outFileName) { michael@0: rv = -1; michael@0: } michael@0: break; michael@0: michael@0: case 'g': michael@0: g = atoi(optstate->value); michael@0: break; michael@0: michael@0: michael@0: default: michael@0: case '?': michael@0: Usage(); michael@0: break; michael@0: michael@0: } michael@0: } michael@0: PL_DestroyOptState(optstate); michael@0: michael@0: if (status == PL_OPT_BAD) { michael@0: Usage(); michael@0: } michael@0: michael@0: /* exactly 1 of these options must be set. */ michael@0: if (1 != ((output_ascii != PR_FALSE) + michael@0: (output_binary != PR_FALSE) + michael@0: (output_raw != PR_FALSE))) { michael@0: Usage(); michael@0: } michael@0: michael@0: gMax = 2*keySizeInBits; michael@0: if (keySizeInBits < 1024) { michael@0: j = PQG_PBITS_TO_INDEX(keySizeInBits); michael@0: if (j < 0) { michael@0: fprintf(stderr, "%s: Illegal prime length, \n" michael@0: "\tacceptable values are between 512 and 1024,\n" michael@0: "\tand divisible by 64, or 2048 or 3072\n", michael@0: progName); michael@0: return 2; michael@0: } michael@0: gMax =2048; michael@0: if ((qSizeInBits != 0) && (qSizeInBits != 160)) { michael@0: fprintf(stderr, "%s: Illegal subprime length, \n" michael@0: "\tonly 160 is acceptible for primes <= 1024\n", michael@0: progName); michael@0: return 2; michael@0: } michael@0: /* this forces keysizes less than 1024 into the DSA1 generation michael@0: * code. Whether 1024 uses DSA2 or not is triggered by qSizeInBits michael@0: * being non-zero. All larger keysizes will use DSA2. michael@0: */ michael@0: qSizeInBits = 0; michael@0: } michael@0: if (g != 0 && (g < 160 || g >= gMax || g % 8 != 0)) { michael@0: fprintf(stderr, "%s: Illegal g bits, \n" michael@0: "\tacceptable values are between 160 and %d,\n" michael@0: "\tand divisible by 8\n", progName, gMax); michael@0: return 3; michael@0: } michael@0: michael@0: if (!rv && outFileName) { michael@0: outFile = fopen(outFileName, output_binary ? "wb" : "w"); michael@0: if (!outFile) { michael@0: fprintf(stderr, "%s: unable to open \"%s\" for writing\n", michael@0: progName, outFileName); michael@0: rv = -1; michael@0: } michael@0: } michael@0: if (outFileName) { michael@0: PORT_Free(outFileName); michael@0: } michael@0: if (rv != 0) { michael@0: return 1; michael@0: } michael@0: michael@0: if (outFile == NULL) { michael@0: outFile = stdout; michael@0: } michael@0: michael@0: michael@0: NSS_NoDB_Init(NULL); michael@0: michael@0: if (keySizeInBits > 1024 || qSizeInBits != 0) { michael@0: rv = PK11_PQG_ParamGenV2((unsigned)keySizeInBits, michael@0: (unsigned) qSizeInBits, (unsigned)(g/8), &pqgParams, &pqgVerify); michael@0: } else if (g) { michael@0: rv = PK11_PQG_ParamGenSeedLen((unsigned)j, (unsigned)(g/8), michael@0: &pqgParams, &pqgVerify); michael@0: } else { michael@0: rv = PK11_PQG_ParamGen((unsigned)j, &pqgParams, &pqgVerify); michael@0: } michael@0: /* below here, must go to loser */ michael@0: michael@0: if (rv != SECSuccess || pqgParams == NULL || pqgVerify == NULL) { michael@0: SECU_PrintError(progName, "PQG parameter generation failed.\n"); michael@0: goto loser; michael@0: } michael@0: fprintf(stderr, "%s: PQG parameter generation completed.\n", progName); michael@0: michael@0: rv = outputPQGParams(pqgParams, output_binary, output_raw, outFile); michael@0: if (rv) { michael@0: fprintf(stderr, "%s: failed to output PQG params.\n", progName); michael@0: goto loser; michael@0: } michael@0: rv = outputPQGVerify(pqgVerify, output_binary, output_raw, outFile); michael@0: if (rv) { michael@0: fprintf(stderr, "%s: failed to output PQG Verify.\n", progName); michael@0: goto loser; michael@0: } michael@0: michael@0: rv = PK11_PQG_VerifyParams(pqgParams, pqgVerify, &passed); michael@0: if (rv != SECSuccess) { michael@0: fprintf(stderr, "%s: PQG parameter verification aborted.\n", progName); michael@0: goto loser; michael@0: } michael@0: if (passed != SECSuccess) { michael@0: fprintf(stderr, "%s: PQG parameters failed verification.\n", progName); michael@0: goto loser; michael@0: } michael@0: fprintf(stderr, "%s: PQG parameters passed verification.\n", progName); michael@0: michael@0: PK11_PQG_DestroyParams(pqgParams); michael@0: PK11_PQG_DestroyVerify(pqgVerify); michael@0: return 0; michael@0: michael@0: loser: michael@0: PK11_PQG_DestroyParams(pqgParams); michael@0: PK11_PQG_DestroyVerify(pqgVerify); michael@0: return 1; michael@0: }