Skip to content

Commit e8d8f16

Browse files
committed
Merge branch 'development' of https://git01.codeplex.com/casablanca into compatclean
2 parents cc2374d + fe4fa80 commit e8d8f16

File tree

13 files changed

+414
-138
lines changed

13 files changed

+414
-138
lines changed

Release/include/cpprest/ws_client.h

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,15 @@ class _websocket_client_impl
235235
return m_uri;
236236
}
237237

238+
/// <summary>
239+
/// Set the base uri.
240+
/// </summary>
241+
/// <param name="uri"> The user specified uri. </param>
242+
void set_uri(web::uri uri)
243+
{
244+
m_uri = std::move(uri);
245+
}
246+
238247
/// <summary>
239248
/// Get client configuration object
240249
/// </summary>
@@ -266,13 +275,15 @@ class _websocket_client_impl
266275
}
267276
}
268277

278+
269279
protected:
270-
_websocket_client_impl(web::uri address, websocket_client_config client_config)
271-
: m_uri(std::move(address)), m_client_config(std::move(client_config))
280+
web::uri m_uri;
281+
282+
_websocket_client_impl(websocket_client_config client_config)
283+
: m_client_config(std::move(client_config))
272284
{
273285
}
274286

275-
web::uri m_uri;
276287
websocket_client_config m_client_config;
277288
};
278289
}
@@ -284,17 +295,15 @@ class websocket_client
284295
{
285296
public:
286297
/// <summary>
287-
/// Creates a new websocket_client to connect to the specified uri.
298+
/// Creates a new websocket_client.
288299
/// </summary>
289-
/// <param name="base_uri">A string representation of the base uri to be used for all messages. Must start with either "ws://" or "wss://"</param>
290-
_ASYNCRTIMP websocket_client(web::uri base_uri);
300+
_ASYNCRTIMP websocket_client();
291301

292302
/// <summary>
293-
/// Creates a new websocket_client to connect to the specified uri.
303+
/// Creates a new websocket_client.
294304
/// </summary>
295-
/// <param name="base_uri">A string representation of the base uri to be used for all requests. Must start with either "ws://" or "wss://"</param>
296305
/// <param name="client_config">The client configuration object containing the possible configuration options to intitialize the <c>websocket_client</c>. </param>
297-
_ASYNCRTIMP websocket_client(web::uri base_uri, websocket_client_config client_config);
306+
_ASYNCRTIMP websocket_client(websocket_client_config client_config);
298307

299308
/// <summary>
300309
/// </summary>
@@ -324,8 +333,13 @@ class websocket_client
324333
/// Connects to the remote network destination. The connect method initiates the websocket handshake with the
325334
/// remote network destination, takes care of the protocol upgrade request.
326335
/// </summary>
336+
/// <param name="uri">The uri address to connect. </param>
327337
/// <returns>An asynchronous operation that is completed once the client has successfully connected to the websocket server.</returns>
328-
pplx::task<void> connect() { return m_client->connect(); }
338+
pplx::task<void> connect(web::uri uri)
339+
{
340+
m_client->set_uri(std::move(uri));
341+
return m_client->connect();
342+
}
329343

330344
/// <summary>
331345
/// Sends a websocket message to the server .
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/***
2+
* ==++==
3+
*
4+
* Copyright (c) Microsoft Corporation. All rights reserved.
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* ==--==
17+
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
18+
*
19+
* x509_cert_utilities.h
20+
*
21+
* Contains utility functions for helping to verify server certificates in OS X/iOS.
22+
*
23+
* For the latest on this and related APIs, please see http://casablanca.codeplex.com.
24+
*
25+
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
26+
****/
27+
28+
#pragma once
29+
30+
#include <vector>
31+
#include <string>
32+
33+
namespace web { namespace http { namespace client { namespace details {
34+
35+
bool verify_X509_cert_chain(const std::vector<std::string> &certChain, const std::string &hostName);
36+
37+
}}}}

Release/src/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ if(UNIX)
1717
http/common/http_helpers.cpp
1818
http/client/http_msg_client.cpp
1919
http/client/http_linux.cpp
20+
http/client/x509_cert_utilities.cpp
2021
http/listener/http_linux_server.cpp
2122
http/listener/http_listener.cpp
2223
http/listener/http_msg_listen.cpp
@@ -30,7 +31,8 @@ if(UNIX)
3031
if(APPLE)
3132
set(SOURCES ${SOURCES} pplx/apple/pplxapple.cpp)
3233
find_library(COREFOUNDATION CoreFoundation "/")
33-
set(EXTRALINKS ${COREFOUNDATION})
34+
find_library(SECURITY Security "/")
35+
set(EXTRALINKS ${COREFOUNDATION} ${SECURITY})
3436
else()
3537
set(SOURCES ${SOURCES} pplx/linux/pplxlinux.cpp)
3638
endif()
@@ -46,6 +48,7 @@ elseif(WIN32)
4648
http/common/http_msg.cpp
4749
http/common/http_helpers.cpp
4850
http/client/http_msg_client.cpp
51+
http/client/x509_cert_utilities.cpp
4952
http/listener/http_listener.cpp
5053
http/listener/http_msg_listen.cpp
5154
http/listener/http_server_api.cpp
@@ -82,7 +85,6 @@ target_link_libraries(${Casablanca_LIBRARY}
8285
${Boost_LOCALE_LIBRARY}
8386
${Boost_REGEX_LIBRARY}
8487
${Boost_RANDOM_LIBRARY}
85-
${COREFOUNDATION}
8688
${EXTRALINKS}
8789
)
8890

Release/src/http/client/http_linux.cpp

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "stdafx.h"
3131

3232
#include "cpprest/http_client_impl.h"
33+
#include "cpprest/x509_cert_utilities.h"
3334
#include <unordered_set>
3435

3536
using boost::asio::ip::tcp;
@@ -280,7 +281,7 @@ namespace web { namespace http
280281
bool m_timedout;
281282
boost::asio::streambuf m_body_buf;
282283
boost::asio::deadline_timer m_timeout_timer;
283-
284+
284285
virtual ~linux_client_request_context();
285286

286287
void handle_timeout_timer(const boost::system::error_code& ec)
@@ -452,7 +453,10 @@ namespace web { namespace http
452453

453454
private:
454455
tcp::resolver m_resolver;
455-
456+
#if defined(__APPLE__)
457+
bool m_openssl_failed;
458+
#endif
459+
456460
static bool _check_streambuf(std::shared_ptr<linux_client_request_context> ctx, concurrency::streams::streambuf<uint8_t> rdbuf, const utility::char_t* msg)
457461
{
458462
if (!rdbuf.is_open())
@@ -485,7 +489,10 @@ namespace web { namespace http
485489
if(client_config().validate_certificates())
486490
{
487491
ctx->m_ssl_stream->set_verify_mode(boost::asio::ssl::context::verify_peer);
488-
ctx->m_ssl_stream->set_verify_callback(boost::asio::ssl::rfc2818_verification(m_uri.host()));
492+
ctx->m_ssl_stream->set_verify_callback(boost::bind(&linux_client::handle_cert_verification, shared_from_this(), _1, _2));
493+
#if defined(__APPLE__)
494+
m_openssl_failed = false;
495+
#endif
489496
}
490497
else
491498
{
@@ -536,7 +543,10 @@ namespace web { namespace http
536543
if(client_config().validate_certificates())
537544
{
538545
ctx->m_ssl_stream->set_verify_mode(boost::asio::ssl::context::verify_peer);
539-
ctx->m_ssl_stream->set_verify_callback(boost::asio::ssl::rfc2818_verification(m_uri.host()));
546+
ctx->m_ssl_stream->set_verify_callback(boost::bind(&linux_client::handle_cert_verification, shared_from_this(), _1, _2));
547+
#if defined(__APPLE__)
548+
m_openssl_failed = false;
549+
#endif
540550
}
541551
else
542552
{
@@ -548,6 +558,72 @@ namespace web { namespace http
548558
}
549559
}
550560

561+
bool handle_cert_verification(bool preverified, boost::asio::ssl::verify_context &ctx)
562+
{
563+
// OpenSSL calls the verification callback once per certificate in the chain,
564+
// starting with the root CA certificate. The 'leaf', non-Certificate Authority (CA)
565+
// certificate, i.e. actual server certificate is at the '0' position in the
566+
// certificate chain, the rest are optional intermediate certificates, followed
567+
// finally by the root CA self signed certificate.
568+
569+
#if defined(__APPLE__)
570+
if(!preverified)
571+
{
572+
m_openssl_failed = true;
573+
}
574+
if(m_openssl_failed)
575+
{
576+
// On OS X, iOS, and Android, OpenSSL doesn't have access to where the OS
577+
// stores keychains. If OpenSSL fails we will doing verification at the
578+
// end using the whole certificate chain so wait until the 'leaf' cert.
579+
// For now return true so OpenSSL continues down the certificate chain.
580+
X509_STORE_CTX *storeContext = ctx.native_handle();
581+
int currentDepth = X509_STORE_CTX_get_error_depth(storeContext);
582+
if(currentDepth != 0)
583+
{
584+
return true;
585+
}
586+
587+
STACK_OF(X509) *certStack = X509_STORE_CTX_get_chain(storeContext);
588+
const int numCerts = sk_X509_num(certStack);
589+
if(numCerts < 0)
590+
{
591+
return false;
592+
}
593+
594+
std::vector<std::string> certChain;
595+
certChain.reserve(numCerts);
596+
for(int i = 0; i < numCerts; ++i)
597+
{
598+
X509 *cert = sk_X509_value(certStack, i);
599+
600+
// Encode into DER format into raw memory.
601+
int len = i2d_X509(cert, nullptr);
602+
if(len < 0)
603+
{
604+
return false;
605+
}
606+
607+
std::string certData;
608+
certData.resize(len);
609+
unsigned char * buffer = reinterpret_cast<unsigned char *>(&certData[0]);
610+
len = i2d_X509(cert, &buffer);
611+
if(len < 0)
612+
{
613+
return false;
614+
}
615+
616+
certChain.push_back(std::move(certData));
617+
}
618+
619+
return verify_X509_cert_chain(certChain, m_uri.host());
620+
}
621+
#endif
622+
623+
boost::asio::ssl::rfc2818_verification rfc2818(m_uri.host());
624+
return rfc2818(preverified, ctx);
625+
}
626+
551627
void handle_handshake(const boost::system::error_code& ec, std::shared_ptr<linux_client_request_context> ctx)
552628
{
553629
if (!ec)
@@ -556,7 +632,7 @@ namespace web { namespace http
556632
}
557633
else
558634
{
559-
ctx->report_error("Error code in handle_handshake is ", ec, httpclient_errorcode_context::handshake);
635+
ctx->report_error("Error in SSL handshake", ec, httpclient_errorcode_context::handshake);
560636
}
561637
}
562638

0 commit comments

Comments
 (0)