Skip to content

Commit 8c0d858

Browse files
committed
Encrypting passwords in memory when running on Windows desktop.
1 parent 470a9f7 commit 8c0d858

File tree

8 files changed

+197
-117
lines changed

8 files changed

+197
-117
lines changed

Release/include/cpprest/oauth1.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ namespace web
3535
{
3636
namespace http
3737
{
38+
namespace client
39+
{
40+
// Forward declaration to avoid circular include dependency.
41+
class http_client_config;
42+
}
43+
3844
/// oAuth 1.0 library.
3945
namespace oauth1
4046
{

Release/include/cpprest/oauth2.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ namespace web
3535
{
3636
namespace http
3737
{
38+
namespace client
39+
{
40+
// Forward declaration to avoid circular include dependency.
41+
class http_client_config;
42+
}
43+
3844
/// oAuth 2.0 library.
3945
namespace oauth2
4046
{

Release/include/cpprest/web_utilities.h

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -32,56 +32,77 @@
3232

3333
namespace web
3434
{
35-
class web_proxy;
36-
namespace http { namespace client {
37-
class http_client_config;
38-
}}
39-
40-
namespace experimental { namespace websockets { namespace client {
41-
class websocket_client_config;
42-
}}}
35+
namespace details
36+
{
37+
#if defined(_MS_WINDOWS) && !defined(__cplusplus_winrt)
38+
class win32_encryption
39+
{
40+
public:
41+
win32_encryption() {}
42+
_ASYNCRTIMP win32_encryption(const std::wstring &data);
43+
_ASYNCRTIMP ~win32_encryption();
44+
_ASYNCRTIMP std::wstring decrypt() const;
45+
private:
46+
std::vector<char> m_buffer;
47+
size_t m_numCharacters;
48+
};
49+
#endif
50+
}
4351

4452
/// <summary>
45-
/// credentials represents a set of user credentials (username and password) to be used
46-
/// for the client and proxy authentication
53+
/// Represents a set of user credentials (user name and password) to be used
54+
/// for authentication.
4755
/// </summary>
4856
class credentials
4957
{
5058
public:
51-
credentials(utility::string_t username, utility::string_t password) :
52-
m_is_set(true),
59+
/// <summary>
60+
/// Constructs and empty set of credentials without a user name or password.
61+
/// </summary>
62+
credentials() {}
63+
64+
/// <summary>
65+
/// Constructs credentials from given user name and password.
66+
/// </summary>
67+
/// <param name="username">User name as a string.</param>
68+
/// <param name="password">Password as a string.</param>
69+
credentials(utility::string_t username, const utility::string_t &password) :
5370
m_username(std::move(username)),
54-
m_password(std::move(password))
71+
m_password(password)
5572
{}
5673

5774
/// <summary>
5875
/// The user name associated with the credentials.
5976
/// </summary>
60-
/// <returns>A reference to the username string.</returns>
61-
const utility::string_t& username() const { return m_username; }
77+
/// <returns>A string containing the user name.</returns>
78+
const utility::string_t &username() const { return m_username; }
6279

6380
/// <summary>
6481
/// The password for the user name associated with the credentials.
6582
/// </summary>
66-
/// <returns>A reference to the password string.</returns>
67-
const utility::string_t& password() const { return m_password; }
83+
/// <returns>A string containing the password.</returns>
84+
utility::string_t password() const
85+
{
86+
#if defined(_MS_WINDOWS) && !defined(__cplusplus_winrt)
87+
return m_password.decrypt();
88+
#else
89+
return m_password;
90+
#endif
91+
}
6892

6993
/// <summary>
7094
/// Checks if credentials have been set
7195
/// </summary>
72-
/// <returns><c>true</c> if username and password is set, <c>false</c> otherwise.</returns>
73-
bool is_set() const { return m_is_set; }
96+
/// <returns><c>true</c> if user name and password is set, <c>false</c> otherwise.</returns>
97+
bool is_set() const { return !m_username.empty(); }
7498

7599
private:
76-
friend class web::web_proxy;
77-
friend class web::http::client::http_client_config;
78-
friend class web::experimental::websockets::client::websocket_client_config;
79-
80-
credentials() : m_is_set(false) {}
81-
82-
bool m_is_set;
83-
utility::string_t m_username;
84-
utility::string_t m_password;
100+
::utility::string_t m_username;
101+
#if defined(_MS_WINDOWS) && !defined(__cplusplus_winrt)
102+
::web::details::win32_encryption m_password;
103+
#else
104+
::utility::string_t m_password;
105+
#endif
85106
};
86107

87108
/// <summary>
@@ -160,7 +181,7 @@ class web_proxy
160181
bool is_specified() const { return m_mode == user_provided_; }
161182

162183
private:
163-
uri m_address;
184+
web::uri m_address;
164185
web_proxy_mode_internal m_mode;
165186
web::credentials m_credentials;
166187
};

Release/src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ if(UNIX)
88
json/json_parsing.cpp
99
json/json_serialization.cpp
1010
utilities/asyncrt_utils.cpp
11+
utilities/web_utilities.cpp
1112
pplx/pplx.cpp
1213
pplx/threadpool.cpp
1314
uri/uri.cpp
@@ -46,6 +47,7 @@ elseif(WIN32)
4647
json/json_parsing.cpp
4748
json/json_serialization.cpp
4849
utilities/asyncrt_utils.cpp
50+
utilities/web_utilities.cpp
4951
uri/uri.cpp
5052
uri/uri_builder.cpp
5153
uri/uri_parser.cpp

Release/src/build/sources.proj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@
182182
<ClCompile Include="$(CasablancaSrcDir)\utilities\asyncrt_utils.cpp">
183183
<Filter>Source Files</Filter>
184184
</ClCompile>
185+
<ClCompile Include="$(CasablancaSrcDir)\utilities\web_utilities.cpp">
186+
<Filter>Source Files</Filter>
187+
</ClCompile>
185188
<ClCompile Include="$(CasablancaSrcDir)\utilities\base64.cpp">
186189
<Filter>Source Files</Filter>
187190
</ClCompile>

Release/src/http/client/http_win7.cpp

Lines changed: 30 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ class winhttp_client : public _http_client_communicator
521521
// If credentials are specified, use autologon policy: WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH
522522
// => default credentials are not used.
523523
// Else, the default autologon policy WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM will be used.
524-
if ( !client_config().credentials().username().empty() )
524+
if (!client_config().credentials().is_set())
525525
{
526526
DWORD data = WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH;
527527

@@ -674,17 +674,6 @@ class winhttp_client : public _http_client_communicator
674674
}
675675
}
676676

677-
static bool has_credentials(winhttp_request_context * p_request_context)
678-
{
679-
auto has_proxy_credentials = !p_request_context->m_http_client->client_config().proxy().credentials().username().empty()
680-
&& !p_request_context->m_http_client->client_config().proxy().credentials().password().empty();
681-
682-
auto has_server_credentials = !p_request_context->m_http_client->client_config().credentials().username().empty()
683-
&& !p_request_context->m_http_client->client_config().credentials().password().empty();
684-
685-
return has_proxy_credentials || has_server_credentials;
686-
}
687-
688677
// Helper function to query/read next part of response data from winhttp.
689678
static void read_next_response_chunk(winhttp_request_context *pContext, DWORD bytesRead, bool firstRead=false)
690679
{
@@ -865,7 +854,7 @@ class winhttp_client : public _http_client_communicator
865854
}
866855
}
867856

868-
// Returns true if we handle successfuly and resending the request
857+
// Returns true if we handle successfully and resending the request
869858
// or false if we fail to handle.
870859
static bool handle_authentication_failure(
871860
HINTERNET hRequestHandle,
@@ -878,22 +867,12 @@ class winhttp_client : public _http_client_communicator
878867
_ASSERTE(response.status_code() == status_codes::Unauthorized || response.status_code() == status_codes::ProxyAuthRequired
879868
|| error == ERROR_WINHTTP_RESEND_REQUEST);
880869

881-
bool got_credentials = false;
882-
BOOL results;
883-
DWORD dwSupportedSchemes;
884-
DWORD dwFirstScheme;
885-
DWORD dwTarget = 0;
886-
DWORD dwSelectedScheme = 0;
887-
string_t username;
888-
string_t password;
889-
890870
// Check if the saved read position is valid
891871
auto rdpos = p_request_context->m_startingPosition;
892872
if (rdpos != static_cast<std::char_traits<uint8_t>::pos_type>(std::char_traits<uint8_t>::eof()))
893873
{
894-
auto rbuf = p_request_context->_get_readbuffer();
895-
896874
// Try to seek back to the saved read position
875+
auto rbuf = p_request_context->_get_readbuffer();
897876
if (rbuf.seekpos(rdpos, std::ios::ios_base::in) != rdpos)
898877
{
899878
return false;
@@ -904,66 +883,54 @@ class winhttp_client : public _http_client_communicator
904883
// we cannot call WinHttpQueryAuthSchemes and WinHttpSetCredentials.
905884
if (error != ERROR_WINHTTP_RESEND_REQUEST)
906885
{
907-
// The proxy requires authentication. Sending credentials...
908-
// Obtain the supported and preferred schemes.
909-
results = WinHttpQueryAuthSchemes( hRequestHandle,
910-
&dwSupportedSchemes,
911-
&dwFirstScheme,
912-
&dwTarget );
886+
DWORD dwSupportedSchemes;
887+
DWORD dwFirstScheme;
888+
DWORD dwSelectedScheme = 0;
889+
DWORD dwAuthTarget;
890+
credentials cred;
913891

914-
if (!results)
892+
// Obtain the supported and preferred schemes.
893+
if(!WinHttpQueryAuthSchemes(
894+
hRequestHandle,
895+
&dwSupportedSchemes,
896+
&dwFirstScheme,
897+
&dwAuthTarget))
915898
{
916899
// This will return the authentication failure to the user, without reporting fatal errors
917900
return false;
918901
}
919902

920-
dwSelectedScheme = ChooseAuthScheme( dwSupportedSchemes);
921-
if( dwSelectedScheme == 0 )
903+
dwSelectedScheme = ChooseAuthScheme(dwSupportedSchemes);
904+
if(dwSelectedScheme == 0)
922905
{
923906
// This will return the authentication failure to the user, without reporting fatal errors
924907
return false;
925908
}
926909

927-
if(response.status_code() == status_codes::ProxyAuthRequired /*407*/ && !p_request_context->m_proxy_authentication_tried)
910+
if (dwAuthTarget == WINHTTP_AUTH_TARGET_SERVER && !p_request_context->m_server_authentication_tried)
928911
{
929-
// See if the credentials on the proxy were set. If not, there are no credentials to supply hence we cannot resend
930-
web_proxy proxy = p_request_context->m_http_client->client_config().proxy();
931-
// No need to check if proxy is disabled, because disabled proxies cannot have credentials set on them
932-
credentials cred = proxy.credentials();
933-
if(cred.is_set())
934-
{
935-
username = cred.username();
936-
password = cred.password();
937-
dwTarget = WINHTTP_AUTH_TARGET_PROXY;
938-
got_credentials = !username.empty();
939-
p_request_context->m_proxy_authentication_tried = true;
940-
}
912+
cred = p_request_context->m_http_client->client_config().credentials();
913+
p_request_context->m_server_authentication_tried = true;
941914
}
942-
else if(response.status_code() == status_codes::Unauthorized /*401*/ && !p_request_context->m_server_authentication_tried)
915+
else if (dwAuthTarget == WINHTTP_AUTH_TARGET_PROXY && !p_request_context->m_proxy_authentication_tried)
943916
{
944-
username = p_request_context->m_http_client->client_config().credentials().username();
945-
password = p_request_context->m_http_client->client_config().credentials().password();
946-
dwTarget = WINHTTP_AUTH_TARGET_SERVER;
947-
got_credentials = !username.empty();
948-
p_request_context->m_server_authentication_tried = true;
917+
cred = p_request_context->m_http_client->client_config().proxy().credentials();
918+
p_request_context->m_proxy_authentication_tried = true;
949919
}
950920

951-
if(!got_credentials)
921+
// No credentials found so can't resend.
922+
if (!cred.is_set())
952923
{
953-
// Either we cannot resend, or the user did not provide non-empty credentials.
954-
// Return the authentication failure to the user.
955924
return false;
956925
}
957-
958-
results = WinHttpSetCredentials( hRequestHandle,
959-
dwTarget,
926+
if (!WinHttpSetCredentials(
927+
hRequestHandle,
928+
dwAuthTarget,
960929
dwSelectedScheme,
961-
username.c_str(),
962-
password.c_str(),
963-
nullptr );
964-
if(!results)
930+
cred.username().c_str(),
931+
cred.password().c_str(),
932+
nullptr))
965933
{
966-
// This will return the authentication failure to the user, without reporting fatal errors
967934
return false;
968935
}
969936
}

0 commit comments

Comments
 (0)