security/nss/cmd/vfyserv/vfyutil.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial