|
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 "vfyserv.h" |
|
6 #include "secerr.h" |
|
7 #include "sslerr.h" |
|
8 #include "nspr.h" |
|
9 #include "secutil.h" |
|
10 |
|
11 |
|
12 extern PRBool dumpChain; |
|
13 extern void dumpCertChain(CERTCertificate *, SECCertUsage); |
|
14 |
|
15 /* Declare SSL cipher suites. */ |
|
16 |
|
17 int ssl2CipherSuites[] = { |
|
18 SSL_EN_RC4_128_WITH_MD5, /* A */ |
|
19 SSL_EN_RC4_128_EXPORT40_WITH_MD5, /* B */ |
|
20 SSL_EN_RC2_128_CBC_WITH_MD5, /* C */ |
|
21 SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */ |
|
22 SSL_EN_DES_64_CBC_WITH_MD5, /* E */ |
|
23 SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */ |
|
24 0 |
|
25 }; |
|
26 |
|
27 int ssl3CipherSuites[] = { |
|
28 -1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */ |
|
29 -1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, * b */ |
|
30 TLS_RSA_WITH_RC4_128_MD5, /* c */ |
|
31 TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* d */ |
|
32 TLS_RSA_WITH_DES_CBC_SHA, /* e */ |
|
33 TLS_RSA_EXPORT_WITH_RC4_40_MD5, /* f */ |
|
34 TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* g */ |
|
35 -1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA, * h */ |
|
36 TLS_RSA_WITH_NULL_MD5, /* i */ |
|
37 SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, /* j */ |
|
38 SSL_RSA_FIPS_WITH_DES_CBC_SHA, /* k */ |
|
39 TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */ |
|
40 TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, /* m */ |
|
41 TLS_RSA_WITH_RC4_128_SHA, /* n */ |
|
42 TLS_DHE_DSS_WITH_RC4_128_SHA, /* o */ |
|
43 TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* p */ |
|
44 TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* q */ |
|
45 TLS_DHE_RSA_WITH_DES_CBC_SHA, /* r */ |
|
46 TLS_DHE_DSS_WITH_DES_CBC_SHA, /* s */ |
|
47 TLS_DHE_DSS_WITH_AES_128_CBC_SHA, /* t */ |
|
48 TLS_DHE_RSA_WITH_AES_128_CBC_SHA, /* u */ |
|
49 TLS_RSA_WITH_AES_128_CBC_SHA, /* v */ |
|
50 TLS_DHE_DSS_WITH_AES_256_CBC_SHA, /* w */ |
|
51 TLS_DHE_RSA_WITH_AES_256_CBC_SHA, /* x */ |
|
52 TLS_RSA_WITH_AES_256_CBC_SHA, /* y */ |
|
53 TLS_RSA_WITH_NULL_SHA, /* z */ |
|
54 0 |
|
55 }; |
|
56 |
|
57 /************************************************************************** |
|
58 ** |
|
59 ** SSL callback routines. |
|
60 ** |
|
61 **************************************************************************/ |
|
62 |
|
63 /* Function: char * myPasswd() |
|
64 * |
|
65 * Purpose: This function is our custom password handler that is called by |
|
66 * SSL when retreiving private certs and keys from the database. Returns a |
|
67 * pointer to a string that with a password for the database. Password pointer |
|
68 * should point to dynamically allocated memory that will be freed later. |
|
69 */ |
|
70 char * |
|
71 myPasswd(PK11SlotInfo *info, PRBool retry, void *arg) |
|
72 { |
|
73 char * passwd = NULL; |
|
74 |
|
75 if ( (!retry) && arg ) { |
|
76 passwd = PORT_Strdup((char *)arg); |
|
77 } |
|
78 return passwd; |
|
79 } |
|
80 |
|
81 /* Function: SECStatus myAuthCertificate() |
|
82 * |
|
83 * Purpose: This function is our custom certificate authentication handler. |
|
84 * |
|
85 * Note: This implementation is essentially the same as the default |
|
86 * SSL_AuthCertificate(). |
|
87 */ |
|
88 SECStatus |
|
89 myAuthCertificate(void *arg, PRFileDesc *socket, |
|
90 PRBool checksig, PRBool isServer) |
|
91 { |
|
92 |
|
93 SECCertificateUsage certUsage; |
|
94 CERTCertificate * cert; |
|
95 void * pinArg; |
|
96 char * hostName; |
|
97 SECStatus secStatus; |
|
98 |
|
99 if (!arg || !socket) { |
|
100 errWarn("myAuthCertificate"); |
|
101 return SECFailure; |
|
102 } |
|
103 |
|
104 /* Define how the cert is being used based upon the isServer flag. */ |
|
105 |
|
106 certUsage = isServer ? certificateUsageSSLClient : certificateUsageSSLServer; |
|
107 |
|
108 cert = SSL_PeerCertificate(socket); |
|
109 |
|
110 pinArg = SSL_RevealPinArg(socket); |
|
111 |
|
112 if (dumpChain == PR_TRUE) { |
|
113 dumpCertChain(cert, certUsage); |
|
114 } |
|
115 |
|
116 secStatus = CERT_VerifyCertificateNow((CERTCertDBHandle *)arg, |
|
117 cert, |
|
118 checksig, |
|
119 certUsage, |
|
120 pinArg, |
|
121 NULL); |
|
122 |
|
123 /* If this is a server, we're finished. */ |
|
124 if (isServer || secStatus != SECSuccess) { |
|
125 SECU_printCertProblems(stderr, (CERTCertDBHandle *)arg, cert, |
|
126 checksig, certUsage, pinArg, PR_FALSE); |
|
127 CERT_DestroyCertificate(cert); |
|
128 return secStatus; |
|
129 } |
|
130 |
|
131 /* Certificate is OK. Since this is the client side of an SSL |
|
132 * connection, we need to verify that the name field in the cert |
|
133 * matches the desired hostname. This is our defense against |
|
134 * man-in-the-middle attacks. |
|
135 */ |
|
136 |
|
137 /* SSL_RevealURL returns a hostName, not an URL. */ |
|
138 hostName = SSL_RevealURL(socket); |
|
139 |
|
140 if (hostName && hostName[0]) { |
|
141 secStatus = CERT_VerifyCertName(cert, hostName); |
|
142 } else { |
|
143 PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0); |
|
144 secStatus = SECFailure; |
|
145 } |
|
146 |
|
147 if (hostName) |
|
148 PR_Free(hostName); |
|
149 |
|
150 CERT_DestroyCertificate(cert); |
|
151 return secStatus; |
|
152 } |
|
153 |
|
154 /* Function: SECStatus myBadCertHandler() |
|
155 * |
|
156 * Purpose: This callback is called when the incoming certificate is not |
|
157 * valid. We define a certain set of parameters that still cause the |
|
158 * certificate to be "valid" for this session, and return SECSuccess to cause |
|
159 * the server to continue processing the request when any of these conditions |
|
160 * are met. Otherwise, SECFailure is return and the server rejects the |
|
161 * request. |
|
162 */ |
|
163 SECStatus |
|
164 myBadCertHandler(void *arg, PRFileDesc *socket) |
|
165 { |
|
166 |
|
167 SECStatus secStatus = SECFailure; |
|
168 PRErrorCode err; |
|
169 |
|
170 /* log invalid cert here */ |
|
171 |
|
172 if (!arg) { |
|
173 return secStatus; |
|
174 } |
|
175 |
|
176 *(PRErrorCode *)arg = err = PORT_GetError(); |
|
177 |
|
178 /* If any of the cases in the switch are met, then we will proceed */ |
|
179 /* with the processing of the request anyway. Otherwise, the default */ |
|
180 /* case will be reached and we will reject the request. */ |
|
181 |
|
182 switch (err) { |
|
183 case SEC_ERROR_INVALID_AVA: |
|
184 case SEC_ERROR_INVALID_TIME: |
|
185 case SEC_ERROR_BAD_SIGNATURE: |
|
186 case SEC_ERROR_EXPIRED_CERTIFICATE: |
|
187 case SEC_ERROR_UNKNOWN_ISSUER: |
|
188 case SEC_ERROR_UNTRUSTED_CERT: |
|
189 case SEC_ERROR_CERT_VALID: |
|
190 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: |
|
191 case SEC_ERROR_CRL_EXPIRED: |
|
192 case SEC_ERROR_CRL_BAD_SIGNATURE: |
|
193 case SEC_ERROR_EXTENSION_VALUE_INVALID: |
|
194 case SEC_ERROR_CA_CERT_INVALID: |
|
195 case SEC_ERROR_CERT_USAGES_INVALID: |
|
196 case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION: |
|
197 secStatus = SECSuccess; |
|
198 break; |
|
199 default: |
|
200 secStatus = SECFailure; |
|
201 break; |
|
202 } |
|
203 |
|
204 fprintf(stderr, "Bad certificate: %d, %s\n", err, SECU_Strerror(err)); |
|
205 |
|
206 return secStatus; |
|
207 } |
|
208 |
|
209 /* Function: SECStatus ownGetClientAuthData() |
|
210 * |
|
211 * Purpose: This callback is used by SSL to pull client certificate |
|
212 * information upon server request. |
|
213 */ |
|
214 SECStatus |
|
215 myGetClientAuthData(void *arg, |
|
216 PRFileDesc *socket, |
|
217 struct CERTDistNamesStr *caNames, |
|
218 struct CERTCertificateStr **pRetCert, |
|
219 struct SECKEYPrivateKeyStr **pRetKey) |
|
220 { |
|
221 |
|
222 CERTCertificate * cert; |
|
223 SECKEYPrivateKey * privKey; |
|
224 char * chosenNickName = (char *)arg; |
|
225 void * proto_win = NULL; |
|
226 SECStatus secStatus = SECFailure; |
|
227 |
|
228 proto_win = SSL_RevealPinArg(socket); |
|
229 |
|
230 if (chosenNickName) { |
|
231 cert = PK11_FindCertFromNickname(chosenNickName, proto_win); |
|
232 if (cert) { |
|
233 privKey = PK11_FindKeyByAnyCert(cert, proto_win); |
|
234 if (privKey) { |
|
235 secStatus = SECSuccess; |
|
236 } else { |
|
237 CERT_DestroyCertificate(cert); |
|
238 } |
|
239 } |
|
240 } else { /* no nickname given, automatically find the right cert */ |
|
241 CERTCertNicknames *names; |
|
242 int i; |
|
243 |
|
244 names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(), |
|
245 SEC_CERT_NICKNAMES_USER, proto_win); |
|
246 |
|
247 if (names != NULL) { |
|
248 for(i = 0; i < names->numnicknames; i++ ) { |
|
249 |
|
250 cert = PK11_FindCertFromNickname(names->nicknames[i], |
|
251 proto_win); |
|
252 if (!cert) { |
|
253 continue; |
|
254 } |
|
255 |
|
256 /* Only check unexpired certs */ |
|
257 if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE) |
|
258 != secCertTimeValid ) { |
|
259 CERT_DestroyCertificate(cert); |
|
260 continue; |
|
261 } |
|
262 |
|
263 secStatus = NSS_CmpCertChainWCANames(cert, caNames); |
|
264 if (secStatus == SECSuccess) { |
|
265 privKey = PK11_FindKeyByAnyCert(cert, proto_win); |
|
266 if (privKey) { |
|
267 break; |
|
268 } |
|
269 secStatus = SECFailure; |
|
270 } |
|
271 CERT_DestroyCertificate(cert); |
|
272 } /* for loop */ |
|
273 CERT_FreeNicknames(names); |
|
274 } |
|
275 } |
|
276 |
|
277 if (secStatus == SECSuccess) { |
|
278 *pRetCert = cert; |
|
279 *pRetKey = privKey; |
|
280 } |
|
281 |
|
282 return secStatus; |
|
283 } |
|
284 |
|
285 /* Function: void myHandshakeCallback() |
|
286 * |
|
287 * Purpose: Called by SSL to inform application that the handshake is |
|
288 * complete. This function is mostly used on the server side of an SSL |
|
289 * connection, although it is provided for a client as well. |
|
290 * Useful when a non-blocking SSL_ReHandshake or SSL_ResetHandshake |
|
291 * is used to initiate a handshake. |
|
292 * |
|
293 * A typical scenario would be: |
|
294 * |
|
295 * 1. Server accepts an SSL connection from the client without client auth. |
|
296 * 2. Client sends a request. |
|
297 * 3. Server determines that to service request it needs to authenticate the |
|
298 * client and initiates another handshake requesting client auth. |
|
299 * 4. While handshake is in progress, server can do other work or spin waiting |
|
300 * for the handshake to complete. |
|
301 * 5. Server is notified that handshake has been successfully completed by |
|
302 * the custom handshake callback function and it can service the client's |
|
303 * request. |
|
304 * |
|
305 * Note: This function is not implemented in this sample, as we are using |
|
306 * blocking sockets. |
|
307 */ |
|
308 void |
|
309 myHandshakeCallback(PRFileDesc *socket, void *arg) |
|
310 { |
|
311 fprintf(stderr,"Handshake Complete: SERVER CONFIGURED CORRECTLY\n"); |
|
312 } |
|
313 |
|
314 |
|
315 /************************************************************************** |
|
316 ** |
|
317 ** Routines for disabling SSL ciphers. |
|
318 ** |
|
319 **************************************************************************/ |
|
320 |
|
321 void |
|
322 disableAllSSLCiphers(void) |
|
323 { |
|
324 const PRUint16 *cipherSuites = SSL_ImplementedCiphers; |
|
325 int i = SSL_NumImplementedCiphers; |
|
326 SECStatus rv; |
|
327 |
|
328 /* disable all the SSL3 cipher suites */ |
|
329 while (--i >= 0) { |
|
330 PRUint16 suite = cipherSuites[i]; |
|
331 rv = SSL_CipherPrefSetDefault(suite, PR_FALSE); |
|
332 if (rv != SECSuccess) { |
|
333 fprintf(stderr, |
|
334 "SSL_CipherPrefSetDefault didn't like value 0x%04x (i = %d)\n", |
|
335 suite, i); |
|
336 errWarn("SSL_CipherPrefSetDefault"); |
|
337 exit(2); |
|
338 } |
|
339 } |
|
340 } |
|
341 |
|
342 /************************************************************************** |
|
343 ** |
|
344 ** Error and information routines. |
|
345 ** |
|
346 **************************************************************************/ |
|
347 |
|
348 void |
|
349 errWarn(char *function) |
|
350 { |
|
351 PRErrorCode errorNumber = PR_GetError(); |
|
352 const char * errorString = SECU_Strerror(errorNumber); |
|
353 |
|
354 fprintf(stderr, "Error in function %s: %d\n - %s\n", |
|
355 function, errorNumber, errorString); |
|
356 } |
|
357 |
|
358 void |
|
359 exitErr(char *function) |
|
360 { |
|
361 errWarn(function); |
|
362 /* Exit gracefully. */ |
|
363 /* ignoring return value of NSS_Shutdown as code exits with 1 anyway*/ |
|
364 (void) NSS_Shutdown(); |
|
365 PR_Cleanup(); |
|
366 exit(1); |
|
367 } |
|
368 |
|
369 void |
|
370 printSecurityInfo(FILE *outfile, PRFileDesc *fd) |
|
371 { |
|
372 char * cp; /* bulk cipher name */ |
|
373 char * ip; /* cert issuer DN */ |
|
374 char * sp; /* cert subject DN */ |
|
375 int op; /* High, Low, Off */ |
|
376 int kp0; /* total key bits */ |
|
377 int kp1; /* secret key bits */ |
|
378 int result; |
|
379 SSL3Statistics * ssl3stats = SSL_GetStatistics(); |
|
380 |
|
381 if (!outfile) { |
|
382 outfile = stdout; |
|
383 } |
|
384 |
|
385 result = SSL_SecurityStatus(fd, &op, &cp, &kp0, &kp1, &ip, &sp); |
|
386 if (result != SECSuccess) |
|
387 return; |
|
388 fprintf(outfile, |
|
389 " bulk cipher %s, %d secret key bits, %d key bits, status: %d\n" |
|
390 " subject DN:\n %s\n" |
|
391 " issuer DN:\n %s\n", cp, kp1, kp0, op, sp, ip); |
|
392 PR_Free(cp); |
|
393 PR_Free(ip); |
|
394 PR_Free(sp); |
|
395 |
|
396 fprintf(outfile, |
|
397 " %ld cache hits; %ld cache misses, %ld cache not reusable\n", |
|
398 ssl3stats->hch_sid_cache_hits, ssl3stats->hch_sid_cache_misses, |
|
399 ssl3stats->hch_sid_cache_not_ok); |
|
400 |
|
401 } |
|
402 |
|
403 |
|
404 /************************************************************************** |
|
405 ** Begin thread management routines and data. |
|
406 **************************************************************************/ |
|
407 |
|
408 void |
|
409 thread_wrapper(void * arg) |
|
410 { |
|
411 GlobalThreadMgr *threadMGR = (GlobalThreadMgr *)arg; |
|
412 perThread *slot = &threadMGR->threads[threadMGR->index]; |
|
413 |
|
414 /* wait for parent to finish launching us before proceeding. */ |
|
415 PR_Lock(threadMGR->threadLock); |
|
416 PR_Unlock(threadMGR->threadLock); |
|
417 |
|
418 slot->rv = (* slot->startFunc)(slot->a, slot->b); |
|
419 |
|
420 PR_Lock(threadMGR->threadLock); |
|
421 slot->running = rs_zombie; |
|
422 |
|
423 /* notify the thread exit handler. */ |
|
424 PR_NotifyCondVar(threadMGR->threadEndQ); |
|
425 |
|
426 PR_Unlock(threadMGR->threadLock); |
|
427 } |
|
428 |
|
429 SECStatus |
|
430 launch_thread(GlobalThreadMgr *threadMGR, |
|
431 startFn *startFunc, |
|
432 void *a, |
|
433 int b) |
|
434 { |
|
435 perThread *slot; |
|
436 int i; |
|
437 |
|
438 if (!threadMGR->threadStartQ) { |
|
439 threadMGR->threadLock = PR_NewLock(); |
|
440 threadMGR->threadStartQ = PR_NewCondVar(threadMGR->threadLock); |
|
441 threadMGR->threadEndQ = PR_NewCondVar(threadMGR->threadLock); |
|
442 } |
|
443 PR_Lock(threadMGR->threadLock); |
|
444 while (threadMGR->numRunning >= MAX_THREADS) { |
|
445 PR_WaitCondVar(threadMGR->threadStartQ, PR_INTERVAL_NO_TIMEOUT); |
|
446 } |
|
447 for (i = 0; i < threadMGR->numUsed; ++i) { |
|
448 slot = &threadMGR->threads[i]; |
|
449 if (slot->running == rs_idle) |
|
450 break; |
|
451 } |
|
452 if (i >= threadMGR->numUsed) { |
|
453 if (i >= MAX_THREADS) { |
|
454 /* something's really wrong here. */ |
|
455 PORT_Assert(i < MAX_THREADS); |
|
456 PR_Unlock(threadMGR->threadLock); |
|
457 return SECFailure; |
|
458 } |
|
459 ++(threadMGR->numUsed); |
|
460 PORT_Assert(threadMGR->numUsed == i + 1); |
|
461 slot = &threadMGR->threads[i]; |
|
462 } |
|
463 |
|
464 slot->a = a; |
|
465 slot->b = b; |
|
466 slot->startFunc = startFunc; |
|
467 |
|
468 threadMGR->index = i; |
|
469 |
|
470 slot->prThread = PR_CreateThread(PR_USER_THREAD, |
|
471 thread_wrapper, threadMGR, |
|
472 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, |
|
473 PR_JOINABLE_THREAD, 0); |
|
474 |
|
475 if (slot->prThread == NULL) { |
|
476 PR_Unlock(threadMGR->threadLock); |
|
477 printf("Failed to launch thread!\n"); |
|
478 return SECFailure; |
|
479 } |
|
480 |
|
481 slot->inUse = 1; |
|
482 slot->running = 1; |
|
483 ++(threadMGR->numRunning); |
|
484 PR_Unlock(threadMGR->threadLock); |
|
485 |
|
486 return SECSuccess; |
|
487 } |
|
488 |
|
489 SECStatus |
|
490 reap_threads(GlobalThreadMgr *threadMGR) |
|
491 { |
|
492 perThread * slot; |
|
493 int i; |
|
494 |
|
495 if (!threadMGR->threadLock) |
|
496 return SECSuccess; |
|
497 PR_Lock(threadMGR->threadLock); |
|
498 while (threadMGR->numRunning > 0) { |
|
499 PR_WaitCondVar(threadMGR->threadEndQ, PR_INTERVAL_NO_TIMEOUT); |
|
500 for (i = 0; i < threadMGR->numUsed; ++i) { |
|
501 slot = &threadMGR->threads[i]; |
|
502 if (slot->running == rs_zombie) { |
|
503 /* Handle cleanup of thread here. */ |
|
504 |
|
505 /* Now make sure the thread has ended OK. */ |
|
506 PR_JoinThread(slot->prThread); |
|
507 slot->running = rs_idle; |
|
508 --threadMGR->numRunning; |
|
509 |
|
510 /* notify the thread launcher. */ |
|
511 PR_NotifyCondVar(threadMGR->threadStartQ); |
|
512 } |
|
513 } |
|
514 } |
|
515 |
|
516 /* Safety Sam sez: make sure count is right. */ |
|
517 for (i = 0; i < threadMGR->numUsed; ++i) { |
|
518 slot = &threadMGR->threads[i]; |
|
519 if (slot->running != rs_idle) { |
|
520 fprintf(stderr, "Thread in slot %d is in state %d!\n", |
|
521 i, slot->running); |
|
522 } |
|
523 } |
|
524 PR_Unlock(threadMGR->threadLock); |
|
525 return SECSuccess; |
|
526 } |
|
527 |
|
528 void |
|
529 destroy_thread_data(GlobalThreadMgr *threadMGR) |
|
530 { |
|
531 PORT_Memset(threadMGR->threads, 0, sizeof(threadMGR->threads)); |
|
532 |
|
533 if (threadMGR->threadEndQ) { |
|
534 PR_DestroyCondVar(threadMGR->threadEndQ); |
|
535 threadMGR->threadEndQ = NULL; |
|
536 } |
|
537 if (threadMGR->threadStartQ) { |
|
538 PR_DestroyCondVar(threadMGR->threadStartQ); |
|
539 threadMGR->threadStartQ = NULL; |
|
540 } |
|
541 if (threadMGR->threadLock) { |
|
542 PR_DestroyLock(threadMGR->threadLock); |
|
543 threadMGR->threadLock = NULL; |
|
544 } |
|
545 } |
|
546 |
|
547 /************************************************************************** |
|
548 ** End thread management routines. |
|
549 **************************************************************************/ |
|
550 |
|
551 void |
|
552 lockedVars_Init( lockedVars * lv) |
|
553 { |
|
554 lv->count = 0; |
|
555 lv->waiters = 0; |
|
556 lv->lock = PR_NewLock(); |
|
557 lv->condVar = PR_NewCondVar(lv->lock); |
|
558 } |
|
559 |
|
560 void |
|
561 lockedVars_Destroy( lockedVars * lv) |
|
562 { |
|
563 PR_DestroyCondVar(lv->condVar); |
|
564 lv->condVar = NULL; |
|
565 |
|
566 PR_DestroyLock(lv->lock); |
|
567 lv->lock = NULL; |
|
568 } |
|
569 |
|
570 void |
|
571 lockedVars_WaitForDone(lockedVars * lv) |
|
572 { |
|
573 PR_Lock(lv->lock); |
|
574 while (lv->count > 0) { |
|
575 PR_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT); |
|
576 } |
|
577 PR_Unlock(lv->lock); |
|
578 } |
|
579 |
|
580 int /* returns count */ |
|
581 lockedVars_AddToCount(lockedVars * lv, int addend) |
|
582 { |
|
583 int rv; |
|
584 |
|
585 PR_Lock(lv->lock); |
|
586 rv = lv->count += addend; |
|
587 if (rv <= 0) { |
|
588 PR_NotifyCondVar(lv->condVar); |
|
589 } |
|
590 PR_Unlock(lv->lock); |
|
591 return rv; |
|
592 } |
|
593 |
|
594 |
|
595 /* |
|
596 * Dump cert chain in to cert.* files. This function is will |
|
597 * create collisions while dumping cert chains if called from |
|
598 * multiple treads. But it should not be a problem since we |
|
599 * consider vfyserv to be single threaded(see bug 353477). |
|
600 */ |
|
601 |
|
602 void |
|
603 dumpCertChain(CERTCertificate *cert, SECCertUsage usage) |
|
604 { |
|
605 CERTCertificateList *certList; |
|
606 int count = 0; |
|
607 |
|
608 certList = CERT_CertChainFromCert(cert, usage, PR_TRUE); |
|
609 if (certList == NULL) { |
|
610 errWarn("CERT_CertChainFromCert"); |
|
611 return; |
|
612 } |
|
613 |
|
614 for(count = 0; count < (unsigned int)certList->len; count++) { |
|
615 char certFileName[16]; |
|
616 PRFileDesc *cfd; |
|
617 |
|
618 PR_snprintf(certFileName, sizeof certFileName, "cert.%03d", |
|
619 count); |
|
620 cfd = PR_Open(certFileName, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, |
|
621 0664); |
|
622 if (!cfd) { |
|
623 PR_fprintf(PR_STDOUT, |
|
624 "Error: couldn't save cert der in file '%s'\n", |
|
625 certFileName); |
|
626 } else { |
|
627 PR_Write(cfd, certList->certs[count].data, certList->certs[count].len); |
|
628 PR_Close(cfd); |
|
629 PR_fprintf(PR_STDOUT, "Cert file %s was created.\n", certFileName); |
|
630 } |
|
631 } |
|
632 CERT_DestroyCertificateList(certList); |
|
633 } |