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
Usage(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
outputPQGParams(PQGParams * pqgParams,PRBool output_binary,PRBool output_raw,FILE * outFile)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
outputPQGVerify(PQGVerify * pqgVerify,PRBool output_binary,PRBool output_raw,FILE * outFile)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
main(int argc,char ** argv)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 NSS_NoDB_Init(NULL);
299
300 if (keySizeInBits > 1024 || qSizeInBits != 0) {
301 rv = PK11_PQG_ParamGenV2((unsigned)keySizeInBits,
302 (unsigned)qSizeInBits, (unsigned)(g /
303 8),
304 &pqgParams, &pqgVerify);
305 } else if (g) {
306 rv = PK11_PQG_ParamGenSeedLen((unsigned)j, (unsigned)(g / 8),
307 &pqgParams, &pqgVerify);
308 } else {
309 rv = PK11_PQG_ParamGen((unsigned)j, &pqgParams, &pqgVerify);
310 }
311 /* below here, must go to loser */
312
313 if (rv != SECSuccess || pqgParams == NULL || pqgVerify == NULL) {
314 SECU_PrintError(progName, "PQG parameter generation failed.\n");
315 goto loser;
316 }
317 fprintf(stderr, "%s: PQG parameter generation completed.\n", progName);
318
319 rv = outputPQGParams(pqgParams, output_binary, output_raw, outFile);
320 if (rv) {
321 fprintf(stderr, "%s: failed to output PQG params.\n", progName);
322 goto loser;
323 }
324 rv = outputPQGVerify(pqgVerify, output_binary, output_raw, outFile);
325 if (rv) {
326 fprintf(stderr, "%s: failed to output PQG Verify.\n", progName);
327 goto loser;
328 }
329
330 rv = PK11_PQG_VerifyParams(pqgParams, pqgVerify, &passed);
331 if (rv != SECSuccess) {
332 fprintf(stderr, "%s: PQG parameter verification aborted.\n", progName);
333 goto loser;
334 }
335 if (passed != SECSuccess) {
336 fprintf(stderr, "%s: PQG parameters failed verification.\n", progName);
337 goto loser;
338 }
339 fprintf(stderr, "%s: PQG parameters passed verification.\n", progName);
340
341 PK11_PQG_DestroyParams(pqgParams);
342 PK11_PQG_DestroyVerify(pqgVerify);
343 return 0;
344
345 loser:
346 PK11_PQG_DestroyParams(pqgParams);
347 PK11_PQG_DestroyVerify(pqgVerify);
348 return 1;
349 }
350