makepqg.c (10462B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "prtypes.h" 6 #include "prtime.h" 7 #include "prlong.h" 8 9 #include "nss.h" 10 #include "secutil.h" 11 #include "secitem.h" 12 #include "pk11func.h" 13 #include "pk11pqg.h" 14 15 #if defined(XP_UNIX) 16 #include <unistd.h> 17 #endif 18 19 #include "plgetopt.h" 20 21 #define BPB 8 /* bits per byte. */ 22 23 char *progName; 24 25 const SEC_ASN1Template seckey_PQGParamsTemplate[] = { 26 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPQGParams) }, 27 { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams, prime) }, 28 { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams, subPrime) }, 29 { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams, base) }, 30 { 0 } 31 }; 32 33 void 34 Usage(void) 35 { 36 fprintf(stderr, "Usage: %s\n", progName); 37 fprintf(stderr, 38 "-a Output DER-encoded PQG params, BTOA encoded.\n" 39 "-b Output DER-encoded PQG params in binary\n" 40 "-r Output P, Q and G in ASCII hexadecimal. \n" 41 " -l prime-length Length of prime in bits (1024 is default)\n" 42 " -n subprime-length Length of subprime in bits\n" 43 " -o file Output to this file (default is stdout)\n" 44 " -g bits Generate SEED this many bits long.\n"); 45 exit(-1); 46 } 47 48 SECStatus 49 outputPQGParams(PQGParams *pqgParams, PRBool output_binary, PRBool output_raw, 50 FILE *outFile) 51 { 52 PLArenaPool *arena = NULL; 53 char *PQG; 54 SECItem *pItem; 55 int cc; 56 SECStatus rv; 57 SECItem encodedParams; 58 59 if (output_raw) { 60 SECItem item; 61 62 rv = PK11_PQG_GetPrimeFromParams(pqgParams, &item); 63 if (rv) { 64 SECU_PrintError(progName, "PK11_PQG_GetPrimeFromParams"); 65 return rv; 66 } 67 SECU_PrintInteger(outFile, &item, "Prime", 1); 68 SECITEM_FreeItem(&item, PR_FALSE); 69 70 rv = PK11_PQG_GetSubPrimeFromParams(pqgParams, &item); 71 if (rv) { 72 SECU_PrintError(progName, "PK11_PQG_GetPrimeFromParams"); 73 return rv; 74 } 75 SECU_PrintInteger(outFile, &item, "Subprime", 1); 76 SECITEM_FreeItem(&item, PR_FALSE); 77 78 rv = PK11_PQG_GetBaseFromParams(pqgParams, &item); 79 if (rv) { 80 SECU_PrintError(progName, "PK11_PQG_GetPrimeFromParams"); 81 return rv; 82 } 83 SECU_PrintInteger(outFile, &item, "Base", 1); 84 SECITEM_FreeItem(&item, PR_FALSE); 85 86 fprintf(outFile, "\n"); 87 return SECSuccess; 88 } 89 90 encodedParams.data = NULL; 91 encodedParams.len = 0; 92 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 93 if (!arena) { 94 SECU_PrintError(progName, "PORT_NewArena"); 95 return SECFailure; 96 } 97 pItem = SEC_ASN1EncodeItem(arena, &encodedParams, pqgParams, 98 seckey_PQGParamsTemplate); 99 if (!pItem) { 100 SECU_PrintError(progName, "SEC_ASN1EncodeItem"); 101 PORT_FreeArena(arena, PR_FALSE); 102 return SECFailure; 103 } 104 if (output_binary) { 105 size_t len; 106 len = fwrite(encodedParams.data, 1, encodedParams.len, outFile); 107 PORT_FreeArena(arena, PR_FALSE); 108 if (len != encodedParams.len) { 109 fprintf(stderr, "%s: fwrite failed\n", progName); 110 return SECFailure; 111 } 112 return SECSuccess; 113 } 114 115 /* must be output ASCII */ 116 PQG = BTOA_DataToAscii(encodedParams.data, encodedParams.len); 117 PORT_FreeArena(arena, PR_FALSE); 118 if (!PQG) { 119 SECU_PrintError(progName, "BTOA_DataToAscii"); 120 return SECFailure; 121 } 122 123 cc = fprintf(outFile, "%s\n", PQG); 124 PORT_Free(PQG); 125 if (cc <= 0) { 126 fprintf(stderr, "%s: fprintf failed\n", progName); 127 return SECFailure; 128 } 129 return SECSuccess; 130 } 131 132 SECStatus 133 outputPQGVerify(PQGVerify *pqgVerify, PRBool output_binary, PRBool output_raw, 134 FILE *outFile) 135 { 136 SECStatus rv = SECSuccess; 137 if (output_raw) { 138 SECItem item; 139 unsigned int counter; 140 141 rv = PK11_PQG_GetHFromVerify(pqgVerify, &item); 142 if (rv) { 143 SECU_PrintError(progName, "PK11_PQG_GetHFromVerify"); 144 return rv; 145 } 146 SECU_PrintInteger(outFile, &item, "h", 1); 147 SECITEM_FreeItem(&item, PR_FALSE); 148 149 rv = PK11_PQG_GetSeedFromVerify(pqgVerify, &item); 150 if (rv) { 151 SECU_PrintError(progName, "PK11_PQG_GetSeedFromVerify"); 152 return rv; 153 } 154 SECU_PrintInteger(outFile, &item, "SEED", 1); 155 fprintf(outFile, " g: %d\n", item.len * BPB); 156 SECITEM_FreeItem(&item, PR_FALSE); 157 158 counter = PK11_PQG_GetCounterFromVerify(pqgVerify); 159 fprintf(outFile, " counter: %d\n", counter); 160 fprintf(outFile, "\n"); 161 } 162 return rv; 163 } 164 165 int 166 main(int argc, char **argv) 167 { 168 FILE *outFile = NULL; 169 char *outFileName = NULL; 170 PQGParams *pqgParams = NULL; 171 PQGVerify *pqgVerify = NULL; 172 int keySizeInBits = 1024; 173 int j = 8; 174 int g = 0; 175 int gMax = 0; 176 int qSizeInBits = 0; 177 SECStatus rv = 0; 178 SECStatus passed = 0; 179 PRBool output_ascii = PR_FALSE; 180 PRBool output_binary = PR_FALSE; 181 PRBool output_raw = PR_FALSE; 182 PLOptState *optstate; 183 PLOptStatus status; 184 185 progName = strrchr(argv[0], '/'); 186 if (!progName) 187 progName = strrchr(argv[0], '\\'); 188 progName = progName ? progName + 1 : argv[0]; 189 190 /* Parse command line arguments */ 191 optstate = PL_CreateOptState(argc, argv, "?abg:l:n:o:r"); 192 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { 193 switch (optstate->option) { 194 195 case 'l': 196 keySizeInBits = atoi(optstate->value); 197 break; 198 199 case 'n': 200 qSizeInBits = atoi(optstate->value); 201 break; 202 203 case 'a': 204 output_ascii = PR_TRUE; 205 break; 206 207 case 'b': 208 output_binary = PR_TRUE; 209 break; 210 211 case 'r': 212 output_raw = PR_TRUE; 213 break; 214 215 case 'o': 216 if (outFileName) { 217 PORT_Free(outFileName); 218 } 219 outFileName = PORT_Strdup(optstate->value); 220 if (!outFileName) { 221 rv = -1; 222 } 223 break; 224 225 case 'g': 226 g = atoi(optstate->value); 227 break; 228 229 default: 230 case '?': 231 Usage(); 232 break; 233 } 234 } 235 PL_DestroyOptState(optstate); 236 237 if (status == PL_OPT_BAD) { 238 Usage(); 239 } 240 241 /* exactly 1 of these options must be set. */ 242 if (1 != ((output_ascii != PR_FALSE) + 243 (output_binary != PR_FALSE) + 244 (output_raw != PR_FALSE))) { 245 Usage(); 246 } 247 248 gMax = 2 * keySizeInBits; 249 if (keySizeInBits < 1024) { 250 j = PQG_PBITS_TO_INDEX(keySizeInBits); 251 if (j < 0) { 252 fprintf(stderr, "%s: Illegal prime length, \n" 253 "\tacceptable values are between 512 and 1024,\n" 254 "\tand divisible by 64, or 2048 or 3072\n", 255 progName); 256 return 2; 257 } 258 gMax = 2048; 259 if ((qSizeInBits != 0) && (qSizeInBits != 160)) { 260 fprintf(stderr, "%s: Illegal subprime length, \n" 261 "\tonly 160 is acceptible for primes <= 1024\n", 262 progName); 263 return 2; 264 } 265 /* this forces keysizes less than 1024 into the DSA1 generation 266 * code. Whether 1024 uses DSA2 or not is triggered by qSizeInBits 267 * being non-zero. All larger keysizes will use DSA2. 268 */ 269 qSizeInBits = 0; 270 } 271 if (g != 0 && (g < 160 || g >= gMax || g % 8 != 0)) { 272 fprintf(stderr, "%s: Illegal g bits, \n" 273 "\tacceptable values are between 160 and %d,\n" 274 "\tand divisible by 8\n", 275 progName, gMax); 276 return 3; 277 } 278 279 if (!rv && outFileName) { 280 outFile = fopen(outFileName, output_binary ? "wb" : "w"); 281 if (!outFile) { 282 fprintf(stderr, "%s: unable to open \"%s\" for writing\n", 283 progName, outFileName); 284 rv = -1; 285 } 286 } 287 if (outFileName) { 288 PORT_Free(outFileName); 289 } 290 if (rv != 0) { 291 return 1; 292 } 293 294 if (outFile == NULL) { 295 outFile = stdout; 296 } 297 298 if (NSS_NoDB_Init(NULL) != SECSuccess) { 299 return 1; 300 } 301 302 if (keySizeInBits > 1024 || qSizeInBits != 0) { 303 rv = PK11_PQG_ParamGenV2((unsigned)keySizeInBits, 304 (unsigned)qSizeInBits, (unsigned)(g / 8), 305 &pqgParams, &pqgVerify); 306 } else if (g) { 307 rv = PK11_PQG_ParamGenSeedLen((unsigned)j, (unsigned)(g / 8), 308 &pqgParams, &pqgVerify); 309 } else { 310 rv = PK11_PQG_ParamGen((unsigned)j, &pqgParams, &pqgVerify); 311 } 312 /* below here, must go to loser */ 313 314 if (rv != SECSuccess || pqgParams == NULL || pqgVerify == NULL) { 315 SECU_PrintError(progName, "PQG parameter generation failed.\n"); 316 goto loser; 317 } 318 fprintf(stderr, "%s: PQG parameter generation completed.\n", progName); 319 320 rv = outputPQGParams(pqgParams, output_binary, output_raw, outFile); 321 if (rv) { 322 fprintf(stderr, "%s: failed to output PQG params.\n", progName); 323 goto loser; 324 } 325 rv = outputPQGVerify(pqgVerify, output_binary, output_raw, outFile); 326 if (rv) { 327 fprintf(stderr, "%s: failed to output PQG Verify.\n", progName); 328 goto loser; 329 } 330 331 rv = PK11_PQG_VerifyParams(pqgParams, pqgVerify, &passed); 332 if (rv != SECSuccess) { 333 fprintf(stderr, "%s: PQG parameter verification aborted.\n", progName); 334 goto loser; 335 } 336 if (passed != SECSuccess) { 337 fprintf(stderr, "%s: PQG parameters failed verification.\n", progName); 338 goto loser; 339 } 340 fprintf(stderr, "%s: PQG parameters passed verification.\n", progName); 341 342 PK11_PQG_DestroyParams(pqgParams); 343 PK11_PQG_DestroyVerify(pqgVerify); 344 if (NSS_Shutdown() != SECSuccess) { 345 return 1; 346 } 347 return 0; 348 349 loser: 350 PK11_PQG_DestroyParams(pqgParams); 351 PK11_PQG_DestroyVerify(pqgVerify); 352 return 1; 353 }