1 #if defined(XP_UNIX)
2 #include <unistd.h>
3 #endif
4 #include <stdio.h>
5 #include <nss.h>
6 #include <prtypes.h>
7 #include <prerr.h>
8 #include <prerror.h>
9 #include <prthread.h>
10 #include <pk11pub.h>
11 #include <keyhi.h>
12 
13 #define MAX_THREAD_COUNT 100
14 
15 /* globals */
16 int THREAD_COUNT = 30;
17 int FAILED = 0;
18 int ERROR = 0;
19 int LOOP_COUNT = 100;
20 int KEY_SIZE = 3072;
21 int STACK_SIZE = 0;
22 int VERBOSE = 0;
23 char *NSSDIR = ".";
24 PRBool ISTOKEN = PR_TRUE;
25 CK_MECHANISM_TYPE MECHANISM = CKM_RSA_PKCS_KEY_PAIR_GEN;
26 
27 void
usage(char * prog,char * error)28 usage(char *prog, char *error)
29 {
30     if (error) {
31         fprintf(stderr, "Bad Arguments: %s", error);
32     }
33     fprintf(stderr, "usage: %s [-l loop_count] [-t thread_count] "
34                     "[-k key_size] [-s stack_size] [-d nss_dir] [-e] [-v] [-h]\n",
35             prog);
36     fprintf(stderr, "    loop_count   -- "
37                     "number of keys to generate on each thread (default=%d)\n",
38             LOOP_COUNT);
39     fprintf(stderr, "    thread_count -- "
40                     "number of of concurrent threads to run (def=%d,max=%d)\n",
41             THREAD_COUNT, MAX_THREAD_COUNT);
42     fprintf(stderr, "    key_size     -- "
43                     "rsa key size in bits (default=%d)\n",
44             KEY_SIZE);
45     fprintf(stderr, "    stack_size     -- "
46                     "thread stack size in bytes, 0=optimal (default=%d)\n",
47             STACK_SIZE);
48     fprintf(stderr, "    nss_dir     -- "
49                     "location of the nss directory (default=%s)\n",
50             NSSDIR);
51     fprintf(stderr, "    -e use session keys rather than token keys\n");
52     fprintf(stderr, "    -v verbose, print progress indicators\n");
53     fprintf(stderr, "    -h print this message\n");
54     exit(2);
55 }
56 
57 void
create_key_loop(void * arg)58 create_key_loop(void *arg)
59 {
60     int i;
61     PK11SlotInfo *slot = PK11_GetInternalKeySlot();
62     PK11RSAGenParams param;
63     int threadnumber = *(int *)arg;
64     int failures = 0;
65     int progress = 5;
66     PRIntervalTime epoch = PR_IntervalNow();
67     param.keySizeInBits = KEY_SIZE;
68     param.pe = 0x10001L;
69     printf(" - thread %d starting\n", threadnumber);
70     progress = 30 / THREAD_COUNT;
71     if (progress < 2)
72         progress = 2;
73     for (i = 0; i < LOOP_COUNT; i++) {
74         SECKEYPrivateKey *privKey;
75         SECKEYPublicKey *pubKey;
76         privKey = PK11_GenerateKeyPair(slot, MECHANISM, &param, &pubKey,
77                                        ISTOKEN, PR_TRUE, NULL);
78         if (privKey == NULL) {
79             fprintf(stderr,
80                     "keypair gen in thread %d failed %s\n", threadnumber,
81                     PORT_ErrorToString(PORT_GetError()));
82             FAILED++;
83             failures++;
84         }
85         if (VERBOSE && (i % progress) == 0) {
86             PRIntervalTime current = PR_IntervalNow();
87             PRIntervalTime interval = current - epoch;
88             int seconds = (interval / PR_TicksPerSecond());
89             int mseconds = ((interval * 1000) / PR_TicksPerSecond()) - (seconds * 1000);
90             epoch = current;
91             printf(" - thread %d @ %d iterations %d.%03d sec\n", threadnumber,
92                    i, seconds, mseconds);
93         }
94         if (ISTOKEN && privKey) {
95             SECKEY_DestroyPublicKey(pubKey);
96             SECKEY_DestroyPrivateKey(privKey);
97         }
98     }
99     PK11_FreeSlot(slot);
100     printf(" * thread %d ending with %d failures\n", threadnumber, failures);
101     return;
102 }
103 
104 int
main(int argc,char ** argv)105 main(int argc, char **argv)
106 {
107     PRThread *thread[MAX_THREAD_COUNT];
108     int threadnumber[MAX_THREAD_COUNT];
109     int i;
110     PRStatus status;
111     SECStatus rv;
112     char *prog = *argv++;
113     char buf[2048];
114     char *arg;
115 
116     while ((arg = *argv++) != NULL) {
117         if (*arg == '-') {
118             switch (arg[1]) {
119                 case 'l':
120                     if (*argv == NULL)
121                         usage(prog, "missing loop count");
122                     LOOP_COUNT = atoi(*argv++);
123                     break;
124                 case 'k':
125                     if (*argv == NULL)
126                         usage(prog, "missing key size");
127                     KEY_SIZE = atoi(*argv++);
128                     break;
129                 case 's':
130                     if (*argv == NULL)
131                         usage(prog, "missing stack size");
132                     STACK_SIZE = atoi(*argv++);
133                     break;
134                 case 't':
135                     if (*argv == NULL)
136                         usage(prog, "missing thread count");
137                     THREAD_COUNT = atoi(*argv++);
138                     if (THREAD_COUNT > MAX_THREAD_COUNT) {
139                         usage(prog, "max thread count exceeded");
140                     }
141                     break;
142                 case 'v':
143                     VERBOSE = 1;
144                     break;
145                 case 'd':
146                     if (*argv == NULL)
147                         usage(prog, "missing directory");
148                     NSSDIR = *argv++;
149                     break;
150                 case 'e':
151                     ISTOKEN = PR_FALSE;
152                     break;
153                 case 'h':
154                     usage(prog, NULL);
155                     break;
156                 default:
157                     sprintf(buf, "unknown option %c", arg[1]);
158                     usage(prog, buf);
159             }
160         } else {
161             sprintf(buf, "unknown argument %s", arg);
162             usage(prog, buf);
163         }
164     }
165     /* initialize NSS */
166     rv = NSS_InitReadWrite(NSSDIR);
167     if (rv != SECSuccess) {
168         fprintf(stderr,
169                 "NSS_InitReadWrite(%s) failed(%s)\n", NSSDIR,
170                 PORT_ErrorToString(PORT_GetError()));
171         exit(2);
172     }
173 
174     /* need to initialize the database here if it's not already */
175 
176     printf("creating %d threads\n", THREAD_COUNT);
177     for (i = 0; i < THREAD_COUNT; i++) {
178         threadnumber[i] = i;
179         thread[i] = PR_CreateThread(PR_USER_THREAD, create_key_loop,
180                                     &threadnumber[i], PR_PRIORITY_NORMAL,
181                                     PR_GLOBAL_THREAD,
182                                     PR_JOINABLE_THREAD, STACK_SIZE);
183         if (thread[i] == NULL) {
184             ERROR++;
185             fprintf(stderr,
186                     "PR_CreateThread failed iteration %d, %s\n", i,
187                     PORT_ErrorToString(PORT_GetError()));
188         }
189     }
190     printf("waiting on %d threads\n", THREAD_COUNT);
191     for (i = 0; i < THREAD_COUNT; i++) {
192         if (thread[i] == NULL) {
193             continue;
194         }
195         status = PR_JoinThread(thread[i]);
196         if (status != PR_SUCCESS) {
197             ERROR++;
198             fprintf(stderr,
199                     "PR_CreateThread filed iteration %d, %s\n", i,
200                     PORT_ErrorToString(PORT_GetError()));
201         }
202     }
203     if (NSS_Shutdown() != SECSuccess) {
204         ERROR++;
205         fprintf(stderr, "NSS_Shutdown failed: %s\n",
206                 PORT_ErrorToString(PORT_GetError()));
207     }
208     printf("%d failures and %d errors found\n", FAILED, ERROR);
209     /* clean up */
210     if (FAILED) {
211         exit(1);
212     }
213     if (ERROR) {
214         exit(2);
215     }
216     exit(0);
217 }
218