Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Work in progress] Certificate pinning support #1659

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
6 changes: 6 additions & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ LeonidCSIT
kreuzerkrieg
evanc
Jesse Towner (jwtowner)
Atul Bagga (atbagga)

Abinsula s.r.l.
Gianfranco Costamagna (LocutusOfBorg)
Expand All @@ -36,10 +37,15 @@ Gery Vessere ([email protected])
Cisco Systems
Gergely Lukacsy (glukacsy)
Chris Deering (deeringc)
Chris O'Gorman (chogorma)

Ocedo GmbH
Henning Pfeiffer (megaposer)

neXenio GmbH
Patrik Fiedler (xqp)
René Meusel (reneme)

thomasschaub

Trimble
Expand Down
45 changes: 45 additions & 0 deletions Release/include/cpprest/certificate_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/***
* Copyright (C) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
*
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* Certificate info
*
* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/

#pragma once

#include <string>
#include <vector>

namespace web
{
namespace http
{
namespace client
{
using CertificateChain = std::vector<std::vector<unsigned char>>;

struct certificate_info
{
std::string host_name;
CertificateChain certificate_chain;
long certificate_error {0};
bool verified {false};

certificate_info(const std::string host) : host_name(host) { }
certificate_info(const std::string host, CertificateChain chain, long error = 0)
: host_name(host), certificate_chain(chain), certificate_error(error)
{
}
};

using CertificateChainFunction = std::function<bool(const std::shared_ptr<certificate_info> certificate_Info)>;

} // namespace client
} // namespace http
} // namespace web
24 changes: 24 additions & 0 deletions Release/include/cpprest/http_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ typedef void* native_handle;
#endif // __cplusplus_winrt

#include "cpprest/asyncrt_utils.h"
#include "cpprest/certificate_info.h"
#include "cpprest/details/basic_types.h"
#include "cpprest/details/web_utilities.h"
#include "cpprest/http_msg.h"
Expand Down Expand Up @@ -101,6 +102,7 @@ class http_client_config
#if !defined(__cplusplus_winrt)
, m_validate_certificates(true)
#endif
, m_certificate_chain_callback([](const std::shared_ptr<certificate_info>&) -> bool { return true; })
#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO)
, m_tlsext_sni_enabled(true)
#endif
Expand Down Expand Up @@ -362,6 +364,27 @@ class http_client_config
if (m_set_user_nativehandle_options) m_set_user_nativehandle_options(handle);
}


/// <summary>
/// Set the certificate chain callback. If set, HTTP client will call this callback in a blocking manner during HTTP
/// connection.
/// </summary>
void set_user_certificate_chain_callback(const CertificateChainFunction& callback)
{
m_certificate_chain_callback = callback;
}

/// <summary>
/// Invokes the certificate chain callback.
/// </summary>
/// <param name="certificate_info">Pointer to the certificate_info struct that has the certificate
/// information.</param> <returns>True if the consumer code allows the connection, false otherwise. False will
/// terminate the HTTP connection.</returns>
bool invoke_certificate_chain_callback(const std::shared_ptr<certificate_info>& certificate_Info) const
{
return m_certificate_chain_callback(certificate_Info);
}

#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO)
/// <summary>
/// Sets a callback to enable custom setting of the ssl context, at construction time.
Expand Down Expand Up @@ -416,6 +439,7 @@ class http_client_config
bool m_validate_certificates;
#endif

CertificateChainFunction m_certificate_chain_callback;
std::function<void(native_handle)> m_set_user_nativehandle_options;
std::function<void(native_handle)> m_set_user_nativesessionhandle_options;

Expand Down
22 changes: 22 additions & 0 deletions Release/include/cpprest/oauth2.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#ifndef CASA_OAUTH2_H
#define CASA_OAUTH2_H

#include "cpprest/certificate_info.h"
#include "cpprest/details/web_utilities.h"
#include "cpprest/http_msg.h"

Expand Down Expand Up @@ -219,6 +220,8 @@ class oauth2_config
, m_bearer_auth(true)
, m_http_basic_auth(true)
, m_access_token_key(details::oauth2_strings::access_token)
, m_certificate_chain_callback([](const std::shared_ptr<web::http::client::certificate_info>&) -> bool
{ return true; })
{
}

Expand Down Expand Up @@ -480,6 +483,23 @@ class oauth2_config
/// </summary>
void set_user_agent(utility::string_t user_agent) { m_user_agent = std::move(user_agent); }

/// <summary>
/// Set the certificate chain callback to be used by the http client.
/// </summary>
void set_user_certificate_chain_callback(const web::http::client::CertificateChainFunction& callback)
{
m_certificate_chain_callback = callback;
}

/// <summary>
/// Get the cert chain callback.
/// </summary>
/// <returns>A reference to cert chain callback user by the client.</returns>
const web::http::client::CertificateChainFunction& user_certificate_chain_callback()
{
return m_certificate_chain_callback;
}

private:
friend class web::http::client::http_client_config;
friend class web::http::oauth2::details::oauth2_handler;
Expand Down Expand Up @@ -523,6 +543,8 @@ class oauth2_config
oauth2_token m_token;

utility::nonce_generator m_state_generator;

web::http::client::CertificateChainFunction m_certificate_chain_callback;
};

} // namespace experimental
Expand Down
32 changes: 31 additions & 1 deletion Release/include/cpprest/ws_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
#if !defined(CPPREST_EXCLUDE_WEBSOCKETS)

#include "cpprest/asyncrt_utils.h"
#include "cpprest/certificate_info.h"
#include "cpprest/details/web_utilities.h"
#include "cpprest/http_headers.h"
#include "cpprest/json.h"
#include "cpprest/uri.h"
#include "cpprest/ws_msg.h"
#include "pplx/pplxtasks.h"
Expand Down Expand Up @@ -79,7 +81,13 @@ class websocket_client_config
/// <summary>
/// Creates a websocket client configuration with default settings.
/// </summary>
websocket_client_config() : m_sni_enabled(true), m_validate_certificates(true) {}
websocket_client_config()
: m_certificate_chain_callback([](const std::shared_ptr<http::client::certificate_info>&) -> bool
{ return true; })
, m_sni_enabled(true)
, m_validate_certificates(true)
{
}

/// <summary>
/// Get the web proxy object
Expand Down Expand Up @@ -199,13 +207,35 @@ class websocket_client_config
}
#endif

/// Set the certificate chain callback. If set, HTTP client will call this callback in a blocking manner during HTTP
/// connection.
/// </summary>
void set_user_certificate_chain_callback(const http::client::CertificateChainFunction& callback)
{
m_certificate_chain_callback = callback;
}

/// <summary>
/// Invokes the certificate chain callback.
/// </summary>
/// <param name="certificate_info">Pointer to the certificate_info struct that has the certificate
/// information.</param> <returns>True if the consumer code allows the connection, false otherwise. False will
/// terminate the HTTP connection.</returns>
bool invoke_certificate_chain_callback(
const std::shared_ptr<http::client::certificate_info>& certificate_Info) const
{
return m_certificate_chain_callback(certificate_Info);
}

private:
web::web_proxy m_proxy;
web::credentials m_credentials;
web::http::http_headers m_headers;
bool m_sni_enabled;
utf8string m_sni_hostname;
bool m_validate_certificates;
http::client::CertificateChainFunction m_certificate_chain_callback;

#if !defined(_WIN32) || !defined(__cplusplus_winrt)
std::function<void(boost::asio::ssl::context&)> m_ssl_context_callback;
#endif
Expand Down
Loading