4 * SSL implementation for PTLib using the SSLeay package
6 * Portable Windows Library
8 * Copyright (c) 1993-2002 Equivalence Pty. Ltd.
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/
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
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * Portions bsed upon the file crypto/buffer/bss_sock.c
27 * Original copyright notice appears below
31 * Revision 1.38 2004/02/23 23:52:20 csoutheren
32 * Added pragmas to avoid every Windows application needing to include libs explicitly
34 * Revision 1.37 2004/02/22 01:57:37 ykiryanov
35 * Put a fix for a compiler choke on BeOS when calling macro d2i_DHparams_bio in PSSLDiffieHellman::Load. Fast on Monday.
37 * Revision 1.36 2003/04/16 08:00:19 robertj
38 * Windoes psuedo autoconf support
40 * Revision 1.35 2002/11/06 22:47:25 robertj
41 * Fixed header comment (copyright etc)
43 * Revision 1.34 2002/06/07 02:55:23 robertj
46 * Revision 1.33 2002/04/02 16:59:35 robertj
49 * Revision 1.32 2002/04/02 16:17:28 robertj
50 * Fixed bug where returned TRUE when read count 0 or write count not len
51 * which is not according to Read()/Write() semantics. Could cause high CPU
52 * loops when sockets shutdown.
54 * Revision 1.31 2002/03/28 07:26:25 robertj
55 * Added Diffie-Hellman parameters wrapper class.
57 * Revision 1.30 2001/12/13 09:15:41 robertj
58 * Added function to get private key as ray DER binary data or as base64 string.
60 * Revision 1.29 2001/12/06 04:06:03 robertj
61 * Removed "Win32 SSL xxx" build configurations in favour of system
62 * environment variables to select optional libraries.
64 * Revision 1.28 2001/12/04 02:59:18 robertj
65 * Fixed problem on platforms where a pointer is not the same size as an int.
67 * Revision 1.27 2001/10/31 01:31:26 robertj
68 * Added enhancements for saving/loading/creating certificates and keys.
70 * Revision 1.26 2001/09/28 08:50:48 robertj
71 * Fixed bug where last count not set to zero if have error on read/write.
73 * Revision 1.25 2001/09/10 02:51:23 robertj
74 * Major change to fix problem with error codes being corrupted in a
75 * PChannel when have simultaneous reads and writes in threads.
77 * Revision 1.24 2001/06/01 00:53:59 robertj
78 * Added certificate constructor that takes a PBYTEArray
80 * Revision 1.23 2001/05/31 07:04:11 craigs
81 * Changed random seed function
83 * Revision 1.22 2001/05/29 03:33:54 craigs
84 * Added options to be compatible with OpenSSL 0.9.6
86 * Revision 1.21 2001/05/16 06:31:37 robertj
87 * Fixed GNU C++ compatibility
89 * Revision 1.20 2001/05/16 06:02:37 craigs
90 * Changed to allow detection of non-SSL connection to SecureHTTPServiceProcess
92 * Revision 1.19 2001/05/09 07:00:22 robertj
93 * Removed clearing of lock callbacks in context destructor, should not!
95 * Revision 1.18 2001/02/16 07:13:41 robertj
96 * Fixed bug in PSSLChannel error detection, thinks a zero byte write is error.
98 * Revision 1.17 2000/11/27 06:46:16 robertj
99 * Added asserts with SSL error message text.
101 * Revision 1.16 2000/11/14 08:33:16 robertj
102 * Added certificate and private key classes.
104 * Revision 1.15 2000/11/03 10:00:43 robertj
105 * Fixed initialisation of SSL, needed random number seed for some modes.
107 * Revision 1.14 2000/09/01 03:32:46 robertj
108 * Fixed assert on setting directories for CAs.
110 * Revision 1.13 2000/09/01 02:06:00 craigs
111 * Changed to OpenSSL_add_ssl_algorthms to fix link problem on some machines
113 * Revision 1.12 2000/08/25 13:56:46 robertj
114 * Fixed some GNU warnings
116 * Revision 1.11 2000/08/25 08:11:02 robertj
117 * Fixed OpenSSL support so can operate as a server channel.
119 * Revision 1.10 2000/08/04 12:52:18 robertj
120 * SSL changes, added error functions, removed need to have openssl include directory in app.
122 * Revision 1.9 2000/01/10 02:24:09 craigs
123 * Updated for new OpenSSL
125 * Revision 1.8 1998/12/04 13:04:18 craigs
126 * Changed for SSLeay 0.9
128 * Revision 1.7 1998/09/23 06:22:35 robertj
129 * Added open source copyright license.
131 * Revision 1.6 1998/01/26 02:50:17 robertj
134 * Revision 1.5 1997/05/04 02:50:54 craigs
135 * Added support for client and server sertificates
137 * Revision 1.1 1996/11/15 07:38:34 craigs
142 /* crypto/buffer/bss_sock.c */
143 /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au)
144 * All rights reserved.
146 * This file is part of an SSL implementation written
147 * by Eric Young (eay@mincom.oz.au).
148 * The implementation was written so as to conform with Netscapes SSL
149 * specification. This library and applications are
150 * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE
151 * as long as the following conditions are aheared to.
153 * Copyright remains Eric Young's, and as such any Copyright notices in
154 * the code are not to be removed. If this code is used in a product,
155 * Eric Young should be given attribution as the author of the parts used.
156 * This can be in the form of a textual message at program startup or
157 * in documentation (online or textual) provided with the package.
159 * Redistribution and use in source and binary forms, with or without
160 * modification, are permitted provided that the following conditions
162 * 1. Redistributions of source code must retain the copyright
163 * notice, this list of conditions and the following disclaimer.
164 * 2. Redistributions in binary form must reproduce the above copyright
165 * notice, this list of conditions and the following disclaimer in the
166 * documentation and/or other materials provided with the distribution.
167 * 3. All advertising materials mentioning features or use of this software
168 * must display the following acknowledgement:
169 * This product includes software developed by Eric Young (eay@mincom.oz.au)
171 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
172 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
173 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
174 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
175 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
176 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
177 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
178 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
179 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
180 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
183 * The licence and distribution terms for any publically available version or
184 * derivative of this code cannot be changed. i.e. this code cannot simply be
185 * copied and put under another distribution licence
186 * [including the GNU Public Licence.]
190 #pragma implementation "pssl.h"
195 #include <ptclib/pssl.h>
196 #include <ptclib/mime.h>
204 #include <openssl/ssl.h>
205 #include <openssl/err.h>
206 #include <openssl/rand.h>
213 #pragma comment(lib, P_SSL_LIB1)
214 #pragma comment(lib, P_SSL_LIB2)
215 #pragma comment(linker, "/delayload:ssleay32.dll")
216 #pragma comment(linker, "/delayload:libeay32.dll")
217 #pragma comment(lib, "Delayimp.lib")
222 ///////////////////////////////////////////////////////////////////////////////
224 PARRAY(PSSLMutexArrayBase
, PMutex
);
225 class PSSLMutexArray
: public PSSLMutexArrayBase
227 PCLASSINFO(PSSLMutexArray
, PSSLMutexArrayBase
);
236 PSSL_BIO(BIO_METHOD
*method
= BIO_s_file_internal())
237 { bio
= BIO_new(method
); }
242 operator BIO
*() const
245 bool OpenRead(const PFilePath
& filename
)
246 { return BIO_read_filename(bio
, (char *)(const char *)filename
) > 0; }
248 bool OpenWrite(const PFilePath
& filename
)
249 { return BIO_write_filename(bio
, (char *)(const char *)filename
) > 0; }
251 bool OpenAppend(const PFilePath
& filename
)
252 { return BIO_append_filename(bio
, (char *)(const char *)filename
) > 0; }
262 ///////////////////////////////////////////////////////////////////////////////
264 PSSLMutexArray::PSSLMutexArray()
266 // Initialise all of the mutexes for multithreaded operation.
267 SetSize(CRYPTO_num_locks());
268 for (PINDEX i
= 0; i
< GetSize(); i
++)
269 SetAt(i
, new PMutex
);
273 ///////////////////////////////////////////////////////////////////////////////
275 PSSLPrivateKey::PSSLPrivateKey()
281 PSSLPrivateKey::PSSLPrivateKey(unsigned modulus
,
282 void (*callback
)(int,int,void *),
286 Create(modulus
, callback
, cb_arg
);
290 PSSLPrivateKey::PSSLPrivateKey(const PFilePath
& keyFile
, PSSLFileTypes fileType
)
293 Load(keyFile
, fileType
);
297 PSSLPrivateKey::PSSLPrivateKey(const BYTE
* keyData
, PINDEX keySize
)
299 key
= d2i_AutoPrivateKey(NULL
, (BYTE
**)&keyData
, keySize
);
303 PSSLPrivateKey::PSSLPrivateKey(const PBYTEArray
& keyData
)
305 const BYTE
* keyPtr
= keyData
;
306 key
= d2i_AutoPrivateKey(NULL
, (BYTE
**)&keyPtr
, keyData
.GetSize());
310 PSSLPrivateKey::PSSLPrivateKey(const PSSLPrivateKey
& privKey
)
316 PSSLPrivateKey
& PSSLPrivateKey::operator=(const PSSLPrivateKey
& privKey
)
327 PSSLPrivateKey::~PSSLPrivateKey()
334 BOOL
PSSLPrivateKey::Create(unsigned modulus
,
335 void (*callback
)(int,int,void *),
347 key
= EVP_PKEY_new();
351 if (EVP_PKEY_assign_RSA(key
, RSA_generate_key(modulus
, 0x10001, callback
, cb_arg
)))
360 PBYTEArray
PSSLPrivateKey::GetData() const
365 BYTE
* keyPtr
= data
.GetPointer(i2d_PrivateKey(key
, NULL
));
366 i2d_PrivateKey(key
, &keyPtr
);
373 PString
PSSLPrivateKey::AsString() const
375 return PBase64::Encode(GetData());
379 BOOL
PSSLPrivateKey::Load(const PFilePath
& keyFile
, PSSLFileTypes fileType
)
387 if (!in
.OpenRead(keyFile
)) {
388 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
,ERR_R_SYS_LIB
);
392 if (fileType
== PSSLFileTypeDEFAULT
)
393 fileType
= keyFile
.GetType() == ".pem" ? PSSLFileTypePEM
: PSSLFileTypeASN1
;
396 case PSSLFileTypeASN1
:
397 key
= d2i_PrivateKey_bio(in
, NULL
);
401 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
, ERR_R_ASN1_LIB
);
404 case PSSLFileTypePEM
:
405 key
= PEM_read_bio_PrivateKey(in
, NULL
, NULL
, NULL
);
409 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
, ERR_R_PEM_LIB
);
413 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
,SSL_R_BAD_SSL_FILETYPE
);
420 BOOL
PSSLPrivateKey::Save(const PFilePath
& keyFile
, BOOL append
, PSSLFileTypes fileType
)
426 if (!(append
? out
.OpenAppend(keyFile
) : out
.OpenWrite(keyFile
))) {
427 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
,ERR_R_SYS_LIB
);
431 if (fileType
== PSSLFileTypeDEFAULT
)
432 fileType
= keyFile
.GetType() == ".pem" ? PSSLFileTypePEM
: PSSLFileTypeASN1
;
435 case PSSLFileTypeASN1
:
436 if (i2d_PrivateKey_bio(out
, key
))
439 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
, ERR_R_ASN1_LIB
);
442 case PSSLFileTypePEM
:
443 if (PEM_write_bio_PrivateKey(out
, key
, NULL
, NULL
, 0, 0, NULL
))
446 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
, ERR_R_PEM_LIB
);
450 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
,SSL_R_BAD_SSL_FILETYPE
);
457 ///////////////////////////////////////////////////////////////////////////////
459 PSSLCertificate::PSSLCertificate()
465 PSSLCertificate::PSSLCertificate(const PFilePath
& certFile
, PSSLFileTypes fileType
)
468 Load(certFile
, fileType
);
472 PSSLCertificate::PSSLCertificate(const BYTE
* certData
, PINDEX certSize
)
474 certificate
= d2i_X509(NULL
, (unsigned char **)&certData
, certSize
);
478 PSSLCertificate::PSSLCertificate(const PBYTEArray
& certData
)
480 const BYTE
* certPtr
= certData
;
481 certificate
= d2i_X509(NULL
, (unsigned char **)&certPtr
, certData
.GetSize());
485 PSSLCertificate::PSSLCertificate(const PString
& certStr
)
488 PBase64::Decode(certStr
, certData
);
489 if (certData
.GetSize() > 0) {
490 const BYTE
* certPtr
= certData
;
491 certificate
= d2i_X509(NULL
, (unsigned char **)&certPtr
, certData
.GetSize());
498 PSSLCertificate::PSSLCertificate(const PSSLCertificate
& cert
)
500 if (cert
.certificate
== NULL
)
503 certificate
= X509_dup(cert
.certificate
);
507 PSSLCertificate
& PSSLCertificate::operator=(const PSSLCertificate
& cert
)
509 if (certificate
!= NULL
)
510 X509_free(certificate
);
511 if (cert
.certificate
== NULL
)
514 certificate
= X509_dup(cert
.certificate
);
520 PSSLCertificate::~PSSLCertificate()
522 if (certificate
!= NULL
)
523 X509_free(certificate
);
527 BOOL
PSSLCertificate::CreateRoot(const PString
& subject
,
528 const PSSLPrivateKey
& privateKey
)
530 if (certificate
!= NULL
) {
531 X509_free(certificate
);
535 if (privateKey
== NULL
)
538 POrdinalToString info
;
539 PStringArray fields
= subject
.Tokenise('/', FALSE
);
541 for (i
= 0; i
< fields
.GetSize(); i
++) {
542 PString field
= fields
[i
];
543 PINDEX equals
= field
.Find('=');
544 if (equals
!= P_MAX_INDEX
) {
545 int nid
= OBJ_txt2nid((char *)(const char *)field
.Left(equals
));
546 if (nid
!= NID_undef
)
547 info
.SetAt(nid
, field
.Mid(equals
+1));
553 certificate
= X509_new();
554 if (certificate
== NULL
)
557 if (X509_set_version(certificate
, 2)) {
558 /* Set version to V3 */
559 ASN1_INTEGER_set(X509_get_serialNumber(certificate
), 0L);
561 X509_NAME
* name
= X509_NAME_new();
562 for (i
= 0; i
< info
.GetSize(); i
++)
563 X509_NAME_add_entry_by_NID(name
,
566 (unsigned char *)(const char *)info
.GetDataAt(i
),
568 X509_set_issuer_name(certificate
, name
);
569 X509_set_subject_name(certificate
, name
);
570 X509_NAME_free(name
);
572 X509_gmtime_adj(X509_get_notBefore(certificate
), 0);
573 X509_gmtime_adj(X509_get_notAfter(certificate
), (long)60*60*24*365*5);
575 X509_PUBKEY
* pubkey
= X509_PUBKEY_new();
576 if (pubkey
!= NULL
) {
577 X509_PUBKEY_set(&pubkey
, privateKey
);
578 EVP_PKEY
* pkey
= X509_PUBKEY_get(pubkey
);
579 X509_set_pubkey(certificate
, pkey
);
581 X509_PUBKEY_free(pubkey
);
583 if (X509_sign(certificate
, privateKey
, EVP_md5()) > 0)
588 X509_free(certificate
);
594 PBYTEArray
PSSLCertificate::GetData() const
598 if (certificate
!= NULL
) {
599 BYTE
* certPtr
= data
.GetPointer(i2d_X509(certificate
, NULL
));
600 i2d_X509(certificate
, &certPtr
);
607 PString
PSSLCertificate::AsString() const
609 return PBase64::Encode(GetData());
613 BOOL
PSSLCertificate::Load(const PFilePath
& certFile
, PSSLFileTypes fileType
)
615 if (certificate
!= NULL
) {
616 X509_free(certificate
);
621 if (!in
.OpenRead(certFile
)) {
622 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
,ERR_R_SYS_LIB
);
626 if (fileType
== PSSLFileTypeDEFAULT
)
627 fileType
= certFile
.GetType() == ".pem" ? PSSLFileTypePEM
: PSSLFileTypeASN1
;
630 case PSSLFileTypeASN1
:
631 certificate
= d2i_X509_bio(in
, NULL
);
632 if (certificate
!= NULL
)
635 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
, ERR_R_ASN1_LIB
);
638 case PSSLFileTypePEM
:
639 certificate
= PEM_read_bio_X509(in
, NULL
, NULL
, NULL
);
640 if (certificate
!= NULL
)
643 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
, ERR_R_PEM_LIB
);
647 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
,SSL_R_BAD_SSL_FILETYPE
);
654 BOOL
PSSLCertificate::Save(const PFilePath
& certFile
, BOOL append
, PSSLFileTypes fileType
)
656 if (certificate
== NULL
)
660 if (!(append
? out
.OpenAppend(certFile
) : out
.OpenWrite(certFile
))) {
661 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
,ERR_R_SYS_LIB
);
665 if (fileType
== PSSLFileTypeDEFAULT
)
666 fileType
= certFile
.GetType() == ".pem" ? PSSLFileTypePEM
: PSSLFileTypeASN1
;
669 case PSSLFileTypeASN1
:
670 if (i2d_X509_bio(out
, certificate
))
673 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
, ERR_R_ASN1_LIB
);
676 case PSSLFileTypePEM
:
677 if (PEM_write_bio_X509(out
, certificate
))
680 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
, ERR_R_PEM_LIB
);
684 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
,SSL_R_BAD_SSL_FILETYPE
);
691 ///////////////////////////////////////////////////////////////////////////////
693 PSSLDiffieHellman::PSSLDiffieHellman()
699 PSSLDiffieHellman::PSSLDiffieHellman(const PFilePath
& dhFile
,
700 PSSLFileTypes fileType
)
703 Load(dhFile
, fileType
);
707 PSSLDiffieHellman::PSSLDiffieHellman(const BYTE
* pData
, PINDEX pSize
,
708 const BYTE
* gData
, PINDEX gSize
)
714 dh
->p
= BN_bin2bn(pData
, pSize
, NULL
);
715 dh
->g
= BN_bin2bn(gData
, gSize
, NULL
);
716 if (dh
->p
!= NULL
&& dh
->g
!= NULL
)
724 PSSLDiffieHellman::PSSLDiffieHellman(const PSSLDiffieHellman
& diffie
)
730 PSSLDiffieHellman
& PSSLDiffieHellman::operator=(const PSSLDiffieHellman
& diffie
)
739 PSSLDiffieHellman::~PSSLDiffieHellman()
746 // 2/21/04 Yuri Kiryanov - fix for compiler choke on BeOS for usage of
747 // SSL function d2i_DHparams_bio below in PSSLDiffieHellman::Load
748 #undef d2i_DHparams_bio
749 #define d2i_DHparams_bio(bp,x) \
750 (DH *)ASN1_d2i_bio( \
751 (char *(*)(...))(void *)DH_new, \
752 (char *(*)(...))(void *)d2i_DHparams, \
754 (unsigned char **)(x) \
758 BOOL
PSSLDiffieHellman::Load(const PFilePath
& dhFile
,
759 PSSLFileTypes fileType
)
767 if (!in
.OpenRead(dhFile
)) {
768 SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE
,ERR_R_SYS_LIB
);
772 if (fileType
== PSSLFileTypeDEFAULT
)
773 fileType
= dhFile
.GetType() == ".pem" ? PSSLFileTypePEM
: PSSLFileTypeASN1
;
776 case PSSLFileTypeASN1
:
777 dh
= d2i_DHparams_bio(in
, NULL
);
781 SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE
, ERR_R_ASN1_LIB
);
784 case PSSLFileTypePEM
:
785 dh
= PEM_read_bio_DHparams(in
, NULL
, NULL
, NULL
);
789 SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE
, ERR_R_PEM_LIB
);
793 SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE
,SSL_R_BAD_SSL_FILETYPE
);
800 ///////////////////////////////////////////////////////////////////////////////
802 static void LockingCallback(int mode
, int n
, const char * /*file*/, int /*line*/)
804 static PSSLMutexArray mutexes
;
805 if ((mode
& CRYPTO_LOCK
) != 0)
812 static int VerifyCallBack(int ok
, X509_STORE_CTX
* ctx
)
814 X509
* err_cert
= X509_STORE_CTX_get_current_cert(ctx
);
815 //int err = X509_STORE_CTX_get_error(ctx);
817 // get the subject name, just for verification
819 X509_NAME_oneline(X509_get_subject_name(err_cert
), buf
, 256);
821 PTRACE(1, "SSL\tVerify callback depth "
822 << X509_STORE_CTX_get_error_depth(ctx
)
823 << " : cert name = " << buf
);
829 static void PSSLAssert(const char * msg
)
833 ERR_error_string(ERR_peek_error(), &buf
[strlen(msg
)]);
834 PTRACE(1, "SSL\t" << buf
);
839 PSSLContext::PSSLContext(const void * sessionId
, PINDEX idSize
)
841 static PMutex InitialisationMutex
;
842 InitialisationMutex
.Wait();
844 static BOOL needInitialisation
= TRUE
;
845 if (needInitialisation
) {
846 SSL_load_error_strings();
847 OpenSSL_add_ssl_algorithms();
849 // Seed the random number generator
851 for (size_t i
= 0; i
< sizeof(seed
); i
++)
852 seed
[i
] = (BYTE
)rand();
853 RAND_seed(seed
, sizeof(seed
));
855 // set up multithread stuff
856 CRYPTO_set_locking_callback(LockingCallback
);
858 needInitialisation
= FALSE
;
861 InitialisationMutex
.Signal();
863 // create the new SSL context
864 SSL_METHOD
* meth
= SSLv23_method();
865 context
= SSL_CTX_new(meth
);
867 PSSLAssert("Error creating context: ");
870 SSL_CTX_set_quiet_shutdown(context
, 1);
872 // Set default locations
873 if (!SSL_CTX_load_verify_locations(context
, NULL
, ".") ||
874 !SSL_CTX_set_default_verify_paths(context
))
875 PSSLAssert("Cannot set CAfile and path: ");
877 if (sessionId
!= NULL
) {
879 idSize
= ::strlen((const char *)sessionId
)+1;
880 SSL_CTX_set_session_id_context(context
, (const BYTE
*)sessionId
, idSize
);
881 SSL_CTX_sess_set_cache_size(context
, 128);
884 // set default verify mode
885 SSL_CTX_set_verify(context
, SSL_VERIFY_NONE
, VerifyCallBack
);
889 PSSLContext::~PSSLContext()
891 SSL_CTX_free(context
);
895 BOOL
PSSLContext::SetCAPath(const PDirectory
& caPath
)
897 PString path
= caPath
.Left(caPath
.GetLength()-1);
898 if (!SSL_CTX_load_verify_locations(context
, NULL
, path
))
901 return SSL_CTX_set_default_verify_paths(context
);
905 BOOL
PSSLContext::SetCAFile(const PFilePath
& caFile
)
907 if (!SSL_CTX_load_verify_locations(context
, caFile
, NULL
))
910 return SSL_CTX_set_default_verify_paths(context
);
914 BOOL
PSSLContext::UseCertificate(const PSSLCertificate
& certificate
)
916 return SSL_CTX_use_certificate(context
, certificate
) > 0;
920 BOOL
PSSLContext::UsePrivateKey(const PSSLPrivateKey
& key
)
922 if (SSL_CTX_use_PrivateKey(context
, key
) <= 0)
925 return SSL_CTX_check_private_key(context
);
929 BOOL
PSSLContext::UseDiffieHellman(const PSSLDiffieHellman
& dh
)
931 return SSL_CTX_set_tmp_dh(context
, (dh_st
*)dh
) > 0;
935 BOOL
PSSLContext::SetCipherList(const PString
& ciphers
)
937 if (ciphers
.IsEmpty())
940 return SSL_CTX_set_cipher_list(context
, (char *)(const char *)ciphers
);
944 /////////////////////////////////////////////////////////////////////////
949 PSSLChannel::PSSLChannel(PSSLContext
* ctx
, BOOL autoDel
)
953 autoDeleteContext
= autoDel
;
956 context
= new PSSLContext
;
957 autoDeleteContext
= TRUE
;
960 ssl
= SSL_new(*context
);
962 PSSLAssert("Error creating channel: ");
966 PSSLChannel::PSSLChannel(PSSLContext
& ctx
)
969 autoDeleteContext
= FALSE
;
971 ssl
= SSL_new(*context
);
975 PSSLChannel::~PSSLChannel()
977 // free the SSL connection
981 if (autoDeleteContext
)
986 BOOL
PSSLChannel::Read(void * buf
, PINDEX len
)
990 channelPointerMutex
.StartRead();
994 BOOL returnValue
= FALSE
;
995 if (readChannel
== NULL
)
996 SetErrorValues(NotOpen
, EBADF
, LastReadError
);
997 else if (readTimeout
== 0 && SSL_pending(ssl
) == 0)
998 SetErrorValues(Timeout
, ETIMEDOUT
, LastReadError
);
1000 readChannel
->SetReadTimeout(readTimeout
);
1002 int readResult
= SSL_read(ssl
, (char *)buf
, len
);
1003 lastReadCount
= readResult
;
1004 returnValue
= readResult
> 0;
1005 if (readResult
< 0 && GetErrorCode(LastReadError
) == NoError
)
1006 ConvertOSError(-1, LastReadError
);
1009 channelPointerMutex
.EndRead();
1014 BOOL
PSSLChannel::Write(const void * buf
, PINDEX len
)
1018 channelPointerMutex
.StartRead();
1023 if (writeChannel
== NULL
) {
1024 SetErrorValues(NotOpen
, EBADF
, LastWriteError
);
1025 returnValue
= FALSE
;
1028 writeChannel
->SetWriteTimeout(writeTimeout
);
1030 int writeResult
= SSL_write(ssl
, (const char *)buf
, len
);
1031 lastWriteCount
= writeResult
;
1032 returnValue
= lastWriteCount
>= len
;
1033 if (writeResult
< 0 && GetErrorCode(LastWriteError
) == NoError
)
1034 ConvertOSError(-1, LastWriteError
);
1037 channelPointerMutex
.EndRead();
1043 BOOL
PSSLChannel::Close()
1045 BOOL ok
= SSL_shutdown(ssl
);
1046 return PIndirectChannel::Close() && ok
;
1050 BOOL
PSSLChannel::ConvertOSError(int error
, ErrorGroup group
)
1052 Errors lastError
= NoError
;
1054 if (SSL_get_error(ssl
, error
) != SSL_ERROR_NONE
&& (osError
= ERR_peek_error()) != 0) {
1055 osError
|= 0x80000000;
1056 lastError
= Miscellaneous
;
1059 return SetErrorValues(lastError
, osError
, group
);
1063 PString
PSSLChannel::GetErrorText(ErrorGroup group
) const
1065 if ((lastErrorNumber
[group
]&0x80000000) == 0)
1066 return PIndirectChannel::GetErrorText(group
);
1069 return ERR_error_string(lastErrorNumber
[group
]&0x7fffffff, buf
);
1073 BOOL
PSSLChannel::Accept()
1076 return ConvertOSError(SSL_accept(ssl
));
1081 BOOL
PSSLChannel::Accept(PChannel
& channel
)
1084 return ConvertOSError(SSL_accept(ssl
));
1089 BOOL
PSSLChannel::Accept(PChannel
* channel
, BOOL autoDelete
)
1091 if (Open(channel
, autoDelete
))
1092 return ConvertOSError(SSL_accept(ssl
));
1097 BOOL
PSSLChannel::Connect()
1100 return ConvertOSError(SSL_connect(ssl
));
1105 BOOL
PSSLChannel::Connect(PChannel
& channel
)
1108 return ConvertOSError(SSL_connect(ssl
));
1113 BOOL
PSSLChannel::Connect(PChannel
* channel
, BOOL autoDelete
)
1115 if (Open(channel
, autoDelete
))
1116 return ConvertOSError(SSL_connect(ssl
));
1121 BOOL
PSSLChannel::UseCertificate(const PSSLCertificate
& certificate
)
1123 return SSL_use_certificate(ssl
, certificate
);
1127 void PSSLChannel::SetVerifyMode(VerifyMode mode
)
1134 verify
= SSL_VERIFY_NONE
;
1138 verify
= SSL_VERIFY_PEER
| SSL_VERIFY_CLIENT_ONCE
;
1141 case VerifyPeerMandatory
:
1142 verify
= SSL_VERIFY_PEER
| SSL_VERIFY_CLIENT_ONCE
| SSL_VERIFY_FAIL_IF_NO_PEER_CERT
;
1145 SSL_set_verify(ssl
, verify
, VerifyCallBack
);
1149 BOOL
PSSLChannel::RawSSLRead(void * buf
, PINDEX
& len
)
1151 if (!PIndirectChannel::Read(buf
, len
))
1154 len
= GetLastReadCount();
1159 //////////////////////////////////////////////////////////////////////////
1161 // Low level interface to SSLEay routines
1165 #define PSSLCHANNEL(bio) ((PSSLChannel *)(bio->ptr))
1169 #if (OPENSSL_VERSION_NUMBER < 0x00906000)
1171 typedef int (*ifptr
)();
1172 typedef long (*lfptr
)();
1176 static int Psock_new(BIO
* bio
)
1180 bio
->ptr
= NULL
; // this is really (PSSLChannel *)
1187 static int Psock_free(BIO
* bio
)
1192 if (bio
->shutdown
) {
1194 PSSLCHANNEL(bio
)->Shutdown(PSocket::ShutdownReadAndWrite
);
1195 PSSLCHANNEL(bio
)->Close();
1204 static long Psock_ctrl(BIO
* bio
, int cmd
, long num
, void * /*ptr*/)
1207 case BIO_CTRL_SET_CLOSE
:
1208 bio
->shutdown
= (int)num
;
1211 case BIO_CTRL_GET_CLOSE
:
1212 return bio
->shutdown
;
1214 case BIO_CTRL_FLUSH
:
1218 // Other BIO commands, return 0
1223 static int Psock_read(BIO
* bio
, char * out
, int outl
)
1228 BIO_clear_retry_flags(bio
);
1230 // Skip over the polymorphic read, want to do real one
1232 if (PSSLCHANNEL(bio
)->RawSSLRead(out
, len
))
1235 switch (PSSLCHANNEL(bio
)->GetErrorCode(PChannel::LastReadError
)) {
1236 case PChannel::Interrupted
:
1237 case PChannel::Timeout
:
1238 BIO_set_retry_read(bio
);
1249 static int Psock_write(BIO
* bio
, const char * in
, int inl
)
1254 BIO_clear_retry_flags(bio
);
1256 // Skip over the polymorphic write, want to do real one
1257 if (PSSLCHANNEL(bio
)->PIndirectChannel::Write(in
, inl
))
1258 return PSSLCHANNEL(bio
)->GetLastWriteCount();
1260 switch (PSSLCHANNEL(bio
)->GetErrorCode(PChannel::LastWriteError
)) {
1261 case PChannel::Interrupted
:
1262 case PChannel::Timeout
:
1263 BIO_set_retry_write(bio
);
1274 static int Psock_puts(BIO
* bio
, const char * str
)
1279 ret
= Psock_write(bio
,str
,n
);
1287 static BIO_METHOD methods_Psock
=
1290 "PTLib-PSSLChannel",
1291 #if (OPENSSL_VERSION_NUMBER < 0x00906000)
1311 BOOL
PSSLChannel::OnOpen()
1313 BIO
* bio
= BIO_new(&methods_Psock
);
1315 SSLerr(SSL_F_SSL_SET_FD
,ERR_R_BUF_LIB
);
1323 SSL_set_bio(ssl
, bio
, bio
);
1328 //////////////////////////////////////////////////////////////////////////
1337 static verify_depth
= 0;
1338 static verify_error
= VERIFY_OK
;
1340 // should be X509 * but we can just have them as char *.
1341 int verify_callback(int ok
, X509
* xs
, X509
* xi
, int depth
, int error
)
1345 s
= (char *)X509_NAME_oneline(X509_get_subject_name(xs
));
1347 // ERR_print_errors(bio_err);
1350 PError
<< "depth= " << depth
<< " " << (char *)s
<< endl
;
1352 if (error
== VERIFY_ERR_UNABLE_TO_GET_ISSUER
) {
1353 s
=(char *)X509_NAME_oneline(X509_get_issuer_name(xs
));
1355 PError
<< "verify error" << endl
;
1356 //ERR_print_errors(bio_err);
1359 PError
<< "issuer = " << s
<< endl
;
1364 PError
<< "verify error:num=" << error
<< " " <<
1365 X509_cert_verify_error_string(error
) << endl
;
1366 if (verify_depth
<= depth
) {
1368 verify_error
=VERIFY_OK
;
1374 PError
<< "verify return:" << ok
<< endl
;
1385 // End of file ////////////////////////////////////////////////////////////////