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