sslsample.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:17k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. #include "sslsample.h"
  34. #include "sslerror.h"
  35. /* Declare SSL cipher suites. */
  36. int cipherSuites[] = {
  37. SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA,
  38. SSL_FORTEZZA_DMS_WITH_RC4_128_SHA,
  39. SSL_RSA_WITH_RC4_128_MD5,
  40. SSL_RSA_WITH_3DES_EDE_CBC_SHA,
  41. SSL_RSA_WITH_DES_CBC_SHA,
  42. SSL_RSA_EXPORT_WITH_RC4_40_MD5,
  43. SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
  44. SSL_FORTEZZA_DMS_WITH_NULL_SHA,
  45. SSL_RSA_WITH_NULL_MD5,
  46. 0
  47. };
  48. int ssl2CipherSuites[] = {
  49. SSL_EN_RC4_128_WITH_MD5,              /* A */
  50. SSL_EN_RC4_128_EXPORT40_WITH_MD5,     /* B */
  51. SSL_EN_RC2_128_CBC_WITH_MD5,          /* C */
  52. SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */
  53. SSL_EN_DES_64_CBC_WITH_MD5,           /* E */
  54. SSL_EN_DES_192_EDE3_CBC_WITH_MD5,     /* F */
  55. 0
  56. };
  57. int ssl3CipherSuites[] = {
  58. SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, /* a */
  59. SSL_FORTEZZA_DMS_WITH_RC4_128_SHA,      /* b */
  60. SSL_RSA_WITH_RC4_128_MD5,               /* c */
  61. SSL_RSA_WITH_3DES_EDE_CBC_SHA,          /* d */
  62. SSL_RSA_WITH_DES_CBC_SHA,               /* e */
  63. SSL_RSA_EXPORT_WITH_RC4_40_MD5,         /* f */
  64. SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5,     /* g */
  65. SSL_FORTEZZA_DMS_WITH_NULL_SHA,         /* h */
  66. SSL_RSA_WITH_NULL_MD5,                  /* i */
  67. SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,     /* j */
  68. SSL_RSA_FIPS_WITH_DES_CBC_SHA,          /* k */
  69. TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,    /* l */
  70. TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,     /* m */
  71. 0
  72. };
  73. /**************************************************************************
  74. ** 
  75. ** SSL callback routines.
  76. **
  77. **************************************************************************/
  78. /* Function: char * myPasswd()
  79.  * 
  80.  * Purpose: This function is our custom password handler that is called by
  81.  * SSL when retreiving private certs and keys from the database. Returns a
  82.  * pointer to a string that with a password for the database. Password pointer
  83.  * should point to dynamically allocated memory that will be freed later.
  84.  */
  85. char *
  86. myPasswd(PK11SlotInfo *info, PRBool retry, void *arg)
  87. {
  88. char * passwd = NULL;
  89. if ( (!retry) && arg ) {
  90. passwd = PORT_Strdup((char *)arg);
  91. }
  92. return passwd;
  93. }
  94. /* Function: SECStatus myAuthCertificate()
  95.  *
  96.  * Purpose: This function is our custom certificate authentication handler.
  97.  * 
  98.  * Note: This implementation is essentially the same as the default 
  99.  *       SSL_AuthCertificate().
  100.  */
  101. SECStatus 
  102. myAuthCertificate(void *arg, PRFileDesc *socket, 
  103.                   PRBool checksig, PRBool isServer) 
  104. {
  105. SECCertUsage        certUsage;
  106. CERTCertificate *   cert;
  107. void *              pinArg;
  108. char *              hostName;
  109. SECStatus           secStatus;
  110. if (!arg || !socket) {
  111. errWarn("myAuthCertificate");
  112. return SECFailure;
  113. }
  114. /* Define how the cert is being used based upon the isServer flag. */
  115. certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
  116. cert = SSL_PeerCertificate(socket);
  117. pinArg = SSL_RevealPinArg(socket);
  118. secStatus = CERT_VerifyCertNow((CERTCertDBHandle *)arg,
  119.                                cert,
  120.                                checksig,
  121.                                certUsage,
  122.                                pinArg);
  123. /* If this is a server, we're finished. */
  124. if (isServer || secStatus != SECSuccess) {
  125. return secStatus;
  126. }
  127. /* Certificate is OK.  Since this is the client side of an SSL
  128.  * connection, we need to verify that the name field in the cert
  129.  * matches the desired hostname.  This is our defense against
  130.  * man-in-the-middle attacks.
  131.  */
  132. /* SSL_RevealURL returns a hostName, not an URL. */
  133. hostName = SSL_RevealURL(socket);
  134. if (hostName && hostName[0]) {
  135. secStatus = CERT_VerifyCertName(cert, hostName);
  136. } else {
  137. PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0);
  138. secStatus = SECFailure;
  139. }
  140. if (hostName)
  141. PR_Free(hostName);
  142. return secStatus;
  143. }
  144. /* Function: SECStatus myBadCertHandler()
  145.  *
  146.  * Purpose: This callback is called when the incoming certificate is not
  147.  * valid. We define a certain set of parameters that still cause the
  148.  * certificate to be "valid" for this session, and return SECSuccess to cause
  149.  * the server to continue processing the request when any of these conditions
  150.  * are met. Otherwise, SECFailure is return and the server rejects the 
  151.  * request.
  152.  */
  153. SECStatus 
  154. myBadCertHandler(void *arg, PRFileDesc *socket) 
  155. {
  156.     SECStatus secStatus = SECFailure;
  157.     PRErrorCode err;
  158.     /* log invalid cert here */
  159.     if (!arg) {
  160. return secStatus;
  161.     }
  162.     *(PRErrorCode *)arg = err = PORT_GetError();
  163.     /* If any of the cases in the switch are met, then we will proceed   */
  164.     /* with the processing of the request anyway. Otherwise, the default */
  165.     /* case will be reached and we will reject the request.              */
  166.     switch (err) {
  167.     case SEC_ERROR_INVALID_AVA:
  168.     case SEC_ERROR_INVALID_TIME:
  169.     case SEC_ERROR_BAD_SIGNATURE:
  170.     case SEC_ERROR_EXPIRED_CERTIFICATE:
  171.     case SEC_ERROR_UNKNOWN_ISSUER:
  172.     case SEC_ERROR_UNTRUSTED_CERT:
  173.     case SEC_ERROR_CERT_VALID:
  174.     case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
  175.     case SEC_ERROR_CRL_EXPIRED:
  176.     case SEC_ERROR_CRL_BAD_SIGNATURE:
  177.     case SEC_ERROR_EXTENSION_VALUE_INVALID:
  178.     case SEC_ERROR_CA_CERT_INVALID:
  179.     case SEC_ERROR_CERT_USAGES_INVALID:
  180.     case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
  181. secStatus = SECSuccess;
  182. break;
  183.     default:
  184. secStatus = SECFailure;
  185. break;
  186.     }
  187. printf("Bad certificate: %d, %sn", err, SSL_Strerror(err));
  188.     return secStatus;
  189. }
  190. /* Function: SECStatus ownGetClientAuthData()
  191.  *
  192.  * Purpose: This callback is used by SSL to pull client certificate 
  193.  * information upon server request.
  194.  */
  195. SECStatus 
  196. myGetClientAuthData(void *arg,
  197.                     PRFileDesc *socket,
  198.                     struct CERTDistNamesStr *caNames,
  199.                     struct CERTCertificateStr **pRetCert,
  200.                     struct SECKEYPrivateKeyStr **pRetKey) 
  201. {
  202.     CERTCertificate *  cert;
  203.     SECKEYPrivateKey * privKey;
  204.     char *             chosenNickName = (char *)arg;
  205.     void *             proto_win      = NULL;
  206.     SECStatus          secStatus      = SECFailure;
  207.     proto_win = SSL_RevealPinArg(socket);
  208.     if (chosenNickName) {
  209. cert = PK11_FindCertFromNickname(chosenNickName, proto_win);
  210. if (cert) {
  211.     privKey = PK11_FindKeyByAnyCert(cert, proto_win);
  212.     if (privKey) {
  213. secStatus = SECSuccess;
  214.     } else {
  215. CERT_DestroyCertificate(cert);
  216.     }
  217. }
  218.     } else { /* no nickname given, automatically find the right cert */
  219. CERTCertNicknames *names;
  220. int                i;
  221. names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(), 
  222.                               SEC_CERT_NICKNAMES_USER, proto_win);
  223. if (names != NULL) {
  224.     for(i = 0; i < names->numnicknames; i++ ) {
  225. cert = PK11_FindCertFromNickname(names->nicknames[i], 
  226.                                  proto_win);
  227. if (!cert) {
  228.     continue;
  229. }
  230. /* Only check unexpired certs */
  231. if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE)
  232.       != secCertTimeValid ) {
  233.     CERT_DestroyCertificate(cert);
  234.     continue;
  235. }
  236. secStatus = NSS_CmpCertChainWCANames(cert, caNames);
  237. if (secStatus == SECSuccess) {
  238.     privKey = PK11_FindKeyByAnyCert(cert, proto_win);
  239.     if (privKey) {
  240. break;
  241.     }
  242.     secStatus = SECFailure;
  243.     break;
  244. }
  245. CERT_FreeNicknames(names);
  246.     } /* for loop */
  247. }
  248.     }
  249.     if (secStatus == SECSuccess) {
  250. *pRetCert = cert;
  251. *pRetKey  = privKey;
  252.     }
  253.     return secStatus;
  254. }
  255. /* Function: SECStatus myHandshakeCallback()
  256.  *
  257.  * Purpose: Called by SSL to inform application that the handshake is
  258.  * complete. This function is mostly used on the server side of an SSL
  259.  * connection, although it is provided for a client as well.
  260.  * Useful when a non-blocking SSL_RedoHandshake or SSL_ResetHandshake 
  261.  * is used to initiate a handshake.
  262.  *
  263.  * A typical scenario would be:
  264.  *
  265.  * 1. Server accepts an SSL connection from the client without client auth.
  266.  * 2. Client sends a request.
  267.  * 3. Server determines that to service request it needs to authenticate the
  268.  * client and initiates another handshake requesting client auth.
  269.  * 4. While handshake is in progress, server can do other work or spin waiting
  270.  * for the handshake to complete.
  271.  * 5. Server is notified that handshake has been successfully completed by
  272.  * the custom handshake callback function and it can service the client's
  273.  * request.
  274.  *
  275.  * Note: This function is not implemented in this sample, as we are using
  276.  * blocking sockets.
  277.  */
  278. SECStatus 
  279. myHandshakeCallback(PRFileDesc *socket, void *arg) 
  280. {
  281.     printf("Handshake has completed, ready to send data securely.n");
  282.     return SECSuccess;
  283. }
  284. /**************************************************************************
  285. ** 
  286. ** Routines for disabling SSL ciphers.
  287. **
  288. **************************************************************************/
  289. void
  290. disableSSL2Ciphers(void)
  291. {
  292. int i;
  293. /* disable all the SSL2 cipher suites */
  294. for (i = 0; ssl2CipherSuites[i] != 0;  ++i) {
  295. SSL_EnableCipher(ssl2CipherSuites[i], SSL_NOT_ALLOWED);
  296. }
  297. }
  298. void
  299. disableSSL3Ciphers(void)
  300. {
  301. int i;
  302. /* disable all the SSL3 cipher suites */
  303. for (i = 0; ssl3CipherSuites[i] != 0;  ++i) {
  304. SSL_EnableCipher(ssl3CipherSuites[i], SSL_NOT_ALLOWED);
  305. }
  306. }
  307. /**************************************************************************
  308. ** 
  309. ** Error and information routines.
  310. **
  311. **************************************************************************/
  312. void
  313. errWarn(char *function)
  314. {
  315. PRErrorCode  errorNumber = PR_GetError();
  316. const char * errorString = SSL_Strerror(errorNumber);
  317. printf("Error in function %s: %dn - %sn",
  318. function, errorNumber, errorString);
  319. }
  320. void
  321. exitErr(char *function)
  322. {
  323. errWarn(function);
  324. /* Exit gracefully. */
  325. NSS_Shutdown();
  326. PR_Cleanup();
  327. exit(1);
  328. }
  329. void 
  330. printSecurityInfo(PRFileDesc *fd)
  331. {
  332. char * cp; /* bulk cipher name */
  333. char * ip; /* cert issuer DN */
  334. char * sp; /* cert subject DN */
  335. int    op; /* High, Low, Off */
  336. int    kp0; /* total key bits */
  337. int    kp1; /* secret key bits */
  338. int    result;
  339. #if 0
  340. /* statistics from ssl3_SendClientHello (sch) */
  341. extern long ssl3_sch_sid_cache_hits;
  342. extern long ssl3_sch_sid_cache_misses;
  343. extern long ssl3_sch_sid_cache_not_ok;
  344. /* statistics from ssl3_HandleServerHello (hsh) */
  345. extern long ssl3_hsh_sid_cache_hits;
  346. extern long ssl3_hsh_sid_cache_misses;
  347. extern long ssl3_hsh_sid_cache_not_ok;
  348. #endif
  349. /* statistics from ssl3_HandleClientHello (hch) */
  350. extern long ssl3_hch_sid_cache_hits;
  351. extern long ssl3_hch_sid_cache_misses;
  352. extern long ssl3_hch_sid_cache_not_ok;
  353. result = SSL_SecurityStatus(fd, &op, &cp, &kp0, &kp1, &ip, &sp);
  354. if (result != SECSuccess)
  355. return;
  356. printf("bulk cipher %s, %d secret key bits, %d key bits, status: %dn"
  357.    "subject DN: %sn"
  358.    "issuer DN: %sn", cp, kp1, kp0, op, sp, ip);
  359. PR_Free(cp);
  360. PR_Free(ip);
  361. PR_Free(sp);
  362. printf("%ld cache hits; %ld cache misses, %ld cache not reusablen",
  363. ssl3_hch_sid_cache_hits, ssl3_hch_sid_cache_misses,
  364. ssl3_hch_sid_cache_not_ok);
  365. }
  366. /**************************************************************************
  367. ** Begin thread management routines and data.
  368. **************************************************************************/
  369. void
  370. thread_wrapper(void * arg)
  371. {
  372. GlobalThreadMgr *threadMGR = (GlobalThreadMgr *)arg;
  373. perThread *slot = &threadMGR->threads[threadMGR->index];
  374. /* wait for parent to finish launching us before proceeding. */
  375. PR_Lock(threadMGR->threadLock);
  376. PR_Unlock(threadMGR->threadLock);
  377. slot->rv = (* slot->startFunc)(slot->a, slot->b);
  378. PR_Lock(threadMGR->threadLock);
  379. slot->running = rs_zombie;
  380. /* notify the thread exit handler. */
  381. PR_NotifyCondVar(threadMGR->threadEndQ);
  382. PR_Unlock(threadMGR->threadLock);
  383. }
  384. SECStatus
  385. launch_thread(GlobalThreadMgr *threadMGR,
  386.               startFn         *startFunc,
  387.               void            *a,
  388.               int              b)
  389. {
  390. perThread *slot;
  391. int        i;
  392. if (!threadMGR->threadStartQ) {
  393. threadMGR->threadLock   = PR_NewLock();
  394. threadMGR->threadStartQ = PR_NewCondVar(threadMGR->threadLock);
  395. threadMGR->threadEndQ   = PR_NewCondVar(threadMGR->threadLock);
  396. }
  397. PR_Lock(threadMGR->threadLock);
  398. while (threadMGR->numRunning >= MAX_THREADS) {
  399. PR_WaitCondVar(threadMGR->threadStartQ, PR_INTERVAL_NO_TIMEOUT);
  400. }
  401. for (i = 0; i < threadMGR->numUsed; ++i) {
  402. slot = &threadMGR->threads[i];
  403. if (slot->running == rs_idle) 
  404. break;
  405. }
  406. if (i >= threadMGR->numUsed) {
  407. if (i >= MAX_THREADS) {
  408. /* something's really wrong here. */
  409. PORT_Assert(i < MAX_THREADS);
  410. PR_Unlock(threadMGR->threadLock);
  411. return SECFailure;
  412. }
  413. ++(threadMGR->numUsed);
  414. PORT_Assert(threadMGR->numUsed == i + 1);
  415. slot = &threadMGR->threads[i];
  416. }
  417. slot->a = a;
  418. slot->b = b;
  419. slot->startFunc = startFunc;
  420. threadMGR->index = i;
  421. slot->prThread = PR_CreateThread(PR_USER_THREAD,
  422.                                  thread_wrapper, threadMGR,
  423.                                  PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  424.                                  PR_JOINABLE_THREAD, 0);
  425. if (slot->prThread == NULL) {
  426. PR_Unlock(threadMGR->threadLock);
  427. printf("Failed to launch thread!n");
  428. return SECFailure;
  429. slot->inUse   = 1;
  430. slot->running = 1;
  431. ++(threadMGR->numRunning);
  432. PR_Unlock(threadMGR->threadLock);
  433. printf("Launched thread in slot %d n", threadMGR->index);
  434. return SECSuccess;
  435. }
  436. SECStatus 
  437. reap_threads(GlobalThreadMgr *threadMGR)
  438. {
  439. perThread * slot;
  440. int i;
  441. if (!threadMGR->threadLock)
  442. return 0;
  443. PR_Lock(threadMGR->threadLock);
  444. while (threadMGR->numRunning > 0) {
  445. PR_WaitCondVar(threadMGR->threadEndQ, PR_INTERVAL_NO_TIMEOUT);
  446. for (i = 0; i < threadMGR->numUsed; ++i) {
  447. slot = &threadMGR->threads[i];
  448. if (slot->running == rs_zombie)  {
  449. /* Handle cleanup of thread here. */
  450. printf("Thread in slot %d returned %dn", i, slot->rv);
  451. /* Now make sure the thread has ended OK. */
  452. PR_JoinThread(slot->prThread);
  453. slot->running = rs_idle;
  454. --threadMGR->numRunning;
  455. /* notify the thread launcher. */
  456. PR_NotifyCondVar(threadMGR->threadStartQ);
  457. }
  458. }
  459. }
  460. /* Safety Sam sez: make sure count is right. */
  461. for (i = 0; i < threadMGR->numUsed; ++i) {
  462. slot = &threadMGR->threads[i];
  463. if (slot->running != rs_idle)  {
  464. fprintf(stderr, "Thread in slot %d is in state %d!n", 
  465.                  i, slot->running);
  466. }
  467. }
  468. PR_Unlock(threadMGR->threadLock);
  469. return 0;
  470. }
  471. void
  472. destroy_thread_data(GlobalThreadMgr *threadMGR)
  473. {
  474. PORT_Memset(threadMGR->threads, 0, sizeof(threadMGR->threads));
  475. if (threadMGR->threadEndQ) {
  476. PR_DestroyCondVar(threadMGR->threadEndQ);
  477. threadMGR->threadEndQ = NULL;
  478. }
  479. if (threadMGR->threadStartQ) {
  480. PR_DestroyCondVar(threadMGR->threadStartQ);
  481. threadMGR->threadStartQ = NULL;
  482. }
  483. if (threadMGR->threadLock) {
  484. PR_DestroyLock(threadMGR->threadLock);
  485. threadMGR->threadLock = NULL;
  486. }
  487. }
  488. /**************************************************************************
  489. ** End  thread management routines.
  490. **************************************************************************/
  491. void 
  492. lockedVars_Init( lockedVars * lv)
  493. {
  494. lv->count = 0;
  495. lv->waiters = 0;
  496. lv->lock = PR_NewLock();
  497. lv->condVar = PR_NewCondVar(lv->lock);
  498. }
  499. void
  500. lockedVars_Destroy( lockedVars * lv)
  501. {
  502. PR_DestroyCondVar(lv->condVar);
  503. lv->condVar = NULL;
  504. PR_DestroyLock(lv->lock);
  505. lv->lock = NULL;
  506. }
  507. void
  508. lockedVars_WaitForDone(lockedVars * lv)
  509. {
  510. PR_Lock(lv->lock);
  511. while (lv->count > 0) {
  512. PR_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT);
  513. }
  514. PR_Unlock(lv->lock);
  515. }
  516. int /* returns count */
  517. lockedVars_AddToCount(lockedVars * lv, int addend)
  518. {
  519. int rv;
  520. PR_Lock(lv->lock);
  521. rv = lv->count += addend;
  522. if (rv <= 0) {
  523. PR_NotifyCondVar(lv->condVar);
  524. }
  525. PR_Unlock(lv->lock);
  526. return rv;
  527. }