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  * libpkixBuildThreads.c
6  *
7  * libpkix Builder Performance Evaluation application (multi-threaded)
8  *
9  */
10 
11 #include <stdio.h>
12 #include <string.h>
13 
14 #include "secutil.h"
15 
16 #include <nspr.h>
17 #include "prtypes.h"
18 #include "prtime.h"
19 #include "prlong.h"
20 
21 #include "pk11func.h"
22 #include "secasn1.h"
23 #include "cert.h"
24 #include "cryptohi.h"
25 #include "secoid.h"
26 #include "certdb.h"
27 #include "nss.h"
28 
29 #include "pkix.h"
30 #include "pkix_tools.h"
31 #include "pkix_pl_cert.h"
32 
33 #include "testutil.h"
34 #include "testutil_nss.h"
35 
36 static void *plContext = NULL;
37 
38 #undef pkixTempResult
39 #define PERF_DECREF(obj)                                                                \
40     {                                                                                   \
41         PKIX_Error *pkixTempResult = NULL;                                              \
42         if (obj) {                                                                      \
43             pkixTempResult = PKIX_PL_Object_DecRef((PKIX_PL_Object *)(obj), plContext); \
44             obj = NULL;                                                                 \
45         }                                                                               \
46     }
47 
48 static void finish(char *message, int code);
49 
50 typedef struct ThreadDataStr tData;
51 
52 struct ThreadDataStr {
53     CERTCertificate *anchor;
54     char *eecertName;
55     PRIntervalTime duration;
56     CERTCertDBHandle *handle;
57     PRUint32 iterations;
58 };
59 
60 #define PKIX_LOGGER_ON 1
61 
62 #ifdef PKIX_LOGGER_ON
63 
64 char *logLevels[] = {
65     "None",
66     "Fatal Error",
67     "Error",
68     "Warning",
69     "Debug",
70     "Trace"
71 };
72 
73 static PKIX_Error *
loggerCallback(PKIX_Logger * logger,PKIX_PL_String * message,PKIX_UInt32 logLevel,PKIX_ERRORCLASS logComponent,void * plContext)74 loggerCallback(
75     PKIX_Logger *logger,
76     PKIX_PL_String *message,
77     PKIX_UInt32 logLevel,
78     PKIX_ERRORCLASS logComponent,
79     void *plContext)
80 {
81     char *msg = NULL;
82     static int callCount = 0;
83 
84     msg = PKIX_String2ASCII(message, plContext);
85     printf("Logging %s (%s): %s\n",
86            logLevels[logLevel],
87            PKIX_ERRORCLASSNAMES[logComponent],
88            msg);
89     PR_Free((void *)msg);
90 
91     return (NULL);
92 }
93 
94 #endif /* PKIX_LOGGER_ON */
95 
96 static void
ThreadEntry(void * data)97 ThreadEntry(void *data)
98 {
99     tData *tdata = (tData *)data;
100     PRIntervalTime duration = tdata->duration;
101     PRIntervalTime start = PR_IntervalNow();
102 
103     PKIX_List *anchors = NULL;
104     PKIX_ProcessingParams *procParams = NULL;
105     PKIX_BuildResult *buildResult = NULL;
106     CERTCertificate *nsseecert;
107     PKIX_PL_Cert *eeCert = NULL;
108     PKIX_CertStore *certStore = NULL;
109     PKIX_List *certStores = NULL;
110     PKIX_ComCertSelParams *certSelParams = NULL;
111     PKIX_CertSelector *certSelector = NULL;
112     PKIX_PL_Date *nowDate = NULL;
113     void *state = NULL;       /* only relevant with non-blocking I/O */
114     void *nbioContext = NULL; /* only relevant with non-blocking I/O */
115 
116     PR_ASSERT(duration);
117     if (!duration) {
118         return;
119     }
120 
121     do {
122 
123         /* libpkix code */
124 
125         /* keep more update time, testing cache */
126         PKIX_PL_Date_Create_UTCTime(NULL, &nowDate, plContext);
127 
128         /* CertUsage is 0x10 and no NSS arena */
129         /* We haven't determined how we obtain the value of wincx */
130 
131         nsseecert = CERT_FindCertByNicknameOrEmailAddr(tdata->handle,
132                                                        tdata->eecertName);
133         if (!nsseecert)
134             finish("Unable to find eecert.\n", 1);
135 
136         pkix_pl_Cert_CreateWithNSSCert(nsseecert, &eeCert, plContext);
137 
138         PKIX_List_Create(&anchors, plContext);
139 
140         /*
141          * This code is retired.
142          *      pkix_pl_Cert_CreateWithNSSCert
143          *              (tdata->anchor, &anchorCert, NULL);
144          *      PKIX_TrustAnchor_CreateWithCert(anchorCert, &anchor, NULL);
145          *      PKIX_List_AppendItem(anchors, (PKIX_PL_Object *)anchor, NULL);
146          */
147 
148         PKIX_ProcessingParams_Create(anchors, &procParams, plContext);
149 
150         PKIX_ProcessingParams_SetRevocationEnabled(procParams, PKIX_TRUE, plContext);
151 
152         PKIX_ProcessingParams_SetDate(procParams, nowDate, plContext);
153 
154         /* create CertSelector with target certificate in params */
155 
156         PKIX_ComCertSelParams_Create(&certSelParams, plContext);
157 
158         PKIX_ComCertSelParams_SetCertificate(certSelParams, eeCert, plContext);
159 
160         PKIX_CertSelector_Create(NULL, NULL, &certSelector, plContext);
161 
162         PKIX_CertSelector_SetCommonCertSelectorParams(certSelector, certSelParams, plContext);
163 
164         PKIX_ProcessingParams_SetTargetCertConstraints(procParams, certSelector, plContext);
165 
166         PKIX_PL_Pk11CertStore_Create(&certStore, plContext);
167 
168         PKIX_List_Create(&certStores, plContext);
169         PKIX_List_AppendItem(certStores, (PKIX_PL_Object *)certStore, plContext);
170         PKIX_ProcessingParams_SetCertStores(procParams, certStores, plContext);
171 
172         PKIX_BuildChain(procParams,
173                         &nbioContext,
174                         &state,
175                         &buildResult,
176                         NULL,
177                         plContext);
178 
179         /*
180                  * As long as we use only CertStores with blocking I/O, we
181                  * know we must be done at this point.
182                  */
183 
184         if (!buildResult) {
185             (void)fprintf(stderr, "libpkix BuildChain failed.\n");
186             PORT_Assert(0);
187             return;
188         }
189 
190         tdata->iterations++;
191 
192         PERF_DECREF(nowDate);
193         PERF_DECREF(anchors);
194         PERF_DECREF(procParams);
195         PERF_DECREF(buildResult);
196         PERF_DECREF(certStore);
197         PERF_DECREF(certStores);
198         PERF_DECREF(certSelParams);
199         PERF_DECREF(certSelector);
200         PERF_DECREF(eeCert);
201 
202     } while ((PR_IntervalNow() - start) < duration);
203 }
204 
205 static void
Test(CERTCertificate * anchor,char * eecertName,PRIntervalTime duration,CERTCertDBHandle * handle,PRUint32 threads)206 Test(
207     CERTCertificate *anchor,
208     char *eecertName,
209     PRIntervalTime duration,
210     CERTCertDBHandle *handle,
211     PRUint32 threads)
212 {
213     tData data;
214     tData **alldata;
215     PRIntervalTime starttime, endtime, elapsed;
216     PRUint32 msecs;
217     float total = 0;
218     PRThread **pthreads = NULL;
219     PRUint32 i = 0;
220 
221     data.duration = duration;
222     data.anchor = anchor;
223     data.eecertName = eecertName;
224     data.handle = handle;
225 
226     data.iterations = 0;
227 
228     starttime = PR_IntervalNow();
229     pthreads = (PRThread **)PR_Malloc(threads * sizeof(PRThread *));
230     alldata = (tData **)PR_Malloc(threads * sizeof(tData *));
231     for (i = 0; i < threads; i++) {
232         alldata[i] = (tData *)PR_Malloc(sizeof(tData));
233         *alldata[i] = data;
234         pthreads[i] =
235             PR_CreateThread(PR_USER_THREAD,
236                             ThreadEntry,
237                             (void *)alldata[i],
238                             PR_PRIORITY_NORMAL,
239                             PR_GLOBAL_THREAD,
240                             PR_JOINABLE_THREAD,
241                             0);
242     }
243 
244     for (i = 0; i < threads; i++) {
245         tData *args = alldata[i];
246         PR_JoinThread(pthreads[i]);
247         total += args->iterations;
248         PR_Free((void *)args);
249     }
250 
251     PR_Free((void *)pthreads);
252     PR_Free((void *)alldata);
253     endtime = PR_IntervalNow();
254 
255     endtime = PR_IntervalNow();
256     elapsed = endtime - starttime;
257     msecs = PR_IntervalToMilliseconds(elapsed);
258     total /= msecs;
259     total *= 1000;
260     (void)fprintf(stdout, "%f operations per second.\n", total);
261 }
262 
263 static void
finish(char * message,int code)264 finish(char *message, int code)
265 {
266     (void)printf(message);
267     exit(code);
268 }
269 
270 static void
usage(char * progname)271 usage(char *progname)
272 {
273     (void)printf("Usage : %s <-d certStoreDirectory> <duration> <threads> "
274                  "<anchorNickname> <eecertNickname>\n\n",
275                  progname);
276     finish("", 0);
277 }
278 
279 int
libpkix_buildthreads(int argc,char ** argv)280 libpkix_buildthreads(int argc, char **argv)
281 {
282     CERTCertDBHandle *handle = NULL;
283     CERTCertificate *eecert = NULL;
284     PRIntervalTime duration = PR_SecondsToInterval(1);
285     PRUint32 threads = 1;
286     PKIX_UInt32 actualMinorVersion;
287     PKIX_UInt32 j = 0;
288     PKIX_Logger *logger = NULL;
289     void *wincx = NULL;
290 
291     /* if (argc != 5) -- when TrustAnchor used to be on command line */
292     if (argc != 4) {
293         usage(argv[0]);
294     }
295     if (atoi(argv[1]) > 0) {
296         duration = PR_SecondsToInterval(atoi(argv[1]));
297     }
298     if (atoi(argv[2]) > 0) {
299         threads = atoi(argv[2]);
300     }
301 
302     PKIX_PL_NssContext_Create(certificateUsageEmailSigner, PKIX_FALSE,
303                               NULL, &plContext);
304 
305     handle = CERT_GetDefaultCertDB();
306     PR_ASSERT(handle);
307 
308 #ifdef PKIX_LOGGER_ON
309 
310     /* set logger to log trace and up */
311     PKIX_SetLoggers(NULL, plContext);
312     PKIX_Logger_Create(loggerCallback, NULL, &logger, plContext);
313     PKIX_Logger_SetMaxLoggingLevel(logger, PKIX_LOGGER_LEVEL_WARNING, plContext);
314     PKIX_AddLogger(logger, plContext);
315 
316 #endif /* PKIX_LOGGER_ON */
317 
318     /*
319          * This code is retired
320          *      anchor = CERT_FindCertByNicknameOrEmailAddr(handle, argv[3]);
321          *      if (!anchor) finish("Unable to find anchor.\n", 1);
322          *
323          *      eecert = CERT_FindCertByNicknameOrEmailAddr(handle, argv[4]);
324 
325          *      if (!eecert) finish("Unable to find eecert.\n", 1);
326          *
327          *      Test(anchor, eecert, duration, threads);
328          */
329 
330     Test(NULL, argv[3], duration, handle, threads);
331 
332     PERF_DECREF(logger);
333 
334     PKIX_Shutdown(plContext);
335 
336     return (0);
337 }
338