/
rsaperf.c
695 lines (626 loc) · 21 KB
1
2
3
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
6
7
8
9
10
11
#include "seccomon.h"
#include "cert.h"
#include "secutil.h"
#include "nspr.h"
#include "nss.h"
#include "blapi.h"
#include "plgetopt.h"
12
#include "lowkeyi.h"
13
#include "pk11pub.h"
14
15
16
17
18
19
20
21
22
23
24
25
#define DEFAULT_ITERS 10
#define DEFAULT_DURATION 10
#define DEFAULT_KEY_BITS 1024
#define MIN_KEY_BITS 512
#define MAX_KEY_BITS 65536
#define BUFFER_BYTES MAX_KEY_BITS / 8
#define DEFAULT_THREADS 1
#define DEFAULT_EXPONENT 0x10001
extern NSSLOWKEYPrivateKey *getDefaultRSAPrivateKey(void);
extern NSSLOWKEYPublicKey *getDefaultRSAPublicKey(void);
26
27
28
secuPWData pwData = { PW_NONE, NULL };
29
30
31
typedef struct TimingContextStr TimingContext;
struct TimingContextStr {
32
33
34
PRTime start;
PRTime end;
PRTime interval;
35
36
37
38
39
40
long days;
int hours;
int minutes;
int seconds;
int millisecs;
41
42
};
43
44
45
TimingContext *
CreateTimingContext(void)
{
46
return PORT_Alloc(sizeof(TimingContext));
47
48
}
49
50
51
void
DestroyTimingContext(TimingContext *ctx)
{
52
PORT_Free(ctx);
53
54
}
55
56
57
void
TimingBegin(TimingContext *ctx, PRTime begin)
{
58
ctx->start = begin;
59
60
}
61
62
63
static void
timingUpdate(TimingContext *ctx)
{
64
PRInt64 tmp, remaining;
65
PRInt64 L1000, L60, L24;
66
67
68
69
LL_I2L(L1000, 1000);
LL_I2L(L60, 60);
LL_I2L(L24, 24);
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
LL_DIV(remaining, ctx->interval, L1000);
LL_MOD(tmp, remaining, L1000);
LL_L2I(ctx->millisecs, tmp);
LL_DIV(remaining, remaining, L1000);
LL_MOD(tmp, remaining, L60);
LL_L2I(ctx->seconds, tmp);
LL_DIV(remaining, remaining, L60);
LL_MOD(tmp, remaining, L60);
LL_L2I(ctx->minutes, tmp);
LL_DIV(remaining, remaining, L60);
LL_MOD(tmp, remaining, L24);
LL_L2I(ctx->hours, tmp);
LL_DIV(remaining, remaining, L24);
LL_L2I(ctx->days, remaining);
}
87
88
89
void
TimingEnd(TimingContext *ctx, PRTime end)
{
90
ctx->end = end;
91
92
93
94
95
LL_SUB(ctx->interval, ctx->end, ctx->start);
PORT_Assert(LL_GE_ZERO(ctx->interval));
timingUpdate(ctx);
}
96
97
98
void
TimingDivide(TimingContext *ctx, int divisor)
{
99
PRInt64 tmp;
100
101
102
103
104
105
106
LL_I2L(tmp, divisor);
LL_DIV(ctx->interval, ctx->interval, tmp);
timingUpdate(ctx);
}
107
108
109
char *
TimingGenerateString(TimingContext *ctx)
{
110
111
112
char *buf = NULL;
if (ctx->days != 0) {
113
buf = PR_sprintf_append(buf, "%d days", ctx->days);
114
115
}
if (ctx->hours != 0) {
116
117
118
if (buf != NULL)
buf = PR_sprintf_append(buf, ", ");
buf = PR_sprintf_append(buf, "%d hours", ctx->hours);
119
120
}
if (ctx->minutes != 0) {
121
122
123
if (buf != NULL)
buf = PR_sprintf_append(buf, ", ");
buf = PR_sprintf_append(buf, "%d minutes", ctx->minutes);
124
}
125
126
if (buf != NULL)
buf = PR_sprintf_append(buf, ", and ");
127
if (!buf && ctx->seconds == 0) {
128
129
130
131
132
133
int interval;
LL_L2I(interval, ctx->interval);
if (ctx->millisecs < 100)
buf = PR_sprintf_append(buf, "%d microseconds", interval);
else
buf = PR_sprintf_append(buf, "%d milliseconds", ctx->millisecs);
134
} else if (ctx->millisecs == 0) {
135
buf = PR_sprintf_append(buf, "%d seconds", ctx->seconds);
136
} else {
137
138
buf = PR_sprintf_append(buf, "%d.%03d seconds",
ctx->seconds, ctx->millisecs);
139
140
141
142
143
144
145
}
return buf;
}
void
Usage(char *progName)
{
146
fprintf(stderr, "Usage: %s [-s | -e] [-i iterations | -p period] "
147
148
149
150
151
"[-t threads]\n[-n none [-k keylength] [ [-g] -x exponent] |\n"
" -n token:nickname [-d certdir] [-w password] |\n"
" -h token [-d certdir] [-w password] [-g] [-k keylength] "
"[-x exponent] [-f pwfile]\n",
progName);
152
fprintf(stderr, "%-20s Cert database directory (default is ~/.netscape)\n",
153
"-d certdir");
154
fprintf(stderr, "%-20s How many operations to perform\n", "-i iterations");
155
fprintf(stderr, "%-20s How many seconds to run\n", "-p period");
156
fprintf(stderr, "%-20s Perform signing (private key) operations\n", "-s");
157
fprintf(stderr, "%-20s Perform encryption (public key) operations\n", "-e");
158
fprintf(stderr, "%-20s Nickname of certificate or key, prefixed "
159
160
"by optional token name\n",
"-n nickname");
161
162
163
164
165
166
167
fprintf(stderr, "%-20s PKCS#11 token to perform operation with.\n",
"-h token");
fprintf(stderr, "%-20s key size in bits, from %d to %d\n", "-k keylength",
MIN_KEY_BITS, MAX_KEY_BITS);
fprintf(stderr, "%-20s token password\n", "-w password");
fprintf(stderr, "%-20s temporary key generation. Not for token keys.\n",
"-g");
168
169
170
fprintf(stderr, "%-20s set public exponent for keygen\n", "-x");
fprintf(stderr, "%-20s Number of execution threads (default 1)\n",
"-t threads");
171
172
173
174
exit(-1);
}
static void
175
dumpBytes(unsigned char *b, int l)
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
{
int i;
if (l <= 0)
return;
for (i = 0; i < l; ++i) {
if (i % 16 == 0)
printf("\t");
printf(" %02x", b[i]);
if (i % 16 == 15)
printf("\n");
}
if ((i % 16) != 0)
printf("\n");
}
static void
192
dumpItem(SECItem *item, const char *description)
193
194
{
if (item->len & 1 && item->data[0] == 0) {
195
196
printf("%s: (%d bytes)\n", description, item->len - 1);
dumpBytes(item->data + 1, item->len - 1);
197
} else {
198
199
printf("%s: (%d bytes)\n", description, item->len);
dumpBytes(item->data, item->len);
200
201
202
203
}
}
void
204
printPrivKey(NSSLOWKEYPrivateKey *privKey)
205
{
206
207
RSAPrivateKey *rsa = &privKey->u.rsa;
208
209
210
211
212
213
214
215
dumpItem(&rsa->modulus, "n");
dumpItem(&rsa->publicExponent, "e");
dumpItem(&rsa->privateExponent, "d");
dumpItem(&rsa->prime1, "P");
dumpItem(&rsa->prime2, "Q");
dumpItem(&rsa->exponent1, "d % (P-1)");
dumpItem(&rsa->exponent2, "d % (Q-1)");
dumpItem(&rsa->coefficient, "(Q ** -1) % P");
216
217
218
puts("");
}
219
220
221
typedef SECStatus (*RSAOp)(void *key,
unsigned char *output,
unsigned char *input);
222
223
typedef struct {
224
225
SECKEYPublicKey *pubKey;
SECKEYPrivateKey *privKey;
226
227
} PK11Keys;
228
229
230
231
SECStatus
PK11_PublicKeyOp(SECKEYPublicKey *key,
unsigned char *output,
unsigned char *input)
232
233
234
235
236
{
return PK11_PubEncryptRaw(key, output, input, key->u.rsa.modulus.len,
NULL);
}
237
238
239
240
SECStatus
PK11_PrivateKeyOp(PK11Keys *keys,
unsigned char *output,
unsigned char *input)
241
242
243
244
245
246
247
{
unsigned outLen = 0;
return PK11_PrivDecryptRaw(keys->privKey,
output, &outLen,
keys->pubKey->u.rsa.modulus.len, input,
keys->pubKey->u.rsa.modulus.len);
}
248
249
250
typedef struct ThreadRunDataStr ThreadRunData;
struct ThreadRunDataStr {
251
252
const PRBool *doIters;
const void *rsaKey;
253
const unsigned char *buf;
254
255
256
257
258
259
RSAOp fn;
int seconds;
long iters;
long iterRes;
PRErrorCode errNum;
SECStatus status;
260
261
};
262
263
void
ThreadExecFunction(void *data)
264
{
265
ThreadRunData *tdata = (ThreadRunData *)data;
266
unsigned char buf2[BUFFER_BYTES];
267
268
269
270
tdata->status = SECSuccess;
if (*tdata->doIters) {
long i = tdata->iters;
271
tdata->iterRes = 0;
272
while (i--) {
273
274
SECStatus rv = tdata->fn((void *)tdata->rsaKey, buf2,
(unsigned char *)tdata->buf);
275
276
277
if (rv != SECSuccess) {
tdata->errNum = PORT_GetError();
tdata->status = rv;
278
break;
279
}
280
tdata->iterRes++;
281
282
283
284
285
286
}
} else {
PRIntervalTime total = PR_SecondsToInterval(tdata->seconds);
PRIntervalTime start = PR_IntervalNow();
tdata->iterRes = 0;
while (PR_IntervalNow() - start < total) {
287
288
SECStatus rv = tdata->fn((void *)tdata->rsaKey, buf2,
(unsigned char *)tdata->buf);
289
290
291
if (rv != SECSuccess) {
tdata->errNum = PORT_GetError();
tdata->status = rv;
292
break;
293
294
295
296
297
}
tdata->iterRes++;
}
}
}
298
299
#define INT_ARG(arg, def) atol(arg) > 0 ? atol(arg) : def
300
301
302
303
int
main(int argc, char **argv)
{
304
305
306
307
308
309
310
311
312
313
314
315
TimingContext *timeCtx = NULL;
SECKEYPublicKey *pubHighKey = NULL;
SECKEYPrivateKey *privHighKey = NULL;
NSSLOWKEYPrivateKey *privKey = NULL;
NSSLOWKEYPublicKey *pubKey = NULL;
CERTCertificate *cert = NULL;
char *progName = NULL;
char *secDir = NULL;
char *nickname = NULL;
char *slotname = NULL;
long keybits = 0;
RSAOp fn;
316
void *rsaKeyPtr = NULL;
317
318
319
320
321
322
323
324
325
326
327
328
329
PLOptState *optstate;
PLOptStatus optstatus;
long iters = DEFAULT_ITERS;
int i;
PRBool doPriv = PR_FALSE;
PRBool doPub = PR_FALSE;
int rv;
unsigned char buf[BUFFER_BYTES];
unsigned char buf2[BUFFER_BYTES];
int seconds = DEFAULT_DURATION;
PRBool doIters = PR_FALSE;
PRBool doTime = PR_FALSE;
PRBool useTokenKey = PR_FALSE; /* use PKCS#11 token
330
object key */
331
PRBool useSessionKey = PR_FALSE; /* use PKCS#11 session
332
object key */
333
334
PRBool useBLKey = PR_FALSE; /* use freebl */
PK11SlotInfo *slot = NULL; /* slot for session
335
object key operations */
336
337
PRBool doKeyGen = PR_FALSE;
int publicExponent = DEFAULT_EXPONENT;
338
339
340
341
PK11Keys keys;
int peCount = 0;
CK_BYTE pubEx[4];
SECItem pe;
342
343
344
345
346
RSAPublicKey pubKeyStr;
int threadNum = DEFAULT_THREADS;
ThreadRunData **runDataArr = NULL;
PRThread **threadsArr = NULL;
int calcThreads = 0;
347
348
349
progName = strrchr(argv[0], '/');
if (!progName)
350
351
progName = strrchr(argv[0], '\\');
progName = progName ? progName + 1 : argv[0];
352
353
optstate = PL_CreateOptState(argc, argv, "d:ef:gh:i:k:n:p:st:w:x:");
354
while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
switch (optstate->option) {
case '?':
Usage(progName);
break;
case 'd':
secDir = PORT_Strdup(optstate->value);
break;
case 'i':
iters = INT_ARG(optstate->value, DEFAULT_ITERS);
doIters = PR_TRUE;
break;
case 's':
doPriv = PR_TRUE;
break;
case 'e':
doPub = PR_TRUE;
break;
case 'g':
doKeyGen = PR_TRUE;
break;
case 'n':
nickname = PORT_Strdup(optstate->value);
/* for compatibility, nickname of "none" means go to freebl */
if (nickname && strcmp(nickname, "none")) {
useTokenKey = PR_TRUE;
} else {
useBLKey = PR_TRUE;
}
break;
case 'p':
seconds = INT_ARG(optstate->value, DEFAULT_DURATION);
doTime = PR_TRUE;
break;
case 'h':
slotname = PORT_Strdup(optstate->value);
useSessionKey = PR_TRUE;
break;
case 'k':
keybits = INT_ARG(optstate->value, DEFAULT_KEY_BITS);
break;
case 'w':
pwData.data = PORT_Strdup(optstate->value);
;
pwData.source = PW_PLAINTEXT;
break;
case 'f':
pwData.data = PORT_Strdup(optstate->value);
pwData.source = PW_FROMFILE;
break;
case 'x':
/* -x public exponent (for RSA keygen) */
publicExponent = INT_ARG(optstate->value, DEFAULT_EXPONENT);
break;
case 't':
threadNum = INT_ARG(optstate->value, DEFAULT_THREADS);
break;
}
412
413
}
if (optstatus == PL_OPT_BAD)
414
Usage(progName);
415
416
417
418
if ((doPriv && doPub) || (doIters && doTime) ||
((useTokenKey + useSessionKey + useBLKey) != PR_TRUE) ||
(useTokenKey && keybits) || (useTokenKey && doKeyGen) ||
419
(keybits && (keybits < MIN_KEY_BITS || keybits > MAX_KEY_BITS))) {
420
421
Usage(progName);
}
422
423
424
if (doIters && doTime)
Usage(progName);
425
426
427
428
429
if (!doTime) {
doIters = PR_TRUE;
}
430
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
431
432
PK11_SetPasswordFunc(SECU_GetModulePassword);
433
secDir = SECU_ConfigDirectory(secDir);
434
435
if (useTokenKey || useSessionKey) {
436
437
438
439
440
rv = NSS_Init(secDir);
if (rv != SECSuccess) {
fprintf(stderr, "NSS_Init failed.\n");
exit(1);
}
441
} else {
442
443
444
445
446
rv = NSS_NoDB_Init(NULL);
if (rv != SECSuccess) {
fprintf(stderr, "NSS_NoDB_Init failed.\n");
exit(1);
}
447
448
}
449
450
if (useTokenKey) {
CK_OBJECT_HANDLE kh = CK_INVALID_HANDLE;
451
452
cert = PK11_FindCertFromNickname(nickname, &pwData);
453
454
455
456
457
458
459
460
461
462
463
464
465
466
if (cert == NULL) {
fprintf(stderr,
"Can't find certificate by name \"%s\"\n", nickname);
exit(1);
}
pubHighKey = CERT_ExtractPublicKey(cert);
if (pubHighKey == NULL) {
fprintf(stderr, "Can't extract public key from certificate");
exit(1);
}
if (doPub) {
/* do public key ops */
fn = (RSAOp)PK11_PublicKeyOp;
467
rsaKeyPtr = (void *)pubHighKey;
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
kh = PK11_ImportPublicKey(cert->slot, pubHighKey, PR_FALSE);
if (CK_INVALID_HANDLE == kh) {
fprintf(stderr,
"Unable to import public key to certificate slot.");
exit(1);
}
pubHighKey->pkcs11Slot = PK11_ReferenceSlot(cert->slot);
pubHighKey->pkcs11ID = kh;
printf("Using PKCS#11 for RSA encryption with token %s.\n",
PK11_GetTokenName(cert->slot));
} else {
/* do private key ops */
privHighKey = PK11_FindKeyByAnyCert(cert, &pwData);
if (privHighKey == NULL) {
fprintf(stderr,
"Can't find private key by name \"%s\"\n", nickname);
exit(1);
}
487
488
489
490
491
SECKEY_CacheStaticFlags(privHighKey);
fn = (RSAOp)PK11_PrivateKeyOp;
keys.privKey = privHighKey;
keys.pubKey = pubHighKey;
492
rsaKeyPtr = (void *)&keys;
493
494
printf("Using PKCS#11 for RSA decryption with token %s.\n",
PK11_GetTokenName(privHighKey->pkcs11Slot));
495
}
496
497
} else
498
if (useSessionKey) {
499
/* use PKCS#11 session key objects */
500
501
PK11RSAGenParams rsaparams;
void *params;
502
503
504
505
506
507
slot = PK11_FindSlotByName(slotname); /* locate target slot */
if (!slot) {
fprintf(stderr, "Can't find slot \"%s\"\n", slotname);
exit(1);
}
508
509
/* do a temporary keygen in selected slot */
510
511
512
if (!keybits) {
keybits = DEFAULT_KEY_BITS;
}
513
514
printf("Using PKCS#11 with %ld bits session key in token %s.\n",
515
keybits, PK11_GetTokenName(slot));
516
517
518
519
520
rsaparams.keySizeInBits = keybits;
rsaparams.pe = publicExponent;
params = &rsaparams;
521
fprintf(stderr, "\nGenerating RSA key. This may take a few moments.\n");
522
523
524
privHighKey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
params, &pubHighKey, PR_FALSE,
525
PR_FALSE, (void *)&pwData);
526
527
528
if (!privHighKey) {
fprintf(stderr,
"Key generation failed in token \"%s\"\n",
529
PK11_GetTokenName(slot));
530
531
532
533
exit(1);
}
SECKEY_CacheStaticFlags(privHighKey);
534
535
fprintf(stderr, "Keygen completed.\n");
536
537
538
539
if (doPub) {
/* do public key operations */
fn = (RSAOp)PK11_PublicKeyOp;
540
rsaKeyPtr = (void *)pubHighKey;
541
542
543
544
545
} else {
/* do private key operations */
fn = (RSAOp)PK11_PrivateKeyOp;
keys.privKey = privHighKey;
keys.pubKey = pubHighKey;
546
rsaKeyPtr = (void *)&keys;
547
}
548
} else
549
550
551
552
553
554
555
{
/* use freebl directly */
if (!keybits) {
keybits = DEFAULT_KEY_BITS;
}
if (!doKeyGen) {
556
if (keybits != DEFAULT_KEY_BITS) {
557
558
559
doKeyGen = PR_TRUE;
}
}
560
printf("Using freebl with %ld bits key.\n", keybits);
561
if (doKeyGen) {
562
563
564
fprintf(stderr, "\nGenerating RSA key. "
"This may take a few moments.\n");
for (i = 0; i < 4; i++) {
565
if (peCount || (publicExponent & ((unsigned long)0xff000000L >>
566
567
568
569
(i * 8)))) {
pubEx[peCount] = (CK_BYTE)((publicExponent >>
(3 - i) * 8) &
0xff);
570
571
572
573
574
575
576
peCount++;
}
}
pe.len = peCount;
pe.data = &pubEx[0];
pe.type = siBuffer;
577
rsaKeyPtr = RSA_NewKey(keybits, &pe);
578
fprintf(stderr, "Keygen completed.\n");
579
580
} else {
/* use a hardcoded key */
581
printf("Using hardcoded %ld bits key.\n", keybits);
582
if (doPub) {
583
pubKey = getDefaultRSAPublicKey();
584
} else {
585
privKey = getDefaultRSAPrivateKey();
586
587
588
589
590
591
}
}
if (doPub) {
/* do public key operations */
fn = (RSAOp)RSA_PublicKeyOp;
592
if (rsaKeyPtr) {
593
594
/* convert the RSAPrivateKey to RSAPublicKey */
pubKeyStr.arena = NULL;
595
pubKeyStr.modulus = ((RSAPrivateKey *)rsaKeyPtr)->modulus;
596
pubKeyStr.publicExponent =
597
598
((RSAPrivateKey *)rsaKeyPtr)->publicExponent;
rsaKeyPtr = &pubKeyStr;
599
600
} else {
/* convert NSSLOWKeyPublicKey to RSAPublicKey */
601
rsaKeyPtr = (void *)(&pubKey->u.rsa);
602
}
603
PORT_Assert(rsaKeyPtr);
604
605
606
607
608
} else {
/* do private key operations */
fn = (RSAOp)RSA_PrivateKeyOp;
if (privKey) {
/* convert NSSLOWKeyPrivateKey to RSAPrivateKey */
609
rsaKeyPtr = (void *)(&privKey->u.rsa);
610
}
611
PORT_Assert(rsaKeyPtr);
612
}
613
}
614
615
memset(buf, 1, sizeof buf);
616
rv = fn(rsaKeyPtr, buf2, buf);
617
if (rv != SECSuccess) {
618
619
620
621
622
623
624
625
626
627
628
629
PRErrorCode errNum;
const char *errStr = NULL;
errNum = PORT_GetError();
if (errNum)
errStr = SECU_Strerror(errNum);
else
errNum = rv;
if (!errStr)
errStr = "(null)";
fprintf(stderr, "Error in RSA operation: %d : %s\n", errNum, errStr);
exit(1);
630
631
}
632
633
threadsArr = (PRThread **)PORT_Alloc(threadNum * sizeof(PRThread *));
runDataArr = (ThreadRunData **)PORT_Alloc(threadNum * sizeof(ThreadRunData *));
634
635
timeCtx = CreateTimingContext();
TimingBegin(timeCtx, PR_Now());
636
637
for (i = 0; i < threadNum; i++) {
runDataArr[i] = (ThreadRunData *)PORT_Alloc(sizeof(ThreadRunData));
638
639
640
runDataArr[i]->fn = fn;
runDataArr[i]->buf = buf;
runDataArr[i]->doIters = &doIters;
641
runDataArr[i]->rsaKey = rsaKeyPtr;
642
643
runDataArr[i]->seconds = seconds;
runDataArr[i]->iters = iters;
644
threadsArr[i] =
645
PR_CreateThread(PR_USER_THREAD,
646
647
648
649
650
651
ThreadExecFunction,
(void *)runDataArr[i],
PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD,
0);
652
653
654
}
iters = 0;
calcThreads = 0;
655
for (i = 0; i < threadNum; i++, calcThreads++) {
656
657
PR_JoinThread(threadsArr[i]);
if (runDataArr[i]->status != SECSuccess) {
658
const char *errStr = SECU_Strerror(runDataArr[i]->errNum);
659
fprintf(stderr, "Thread %d: Error in RSA operation: %d : %s\n",
660
661
662
663
i, runDataArr[i]->errNum, errStr);
calcThreads -= 1;
} else {
iters += runDataArr[i]->iterRes;
664
}
665
PORT_Free((void *)runDataArr[i]);
666
}
667
668
669
PORT_Free(runDataArr);
PORT_Free(threadsArr);
670
TimingEnd(timeCtx, PR_Now());
671
672
printf("%ld iterations in %s\n",
673
iters, TimingGenerateString(timeCtx));
674
printf("%.2f operations/s .\n", ((double)(iters) * (double)1000000.0) / (double)timeCtx->interval);
675
676
677
TimingDivide(timeCtx, iters);
printf("one operation every %s\n", TimingGenerateString(timeCtx));
678
679
680
681
682
if (pubHighKey) {
SECKEY_DestroyPublicKey(pubHighKey);
}
if (privHighKey) {
683
SECKEY_DestroyPrivateKey(privHighKey);
684
685
686
687
688
689
}
if (cert) {
CERT_DestroyCertificate(cert);
}
690
691
692
693
if (NSS_Shutdown() != SECSuccess) {
exit(1);
}
694
695
return 0;
}