pssl.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:16k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * pssl.cxx
  3.  *
  4.  * SSL implementation for PTLib using the SSLeay package
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * Portions bsed upon the file crypto/buffer/bss_sock.c 
  30.  * Original copyright notice appears below
  31.  *
  32.  * $Id: pssl.cxx,v 1.9 2000/01/10 02:24:09 craigs Exp $
  33.  * $Log: pssl.cxx,v $
  34.  * Revision 1.9  2000/01/10 02:24:09  craigs
  35.  * Updated for new OpenSSL
  36.  *
  37.  * Revision 1.8  1998/12/04 13:04:18  craigs
  38.  * Changed for SSLeay 0.9
  39.  *
  40.  * Revision 1.7  1998/09/23 06:22:35  robertj
  41.  * Added open source copyright license.
  42.  *
  43.  * Revision 1.6  1998/01/26 02:50:17  robertj
  44.  * GNU Support
  45.  *
  46.  * Revision 1.5  1997/05/04 02:50:54  craigs
  47.  * Added support for client and server sertificates
  48.  *
  49.  * Revision 1.1  1996/11/15 07:38:34  craigs
  50.  * Initial revision
  51.  *
  52.  */
  53. /* crypto/buffer/bss_sock.c */
  54. /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au)
  55.  * All rights reserved.
  56.  * 
  57.  * This file is part of an SSL implementation written
  58.  * by Eric Young (eay@mincom.oz.au).
  59.  * The implementation was written so as to conform with Netscapes SSL
  60.  * specification.  This library and applications are
  61.  * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE
  62.  * as long as the following conditions are aheared to.
  63.  * 
  64.  * Copyright remains Eric Young's, and as such any Copyright notices in
  65.  * the code are not to be removed.  If this code is used in a product,
  66.  * Eric Young should be given attribution as the author of the parts used.
  67.  * This can be in the form of a textual message at program startup or
  68.  * in documentation (online or textual) provided with the package.
  69.  * 
  70.  * Redistribution and use in source and binary forms, with or without
  71.  * modification, are permitted provided that the following conditions
  72.  * are met:
  73.  * 1. Redistributions of source code must retain the copyright
  74.  *    notice, this list of conditions and the following disclaimer.
  75.  * 2. Redistributions in binary form must reproduce the above copyright
  76.  *    notice, this list of conditions and the following disclaimer in the
  77.  *    documentation and/or other materials provided with the distribution.
  78.  * 3. All advertising materials mentioning features or use of this software
  79.  *    must display the following acknowledgement:
  80.  *    This product includes software developed by Eric Young (eay@mincom.oz.au)
  81.  * 
  82.  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
  83.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  84.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  85.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  86.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  87.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  88.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  89.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  90.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  91.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  92.  * SUCH DAMAGE.
  93.  * 
  94.  * The licence and distribution terms for any publically available version or
  95.  * derivative of this code cannot be changed.  i.e. this code cannot simply be
  96.  * copied and put under another distribution licence
  97.  * [including the GNU Public Licence.]
  98.  */
  99. #ifdef __GNUC__
  100. #pragma implementation "pssl.h"
  101. #endif
  102. #include <ptlib.h>
  103. #include <ptclib/pssl.h>
  104. #include <openssl/buffer.h>
  105. #include <openssl/crypto.h>
  106. PMutex PSSLChannel::initFlag;
  107. SSL_CTX * PSSLChannel::context = NULL;
  108. extern "C" {
  109. typedef int (verifyCallBackType)();
  110. };
  111. ///////////////////////////////////////////////////////////////////////////////
  112. static PMutex semaphores[CRYPTO_NUM_LOCKS];
  113. extern "C" {
  114. void locking_callback(int mode, int type, const char * /* file */, int /* line */)
  115. {
  116. if (mode & CRYPTO_LOCK) 
  117. semaphores[type].Wait();
  118. else
  119. semaphores[type].Signal();
  120. }
  121. };
  122. static void thread_setup()
  123. {
  124. CRYPTO_set_locking_callback((void (*)(int,int,const char *,int))locking_callback);
  125. }
  126. void PSSLChannel::Cleanup()
  127. {
  128. CRYPTO_set_locking_callback(NULL);
  129.   SSL_CTX_free(context);
  130. }
  131. ///////////////////////////////////////////////////////////////////////////////
  132. extern "C" {
  133. static int verifyCallBack(int ok, X509_STORE_CTX * ctx)
  134. {
  135.   X509 * err_cert = X509_STORE_CTX_get_current_cert(ctx);
  136.   //int err         = X509_STORE_CTX_get_error(ctx);
  137.   int depth       = X509_STORE_CTX_get_error_depth(ctx);
  138.   // get the subject name, just for verification
  139.   char buf[256];
  140.   X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
  141.   PError << "Verify callback depth " << depth << " : cert name = " << buf << endl;
  142.   return ok;
  143. }
  144. };
  145. /////////////////////////////////////////////////////////////////////////
  146. //
  147. //  SSLChannel
  148. //
  149. PSSLChannel::PSSLChannel()
  150. {
  151.   initFlag.Wait();
  152.   if (context == NULL) {
  153.     SSL_load_error_strings();
  154.     SSLeay_add_ssl_algorithms();
  155.     //SSLeay_add_all_algorithms();
  156.     // create the new SSL context
  157.     SSL_METHOD *meth = SSLv2_client_method();
  158.     context  = SSL_CTX_new(meth);
  159.     PAssert(context != NULL, "Cannot create master SSL context");
  160.     // set other stuff
  161.     SSL_CTX_set_options        (context, 0);
  162.     //SSL_CTX_set_quiet_shutdown (context, 1);
  163.     //SSL_CTX_sess_set_cache_size(context, 128);
  164.     // set default ciphers
  165.     //PConfig config(PConfig::Environment);
  166.     //PString str = config.GetString("SSL_CIPHER");
  167.     //if (!str.IsEmpty())
  168.     //  SSL_CTX_set_cipher_list(context, (char *)(const char *)str);
  169.     // set default verify mode
  170.     //SSL_CTX_set_verify(context, SSL_VERIFY_NONE, (verifyCallBackType *)verifyCallBack);
  171.     PAssert( //SSL_CTX_load_verify_locations(context,NULL,NULL/*CAfile,CApath*/) && 
  172.              SSL_CTX_set_default_verify_paths(context), "Cannot set CAfile and path");
  173.     //PAssert (X509_set_default_verify_paths(context->cert),
  174.     //        "SSL: Cannot load certificates via X509_set_default_verify_paths");
  175.     // set up multithread stuff
  176.     //thread_setup();
  177.     // and make sure everything gets torn-down correctly
  178.     atexit(Cleanup);
  179.   }
  180.   initFlag.Signal();
  181.   // create an SSL context
  182.   ssl = SSL_new(context);
  183. }
  184. PSSLChannel::~PSSLChannel()
  185. {
  186.   // free the SSL context
  187.   SSL_free(ssl);
  188. }
  189. /////////////////////////////////////////////////
  190. int PSSLChannel::SetClientCertificate(const PString & privateCert)
  191. {
  192.   return SetClientCertificate((const char *)privateCert, (const char *)privateCert);
  193. }
  194. int PSSLChannel::SetClientCertificate(const PString & privateCert, const PString & privateKey)
  195. {
  196.   return SetClientCertificate((const char *)privateCert, (const char *)privateKey);
  197. }
  198. int PSSLChannel::SetClientCertificate(const char * certFile, const char * keyFile)
  199. {
  200.   // set up certificate and key 
  201.   if (certFile != NULL) {
  202.     if (!SSL_use_certificate_file(ssl, (char *)certFile, X509_FILETYPE_PEM))
  203.       return PSSLChannel::UnknownCertificate;
  204.     if (keyFile == NULL)
  205.       keyFile = certFile;
  206.     if (!SSL_use_RSAPrivateKey_file(ssl, (char *)keyFile, X509_FILETYPE_PEM))
  207.       return PSSLChannel::UnknownPrivateKey;
  208.     if (!SSL_check_private_key(ssl))
  209.       return PSSLChannel::PrivateKeyMismatch;
  210.   }
  211.   return PSSLChannel::CertificateOK;
  212. }
  213. /////////////////////////////////////////////////
  214. BOOL PSSLChannel::SetCAPath(const PDirectory & caPath)
  215. {
  216.   return SetCAPathAndFile((const char *)caPath, NULL);
  217. }
  218. BOOL PSSLChannel::SetCAFile(const PFilePath & caFile)
  219. {
  220.   return SetCAPathAndFile(NULL, (const char *)caFile);
  221. }
  222. BOOL PSSLChannel::SetCAPathAndFile(const PDirectory & caPath, const PFilePath & caFile)
  223. {
  224.   return SetCAPathAndFile((const char *)caPath, (const char *)caFile);
  225. }
  226. BOOL PSSLChannel::SetCAPathAndFile(const char * CApath, const char * CAfile)
  227. {
  228.   PString path = CApath;
  229.   if (path.Right(1)[0] == PDIR_SEPARATOR)
  230.     path = path.Left(path.GetLength()-1);
  231.   return SSL_CTX_load_verify_locations(context,
  232.                                        (char *)CAfile,
  233.                                        (char *)(const char *)path
  234.          ) && SSL_CTX_set_default_verify_paths(context);
  235. }
  236. /////////////////////////////////////////////////
  237. void PSSLChannel::SetVerifyMode(int mode)
  238. {
  239.   int verify;
  240.   switch (mode) {
  241.     case VerifyNone:
  242.       verify = SSL_VERIFY_NONE;
  243.       break;
  244.     case VerifyPeer:
  245.       verify = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
  246.       break;
  247.     case VerifyPeerMandatory:
  248.       verify = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
  249.   }
  250.   SSL_set_verify(ssl, verify, (verifyCallBackType *)verifyCallBack);
  251. }
  252. /////////////////////////////////////////////////
  253. BOOL PSSLChannel::Accept(PChannel & channel)
  254. {
  255.   if (!Open(channel))
  256.     return FALSE;
  257.   // set the "fd" to use with this SSL context
  258.   Set_SSL_Fd();
  259.   // connect the SSL layer
  260.   return SSL_accept(ssl) > 0;
  261. }
  262. BOOL PSSLChannel::Connect(PChannel & channel)
  263. {
  264.   if (!Open(channel))
  265.     return FALSE;
  266.   // set the "fd" to use with this SSL context
  267.   Set_SSL_Fd();
  268.   // connect the SSL layer
  269.   return SSL_connect(ssl) > 0;
  270. }
  271. BOOL PSSLChannel::Read(void * buf, PINDEX len)
  272. {
  273.   int r = SSL_read(ssl, (char *)buf, len);
  274.   lastReadCount = 0;
  275.   if (!ConvertOSError(r))
  276.     return FALSE;
  277.   lastReadCount = r;
  278.   return TRUE;
  279. }
  280. BOOL PSSLChannel::Write(const void * buf, PINDEX len)
  281. {
  282.   lastWriteCount = 0;
  283.   while (len > 0) {
  284.     int sendResult = SSL_write(ssl, ((char *)buf)+lastWriteCount, len);
  285.     if (!ConvertOSError(sendResult))
  286.       return FALSE;
  287.     lastWriteCount += sendResult;
  288.     len -= sendResult;
  289.   }
  290.   return TRUE;
  291. }
  292. BOOL PSSLChannel::RawRead(void * buf, PINDEX len)
  293. {
  294.   return readChannel->Read(buf, len);
  295. }
  296. PINDEX PSSLChannel::RawGetLastReadCount() const
  297. {
  298.   return readChannel->GetLastReadCount();
  299. }
  300. BOOL PSSLChannel::RawWrite(const void * buf, PINDEX len)
  301. {
  302.   return writeChannel->Write(buf, len);
  303. }
  304. PINDEX PSSLChannel::RawGetLastWriteCount() const
  305. {
  306.   return writeChannel->GetLastWriteCount();
  307. }
  308. //////////////////////////////////////////////////////////////////////////
  309. //
  310. //  Low level interface to SSLEay routines
  311. //
  312. #define PSSLSOCKET(bio) ((PSSLChannel *)(bio->num))
  313. extern "C" {
  314. #include <stdio.h>
  315. #include <errno.h>
  316. #define USE_SOCKETS
  317. //#include <openssl/cryptlib.h>
  318. #include <openssl/err.h>
  319. #include <openssl/buffer.h>
  320. static int  Psock_write(BIO *h,char *buf,int num);
  321. static int  Psock_read(BIO *h,char *buf,int size);
  322. static int  Psock_puts(BIO *h,char *str);
  323. static int  Psock_gets(BIO *h,char *str,int size);
  324. static long Psock_ctrl(BIO *h,int cmd,long arg1,char *arg2);
  325. static int  Psock_new(BIO *h);
  326. static int  Psock_free(BIO *data);
  327. static int  Psock_should_retry(int s);
  328. typedef int (*ifptr)();
  329. typedef long (*lfptr)();
  330. static BIO_METHOD methods_Psock =
  331. {
  332.   BIO_TYPE_SOCKET,
  333.   "ptlib socket",
  334.   (ifptr)Psock_write,
  335.   (ifptr)Psock_read,
  336.   (ifptr)Psock_puts,
  337.   (ifptr)Psock_gets, 
  338.   (lfptr)Psock_ctrl,
  339.   (ifptr)Psock_new,
  340.   (ifptr)Psock_free
  341. };
  342. static long Psock_ctrl(BIO * bio, int cmd, long num, char * ptr)
  343. {
  344.   long ret = 1;
  345.   int *ip;
  346.   switch (cmd) {
  347.     //
  348.     // mandatory BIO commands
  349.     //
  350. //    case BIO_CTRL_SET:
  351.     case BIO_C_SET_FD:
  352.       if (bio != NULL);
  353.         Psock_free(bio);
  354.       bio->num      = *((int *)ptr);
  355.       bio->shutdown = (int)num;
  356.       bio->init     = 1;
  357.       break;
  358.     case BIO_CTRL_GET:
  359.       if (bio->init) {
  360.         ip = (int *)ptr;
  361.       if (ip == NULL)
  362.         ret = 0;
  363.       else
  364.         *ip = bio->num;
  365.       }
  366.       break;
  367.     case BIO_CTRL_GET_CLOSE:
  368.       ret = bio->shutdown;
  369.       break;
  370.     case BIO_CTRL_SET_CLOSE:
  371.       bio->shutdown=(int)num;
  372.       break;
  373.     //
  374.     // optional BIO commands
  375.     //
  376.     case BIO_CTRL_RESET:
  377.       ret = 0;
  378.       break;
  379.     case BIO_CTRL_INFO:
  380.       ret = 0;
  381.       break;
  382.     case BIO_CTRL_EOF:
  383.       ret = 0;
  384.       break;
  385.     case BIO_CTRL_PUSH:
  386.       ret = 0;
  387.       break;
  388.     case BIO_CTRL_POP:
  389.       ret = 0;
  390.       break;
  391.     case BIO_CTRL_PENDING:
  392.       ret = 0;
  393.       break;
  394.     case BIO_CTRL_FLUSH:
  395.       break;
  396.     default:
  397.       ret = 0;
  398.       break;
  399.   }
  400.   return ret;
  401. }
  402. static int Psock_new(BIO * bio)
  403. {
  404.   bio->init     = 0;
  405.   bio->num      = 0;    // this is really (PSSLChannel *), not int
  406.   bio->ptr      = NULL;
  407.   bio->flags    = 0;
  408.   return(1);
  409. }
  410. static int Psock_free(BIO * bio)
  411. {
  412.   if (bio == NULL)
  413.     return 0;
  414.   if (bio->shutdown) {
  415.     if (bio->init) {
  416.       PSSLSOCKET(bio)->Shutdown(PSocket::ShutdownReadAndWrite);
  417.       PSSLSOCKET(bio)->Close();
  418.     }
  419.     bio->init  = 0;
  420.     bio->flags = 0;
  421.   }
  422.   return 1;
  423. }
  424. static int Psock_should_retry(int i)
  425. {
  426.   if (i == PChannel::Interrupted)
  427.     return 1;
  428.   if (i == PChannel::Timeout)
  429.     return 1;
  430.   return 0;
  431. }
  432. static int Psock_read(BIO * bio, char * out, int outl)
  433. {
  434.   int ret = 0;
  435.   if (out != NULL) {
  436.     BOOL b = PSSLSOCKET(bio)->RawRead(out, outl);
  437.     BIO_clear_retry_flags(bio);
  438.     if (b) 
  439.       ret = PSSLSOCKET(bio)->RawGetLastReadCount();
  440.     else if (Psock_should_retry(PSSLSOCKET(bio)->GetErrorCode())) {
  441.       BIO_set_retry_read(bio);
  442.       ret = -1;
  443.     }
  444.   }
  445.   return(ret);
  446. }
  447. static int Psock_write(BIO * bio, char * in, int inl)
  448. {
  449.   int ret = 0;
  450.   if (in != NULL) {
  451.     BOOL b = PSSLSOCKET(bio)->RawWrite(in, inl);
  452.     BIO_clear_retry_flags(bio);
  453.     bio->flags &= ~(BIO_FLAGS_READ|BIO_FLAGS_WRITE|BIO_FLAGS_SHOULD_RETRY);
  454.     if (b)
  455.       ret = PSSLSOCKET(bio)->RawGetLastWriteCount();
  456.     else if (Psock_should_retry(PSSLSOCKET(bio)->GetErrorCode())) {
  457.       BIO_set_retry_write(bio);
  458.       ret = -1;
  459.     }
  460.   }
  461.   return(ret);
  462. }
  463. static int Psock_gets(BIO *,char *, int)
  464. {
  465.   return -1;
  466. }
  467. static int Psock_puts(BIO * bio,char * str)
  468. {
  469.   int n,ret;
  470.   n   = strlen(str);
  471.   ret = Psock_write(bio,str,n);
  472.   return ret;
  473. }
  474. };
  475. int PSSLChannel::Set_SSL_Fd()
  476. {
  477.   int ret=0;
  478.   BIO * bio = NULL;
  479.   bio = BIO_new(&methods_Psock);
  480.   if (bio == NULL) {
  481.     SSLerr(SSL_F_SSL_SET_FD,ERR_R_BUF_LIB);
  482.     goto err;
  483.   }
  484.   SSL_set_bio(ssl, bio, bio);
  485.   BIO_set_fd(bio, (int)this, BIO_NOCLOSE);
  486. /*
  487.   if (ssl->rbio != NULL)
  488.     BIO_free((bio_st *)ssl->rbio);
  489.   if ((ssl->wbio != NULL) && (ssl->wbio != ssl->rbio))
  490.     BIO_free((bio_st *)ssl->wbio);
  491.   ssl->rbio = bio;
  492.   ssl->wbio = bio;
  493.   ret = 1;
  494. */
  495. err:
  496.   return(ret);
  497. }
  498. //////////////////////////////////////////////////////////////////////////
  499. //
  500. //  misc unused code
  501. //
  502. #if 0
  503. extern "C" {
  504. static verify_depth = 0;
  505. static verify_error = VERIFY_OK;
  506. // should be X509 * but we can just have them as char *. 
  507. int verify_callback(int ok, X509 * xs, X509 * xi, int depth, int error)
  508. {
  509.   char *s;
  510.   s = (char *)X509_NAME_oneline(X509_get_subject_name(xs));
  511.   if (s == NULL) {
  512. //    ERR_print_errors(bio_err);
  513.     return(0);
  514.   }
  515.   PError << "depth= " << depth << " " << (char *)s << endl;
  516.   free(s);
  517.   if (error == VERIFY_ERR_UNABLE_TO_GET_ISSUER) {
  518.     s=(char *)X509_NAME_oneline(X509_get_issuer_name(xs));
  519.     if (s == NULL) {
  520.       PError << "verify error" << endl;
  521.       //ERR_print_errors(bio_err);
  522.       return(0);
  523.     }
  524.     PError << "issuer = " << s << endl;
  525.     free(s);
  526.   }
  527.   if (!ok) {
  528.     PError << "verify error:num=" << error << " " <<
  529. X509_cert_verify_error_string(error) << endl;
  530.     if (verify_depth <= depth) {
  531.       ok=1;
  532.       verify_error=VERIFY_OK;
  533.     } else {
  534.       ok=0;
  535.       verify_error=error;
  536.     }
  537.   }
  538.   PError << "verify return:" << ok << endl;
  539.   return(ok);
  540. }
  541. };
  542. #endif