Merge pull request #25959 from neo1973/TagLib_deprecation_warnings
[xbmc.git] / lib / libUPnP / Neptune / Source / Core / NptTls.cpp
blob594adbd456b105e63ae8fa7a37cfcac444e3780e
1 /*****************************************************************
3 | Neptune - TLS/SSL Support
5 | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
6 | All rights reserved.
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 /*----------------------------------------------------------------------
33 | includes
34 +---------------------------------------------------------------------*/
35 #include "NptConfig.h"
36 #include "NptTls.h"
37 #include "NptLogging.h"
38 #include "NptUtils.h"
39 #include "NptSockets.h"
40 #include "NptSystem.h"
41 #include "NptDigest.h"
42 #include "NptAutomaticCleaner.h"
44 /*----------------------------------------------------------------------
45 | logging
46 +---------------------------------------------------------------------*/
47 NPT_SET_LOCAL_LOGGER("neptune.tls")
49 #if defined(NPT_CONFIG_ENABLE_TLS)
50 #include "ssl.h"
52 /*----------------------------------------------------------------------
53 | constants
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 /*----------------------------------------------------------------------
59 | types
60 +---------------------------------------------------------------------*/
61 typedef NPT_Reference<NPT_TlsSessionImpl> NPT_TlsSessionImplReference;
63 /*----------------------------------------------------------------------
64 | SSL_DateTime_Before
65 +---------------------------------------------------------------------*/
66 int
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;
74 } else {
75 return t1->day < t2->day ? 1 : 0;
77 } else {
78 return t1->month < t2->month ? 1 : 0;
80 } else {
81 return t1->year < t2->year ? 1 : 0;
85 /*----------------------------------------------------------------------
86 | SSL_DateTime_Now
87 +---------------------------------------------------------------------*/
88 void
89 SSL_DateTime_Now(SSL_DateTime* now)
91 NPT_TimeStamp ts;
92 NPT_System::GetCurrentTimeStamp(ts);
93 NPT_DateTime dt;
94 dt.FromTimeStamp(ts);
95 now->year = dt.m_Year;
96 now->month = dt.m_Month;
97 now->day = dt.m_Day;
98 now->hours = dt.m_Hours;
99 now->minutes = dt.m_Minutes;
100 now->seconds = dt.m_Seconds;
103 /*----------------------------------------------------------------------
104 | SSL_GetRandomSeed
105 +---------------------------------------------------------------------*/
106 uint64_t
107 SSL_GetRandomSeed()
109 NPT_TimeStamp ts;
110 NPT_System::GetCurrentTimeStamp(ts);
111 return ts.ToNanos();
114 /*----------------------------------------------------------------------
115 | SSL_Mutex_Create
116 +---------------------------------------------------------------------*/
117 void
118 SSL_Mutex_Create(NPT_Mutex** mutex)
120 *mutex = new NPT_Mutex();
123 /*----------------------------------------------------------------------
124 | SSL_Mutex_Destroy
125 +---------------------------------------------------------------------*/
126 void
127 SSL_Mutex_Destroy(NPT_Mutex* mutex)
129 delete mutex;
132 /*----------------------------------------------------------------------
133 | SSL_Mutex_Lock
134 +---------------------------------------------------------------------*/
135 void
136 SSL_Mutex_Lock(NPT_Mutex* mutex)
138 mutex->Lock();
141 /*----------------------------------------------------------------------
142 | SSL_Mutex_Lock
143 +---------------------------------------------------------------------*/
144 void
145 SSL_Mutex_Unlock(NPT_Mutex* mutex)
147 mutex->Unlock();
150 /*----------------------------------------------------------------------
151 | SSL_Sha256_ComputeDigest
152 +---------------------------------------------------------------------*/
153 void
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);
164 delete digest;
167 /*----------------------------------------------------------------------
168 | NPT_Tls::MatchDnsName
169 +---------------------------------------------------------------------*/
170 bool
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] != '.') {
184 ++hostname;
186 if (hostname[0] == '.') ++hostname;
188 // compare the tails
189 return NPT_String::Compare(hostname, dns_name+2, true) == 0;
190 } else {
191 // full match
192 return NPT_String::Compare(hostname, dns_name, true) == 0;
196 /*----------------------------------------------------------------------
197 | NPT_Tls::MatchDnsNames
198 +---------------------------------------------------------------------*/
199 bool
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();
209 ++i) {
210 if (MatchDnsName(hostname, (*i).GetChars())) return true;
213 // no match
214 return false;
217 /*----------------------------------------------------------------------
218 | NPT_Tls_MapResult
219 +---------------------------------------------------------------------*/
220 static NPT_Result
221 NPT_Tls_MapResult(int err)
223 switch (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 /*----------------------------------------------------------------------
263 | NPT_TlsContextImpl
264 +---------------------------------------------------------------------*/
265 class NPT_TlsContextImpl {
266 public:
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);
283 SSL_CTX* m_SSL_CTX;
286 /*----------------------------------------------------------------------
287 | NPT_TlsContextImpl::LoadKey
288 +---------------------------------------------------------------------*/
289 NPT_Result
290 NPT_TlsContextImpl::LoadKey(NPT_TlsKeyFormat key_format,
291 const unsigned char* key_data,
292 NPT_Size key_data_size,
293 const char* password)
295 int object_type;
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 +---------------------------------------------------------------------*/
310 NPT_Result
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);
318 if (result <= 0) {
319 if (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 +---------------------------------------------------------------------*/
333 NPT_Result
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)) {
351 switch (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;
357 return bytes_read;
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)) {
365 switch (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) {
377 m_Base.Read = Read;
378 m_Base.Write = Write;
381 SSL_SOCKET m_Base;
382 NPT_InputStreamReference m_Input;
383 NPT_OutputStreamReference m_Output;
387 /*----------------------------------------------------------------------
388 | NPT_TlsSessionImpl
389 +---------------------------------------------------------------------*/
390 class NPT_TlsSessionImpl {
391 public:
392 NPT_TlsSessionImpl(SSL_CTX* context,
393 NPT_InputStreamReference& input,
394 NPT_OutputStreamReference& output) :
395 m_SSL_CTX(context),
396 m_SSL(NULL),
397 m_StreamAdapter(input, output) {}
398 virtual ~NPT_TlsSessionImpl() { ssl_free(m_SSL); }
400 // methods
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);
410 // members
411 SSL_CTX* m_SSL_CTX;
412 SSL* m_SSL;
413 NPT_TlsStreamAdapter m_StreamAdapter;
416 /*----------------------------------------------------------------------
417 | NPT_TlsSessionImpl::GetHandshakeStatus
418 +---------------------------------------------------------------------*/
419 NPT_Result
420 NPT_TlsSessionImpl::GetHandshakeStatus()
422 int status;
423 if (m_SSL == NULL || (status = ssl_handshake_status(m_SSL)) == SSL_NOT_OK) {
424 // no handshake done
425 return NPT_ERROR_INVALID_STATE;
428 return NPT_Tls_MapResult(status);
431 /*----------------------------------------------------------------------
432 | NPT_TlsSessionImpl::VerifyPeerCertificate
433 +---------------------------------------------------------------------*/
434 NPT_Result
435 NPT_TlsSessionImpl::VerifyPeerCertificate()
437 if (m_SSL == NULL || ssl_handshake_status(m_SSL) == SSL_NOT_OK) {
438 // no handshake done
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 +---------------------------------------------------------------------*/
449 NPT_Result
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) {
454 // no handshake done
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;
472 return NPT_FAILURE;
475 /*----------------------------------------------------------------------
476 | NPT_TlsSessionImpl::GetSessionId
477 +---------------------------------------------------------------------*/
478 NPT_Result
479 NPT_TlsSessionImpl::GetSessionId(NPT_DataBuffer& session_id)
481 if (m_SSL == NULL || ssl_handshake_status(m_SSL) == SSL_NOT_OK) {
482 // no handshake done
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));
490 return NPT_SUCCESS;
493 /*----------------------------------------------------------------------
494 | NPT_TlsSessionImpl::GetCipherSuiteId
495 +---------------------------------------------------------------------*/
496 NPT_UInt32
497 NPT_TlsSessionImpl::GetCipherSuiteId()
499 if (m_SSL == NULL || ssl_handshake_status(m_SSL) == SSL_NOT_OK) {
500 // no handshake done
501 return 0;
504 return ssl_get_cipher_id(m_SSL);
507 /*----------------------------------------------------------------------
508 | NPT_TlsSessionImpl::GetPeerCertificateInfo
509 +---------------------------------------------------------------------*/
510 NPT_Result
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) {
515 // no handshake done
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, &not_before, &not_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;
551 // alternate names
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));
558 return NPT_SUCCESS;
561 /*----------------------------------------------------------------------
562 | NPT_TlsClientSessionImpl
563 +---------------------------------------------------------------------*/
564 class NPT_TlsClientSessionImpl : public NPT_TlsSessionImpl {
565 public:
566 NPT_TlsClientSessionImpl(SSL_CTX* context,
567 NPT_InputStreamReference& input,
568 NPT_OutputStreamReference& output) :
569 NPT_TlsSessionImpl(context, input, output) {}
571 // methods
572 virtual NPT_Result Handshake();
575 /*----------------------------------------------------------------------
576 | NPT_TlsClientSessionImpl::Handshake
577 +---------------------------------------------------------------------*/
578 NPT_Result
579 NPT_TlsClientSessionImpl::Handshake()
581 if (m_SSL == NULL) {
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 {
594 public:
595 NPT_TlsServerSessionImpl(SSL_CTX* context,
596 NPT_InputStreamReference& input,
597 NPT_OutputStreamReference& output) :
598 NPT_TlsSessionImpl(context, input, output) {}
600 // methods
601 virtual NPT_Result Handshake();
604 /*----------------------------------------------------------------------
605 | NPT_TlsServerSessionImpl::Handshake
606 +---------------------------------------------------------------------*/
607 NPT_Result
608 NPT_TlsServerSessionImpl::Handshake()
610 if (m_SSL == NULL) {
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;
616 int result;
617 while ((result = ssl_handshake_status(m_SSL)) == SSL_NOT_OK) {
618 result = ssl_read(m_SSL, &data);
619 if (result != SSL_OK) break;
620 if (data != NULL) {
621 NPT_LOG_WARNING("got data during handshake???");
622 return NPT_ERROR_INTERNAL;
625 return NPT_Tls_MapResult(result);
628 /*----------------------------------------------------------------------
629 | NPT_TlsInputStream
630 +---------------------------------------------------------------------*/
631 class NPT_TlsInputStream : public NPT_InputStream {
632 public:
633 NPT_TlsInputStream(NPT_TlsSessionImplReference& session) :
634 m_Session(session),
635 m_Position(0),
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);
648 private:
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 +---------------------------------------------------------------------*/
658 NPT_Result
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) {
671 int ssl_result;
672 do {
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;
694 } else {
695 // move the cache pointer
696 m_RecordCacheData += bytes_to_read;
699 return NPT_SUCCESS;
702 /*----------------------------------------------------------------------
703 | NPT_TlsInputStream::GetAvailable
704 +---------------------------------------------------------------------*/
705 NPT_Result
706 NPT_TlsInputStream::GetAvailable(NPT_LargeSize& /*available*/)
708 return NPT_SUCCESS;
711 /*----------------------------------------------------------------------
712 | NPT_TlsOutputStream
713 +---------------------------------------------------------------------*/
714 class NPT_TlsOutputStream : public NPT_OutputStream {
715 public:
716 NPT_TlsOutputStream(NPT_TlsSessionImplReference& session) :
717 m_Session(session),
718 m_Position(0) {}
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; }
727 private:
728 NPT_TlsSessionImplReference m_Session;
729 NPT_Position m_Position;
732 /*----------------------------------------------------------------------
733 | NPT_TlsOutputStream::Write
734 +---------------------------------------------------------------------*/
735 NPT_Result
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;
746 // write some data
747 int ssl_result;
748 do {
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;
757 return NPT_SUCCESS;
760 /*----------------------------------------------------------------------
761 | NPT_Tls::GetDefaultTrustAnchors
762 +---------------------------------------------------------------------*/
763 const NPT_TlsTrustAnchorData*
764 NPT_Tls::GetDefaultTrustAnchors(NPT_Ordinal indx)
766 if (indx == 0) {
767 return NptTlsDefaultTrustAnchorsBase;
768 } else if (indx == 2) {
769 return NptTlsDefaultTrustAnchorsExtended;
770 } else {
771 return NULL;
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);
783 if (ta) {
784 AddTrustAnchors(ta);
789 /*----------------------------------------------------------------------
790 | NPT_TlsContext::~NPT_TlsContext
791 +---------------------------------------------------------------------*/
792 NPT_TlsContext::~NPT_TlsContext()
794 delete m_Impl;
797 /*----------------------------------------------------------------------
798 | NPT_TlsContext::LoadKey
799 +---------------------------------------------------------------------*/
800 NPT_Result
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 +---------------------------------------------------------------------*/
812 NPT_Result
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 +---------------------------------------------------------------------*/
823 NPT_Result
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 +---------------------------------------------------------------------*/
833 NPT_Result
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;
839 anchor_count ?
840 (i<anchor_count) :
841 (anchors[i].cert_data && anchors[i].cert_size);
842 i++) {
843 // add the trust anchor and ignore the error
844 m_Impl->AddTrustAnchor(anchors[i].cert_data, anchors[i].cert_size);
846 return NPT_SUCCESS;
849 /*----------------------------------------------------------------------
850 | NPT_TlsSession::NPT_TlsSession
851 +---------------------------------------------------------------------*/
852 NPT_TlsSession::NPT_TlsSession(NPT_TlsContext& context,
853 NPT_TlsSessionImpl* impl) :
854 m_Context(context),
855 m_Impl(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 +---------------------------------------------------------------------*/
871 NPT_Result
872 NPT_TlsSession::Handshake()
874 return m_Impl->Handshake();
877 /*----------------------------------------------------------------------
878 | NPT_TlsSession::GetHandshakeStatus
879 +---------------------------------------------------------------------*/
880 NPT_Result
881 NPT_TlsSession::GetHandshakeStatus()
883 return m_Impl->GetHandshakeStatus();
886 /*----------------------------------------------------------------------
887 | NPT_TlsSession::VerifyPeerCertificate
888 +---------------------------------------------------------------------*/
889 NPT_Result
890 NPT_TlsSession::VerifyPeerCertificate()
892 return m_Impl->VerifyPeerCertificate();
895 /*----------------------------------------------------------------------
896 | NPT_TlsSession::VerifyDnsNameMatch
897 +---------------------------------------------------------------------*/
898 NPT_Result
899 NPT_TlsSession::VerifyDnsNameMatch(const char* hostname)
901 return m_Impl->VerifyDnsNameMatch(hostname);
904 /*----------------------------------------------------------------------
905 | NPT_TlsClientSession::GetSessionId
906 +---------------------------------------------------------------------*/
907 NPT_Result
908 NPT_TlsSession::GetSessionId(NPT_DataBuffer& session_id)
910 return m_Impl->GetSessionId(session_id);
913 /*----------------------------------------------------------------------
914 | NPT_TlsSession::GetCipherSuiteId
915 +---------------------------------------------------------------------*/
916 NPT_UInt32
917 NPT_TlsSession::GetCipherSuiteId()
919 return m_Impl->GetCipherSuiteId();
922 /*----------------------------------------------------------------------
923 | NPT_TlsSession::GetPeerCertificateInfo
924 +---------------------------------------------------------------------*/
925 NPT_Result
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 +---------------------------------------------------------------------*/
935 NPT_Result
936 NPT_TlsSession::GetInputStream(NPT_InputStreamReference& stream)
938 stream = m_InputStream;
939 return NPT_SUCCESS;
942 /*----------------------------------------------------------------------
943 | NPT_TlsSession::GetOutputStream
944 +---------------------------------------------------------------------*/
945 NPT_Result
946 NPT_TlsSession::GetOutputStream(NPT_OutputStreamReference& stream)
948 stream = m_OutputStream;
949 return NPT_SUCCESS;
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()),
982 m_Options(options)
986 /*----------------------------------------------------------------------
987 | NPT_HttpTlsConnector::NPT_HttpTlsConnector
988 +---------------------------------------------------------------------*/
989 NPT_HttpTlsConnector::NPT_HttpTlsConnector(NPT_TlsContext& tls_context, NPT_Flags options) :
990 m_TlsContext(tls_context),
991 m_Options(options)
995 /*----------------------------------------------------------------------
996 | NPT_HttpTlsConnector::GetDefaultTlsContext
997 +---------------------------------------------------------------------*/
998 NPT_TlsContext&
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 +---------------------------------------------------------------------*/
1019 NPT_Result
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");
1029 return result;
1031 } else {
1032 NPT_LOG_WARNING_2("TLS certificate verification failed (%d:%s)", result, NPT_ResultText(result));
1033 return 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;
1047 return NPT_SUCCESS;
1050 #endif // defined(NPT_CONFIG_ENABLE_TLS)
1052 /*----------------------------------------------------------------------
1053 | NPT_HttpSimpleTlsConnection
1054 +---------------------------------------------------------------------*/
1055 class NPT_HttpSimpleTlsConnection : public NPT_HttpClient::Connection
1057 public:
1058 NPT_InputStreamReference& GetInputStream() override {
1059 return m_InputStream;
1061 NPT_OutputStreamReference& GetOutputStream() override {
1062 return m_OutputStream;
1065 // members
1066 NPT_InputStreamReference m_InputStream;
1067 NPT_OutputStreamReference m_OutputStream;
1070 /*----------------------------------------------------------------------
1071 | NPT_HttpTlsConnector::Connect
1072 +---------------------------------------------------------------------*/
1073 NPT_Result
1074 NPT_HttpTlsConnector::Connect(const NPT_HttpUrl& url,
1075 NPT_HttpClient& client,
1076 const NPT_HttpProxyAddress* proxy,
1077 bool reuse,
1078 NPT_HttpClient::Connection*& connection)
1080 // default values
1081 connection = NULL;
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;
1091 if (proxy) {
1092 // the proxy is set
1093 server_hostname = (const char*)proxy->GetHostName();
1094 server_port = proxy->GetPort();
1095 } else {
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);
1112 if (connection) {
1113 NPT_LOG_FINE("reusing connection");
1114 // track connection immediately so we can abort it later
1115 NPT_CHECK_FINE(Connector::TrackConnection(client, connection));
1116 return NPT_SUCCESS;
1120 // create a socket
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,
1130 socket,
1131 input_stream,
1132 output_stream));
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));
1139 // get the streams
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)
1147 if (proxy) {
1148 // RFC 2817 CONNECT
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);
1163 if (!connect_ok) {
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;
1180 connect_ok = true;
1181 } else {
1182 if (connect_response.EndsWith("\r\n\r\n")) {
1183 // this is the end, my friend
1184 break;
1189 if (!connect_ok) {
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));
1199 return 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));
1204 return result;
1207 // return the TLS streams
1208 tls_session.GetInputStream(input_stream);
1209 tls_session.GetOutputStream(output_stream);
1210 #else
1211 return NPT_ERROR_NOT_SUPPORTED;
1212 #endif
1213 } else {
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
1225 return NPT_SUCCESS;