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.37 2004/02/22 01:57:37 ykiryanov
32 * Put a fix for a compiler choke on BeOS when calling macro d2i_DHparams_bio in PSSLDiffieHellman::Load. Fast on Monday.
34 * Revision 1.36 2003/04/16 08:00:19 robertj
35 * Windoes psuedo autoconf support
37 * Revision 1.35 2002/11/06 22:47:25 robertj
38 * Fixed header comment (copyright etc)
40 * Revision 1.34 2002/06/07 02:55:23 robertj
43 * Revision 1.33 2002/04/02 16:59:35 robertj
46 * Revision 1.32 2002/04/02 16:17:28 robertj
47 * Fixed bug where returned TRUE when read count 0 or write count not len
48 * which is not according to Read()/Write() semantics. Could cause high CPU
49 * loops when sockets shutdown.
51 * Revision 1.31 2002/03/28 07:26:25 robertj
52 * Added Diffie-Hellman parameters wrapper class.
54 * Revision 1.30 2001/12/13 09:15:41 robertj
55 * Added function to get private key as ray DER binary data or as base64 string.
57 * Revision 1.29 2001/12/06 04:06:03 robertj
58 * Removed "Win32 SSL xxx" build configurations in favour of system
59 * environment variables to select optional libraries.
61 * Revision 1.28 2001/12/04 02:59:18 robertj
62 * Fixed problem on platforms where a pointer is not the same size as an int.
64 * Revision 1.27 2001/10/31 01:31:26 robertj
65 * Added enhancements for saving/loading/creating certificates and keys.
67 * Revision 1.26 2001/09/28 08:50:48 robertj
68 * Fixed bug where last count not set to zero if have error on read/write.
70 * Revision 1.25 2001/09/10 02:51:23 robertj
71 * Major change to fix problem with error codes being corrupted in a
72 * PChannel when have simultaneous reads and writes in threads.
74 * Revision 1.24 2001/06/01 00:53:59 robertj
75 * Added certificate constructor that takes a PBYTEArray
77 * Revision 1.23 2001/05/31 07:04:11 craigs
78 * Changed random seed function
80 * Revision 1.22 2001/05/29 03:33:54 craigs
81 * Added options to be compatible with OpenSSL 0.9.6
83 * Revision 1.21 2001/05/16 06:31:37 robertj
84 * Fixed GNU C++ compatibility
86 * Revision 1.20 2001/05/16 06:02:37 craigs
87 * Changed to allow detection of non-SSL connection to SecureHTTPServiceProcess
89 * Revision 1.19 2001/05/09 07:00:22 robertj
90 * Removed clearing of lock callbacks in context destructor, should not!
92 * Revision 1.18 2001/02/16 07:13:41 robertj
93 * Fixed bug in PSSLChannel error detection, thinks a zero byte write is error.
95 * Revision 1.17 2000/11/27 06:46:16 robertj
96 * Added asserts with SSL error message text.
98 * Revision 1.16 2000/11/14 08:33:16 robertj
99 * Added certificate and private key classes.
101 * Revision 1.15 2000/11/03 10:00:43 robertj
102 * Fixed initialisation of SSL, needed random number seed for some modes.
104 * Revision 1.14 2000/09/01 03:32:46 robertj
105 * Fixed assert on setting directories for CAs.
107 * Revision 1.13 2000/09/01 02:06:00 craigs
108 * Changed to OpenSSL_add_ssl_algorthms to fix link problem on some machines
110 * Revision 1.12 2000/08/25 13:56:46 robertj
111 * Fixed some GNU warnings
113 * Revision 1.11 2000/08/25 08:11:02 robertj
114 * Fixed OpenSSL support so can operate as a server channel.
116 * Revision 1.10 2000/08/04 12:52:18 robertj
117 * SSL changes, added error functions, removed need to have openssl include directory in app.
119 * Revision 1.9 2000/01/10 02:24:09 craigs
120 * Updated for new OpenSSL
122 * Revision 1.8 1998/12/04 13:04:18 craigs
123 * Changed for SSLeay 0.9
125 * Revision 1.7 1998/09/23 06:22:35 robertj
126 * Added open source copyright license.
128 * Revision 1.6 1998/01/26 02:50:17 robertj
131 * Revision 1.5 1997/05/04 02:50:54 craigs
132 * Added support for client and server sertificates
134 * Revision 1.1 1996/11/15 07:38:34 craigs
139 /* crypto/buffer/bss_sock.c */
140 /* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au)
141 * All rights reserved.
143 * This file is part of an SSL implementation written
144 * by Eric Young (eay@mincom.oz.au).
145 * The implementation was written so as to conform with Netscapes SSL
146 * specification. This library and applications are
147 * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE
148 * as long as the following conditions are aheared to.
150 * Copyright remains Eric Young's, and as such any Copyright notices in
151 * the code are not to be removed. If this code is used in a product,
152 * Eric Young should be given attribution as the author of the parts used.
153 * This can be in the form of a textual message at program startup or
154 * in documentation (online or textual) provided with the package.
156 * Redistribution and use in source and binary forms, with or without
157 * modification, are permitted provided that the following conditions
159 * 1. Redistributions of source code must retain the copyright
160 * notice, this list of conditions and the following disclaimer.
161 * 2. Redistributions in binary form must reproduce the above copyright
162 * notice, this list of conditions and the following disclaimer in the
163 * documentation and/or other materials provided with the distribution.
164 * 3. All advertising materials mentioning features or use of this software
165 * must display the following acknowledgement:
166 * This product includes software developed by Eric Young (eay@mincom.oz.au)
168 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
169 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
170 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
172 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
173 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
174 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
175 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
176 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
177 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
180 * The licence and distribution terms for any publically available version or
181 * derivative of this code cannot be changed. i.e. this code cannot simply be
182 * copied and put under another distribution licence
183 * [including the GNU Public Licence.]
187 #pragma implementation "pssl.h"
192 #include <ptclib/pssl.h>
193 #include <ptclib/mime.h>
201 #include <openssl/ssl.h>
202 #include <openssl/err.h>
203 #include <openssl/rand.h>
209 #pragma comment(lib, P_SSL_LIB1)
210 #pragma comment(lib, P_SSL_LIB2)
214 ///////////////////////////////////////////////////////////////////////////////
216 PARRAY(PSSLMutexArrayBase
, PMutex
);
217 class PSSLMutexArray
: public PSSLMutexArrayBase
219 PCLASSINFO(PSSLMutexArray
, PSSLMutexArrayBase
);
228 PSSL_BIO(BIO_METHOD
*method
= BIO_s_file_internal())
229 { bio
= BIO_new(method
); }
234 operator BIO
*() const
237 bool OpenRead(const PFilePath
& filename
)
238 { return BIO_read_filename(bio
, (char *)(const char *)filename
) > 0; }
240 bool OpenWrite(const PFilePath
& filename
)
241 { return BIO_write_filename(bio
, (char *)(const char *)filename
) > 0; }
243 bool OpenAppend(const PFilePath
& filename
)
244 { return BIO_append_filename(bio
, (char *)(const char *)filename
) > 0; }
254 ///////////////////////////////////////////////////////////////////////////////
256 PSSLMutexArray::PSSLMutexArray()
258 // Initialise all of the mutexes for multithreaded operation.
259 SetSize(CRYPTO_num_locks());
260 for (PINDEX i
= 0; i
< GetSize(); i
++)
261 SetAt(i
, new PMutex
);
265 ///////////////////////////////////////////////////////////////////////////////
267 PSSLPrivateKey::PSSLPrivateKey()
273 PSSLPrivateKey::PSSLPrivateKey(unsigned modulus
,
274 void (*callback
)(int,int,void *),
278 Create(modulus
, callback
, cb_arg
);
282 PSSLPrivateKey::PSSLPrivateKey(const PFilePath
& keyFile
, PSSLFileTypes fileType
)
285 Load(keyFile
, fileType
);
289 PSSLPrivateKey::PSSLPrivateKey(const BYTE
* keyData
, PINDEX keySize
)
291 key
= d2i_AutoPrivateKey(NULL
, (BYTE
**)&keyData
, keySize
);
295 PSSLPrivateKey::PSSLPrivateKey(const PBYTEArray
& keyData
)
297 const BYTE
* keyPtr
= keyData
;
298 key
= d2i_AutoPrivateKey(NULL
, (BYTE
**)&keyPtr
, keyData
.GetSize());
302 PSSLPrivateKey::PSSLPrivateKey(const PSSLPrivateKey
& privKey
)
308 PSSLPrivateKey
& PSSLPrivateKey::operator=(const PSSLPrivateKey
& privKey
)
319 PSSLPrivateKey::~PSSLPrivateKey()
326 BOOL
PSSLPrivateKey::Create(unsigned modulus
,
327 void (*callback
)(int,int,void *),
339 key
= EVP_PKEY_new();
343 if (EVP_PKEY_assign_RSA(key
, RSA_generate_key(modulus
, 0x10001, callback
, cb_arg
)))
352 PBYTEArray
PSSLPrivateKey::GetData() const
357 BYTE
* keyPtr
= data
.GetPointer(i2d_PrivateKey(key
, NULL
));
358 i2d_PrivateKey(key
, &keyPtr
);
365 PString
PSSLPrivateKey::AsString() const
367 return PBase64::Encode(GetData());
371 BOOL
PSSLPrivateKey::Load(const PFilePath
& keyFile
, PSSLFileTypes fileType
)
379 if (!in
.OpenRead(keyFile
)) {
380 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
,ERR_R_SYS_LIB
);
384 if (fileType
== PSSLFileTypeDEFAULT
)
385 fileType
= keyFile
.GetType() == ".pem" ? PSSLFileTypePEM
: PSSLFileTypeASN1
;
388 case PSSLFileTypeASN1
:
389 key
= d2i_PrivateKey_bio(in
, NULL
);
393 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
, ERR_R_ASN1_LIB
);
396 case PSSLFileTypePEM
:
397 key
= PEM_read_bio_PrivateKey(in
, NULL
, NULL
, NULL
);
401 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
, ERR_R_PEM_LIB
);
405 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
,SSL_R_BAD_SSL_FILETYPE
);
412 BOOL
PSSLPrivateKey::Save(const PFilePath
& keyFile
, BOOL append
, PSSLFileTypes fileType
)
418 if (!(append
? out
.OpenAppend(keyFile
) : out
.OpenWrite(keyFile
))) {
419 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
,ERR_R_SYS_LIB
);
423 if (fileType
== PSSLFileTypeDEFAULT
)
424 fileType
= keyFile
.GetType() == ".pem" ? PSSLFileTypePEM
: PSSLFileTypeASN1
;
427 case PSSLFileTypeASN1
:
428 if (i2d_PrivateKey_bio(out
, key
))
431 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
, ERR_R_ASN1_LIB
);
434 case PSSLFileTypePEM
:
435 if (PEM_write_bio_PrivateKey(out
, key
, NULL
, NULL
, 0, 0, NULL
))
438 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
, ERR_R_PEM_LIB
);
442 SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE
,SSL_R_BAD_SSL_FILETYPE
);
449 ///////////////////////////////////////////////////////////////////////////////
451 PSSLCertificate::PSSLCertificate()
457 PSSLCertificate::PSSLCertificate(const PFilePath
& certFile
, PSSLFileTypes fileType
)
460 Load(certFile
, fileType
);
464 PSSLCertificate::PSSLCertificate(const BYTE
* certData
, PINDEX certSize
)
466 certificate
= d2i_X509(NULL
, (unsigned char **)&certData
, certSize
);
470 PSSLCertificate::PSSLCertificate(const PBYTEArray
& certData
)
472 const BYTE
* certPtr
= certData
;
473 certificate
= d2i_X509(NULL
, (unsigned char **)&certPtr
, certData
.GetSize());
477 PSSLCertificate::PSSLCertificate(const PString
& certStr
)
480 PBase64::Decode(certStr
, certData
);
481 if (certData
.GetSize() > 0) {
482 const BYTE
* certPtr
= certData
;
483 certificate
= d2i_X509(NULL
, (unsigned char **)&certPtr
, certData
.GetSize());
490 PSSLCertificate::PSSLCertificate(const PSSLCertificate
& cert
)
492 if (cert
.certificate
== NULL
)
495 certificate
= X509_dup(cert
.certificate
);
499 PSSLCertificate
& PSSLCertificate::operator=(const PSSLCertificate
& cert
)
501 if (certificate
!= NULL
)
502 X509_free(certificate
);
503 if (cert
.certificate
== NULL
)
506 certificate
= X509_dup(cert
.certificate
);
512 PSSLCertificate::~PSSLCertificate()
514 if (certificate
!= NULL
)
515 X509_free(certificate
);
519 BOOL
PSSLCertificate::CreateRoot(const PString
& subject
,
520 const PSSLPrivateKey
& privateKey
)
522 if (certificate
!= NULL
) {
523 X509_free(certificate
);
527 if (privateKey
== NULL
)
530 POrdinalToString info
;
531 PStringArray fields
= subject
.Tokenise('/', FALSE
);
533 for (i
= 0; i
< fields
.GetSize(); i
++) {
534 PString field
= fields
[i
];
535 PINDEX equals
= field
.Find('=');
536 if (equals
!= P_MAX_INDEX
) {
537 int nid
= OBJ_txt2nid((char *)(const char *)field
.Left(equals
));
538 if (nid
!= NID_undef
)
539 info
.SetAt(nid
, field
.Mid(equals
+1));
545 certificate
= X509_new();
546 if (certificate
== NULL
)
549 if (X509_set_version(certificate
, 2)) {
550 /* Set version to V3 */
551 ASN1_INTEGER_set(X509_get_serialNumber(certificate
), 0L);
553 X509_NAME
* name
= X509_NAME_new();
554 for (i
= 0; i
< info
.GetSize(); i
++)
555 X509_NAME_add_entry_by_NID(name
,
558 (unsigned char *)(const char *)info
.GetDataAt(i
),
560 X509_set_issuer_name(certificate
, name
);
561 X509_set_subject_name(certificate
, name
);
562 X509_NAME_free(name
);
564 X509_gmtime_adj(X509_get_notBefore(certificate
), 0);
565 X509_gmtime_adj(X509_get_notAfter(certificate
), (long)60*60*24*365*5);
567 X509_PUBKEY
* pubkey
= X509_PUBKEY_new();
568 if (pubkey
!= NULL
) {
569 X509_PUBKEY_set(&pubkey
, privateKey
);
570 EVP_PKEY
* pkey
= X509_PUBKEY_get(pubkey
);
571 X509_set_pubkey(certificate
, pkey
);
573 X509_PUBKEY_free(pubkey
);
575 if (X509_sign(certificate
, privateKey
, EVP_md5()) > 0)
580 X509_free(certificate
);
586 PBYTEArray
PSSLCertificate::GetData() const
590 if (certificate
!= NULL
) {
591 BYTE
* certPtr
= data
.GetPointer(i2d_X509(certificate
, NULL
));
592 i2d_X509(certificate
, &certPtr
);
599 PString
PSSLCertificate::AsString() const
601 return PBase64::Encode(GetData());
605 BOOL
PSSLCertificate::Load(const PFilePath
& certFile
, PSSLFileTypes fileType
)
607 if (certificate
!= NULL
) {
608 X509_free(certificate
);
613 if (!in
.OpenRead(certFile
)) {
614 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
,ERR_R_SYS_LIB
);
618 if (fileType
== PSSLFileTypeDEFAULT
)
619 fileType
= certFile
.GetType() == ".pem" ? PSSLFileTypePEM
: PSSLFileTypeASN1
;
622 case PSSLFileTypeASN1
:
623 certificate
= d2i_X509_bio(in
, NULL
);
624 if (certificate
!= NULL
)
627 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
, ERR_R_ASN1_LIB
);
630 case PSSLFileTypePEM
:
631 certificate
= PEM_read_bio_X509(in
, NULL
, NULL
, NULL
);
632 if (certificate
!= NULL
)
635 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
, ERR_R_PEM_LIB
);
639 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
,SSL_R_BAD_SSL_FILETYPE
);
646 BOOL
PSSLCertificate::Save(const PFilePath
& certFile
, BOOL append
, PSSLFileTypes fileType
)
648 if (certificate
== NULL
)
652 if (!(append
? out
.OpenAppend(certFile
) : out
.OpenWrite(certFile
))) {
653 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
,ERR_R_SYS_LIB
);
657 if (fileType
== PSSLFileTypeDEFAULT
)
658 fileType
= certFile
.GetType() == ".pem" ? PSSLFileTypePEM
: PSSLFileTypeASN1
;
661 case PSSLFileTypeASN1
:
662 if (i2d_X509_bio(out
, certificate
))
665 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
, ERR_R_ASN1_LIB
);
668 case PSSLFileTypePEM
:
669 if (PEM_write_bio_X509(out
, certificate
))
672 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
, ERR_R_PEM_LIB
);
676 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE
,SSL_R_BAD_SSL_FILETYPE
);
683 ///////////////////////////////////////////////////////////////////////////////
685 PSSLDiffieHellman::PSSLDiffieHellman()
691 PSSLDiffieHellman::PSSLDiffieHellman(const PFilePath
& dhFile
,
692 PSSLFileTypes fileType
)
695 Load(dhFile
, fileType
);
699 PSSLDiffieHellman::PSSLDiffieHellman(const BYTE
* pData
, PINDEX pSize
,
700 const BYTE
* gData
, PINDEX gSize
)
706 dh
->p
= BN_bin2bn(pData
, pSize
, NULL
);
707 dh
->g
= BN_bin2bn(gData
, gSize
, NULL
);
708 if (dh
->p
!= NULL
&& dh
->g
!= NULL
)
716 PSSLDiffieHellman::PSSLDiffieHellman(const PSSLDiffieHellman
& diffie
)
722 PSSLDiffieHellman
& PSSLDiffieHellman::operator=(const PSSLDiffieHellman
& diffie
)
731 PSSLDiffieHellman::~PSSLDiffieHellman()
738 // 2/21/04 Yuri Kiryanov - fix for compiler choke on BeOS for usage of
739 // SSL function d2i_DHparams_bio below in PSSLDiffieHellman::Load
740 #undef d2i_DHparams_bio
741 #define d2i_DHparams_bio(bp,x) \
742 (DH *)ASN1_d2i_bio( \
743 (char *(*)(...))(void *)DH_new, \
744 (char *(*)(...))(void *)d2i_DHparams, \
746 (unsigned char **)(x) \
750 BOOL
PSSLDiffieHellman::Load(const PFilePath
& dhFile
,
751 PSSLFileTypes fileType
)
759 if (!in
.OpenRead(dhFile
)) {
760 SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE
,ERR_R_SYS_LIB
);
764 if (fileType
== PSSLFileTypeDEFAULT
)
765 fileType
= dhFile
.GetType() == ".pem" ? PSSLFileTypePEM
: PSSLFileTypeASN1
;
768 case PSSLFileTypeASN1
:
769 dh
= d2i_DHparams_bio(in
, NULL
);
773 SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE
, ERR_R_ASN1_LIB
);
776 case PSSLFileTypePEM
:
777 dh
= PEM_read_bio_DHparams(in
, NULL
, NULL
, NULL
);
781 SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE
, ERR_R_PEM_LIB
);
785 SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE
,SSL_R_BAD_SSL_FILETYPE
);
792 ///////////////////////////////////////////////////////////////////////////////
794 static void LockingCallback(int mode
, int n
, const char * /*file*/, int /*line*/)
796 static PSSLMutexArray mutexes
;
797 if ((mode
& CRYPTO_LOCK
) != 0)
804 static int VerifyCallBack(int ok
, X509_STORE_CTX
* ctx
)
806 X509
* err_cert
= X509_STORE_CTX_get_current_cert(ctx
);
807 //int err = X509_STORE_CTX_get_error(ctx);
809 // get the subject name, just for verification
811 X509_NAME_oneline(X509_get_subject_name(err_cert
), buf
, 256);
813 PTRACE(1, "SSL\tVerify callback depth "
814 << X509_STORE_CTX_get_error_depth(ctx
)
815 << " : cert name = " << buf
);
821 static void PSSLAssert(const char * msg
)
825 ERR_error_string(ERR_peek_error(), &buf
[strlen(msg
)]);
826 PTRACE(1, "SSL\t" << buf
);
831 PSSLContext::PSSLContext(const void * sessionId
, PINDEX idSize
)
833 static PMutex InitialisationMutex
;
834 InitialisationMutex
.Wait();
836 static BOOL needInitialisation
= TRUE
;
837 if (needInitialisation
) {
838 SSL_load_error_strings();
839 OpenSSL_add_ssl_algorithms();
841 // Seed the random number generator
843 for (size_t i
= 0; i
< sizeof(seed
); i
++)
844 seed
[i
] = (BYTE
)rand();
845 RAND_seed(seed
, sizeof(seed
));
847 // set up multithread stuff
848 CRYPTO_set_locking_callback(LockingCallback
);
850 needInitialisation
= FALSE
;
853 InitialisationMutex
.Signal();
855 // create the new SSL context
856 SSL_METHOD
* meth
= SSLv23_method();
857 context
= SSL_CTX_new(meth
);
859 PSSLAssert("Error creating context: ");
862 SSL_CTX_set_quiet_shutdown(context
, 1);
864 // Set default locations
865 if (!SSL_CTX_load_verify_locations(context
, NULL
, ".") ||
866 !SSL_CTX_set_default_verify_paths(context
))
867 PSSLAssert("Cannot set CAfile and path: ");
869 if (sessionId
!= NULL
) {
871 idSize
= ::strlen((const char *)sessionId
)+1;
872 SSL_CTX_set_session_id_context(context
, (const BYTE
*)sessionId
, idSize
);
873 SSL_CTX_sess_set_cache_size(context
, 128);
876 // set default verify mode
877 SSL_CTX_set_verify(context
, SSL_VERIFY_NONE
, VerifyCallBack
);
881 PSSLContext::~PSSLContext()
883 SSL_CTX_free(context
);
887 BOOL
PSSLContext::SetCAPath(const PDirectory
& caPath
)
889 PString path
= caPath
.Left(caPath
.GetLength()-1);
890 if (!SSL_CTX_load_verify_locations(context
, NULL
, path
))
893 return SSL_CTX_set_default_verify_paths(context
);
897 BOOL
PSSLContext::SetCAFile(const PFilePath
& caFile
)
899 if (!SSL_CTX_load_verify_locations(context
, caFile
, NULL
))
902 return SSL_CTX_set_default_verify_paths(context
);
906 BOOL
PSSLContext::UseCertificate(const PSSLCertificate
& certificate
)
908 return SSL_CTX_use_certificate(context
, certificate
) > 0;
912 BOOL
PSSLContext::UsePrivateKey(const PSSLPrivateKey
& key
)
914 if (SSL_CTX_use_PrivateKey(context
, key
) <= 0)
917 return SSL_CTX_check_private_key(context
);
921 BOOL
PSSLContext::UseDiffieHellman(const PSSLDiffieHellman
& dh
)
923 return SSL_CTX_set_tmp_dh(context
, (dh_st
*)dh
) > 0;
927 BOOL
PSSLContext::SetCipherList(const PString
& ciphers
)
929 if (ciphers
.IsEmpty())
932 return SSL_CTX_set_cipher_list(context
, (char *)(const char *)ciphers
);
936 /////////////////////////////////////////////////////////////////////////
941 PSSLChannel::PSSLChannel(PSSLContext
* ctx
, BOOL autoDel
)
945 autoDeleteContext
= autoDel
;
948 context
= new PSSLContext
;
949 autoDeleteContext
= TRUE
;
952 ssl
= SSL_new(*context
);
954 PSSLAssert("Error creating channel: ");
958 PSSLChannel::PSSLChannel(PSSLContext
& ctx
)
961 autoDeleteContext
= FALSE
;
963 ssl
= SSL_new(*context
);
967 PSSLChannel::~PSSLChannel()
969 // free the SSL connection
973 if (autoDeleteContext
)
978 BOOL
PSSLChannel::Read(void * buf
, PINDEX len
)
982 channelPointerMutex
.StartRead();
986 BOOL returnValue
= FALSE
;
987 if (readChannel
== NULL
)
988 SetErrorValues(NotOpen
, EBADF
, LastReadError
);
989 else if (readTimeout
== 0 && SSL_pending(ssl
) == 0)
990 SetErrorValues(Timeout
, ETIMEDOUT
, LastReadError
);
992 readChannel
->SetReadTimeout(readTimeout
);
994 int readResult
= SSL_read(ssl
, (char *)buf
, len
);
995 lastReadCount
= readResult
;
996 returnValue
= readResult
> 0;
997 if (readResult
< 0 && GetErrorCode(LastReadError
) == NoError
)
998 ConvertOSError(-1, LastReadError
);
1001 channelPointerMutex
.EndRead();
1006 BOOL
PSSLChannel::Write(const void * buf
, PINDEX len
)
1010 channelPointerMutex
.StartRead();
1015 if (writeChannel
== NULL
) {
1016 SetErrorValues(NotOpen
, EBADF
, LastWriteError
);
1017 returnValue
= FALSE
;
1020 writeChannel
->SetWriteTimeout(writeTimeout
);
1022 int writeResult
= SSL_write(ssl
, (const char *)buf
, len
);
1023 lastWriteCount
= writeResult
;
1024 returnValue
= lastWriteCount
>= len
;
1025 if (writeResult
< 0 && GetErrorCode(LastWriteError
) == NoError
)
1026 ConvertOSError(-1, LastWriteError
);
1029 channelPointerMutex
.EndRead();
1035 BOOL
PSSLChannel::Close()
1037 BOOL ok
= SSL_shutdown(ssl
);
1038 return PIndirectChannel::Close() && ok
;
1042 BOOL
PSSLChannel::ConvertOSError(int error
, ErrorGroup group
)
1044 Errors lastError
= NoError
;
1046 if (SSL_get_error(ssl
, error
) != SSL_ERROR_NONE
&& (osError
= ERR_peek_error()) != 0) {
1047 osError
|= 0x80000000;
1048 lastError
= Miscellaneous
;
1051 return SetErrorValues(lastError
, osError
, group
);
1055 PString
PSSLChannel::GetErrorText(ErrorGroup group
) const
1057 if ((lastErrorNumber
[group
]&0x80000000) == 0)
1058 return PIndirectChannel::GetErrorText(group
);
1061 return ERR_error_string(lastErrorNumber
[group
]&0x7fffffff, buf
);
1065 BOOL
PSSLChannel::Accept()
1068 return ConvertOSError(SSL_accept(ssl
));
1073 BOOL
PSSLChannel::Accept(PChannel
& channel
)
1076 return ConvertOSError(SSL_accept(ssl
));
1081 BOOL
PSSLChannel::Accept(PChannel
* channel
, BOOL autoDelete
)
1083 if (Open(channel
, autoDelete
))
1084 return ConvertOSError(SSL_accept(ssl
));
1089 BOOL
PSSLChannel::Connect()
1092 return ConvertOSError(SSL_connect(ssl
));
1097 BOOL
PSSLChannel::Connect(PChannel
& channel
)
1100 return ConvertOSError(SSL_connect(ssl
));
1105 BOOL
PSSLChannel::Connect(PChannel
* channel
, BOOL autoDelete
)
1107 if (Open(channel
, autoDelete
))
1108 return ConvertOSError(SSL_connect(ssl
));
1113 BOOL
PSSLChannel::UseCertificate(const PSSLCertificate
& certificate
)
1115 return SSL_use_certificate(ssl
, certificate
);
1119 void PSSLChannel::SetVerifyMode(VerifyMode mode
)
1126 verify
= SSL_VERIFY_NONE
;
1130 verify
= SSL_VERIFY_PEER
| SSL_VERIFY_CLIENT_ONCE
;
1133 case VerifyPeerMandatory
:
1134 verify
= SSL_VERIFY_PEER
| SSL_VERIFY_CLIENT_ONCE
| SSL_VERIFY_FAIL_IF_NO_PEER_CERT
;
1137 SSL_set_verify(ssl
, verify
, VerifyCallBack
);
1141 BOOL
PSSLChannel::RawSSLRead(void * buf
, PINDEX
& len
)
1143 if (!PIndirectChannel::Read(buf
, len
))
1146 len
= GetLastReadCount();
1151 //////////////////////////////////////////////////////////////////////////
1153 // Low level interface to SSLEay routines
1157 #define PSSLCHANNEL(bio) ((PSSLChannel *)(bio->ptr))
1161 #if (OPENSSL_VERSION_NUMBER < 0x00906000)
1163 typedef int (*ifptr
)();
1164 typedef long (*lfptr
)();
1168 static int Psock_new(BIO
* bio
)
1172 bio
->ptr
= NULL
; // this is really (PSSLChannel *)
1179 static int Psock_free(BIO
* bio
)
1184 if (bio
->shutdown
) {
1186 PSSLCHANNEL(bio
)->Shutdown(PSocket::ShutdownReadAndWrite
);
1187 PSSLCHANNEL(bio
)->Close();
1196 static long Psock_ctrl(BIO
* bio
, int cmd
, long num
, void * /*ptr*/)
1199 case BIO_CTRL_SET_CLOSE
:
1200 bio
->shutdown
= (int)num
;
1203 case BIO_CTRL_GET_CLOSE
:
1204 return bio
->shutdown
;
1206 case BIO_CTRL_FLUSH
:
1210 // Other BIO commands, return 0
1215 static int Psock_read(BIO
* bio
, char * out
, int outl
)
1220 BIO_clear_retry_flags(bio
);
1222 // Skip over the polymorphic read, want to do real one
1224 if (PSSLCHANNEL(bio
)->RawSSLRead(out
, len
))
1227 switch (PSSLCHANNEL(bio
)->GetErrorCode(PChannel::LastReadError
)) {
1228 case PChannel::Interrupted
:
1229 case PChannel::Timeout
:
1230 BIO_set_retry_read(bio
);
1241 static int Psock_write(BIO
* bio
, const char * in
, int inl
)
1246 BIO_clear_retry_flags(bio
);
1248 // Skip over the polymorphic write, want to do real one
1249 if (PSSLCHANNEL(bio
)->PIndirectChannel::Write(in
, inl
))
1250 return PSSLCHANNEL(bio
)->GetLastWriteCount();
1252 switch (PSSLCHANNEL(bio
)->GetErrorCode(PChannel::LastWriteError
)) {
1253 case PChannel::Interrupted
:
1254 case PChannel::Timeout
:
1255 BIO_set_retry_write(bio
);
1266 static int Psock_puts(BIO
* bio
, const char * str
)
1271 ret
= Psock_write(bio
,str
,n
);
1279 static BIO_METHOD methods_Psock
=
1282 "PTLib-PSSLChannel",
1283 #if (OPENSSL_VERSION_NUMBER < 0x00906000)
1303 BOOL
PSSLChannel::OnOpen()
1305 BIO
* bio
= BIO_new(&methods_Psock
);
1307 SSLerr(SSL_F_SSL_SET_FD
,ERR_R_BUF_LIB
);
1315 SSL_set_bio(ssl
, bio
, bio
);
1320 //////////////////////////////////////////////////////////////////////////
1329 static verify_depth
= 0;
1330 static verify_error
= VERIFY_OK
;
1332 // should be X509 * but we can just have them as char *.
1333 int verify_callback(int ok
, X509
* xs
, X509
* xi
, int depth
, int error
)
1337 s
= (char *)X509_NAME_oneline(X509_get_subject_name(xs
));
1339 // ERR_print_errors(bio_err);
1342 PError
<< "depth= " << depth
<< " " << (char *)s
<< endl
;
1344 if (error
== VERIFY_ERR_UNABLE_TO_GET_ISSUER
) {
1345 s
=(char *)X509_NAME_oneline(X509_get_issuer_name(xs
));
1347 PError
<< "verify error" << endl
;
1348 //ERR_print_errors(bio_err);
1351 PError
<< "issuer = " << s
<< endl
;
1356 PError
<< "verify error:num=" << error
<< " " <<
1357 X509_cert_verify_error_string(error
) << endl
;
1358 if (verify_depth
<= depth
) {
1360 verify_error
=VERIFY_OK
;
1366 PError
<< "verify return:" << ok
<< endl
;
1377 // End of file ////////////////////////////////////////////////////////////////