1 /*****************************************************************
3 | Neptune - TLS/SSL Support
5 | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
8 | Redistribution and use in source and binary forms, with or without
9 | modification, are permitted provided that the following conditions are met:
10 | * Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 | * Neither the name of Axiomatic Systems nor the
16 | names of its contributors may be used to endorse or promote products
17 | derived from this software without specific prior written permission.
19 | THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY
20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY
23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 ****************************************************************/
32 /*----------------------------------------------------------------------
34 +---------------------------------------------------------------------*/
35 #include "NptConfig.h"
37 #include "NptLogging.h"
39 #include "NptSockets.h"
40 #include "NptSystem.h"
41 #include "NptDigest.h"
42 #include "NptAutomaticCleaner.h"
44 /*----------------------------------------------------------------------
46 +---------------------------------------------------------------------*/
47 NPT_SET_LOCAL_LOGGER("neptune.tls")
49 #if defined(NPT_CONFIG_ENABLE_TLS)
52 /*----------------------------------------------------------------------
54 +---------------------------------------------------------------------*/
55 const unsigned int NPT_TLS_CONTEXT_DEFAULT_SESSION_CACHE
= 16;
56 const unsigned int NPT_HTTP_TLS_CONNECTOR_MAX_PROXY_RESPONSE_SIZE
= (16*1024);
58 /*----------------------------------------------------------------------
60 +---------------------------------------------------------------------*/
61 typedef NPT_Reference
<NPT_TlsSessionImpl
> NPT_TlsSessionImplReference
;
63 /*----------------------------------------------------------------------
65 +---------------------------------------------------------------------*/
67 SSL_DateTime_Before(const SSL_DateTime
* t1
, const SSL_DateTime
* t2
)
69 if (t1
->year
== t2
->year
) {
70 if (t1
->month
== t2
->month
) {
71 if (t1
->day
== t2
->day
) {
72 return t1
->hours
*3600+t1
->minutes
*60+t1
->seconds
<
73 t2
->hours
*3600+t2
->minutes
*60+t2
->seconds
? 1 : 0;
75 return t1
->day
< t2
->day
? 1 : 0;
78 return t1
->month
< t2
->month
? 1 : 0;
81 return t1
->year
< t2
->year
? 1 : 0;
85 /*----------------------------------------------------------------------
87 +---------------------------------------------------------------------*/
89 SSL_DateTime_Now(SSL_DateTime
* now
)
92 NPT_System::GetCurrentTimeStamp(ts
);
95 now
->year
= dt
.m_Year
;
96 now
->month
= dt
.m_Month
;
98 now
->hours
= dt
.m_Hours
;
99 now
->minutes
= dt
.m_Minutes
;
100 now
->seconds
= dt
.m_Seconds
;
103 /*----------------------------------------------------------------------
105 +---------------------------------------------------------------------*/
110 NPT_System::GetCurrentTimeStamp(ts
);
114 /*----------------------------------------------------------------------
116 +---------------------------------------------------------------------*/
118 SSL_Mutex_Create(NPT_Mutex
** mutex
)
120 *mutex
= new NPT_Mutex();
123 /*----------------------------------------------------------------------
125 +---------------------------------------------------------------------*/
127 SSL_Mutex_Destroy(NPT_Mutex
* mutex
)
132 /*----------------------------------------------------------------------
134 +---------------------------------------------------------------------*/
136 SSL_Mutex_Lock(NPT_Mutex
* mutex
)
141 /*----------------------------------------------------------------------
143 +---------------------------------------------------------------------*/
145 SSL_Mutex_Unlock(NPT_Mutex
* mutex
)
150 /*----------------------------------------------------------------------
151 | SSL_Sha256_ComputeDigest
152 +---------------------------------------------------------------------*/
154 SSL_Sha256_ComputeDigest(const unsigned char* data
,
155 unsigned int data_size
,
156 unsigned char* digest_value
)
158 NPT_Digest
* digest
= NULL
;
159 NPT_Digest::Create(NPT_Digest::ALGORITHM_SHA256
, digest
);
160 digest
->Update(data
, data_size
);
161 NPT_DataBuffer buffer
;
162 digest
->GetDigest(buffer
);
163 NPT_CopyMemory(digest_value
, buffer
.GetData(), 32);
167 /*----------------------------------------------------------------------
168 | NPT_Tls::MatchDnsName
169 +---------------------------------------------------------------------*/
171 NPT_Tls::MatchDnsName(const char* hostname
, const char* dns_name
)
173 // NULL or empty names don't match anything
174 if (hostname
== NULL
|| *hostname
== '\0') return false;
175 if (dns_name
== NULL
|| *dns_name
== '\0') return false;
177 // check for wildcards */
178 if (dns_name
[0] == '*') {
179 // wildcard match, expect '*.' at the start, we don't match '*foo.com'
180 if (dns_name
[1] != '.') return false;
182 // skip the first component of the hostname
183 while (hostname
[0] != '\0' && hostname
[0] != '.') {
186 if (hostname
[0] == '.') ++hostname
;
189 return NPT_String::Compare(hostname
, dns_name
+2, true) == 0;
192 return NPT_String::Compare(hostname
, dns_name
, true) == 0;
196 /*----------------------------------------------------------------------
197 | NPT_Tls::MatchDnsNames
198 +---------------------------------------------------------------------*/
200 NPT_Tls::MatchDnsNames(const char* hostname
,
201 const NPT_List
<NPT_String
>& dns_names
)
203 // NULL or empty names don't match anything
204 if (hostname
== NULL
|| *hostname
== '\0') return false;
206 // check the dns names
207 for (NPT_List
<NPT_String
>::Iterator i
= dns_names
.GetFirstItem();
210 if (MatchDnsName(hostname
, (*i
).GetChars())) return true;
217 /*----------------------------------------------------------------------
219 +---------------------------------------------------------------------*/
221 NPT_Tls_MapResult(int err
)
224 case SSL_ERROR_CONN_LOST
: return NPT_ERROR_CONNECTION_ABORTED
;
225 case SSL_ERROR_TIMEOUT
: return NPT_ERROR_TIMEOUT
;
226 case SSL_ERROR_EOS
: return NPT_ERROR_EOS
;
227 case SSL_CLOSE_NOTIFY
: return NPT_ERROR_EOS
;
228 case SSL_ERROR_NOT_SUPPORTED
: return NPT_ERROR_NOT_SUPPORTED
;
229 case SSL_ERROR_INVALID_HANDSHAKE
: return NPT_ERROR_TLS_INVALID_HANDSHAKE
;
230 case SSL_ERROR_INVALID_PROT_MSG
: return NPT_ERROR_TLS_INVALID_PROTOCOL_MESSAGE
;
231 case SSL_ERROR_INVALID_HMAC
: return NPT_ERROR_TLS_INVALID_HMAC
;
232 case SSL_ERROR_INVALID_VERSION
: return NPT_ERROR_TLS_INVALID_VERSION
;
233 case SSL_ERROR_INVALID_SESSION
: return NPT_ERROR_TLS_INVALID_SESSION
;
234 case SSL_ERROR_NO_CIPHER
: return NPT_ERROR_TLS_NO_CIPHER
;
235 case SSL_ERROR_BAD_CERTIFICATE
: return NPT_ERROR_TLS_BAD_CERTIFICATE
;
236 case SSL_ERROR_INVALID_KEY
: return NPT_ERROR_TLS_INVALID_KEY
;
237 case SSL_ERROR_FINISHED_INVALID
: return NPT_ERROR_TLS_INVALID_FINISHED_MESSAGE
;
238 case SSL_ERROR_NO_CERT_DEFINED
: return NPT_ERROR_TLS_NO_CERTIFICATE_DEFINED
;
239 case SSL_ERROR_NO_CLIENT_RENOG
: return NPT_ERROR_TLS_NO_CLIENT_RENEGOTIATION
;
240 case -SSL_ALERT_HANDSHAKE_FAILURE
: return NPT_ERROR_TLS_ALERT_HANDSHAKE_FAILED
;
241 case -SSL_ALERT_BAD_CERTIFICATE
: return NPT_ERROR_TLS_ALERT_BAD_CERTIFICATE
;
242 case -SSL_ALERT_INVALID_VERSION
: return NPT_ERROR_TLS_ALERT_INVALID_VERSION
;
243 case -SSL_ALERT_BAD_RECORD_MAC
: return NPT_ERROR_TLS_ALERT_BAD_RECORD_MAC
;
244 case -SSL_ALERT_DECODE_ERROR
: return NPT_ERROR_TLS_ALERT_DECODE_ERROR
;
245 case -SSL_ALERT_DECRYPT_ERROR
: return NPT_ERROR_TLS_ALERT_DECRYPT_ERROR
;
246 case -SSL_ALERT_ILLEGAL_PARAMETER
: return NPT_ERROR_TLS_ALERT_ILLEGAL_PARAMETER
;
247 case -SSL_ALERT_UNEXPECTED_MESSAGE
: return NPT_ERROR_TLS_ALERT_UNEXPECTED_MESSAGE
;
248 case SSL_X509_ERROR(X509_NOT_OK
): return NPT_ERROR_TLS_CERTIFICATE_FAILURE
;
249 case SSL_X509_ERROR(X509_VFY_ERROR_NO_TRUSTED_CERT
): return NPT_ERROR_TLS_CERTIFICATE_NO_TRUST_ANCHOR
;
250 case SSL_X509_ERROR(X509_VFY_ERROR_BAD_SIGNATURE
): return NPT_ERROR_TLS_CERTIFICATE_BAD_SIGNATURE
;
251 case SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID
): return NPT_ERROR_TLS_CERTIFICATE_NOT_YET_VALID
;
252 case SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED
): return NPT_ERROR_TLS_CERTIFICATE_EXPIRED
;
253 case SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED
): return NPT_ERROR_TLS_CERTIFICATE_SELF_SIGNED
;
254 case SSL_X509_ERROR(X509_VFY_ERROR_INVALID_CHAIN
): return NPT_ERROR_TLS_CERTIFICATE_INVALID_CHAIN
;
255 case SSL_X509_ERROR(X509_VFY_ERROR_UNSUPPORTED_DIGEST
): return NPT_ERROR_TLS_CERTIFICATE_UNSUPPORTED_DIGEST
;
256 case SSL_X509_ERROR(X509_INVALID_PRIV_KEY
): return NPT_ERROR_TLS_CERTIFICATE_INVALID_PRIVATE_KEY
;
257 case 0: return NPT_SUCCESS
;
258 default: return NPT_FAILURE
;
262 /*----------------------------------------------------------------------
264 +---------------------------------------------------------------------*/
265 class NPT_TlsContextImpl
{
267 NPT_TlsContextImpl(NPT_Flags options
) :
268 m_SSL_CTX(ssl_ctx_new(((options
& NPT_TlsContext::OPTION_VERIFY_LATER
)?SSL_SERVER_VERIFY_LATER
:0) |
269 ((options
& NPT_TlsContext::OPTION_REQUIRE_CLIENT_CERTIFICATE
)?SSL_CLIENT_AUTHENTICATION
:0),
270 (options
& NPT_TlsContext::OPTION_NO_SESSION_CACHE
)?0:NPT_TLS_CONTEXT_DEFAULT_SESSION_CACHE
)) {}
271 ~NPT_TlsContextImpl() { ssl_ctx_free(m_SSL_CTX
); }
273 NPT_Result
LoadKey(NPT_TlsKeyFormat key_format
,
274 const unsigned char* key_data
,
275 NPT_Size key_data_size
,
276 const char* password
);
277 NPT_Result
SelfSignCertificate(const char* common_name
,
278 const char* organization
,
279 const char* organizational_name
);
280 NPT_Result
AddTrustAnchor(const unsigned char* ta_data
,
281 NPT_Size ta_data_size
);
286 /*----------------------------------------------------------------------
287 | NPT_TlsContextImpl::LoadKey
288 +---------------------------------------------------------------------*/
290 NPT_TlsContextImpl::LoadKey(NPT_TlsKeyFormat key_format
,
291 const unsigned char* key_data
,
292 NPT_Size key_data_size
,
293 const char* password
)
296 switch (key_format
) {
297 case NPT_TLS_KEY_FORMAT_RSA_PRIVATE
: object_type
= SSL_OBJ_RSA_KEY
; break;
298 case NPT_TLS_KEY_FORMAT_PKCS8
: object_type
= SSL_OBJ_PKCS8
; break;
299 case NPT_TLS_KEY_FORMAT_PKCS12
: object_type
= SSL_OBJ_PKCS12
; break;
300 default: return NPT_ERROR_INVALID_PARAMETERS
;
303 int result
= ssl_obj_memory_load(m_SSL_CTX
, object_type
, key_data
, key_data_size
, password
);
304 return NPT_Tls_MapResult(result
);
307 /*----------------------------------------------------------------------
308 | NPT_TlsContextImpl::SelfSignCertificate
309 +---------------------------------------------------------------------*/
311 NPT_TlsContextImpl::SelfSignCertificate(const char* common_name
,
312 const char* organization
,
313 const char* organizational_name
)
315 const char* dn
[3] = {common_name
, organization
, organizational_name
};
316 uint8_t* certificate
= NULL
;
317 int result
= ssl_x509_create(m_SSL_CTX
, 0, dn
, &certificate
);
320 ssl_mem_free(certificate
);
322 return NPT_Tls_MapResult(result
);
324 result
= ssl_obj_memory_load(m_SSL_CTX
, SSL_OBJ_X509_CERT
, certificate
, result
, NULL
);
325 ssl_mem_free(certificate
);
327 return NPT_Tls_MapResult(result
);
330 /*----------------------------------------------------------------------
331 | NPT_TlsContextImpl::AddTrustAnchor
332 +---------------------------------------------------------------------*/
334 NPT_TlsContextImpl::AddTrustAnchor(const unsigned char* ta_data
,
335 NPT_Size ta_data_size
)
337 int result
= ssl_obj_memory_load(m_SSL_CTX
, SSL_OBJ_X509_CACERT
, ta_data
, ta_data_size
, NULL
);
338 return NPT_Tls_MapResult(result
);
341 /*----------------------------------------------------------------------
342 | NPT_TlsStreamAdapter
343 +---------------------------------------------------------------------*/
344 struct NPT_TlsStreamAdapter
346 static int Read(SSL_SOCKET
* _self
, void* buffer
, unsigned int size
) {
347 NPT_TlsStreamAdapter
* self
= (NPT_TlsStreamAdapter
*)_self
;
348 NPT_Size bytes_read
= 0;
349 NPT_Result result
= self
->m_Input
->Read(buffer
, size
, &bytes_read
);
350 if (NPT_FAILED(result
)) {
352 case NPT_ERROR_EOS
: return SSL_ERROR_EOS
;
353 case NPT_ERROR_TIMEOUT
: return SSL_ERROR_TIMEOUT
;
354 default: return SSL_ERROR_CONN_LOST
;
360 static int Write(SSL_SOCKET
* _self
, const void* buffer
, unsigned int size
) {
361 NPT_TlsStreamAdapter
* self
= (NPT_TlsStreamAdapter
*)_self
;
362 NPT_Size bytes_written
= 0;
363 NPT_Result result
= self
->m_Output
->Write(buffer
, size
, &bytes_written
);
364 if (NPT_FAILED(result
)) {
366 case NPT_ERROR_EOS
: return SSL_ERROR_EOS
;
367 case NPT_ERROR_TIMEOUT
: return SSL_ERROR_TIMEOUT
;
368 default: return SSL_ERROR_CONN_LOST
;
371 return bytes_written
;
374 NPT_TlsStreamAdapter(NPT_InputStreamReference input
,
375 NPT_OutputStreamReference output
) :
376 m_Input(input
), m_Output(output
) {
378 m_Base
.Write
= Write
;
382 NPT_InputStreamReference m_Input
;
383 NPT_OutputStreamReference m_Output
;
387 /*----------------------------------------------------------------------
389 +---------------------------------------------------------------------*/
390 class NPT_TlsSessionImpl
{
392 NPT_TlsSessionImpl(SSL_CTX
* context
,
393 NPT_InputStreamReference
& input
,
394 NPT_OutputStreamReference
& output
) :
397 m_StreamAdapter(input
, output
) {}
398 virtual ~NPT_TlsSessionImpl() { ssl_free(m_SSL
); }
401 virtual NPT_Result
Handshake() = 0;
402 virtual NPT_Result
GetHandshakeStatus();
403 virtual NPT_Result
VerifyPeerCertificate();
404 virtual NPT_Result
VerifyDnsNameMatch(const char* hostname
);
405 virtual NPT_Result
GetSessionId(NPT_DataBuffer
& session_id
);
406 virtual NPT_UInt32
GetCipherSuiteId();
407 virtual NPT_Result
GetPeerCertificateInfo(NPT_TlsCertificateInfo
& cert_info
,
408 NPT_Ordinal position
);
413 NPT_TlsStreamAdapter m_StreamAdapter
;
416 /*----------------------------------------------------------------------
417 | NPT_TlsSessionImpl::GetHandshakeStatus
418 +---------------------------------------------------------------------*/
420 NPT_TlsSessionImpl::GetHandshakeStatus()
423 if (m_SSL
== NULL
|| (status
= ssl_handshake_status(m_SSL
)) == SSL_NOT_OK
) {
425 return NPT_ERROR_INVALID_STATE
;
428 return NPT_Tls_MapResult(status
);
431 /*----------------------------------------------------------------------
432 | NPT_TlsSessionImpl::VerifyPeerCertificate
433 +---------------------------------------------------------------------*/
435 NPT_TlsSessionImpl::VerifyPeerCertificate()
437 if (m_SSL
== NULL
|| ssl_handshake_status(m_SSL
) == SSL_NOT_OK
) {
439 return NPT_ERROR_INVALID_STATE
;
442 int result
= ssl_verify_cert(m_SSL
);
443 return NPT_Tls_MapResult(result
);
446 /*----------------------------------------------------------------------
447 | NPT_TlsSessionImpl::VerifyDnsNameMatch
448 +---------------------------------------------------------------------*/
450 NPT_TlsSessionImpl::VerifyDnsNameMatch(const char* hostname
)
452 if (hostname
== NULL
) return NPT_ERROR_INVALID_PARAMETERS
;
453 if (m_SSL
== NULL
|| ssl_handshake_status(m_SSL
) == SSL_NOT_OK
) {
455 return NPT_ERROR_INVALID_STATE
;
458 // get the peer certificate
459 const SSL_X509_CERT
* cert
= ssl_get_peer_cert(m_SSL
, 0);
460 if (cert
== NULL
) return NPT_ERROR_NO_SUCH_ITEM
;
462 // try the common name
463 const char* common_name
= ssl_cert_get_dn(cert
, SSL_X509_CERT_COMMON_NAME
);
464 if (common_name
&& NPT_Tls::MatchDnsName(hostname
, common_name
)) return NPT_SUCCESS
;
466 // try all the alt DNS names
467 const char* alt_name
= NULL
;
468 for (unsigned int i
=0; (alt_name
=ssl_cert_get_subject_alt_dnsname(cert
, i
)); i
++) {
469 if (NPT_Tls::MatchDnsName(hostname
, alt_name
)) return NPT_SUCCESS
;
475 /*----------------------------------------------------------------------
476 | NPT_TlsSessionImpl::GetSessionId
477 +---------------------------------------------------------------------*/
479 NPT_TlsSessionImpl::GetSessionId(NPT_DataBuffer
& session_id
)
481 if (m_SSL
== NULL
|| ssl_handshake_status(m_SSL
) == SSL_NOT_OK
) {
483 session_id
.SetDataSize(0);
484 return NPT_ERROR_INVALID_STATE
;
487 // return the session id
488 session_id
.SetData(ssl_get_session_id(m_SSL
),
489 ssl_get_session_id_size(m_SSL
));
493 /*----------------------------------------------------------------------
494 | NPT_TlsSessionImpl::GetCipherSuiteId
495 +---------------------------------------------------------------------*/
497 NPT_TlsSessionImpl::GetCipherSuiteId()
499 if (m_SSL
== NULL
|| ssl_handshake_status(m_SSL
) == SSL_NOT_OK
) {
504 return ssl_get_cipher_id(m_SSL
);
507 /*----------------------------------------------------------------------
508 | NPT_TlsSessionImpl::GetPeerCertificateInfo
509 +---------------------------------------------------------------------*/
511 NPT_TlsSessionImpl::GetPeerCertificateInfo(NPT_TlsCertificateInfo
& cert_info
,
512 NPT_Ordinal position
)
514 if (m_SSL
== NULL
|| ssl_handshake_status(m_SSL
) == SSL_NOT_OK
) {
516 return NPT_ERROR_INVALID_STATE
;
519 // find the certificate at the requested index
520 const SSL_X509_CERT
* cert
= ssl_get_peer_cert(m_SSL
, position
);
521 if (cert
== NULL
) return NPT_ERROR_NO_SUCH_ITEM
;
523 // get the certificate fields
524 cert_info
.subject
.common_name
= ssl_cert_get_dn(cert
, SSL_X509_CERT_COMMON_NAME
);
525 cert_info
.subject
.organization
= ssl_cert_get_dn(cert
, SSL_X509_CERT_ORGANIZATION
);
526 cert_info
.subject
.organizational_name
= ssl_cert_get_dn(cert
, SSL_X509_CERT_ORGANIZATIONAL_NAME
);
527 cert_info
.issuer
.common_name
= ssl_cert_get_dn(cert
, SSL_X509_CA_CERT_COMMON_NAME
);
528 cert_info
.issuer
.organization
= ssl_cert_get_dn(cert
, SSL_X509_CA_CERT_ORGANIZATION
);
529 cert_info
.issuer
.organizational_name
= ssl_cert_get_dn(cert
, SSL_X509_CA_CERT_ORGANIZATIONAL_NAME
);
531 ssl_cert_get_fingerprints(cert
, cert_info
.fingerprint
.md5
, cert_info
.fingerprint
.sha1
);
532 SSL_DateTime not_before
, not_after
;
533 ssl_cert_get_validity_dates(cert
, ¬_before
, ¬_after
);
534 cert_info
.issue_date
.m_Year
= not_before
.year
;
535 cert_info
.issue_date
.m_Month
= not_before
.month
;
536 cert_info
.issue_date
.m_Day
= not_before
.day
;
537 cert_info
.issue_date
.m_Hours
= not_before
.hours
;
538 cert_info
.issue_date
.m_Minutes
= not_before
.minutes
;
539 cert_info
.issue_date
.m_Seconds
= not_before
.seconds
;
540 cert_info
.issue_date
.m_NanoSeconds
= 0;
541 cert_info
.issue_date
.m_TimeZone
= 0;
542 cert_info
.expiration_date
.m_Year
= not_after
.year
;
543 cert_info
.expiration_date
.m_Month
= not_after
.month
;
544 cert_info
.expiration_date
.m_Day
= not_after
.day
;
545 cert_info
.expiration_date
.m_Hours
= not_after
.hours
;
546 cert_info
.expiration_date
.m_Minutes
= not_after
.minutes
;
547 cert_info
.expiration_date
.m_Seconds
= not_after
.seconds
;
548 cert_info
.expiration_date
.m_NanoSeconds
= 0;
549 cert_info
.expiration_date
.m_TimeZone
= 0;
552 cert_info
.alternate_names
.Clear();
553 const char* alt_name
= NULL
;
554 for (unsigned int i
=0; (alt_name
=ssl_cert_get_subject_alt_dnsname(cert
, i
)); i
++) {
555 cert_info
.alternate_names
.Add(NPT_String(alt_name
));
561 /*----------------------------------------------------------------------
562 | NPT_TlsClientSessionImpl
563 +---------------------------------------------------------------------*/
564 class NPT_TlsClientSessionImpl
: public NPT_TlsSessionImpl
{
566 NPT_TlsClientSessionImpl(SSL_CTX
* context
,
567 NPT_InputStreamReference
& input
,
568 NPT_OutputStreamReference
& output
) :
569 NPT_TlsSessionImpl(context
, input
, output
) {}
572 virtual NPT_Result
Handshake();
575 /*----------------------------------------------------------------------
576 | NPT_TlsClientSessionImpl::Handshake
577 +---------------------------------------------------------------------*/
579 NPT_TlsClientSessionImpl::Handshake()
582 // we have not created the client object yet
583 m_SSL
= ssl_client_new(m_SSL_CTX
, &m_StreamAdapter
.m_Base
, NULL
, 0);
586 int result
= ssl_handshake_status(m_SSL
);
587 return NPT_Tls_MapResult(result
);
590 /*----------------------------------------------------------------------
591 | NPT_TlsServerSessionImpl
592 +---------------------------------------------------------------------*/
593 class NPT_TlsServerSessionImpl
: public NPT_TlsSessionImpl
{
595 NPT_TlsServerSessionImpl(SSL_CTX
* context
,
596 NPT_InputStreamReference
& input
,
597 NPT_OutputStreamReference
& output
) :
598 NPT_TlsSessionImpl(context
, input
, output
) {}
601 virtual NPT_Result
Handshake();
604 /*----------------------------------------------------------------------
605 | NPT_TlsServerSessionImpl::Handshake
606 +---------------------------------------------------------------------*/
608 NPT_TlsServerSessionImpl::Handshake()
611 // we have not created the server object yet
612 m_SSL
= ssl_server_new(m_SSL_CTX
, &m_StreamAdapter
.m_Base
);
615 uint8_t* data
= NULL
;
617 while ((result
= ssl_handshake_status(m_SSL
)) == SSL_NOT_OK
) {
618 result
= ssl_read(m_SSL
, &data
);
619 if (result
!= SSL_OK
) break;
621 NPT_LOG_WARNING("got data during handshake???");
622 return NPT_ERROR_INTERNAL
;
625 return NPT_Tls_MapResult(result
);
628 /*----------------------------------------------------------------------
630 +---------------------------------------------------------------------*/
631 class NPT_TlsInputStream
: public NPT_InputStream
{
633 NPT_TlsInputStream(NPT_TlsSessionImplReference
& session
) :
636 m_RecordCacheData(NULL
),
637 m_RecordCacheSize(0) {}
639 // NPT_InputStream methods
640 virtual NPT_Result
Read(void* buffer
,
641 NPT_Size bytes_to_read
,
642 NPT_Size
* bytes_read
= NULL
);
643 virtual NPT_Result
Seek(NPT_Position
) { return NPT_ERROR_NOT_SUPPORTED
; }
644 virtual NPT_Result
Tell(NPT_Position
& offset
) { offset
= m_Position
; return NPT_SUCCESS
; }
645 virtual NPT_Result
GetSize(NPT_LargeSize
& size
) { size
=0; return NPT_ERROR_NOT_SUPPORTED
; }
646 virtual NPT_Result
GetAvailable(NPT_LargeSize
& available
);
649 NPT_TlsSessionImplReference m_Session
;
650 NPT_Position m_Position
;
651 uint8_t* m_RecordCacheData
;
652 NPT_Size m_RecordCacheSize
;
655 /*----------------------------------------------------------------------
656 | NPT_TlsInputStream::Read
657 +---------------------------------------------------------------------*/
659 NPT_TlsInputStream::Read(void* buffer
,
660 NPT_Size bytes_to_read
,
661 NPT_Size
* bytes_read
)
663 // setup default values
664 if (bytes_read
) *bytes_read
= 0;
666 // quick check for edge case
667 if (bytes_to_read
== 0) return NPT_SUCCESS
;
669 // read a new record if we don't have one cached
670 if (m_RecordCacheData
== NULL
) {
673 ssl_result
= ssl_read(m_Session
->m_SSL
, &m_RecordCacheData
);
674 } while (ssl_result
== 0);
675 if (ssl_result
< 0) {
676 return NPT_Tls_MapResult(ssl_result
);
678 m_RecordCacheSize
= ssl_result
;
681 // we now have data in cache
682 if (bytes_to_read
> m_RecordCacheSize
) {
683 // read at most what's in the cache
684 bytes_to_read
= m_RecordCacheSize
;
686 NPT_CopyMemory(buffer
, m_RecordCacheData
, bytes_to_read
);
687 if (bytes_read
) *bytes_read
= bytes_to_read
;
689 // update the record cache
690 m_RecordCacheSize
-= bytes_to_read
;
691 if (m_RecordCacheSize
== 0) {
692 // nothing left in the cache
693 m_RecordCacheData
= NULL
;
695 // move the cache pointer
696 m_RecordCacheData
+= bytes_to_read
;
702 /*----------------------------------------------------------------------
703 | NPT_TlsInputStream::GetAvailable
704 +---------------------------------------------------------------------*/
706 NPT_TlsInputStream::GetAvailable(NPT_LargeSize
& /*available*/)
711 /*----------------------------------------------------------------------
712 | NPT_TlsOutputStream
713 +---------------------------------------------------------------------*/
714 class NPT_TlsOutputStream
: public NPT_OutputStream
{
716 NPT_TlsOutputStream(NPT_TlsSessionImplReference
& session
) :
720 // NPT_OutputStream methods
721 virtual NPT_Result
Write(const void* buffer
,
722 NPT_Size bytes_to_write
,
723 NPT_Size
* bytes_written
= NULL
);
724 virtual NPT_Result
Seek(NPT_Position
) { return NPT_ERROR_NOT_SUPPORTED
; }
725 virtual NPT_Result
Tell(NPT_Position
& offset
) { offset
= m_Position
; return NPT_SUCCESS
; }
728 NPT_TlsSessionImplReference m_Session
;
729 NPT_Position m_Position
;
732 /*----------------------------------------------------------------------
733 | NPT_TlsOutputStream::Write
734 +---------------------------------------------------------------------*/
736 NPT_TlsOutputStream::Write(const void* buffer
,
737 NPT_Size bytes_to_write
,
738 NPT_Size
* bytes_written
)
740 // setup default values
741 if (bytes_written
) *bytes_written
= 0;
743 // quick check for edge case
744 if (bytes_to_write
== 0) return NPT_SUCCESS
;
749 ssl_result
= ssl_write(m_Session
->m_SSL
, (const uint8_t*)buffer
, bytes_to_write
);
750 } while (ssl_result
== 0);
751 if (ssl_result
< 0) {
752 return NPT_Tls_MapResult(ssl_result
);
754 m_Position
+= ssl_result
;
755 if (bytes_written
) *bytes_written
= (NPT_Size
)ssl_result
;
760 /*----------------------------------------------------------------------
761 | NPT_Tls::GetDefaultTrustAnchors
762 +---------------------------------------------------------------------*/
763 const NPT_TlsTrustAnchorData
*
764 NPT_Tls::GetDefaultTrustAnchors(NPT_Ordinal indx
)
767 return NptTlsDefaultTrustAnchorsBase
;
768 } else if (indx
== 2) {
769 return NptTlsDefaultTrustAnchorsExtended
;
775 /*----------------------------------------------------------------------
776 | NPT_TlsContext::NPT_TlsContext
777 +---------------------------------------------------------------------*/
778 NPT_TlsContext::NPT_TlsContext(NPT_Flags options
) :
779 m_Impl(new NPT_TlsContextImpl(options
))
781 if (options
& OPTION_ADD_DEFAULT_TRUST_ANCHORS
) {
782 const NPT_TlsTrustAnchorData
* ta
= NPT_Tls::GetDefaultTrustAnchors(0);
789 /*----------------------------------------------------------------------
790 | NPT_TlsContext::~NPT_TlsContext
791 +---------------------------------------------------------------------*/
792 NPT_TlsContext::~NPT_TlsContext()
797 /*----------------------------------------------------------------------
798 | NPT_TlsContext::LoadKey
799 +---------------------------------------------------------------------*/
801 NPT_TlsContext::LoadKey(NPT_TlsKeyFormat key_format
,
802 const unsigned char* key_data
,
803 NPT_Size key_data_size
,
804 const char* password
)
806 return m_Impl
->LoadKey(key_format
, key_data
, key_data_size
, password
);
809 /*----------------------------------------------------------------------
810 | NPT_TlsContext::SelfSignCertificate
811 +---------------------------------------------------------------------*/
813 NPT_TlsContext::SelfSignCertificate(const char* common_name
,
814 const char* organization
,
815 const char* organizational_name
)
817 return m_Impl
->SelfSignCertificate(common_name
, organization
, organizational_name
);
820 /*----------------------------------------------------------------------
821 | NPT_TlsContext::AddTrustAnchor
822 +---------------------------------------------------------------------*/
824 NPT_TlsContext::AddTrustAnchor(const unsigned char* ta_data
,
825 NPT_Size ta_data_size
)
827 return m_Impl
->AddTrustAnchor(ta_data
, ta_data_size
);
830 /*----------------------------------------------------------------------
831 | NPT_TlsContext::AddTrustAnchors
832 +---------------------------------------------------------------------*/
834 NPT_TlsContext::AddTrustAnchors(const NPT_TlsTrustAnchorData
* anchors
,
835 NPT_Cardinal anchor_count
)
837 if (anchors
== NULL
) return NPT_SUCCESS
;
838 for (unsigned int i
=0;
841 (anchors
[i
].cert_data
&& anchors
[i
].cert_size
);
843 // add the trust anchor and ignore the error
844 m_Impl
->AddTrustAnchor(anchors
[i
].cert_data
, anchors
[i
].cert_size
);
849 /*----------------------------------------------------------------------
850 | NPT_TlsSession::NPT_TlsSession
851 +---------------------------------------------------------------------*/
852 NPT_TlsSession::NPT_TlsSession(NPT_TlsContext
& context
,
853 NPT_TlsSessionImpl
* impl
) :
856 m_InputStream(new NPT_TlsInputStream(m_Impl
)),
857 m_OutputStream(new NPT_TlsOutputStream(m_Impl
))
861 /*----------------------------------------------------------------------
862 | NPT_TlsSession::~NPT_TlsSession
863 +---------------------------------------------------------------------*/
864 NPT_TlsSession::~NPT_TlsSession()
868 /*----------------------------------------------------------------------
869 | NPT_TlsSession::Handshake
870 +---------------------------------------------------------------------*/
872 NPT_TlsSession::Handshake()
874 return m_Impl
->Handshake();
877 /*----------------------------------------------------------------------
878 | NPT_TlsSession::GetHandshakeStatus
879 +---------------------------------------------------------------------*/
881 NPT_TlsSession::GetHandshakeStatus()
883 return m_Impl
->GetHandshakeStatus();
886 /*----------------------------------------------------------------------
887 | NPT_TlsSession::VerifyPeerCertificate
888 +---------------------------------------------------------------------*/
890 NPT_TlsSession::VerifyPeerCertificate()
892 return m_Impl
->VerifyPeerCertificate();
895 /*----------------------------------------------------------------------
896 | NPT_TlsSession::VerifyDnsNameMatch
897 +---------------------------------------------------------------------*/
899 NPT_TlsSession::VerifyDnsNameMatch(const char* hostname
)
901 return m_Impl
->VerifyDnsNameMatch(hostname
);
904 /*----------------------------------------------------------------------
905 | NPT_TlsClientSession::GetSessionId
906 +---------------------------------------------------------------------*/
908 NPT_TlsSession::GetSessionId(NPT_DataBuffer
& session_id
)
910 return m_Impl
->GetSessionId(session_id
);
913 /*----------------------------------------------------------------------
914 | NPT_TlsSession::GetCipherSuiteId
915 +---------------------------------------------------------------------*/
917 NPT_TlsSession::GetCipherSuiteId()
919 return m_Impl
->GetCipherSuiteId();
922 /*----------------------------------------------------------------------
923 | NPT_TlsSession::GetPeerCertificateInfo
924 +---------------------------------------------------------------------*/
926 NPT_TlsSession::GetPeerCertificateInfo(NPT_TlsCertificateInfo
& cert_info
,
927 unsigned int position
)
929 return m_Impl
->GetPeerCertificateInfo(cert_info
, position
);
932 /*----------------------------------------------------------------------
933 | NPT_TlsSession::GetInputStream
934 +---------------------------------------------------------------------*/
936 NPT_TlsSession::GetInputStream(NPT_InputStreamReference
& stream
)
938 stream
= m_InputStream
;
942 /*----------------------------------------------------------------------
943 | NPT_TlsSession::GetOutputStream
944 +---------------------------------------------------------------------*/
946 NPT_TlsSession::GetOutputStream(NPT_OutputStreamReference
& stream
)
948 stream
= m_OutputStream
;
952 /*----------------------------------------------------------------------
953 | NPT_TlsClientSession::NPT_TlsClientSession
954 +---------------------------------------------------------------------*/
955 NPT_TlsClientSession::NPT_TlsClientSession(NPT_TlsContext
& context
,
956 NPT_InputStreamReference
& input
,
957 NPT_OutputStreamReference
& output
) :
958 NPT_TlsSession(context
, new NPT_TlsClientSessionImpl(context
.m_Impl
->m_SSL_CTX
, input
, output
))
962 /*----------------------------------------------------------------------
963 | NPT_TlsServerSession::NPT_TlsServerSession
964 +---------------------------------------------------------------------*/
965 NPT_TlsServerSession::NPT_TlsServerSession(NPT_TlsContext
& context
,
966 NPT_InputStreamReference
& input
,
967 NPT_OutputStreamReference
& output
) :
968 NPT_TlsSession(context
, new NPT_TlsServerSessionImpl(context
.m_Impl
->m_SSL_CTX
, input
, output
))
972 /*----------------------------------------------------------------------
973 | NPT_HttpTlsConnector::DefaultTlsContext
974 +---------------------------------------------------------------------*/
975 NPT_TlsContext
* NPT_HttpTlsConnector::DefaultTlsContext
= NULL
;
977 /*----------------------------------------------------------------------
978 | NPT_HttpTlsConnector::NPT_HttpTlsConnector
979 +---------------------------------------------------------------------*/
980 NPT_HttpTlsConnector::NPT_HttpTlsConnector(NPT_Flags options
) :
981 m_TlsContext(GetDefaultTlsContext()),
986 /*----------------------------------------------------------------------
987 | NPT_HttpTlsConnector::NPT_HttpTlsConnector
988 +---------------------------------------------------------------------*/
989 NPT_HttpTlsConnector::NPT_HttpTlsConnector(NPT_TlsContext
& tls_context
, NPT_Flags options
) :
990 m_TlsContext(tls_context
),
995 /*----------------------------------------------------------------------
996 | NPT_HttpTlsConnector::GetDefaultTlsContext
997 +---------------------------------------------------------------------*/
999 NPT_HttpTlsConnector::GetDefaultTlsContext()
1001 if (DefaultTlsContext
== NULL
) {
1002 NPT_SingletonLock::GetInstance().Lock();
1003 if (DefaultTlsContext
== NULL
) {
1004 DefaultTlsContext
= new NPT_TlsContext(NPT_TlsContext::OPTION_VERIFY_LATER
|
1005 NPT_TlsContext::OPTION_ADD_DEFAULT_TRUST_ANCHORS
);
1007 // Prepare for recycling
1008 NPT_AutomaticCleaner::GetInstance()->RegisterTlsContext(DefaultTlsContext
);
1010 NPT_SingletonLock::GetInstance().Unlock();
1013 return *DefaultTlsContext
;
1016 /*----------------------------------------------------------------------
1017 | NPT_HttpTlsConnector::VerifyPeer
1018 +---------------------------------------------------------------------*/
1020 NPT_HttpTlsConnector::VerifyPeer(NPT_TlsClientSession
& session
, const char* hostname
)
1022 // verify the certificate
1023 NPT_Result result
= session
.VerifyPeerCertificate();
1024 if (NPT_FAILED(result
)) {
1025 if (result
== NPT_ERROR_TLS_CERTIFICATE_SELF_SIGNED
) {
1026 if (!m_Options
&& OPTION_ACCEPT_SELF_SIGNED_CERTS
) {
1027 // self-signed certs are not acceptable
1028 NPT_LOG_FINE("rejecting self-signed certificate");
1032 NPT_LOG_WARNING_2("TLS certificate verification failed (%d:%s)", result
, NPT_ResultText(result
));
1037 // chech the DNS name
1038 if (!(m_Options
& OPTION_ACCEPT_HOSTNAME_MISMATCH
)) {
1039 // check the hostname
1040 result
= session
.VerifyDnsNameMatch(hostname
);
1041 if (NPT_FAILED(result
)) {
1042 NPT_LOG_WARNING_2("TLS certificate does not match DNS name (%d:%s)", result
, NPT_ResultText(result
));
1043 return NPT_ERROR_TLS_DNS_NAME_MISMATCH
;
1050 #endif // defined(NPT_CONFIG_ENABLE_TLS)
1052 /*----------------------------------------------------------------------
1053 | NPT_HttpSimpleTlsConnection
1054 +---------------------------------------------------------------------*/
1055 class NPT_HttpSimpleTlsConnection
: public NPT_HttpClient::Connection
1058 NPT_InputStreamReference
& GetInputStream() override
{
1059 return m_InputStream
;
1061 NPT_OutputStreamReference
& GetOutputStream() override
{
1062 return m_OutputStream
;
1066 NPT_InputStreamReference m_InputStream
;
1067 NPT_OutputStreamReference m_OutputStream
;
1070 /*----------------------------------------------------------------------
1071 | NPT_HttpTlsConnector::Connect
1072 +---------------------------------------------------------------------*/
1074 NPT_HttpTlsConnector::Connect(const NPT_HttpUrl
& url
,
1075 NPT_HttpClient
& client
,
1076 const NPT_HttpProxyAddress
* proxy
,
1078 NPT_HttpClient::Connection
*& connection
)
1083 // local reference holders
1084 NPT_InputStreamReference input_stream
;
1085 NPT_OutputStreamReference output_stream
;
1087 // decide which server we need to connect to
1088 const char* peer_hostname
= (const char*)url
.GetHost();
1089 const char* server_hostname
;
1090 NPT_UInt16 server_port
;
1093 server_hostname
= (const char*)proxy
->GetHostName();
1094 server_port
= proxy
->GetPort();
1096 // no proxy: connect directly
1097 server_hostname
= peer_hostname
;
1098 server_port
= url
.GetPort();
1101 // resolve the server address
1102 NPT_IpAddress ip_address
;
1103 NPT_CHECK_FINE(ip_address
.ResolveName(server_hostname
, client
.GetConfig().m_NameResolverTimeout
));
1105 // check if we can reuse a connection
1106 // TODO: with this we don't yet support reusing a connection to a proxy
1107 NPT_SocketAddress
socket_address(ip_address
, server_port
);
1108 NPT_HttpConnectionManager
* connection_manager
= NPT_HttpConnectionManager::GetInstance();
1109 if (!proxy
&& reuse
) {
1110 NPT_LOG_FINE("looking for a connection to reuse");
1111 connection
= connection_manager
->FindConnection(socket_address
);
1113 NPT_LOG_FINE("reusing connection");
1114 // track connection immediately so we can abort it later
1115 NPT_CHECK_FINE(Connector::TrackConnection(client
, connection
));
1121 NPT_LOG_FINE_2("TLS connector will connect to %s:%d", server_hostname
, server_port
);
1122 NPT_TcpClientSocket
* tcp_socket
= new NPT_TcpClientSocket(NPT_SOCKET_FLAG_CANCELLABLE
);
1123 NPT_SocketReference
socket(tcp_socket
);
1124 tcp_socket
->SetReadTimeout(client
.GetConfig().m_IoTimeout
);
1125 tcp_socket
->SetWriteTimeout(client
.GetConfig().m_IoTimeout
);
1127 // create a connection object for the socket so we can abort it during connect
1128 // even though streams are not valid yet
1129 NPT_Reference
<NPT_HttpConnectionManager::Connection
> cref(new NPT_HttpConnectionManager::Connection(*connection_manager
,
1133 // track connection immediately before connecting so we can abort immediately it if necessary
1134 NPT_CHECK_FINE(Connector::TrackConnection(client
, cref
.AsPointer()));
1136 // connect to the server
1137 NPT_CHECK_FINE(tcp_socket
->Connect(socket_address
, client
.GetConfig().m_ConnectionTimeout
));
1140 NPT_InputStreamReference raw_input
;
1141 NPT_OutputStreamReference raw_output
;
1142 NPT_CHECK_FINE(tcp_socket
->GetInputStream(raw_input
));
1143 NPT_CHECK_FINE(tcp_socket
->GetOutputStream(raw_output
));
1145 if (url
.GetSchemeId() == NPT_Url::SCHEME_ID_HTTPS
) {
1146 #if defined(NPT_CONFIG_ENABLE_TLS)
1149 NPT_String connect_host
= url
.GetHost() + ":" + NPT_String::FromInteger(url
.GetPort());
1150 NPT_String connect
= "CONNECT " + connect_host
+ " HTTP/1.1\r\n"
1151 "Host: " + connect_host
+ "\r\n\r\n";
1152 NPT_Result result
= raw_output
->WriteFully(connect
.GetChars(), connect
.GetLength());
1153 if (NPT_FAILED(result
)) return result
;
1154 NPT_String connect_response
;
1155 connect_response
.Reserve(1024);
1156 bool connect_ok
= false;
1157 for (unsigned int x
=0; x
<NPT_HTTP_TLS_CONNECTOR_MAX_PROXY_RESPONSE_SIZE
; x
++) {
1158 connect_response
.Reserve(x
+1);
1159 result
= raw_input
->Read(connect_response
.UseChars()+x
, 1);
1160 if (NPT_FAILED(result
)) return result
;
1161 if (connect_response
.GetChars()[x
] == '\n') {
1162 connect_response
.SetLength(x
+1);
1164 // check the connection result
1165 NPT_LOG_FINE_1("proxy response: %s", connect_response
.GetChars());
1166 if (connect_response
.GetLength() < 12) {
1167 return NPT_ERROR_HTTP_INVALID_RESPONSE_LINE
;
1169 if (!connect_response
.StartsWith("HTTP/1.")) {
1170 return NPT_ERROR_HTTP_INVALID_RESPONSE_LINE
;
1172 if (connect_response
[8] != ' ') {
1173 return NPT_ERROR_HTTP_INVALID_RESPONSE_LINE
;
1175 NPT_String status_code
= connect_response
.SubString(9, 3);
1176 if (status_code
!= "200") {
1177 NPT_LOG_WARNING_1("proxy response is not 200 (%s)", status_code
.GetChars());
1178 return NPT_ERROR_HTTP_INVALID_RESPONSE_LINE
;
1182 if (connect_response
.EndsWith("\r\n\r\n")) {
1183 // this is the end, my friend
1190 return NPT_ERROR_HTTP_INVALID_RESPONSE_LINE
;
1194 // setup the TLS connection
1195 NPT_TlsClientSession
tls_session(m_TlsContext
, raw_input
, raw_output
);
1196 NPT_Result result
= tls_session
.Handshake();
1197 if (NPT_FAILED(result
)) {
1198 NPT_LOG_WARNING_2("TLS handshake failed (%d:%s)", result
, NPT_ResultText(result
));
1201 result
= VerifyPeer(tls_session
, peer_hostname
);
1202 if (NPT_FAILED(result
)) {
1203 NPT_LOG_WARNING_2("VerifyPeer failed (%d:%s)", result
, NPT_ResultText(result
));
1207 // return the TLS streams
1208 tls_session
.GetInputStream(input_stream
);
1209 tls_session
.GetOutputStream(output_stream
);
1211 return NPT_ERROR_NOT_SUPPORTED
;
1214 input_stream
= raw_input
;
1215 output_stream
= raw_output
;
1218 // update connection streams
1219 cref
->m_InputStream
= input_stream
;
1220 cref
->m_OutputStream
= output_stream
;
1222 connection
= cref
.AsPointer();
1223 cref
.Detach(); // release the internal ref