mirror of https://github.com/grpc/grpc.git
commit
b954c98dbf
34 changed files with 1247 additions and 1832 deletions
@ -0,0 +1,80 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include <string.h> |
||||
|
||||
#include "src/core/security/credentials.h" |
||||
#include "src/core/security/security_context.h" |
||||
#include "src/core/surface/lame_client.h" |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/useful.h> |
||||
|
||||
grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, |
||||
const char *target, |
||||
const grpc_channel_args *args) { |
||||
grpc_secure_channel_factory factories[] = { |
||||
{GRPC_CREDENTIALS_TYPE_SSL, grpc_ssl_channel_create}, |
||||
{GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY, |
||||
grpc_fake_transport_security_channel_create}}; |
||||
return grpc_secure_channel_create_with_factories( |
||||
factories, GPR_ARRAY_SIZE(factories), creds, target, args); |
||||
} |
||||
|
||||
grpc_server *grpc_secure_server_create(grpc_server_credentials *creds, |
||||
grpc_completion_queue *cq, |
||||
const grpc_channel_args *args) { |
||||
grpc_security_status status = GRPC_SECURITY_ERROR; |
||||
grpc_security_context *ctx = NULL; |
||||
grpc_server *server = NULL; |
||||
if (creds == NULL) return NULL; /* TODO(ctiller): Return lame server. */ |
||||
|
||||
if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) { |
||||
status = grpc_ssl_server_security_context_create( |
||||
grpc_ssl_server_credentials_get_config(creds), &ctx); |
||||
} else if (!strcmp(creds->type, |
||||
GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY)) { |
||||
ctx = grpc_fake_server_security_context_create(); |
||||
status = GRPC_SECURITY_OK; |
||||
} |
||||
|
||||
if (status != GRPC_SECURITY_OK) { |
||||
gpr_log(GPR_ERROR, |
||||
"Unable to create secure server with credentials of type %s.", |
||||
creds->type); |
||||
return NULL; /* TODO(ctiller): Return lame server. */ |
||||
} |
||||
server = grpc_secure_server_create_internal(cq, args, ctx); |
||||
grpc_security_context_unref(ctx); |
||||
return server; |
||||
} |
@ -1,151 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/tsi/fake_transport_security.h" |
||||
|
||||
#include "src/core/tsi/transport_security_test_lib.h" |
||||
#include <gtest/gtest.h> |
||||
#include "util/random/permute-inl.h" |
||||
|
||||
namespace { |
||||
|
||||
void CheckStringPeerProperty(const tsi_peer& peer, int property_index, |
||||
const char* expected_name, |
||||
const char* expected_value) { |
||||
EXPECT_LT(property_index, peer.property_count); |
||||
const tsi_peer_property* property = &peer.properties[property_index]; |
||||
EXPECT_EQ(TSI_PEER_PROPERTY_TYPE_STRING, property->type); |
||||
EXPECT_EQ(string(expected_name), string(property->name)); |
||||
EXPECT_EQ(string(expected_value), |
||||
string(property->value.string.data, property->value.string.length)); |
||||
} |
||||
|
||||
class FakeTransportSecurityTest : public tsi::test::TransportSecurityTest { |
||||
protected: |
||||
void SetupHandshakers() override { |
||||
client_handshaker_.reset(tsi_create_fake_handshaker(1)); |
||||
server_handshaker_.reset(tsi_create_fake_handshaker(0)); |
||||
} |
||||
|
||||
void CheckPeer(tsi_handshaker* handshaker) { |
||||
tsi_peer peer; |
||||
EXPECT_EQ(TSI_OK, tsi_handshaker_extract_peer(handshaker, &peer)); |
||||
EXPECT_EQ(1, peer.property_count); |
||||
CheckStringPeerProperty(peer, 0, TSI_CERTIFICATE_TYPE_PEER_PROPERTY, |
||||
TSI_FAKE_CERTIFICATE_TYPE); |
||||
tsi_peer_destruct(&peer); |
||||
} |
||||
|
||||
void CheckHandshakeResults() override { |
||||
CheckPeer(client_handshaker_.get()); |
||||
CheckPeer(server_handshaker_.get()); |
||||
} |
||||
|
||||
const tsi::test::TestConfig* config() { |
||||
return &config_; |
||||
} |
||||
|
||||
tsi::test::TestConfig config_; |
||||
}; |
||||
|
||||
TEST_F(FakeTransportSecurityTest, Handshake) { |
||||
PerformHandshake(); |
||||
} |
||||
|
||||
TEST_F(FakeTransportSecurityTest, HandshakeSmallBuffer) { |
||||
config_.handshake_buffer_size = 3; |
||||
PerformHandshake(); |
||||
} |
||||
TEST_F(FakeTransportSecurityTest, PingPong) { |
||||
PingPong(); |
||||
} |
||||
|
||||
TEST_F(FakeTransportSecurityTest, RoundTrip) { |
||||
config_.client_message = big_message_; |
||||
config_.server_message = small_message_; |
||||
DoRoundTrip(); |
||||
} |
||||
|
||||
TEST_F(FakeTransportSecurityTest, RoundTripSmallMessageBuffer) { |
||||
config_.message_buffer_allocated_size = 42; |
||||
config_.client_message = big_message_; |
||||
config_.server_message = small_message_; |
||||
DoRoundTrip(); |
||||
} |
||||
|
||||
TEST_F(FakeTransportSecurityTest, RoundTripSmallProtectedBufferSize) { |
||||
config_.protected_buffer_size = 37; |
||||
config_.client_message = big_message_; |
||||
config_.server_message = small_message_; |
||||
DoRoundTrip(); |
||||
} |
||||
|
||||
TEST_F(FakeTransportSecurityTest, RoundTripSmallReadBufferSize) { |
||||
config_.read_buffer_allocated_size = 41; |
||||
config_.client_message = big_message_; |
||||
config_.server_message = small_message_; |
||||
DoRoundTrip(); |
||||
} |
||||
|
||||
TEST_F(FakeTransportSecurityTest, RoundTripSmallClientFrames) { |
||||
config_.set_client_max_output_protected_frame_size(39); |
||||
config_.client_message = big_message_; |
||||
config_.server_message = small_message_; |
||||
DoRoundTrip(); |
||||
} |
||||
|
||||
TEST_F(FakeTransportSecurityTest, RoundTripSmallServerFrames) { |
||||
config_.set_server_max_output_protected_frame_size(43); |
||||
config_.client_message = small_message_; |
||||
config_.server_message = big_message_; |
||||
DoRoundTrip(); |
||||
} |
||||
|
||||
TEST_F(FakeTransportSecurityTest, RoundTripOddBufferSizes) { |
||||
int odd_sizes[] = {33, 67, 135, 271, 523}; |
||||
RandomPermutation<int> permute(odd_sizes, arraysize(odd_sizes), |
||||
random_.get()); |
||||
permute.Permute(); |
||||
LOG(ERROR) << odd_sizes[0] << "\t" << odd_sizes[1] << "\t" << odd_sizes[2] |
||||
<< "\t" << odd_sizes[3] << "\t" << odd_sizes[4]; |
||||
config_.message_buffer_allocated_size = odd_sizes[0]; |
||||
config_.protected_buffer_size = odd_sizes[1]; |
||||
config_.read_buffer_allocated_size = odd_sizes[2]; |
||||
config_.set_client_max_output_protected_frame_size(odd_sizes[3]); |
||||
config_.set_server_max_output_protected_frame_size(odd_sizes[4]); |
||||
config_.client_message = big_message_; |
||||
config_.server_message = small_message_; |
||||
DoRoundTrip(); |
||||
} |
||||
|
||||
} // namespace
|
@ -1,534 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include <memory> |
||||
|
||||
#include "base/commandlineflags.h" |
||||
#include "file/base/helpers.h" |
||||
#include "file/base/options.pb.h" |
||||
#include "file/base/path.h" |
||||
#include "src/core/tsi/transport_security_test_lib.h" |
||||
#include "src/core/tsi/ssl_transport_security.h" |
||||
#include "util/random/permute-inl.h" |
||||
|
||||
namespace { |
||||
|
||||
const char kTestCredsDir[] = |
||||
"/internal/tsi/test_creds/"; |
||||
|
||||
enum AlpnMode { |
||||
NO_ALPN, |
||||
ALPN_CLIENT_NO_SERVER, |
||||
ALPN_SERVER_NO_CLIENT, |
||||
ALPN_CLIENT_SERVER_OK, |
||||
ALPN_CLIENT_SERVER_MISMATCH |
||||
}; |
||||
|
||||
class SslTestConfig : public tsi::test::TestConfig { |
||||
public: |
||||
SslTestConfig() |
||||
: do_client_authentication(false), |
||||
subject_name_indication(nullptr), |
||||
use_bad_client_cert(false), |
||||
use_bad_server_cert(false), |
||||
alpn_mode(NO_ALPN) {} |
||||
bool do_client_authentication; |
||||
const char* subject_name_indication; |
||||
bool use_bad_client_cert; |
||||
bool use_bad_server_cert; |
||||
AlpnMode alpn_mode; |
||||
}; |
||||
|
||||
struct TsiSslHandshakerFactoryDeleter { |
||||
inline void operator()(tsi_ssl_handshaker_factory* ptr) { |
||||
tsi_ssl_handshaker_factory_destroy(ptr); |
||||
} |
||||
}; |
||||
typedef std::unique_ptr<tsi_ssl_handshaker_factory, |
||||
TsiSslHandshakerFactoryDeleter> |
||||
TsiSslHandshakerFactoryUniquePtr; |
||||
|
||||
class SslTransportSecurityTest : public tsi::test::TransportSecurityTest { |
||||
protected: |
||||
void CheckSubjectAltName(const tsi_peer_property& property, |
||||
const string& expected_subject_alt_name) { |
||||
EXPECT_EQ(property.type, TSI_PEER_PROPERTY_TYPE_STRING); |
||||
EXPECT_EQ(property.name, nullptr); |
||||
EXPECT_EQ( |
||||
string(property.value.string.data, property.value.string.length), |
||||
expected_subject_alt_name); |
||||
} |
||||
|
||||
const tsi_peer_property* CheckBasicAuthenticatedPeerAndGetCommonName( |
||||
const tsi_peer* peer) { |
||||
const tsi_peer_property* property = |
||||
tsi_peer_get_property_by_name(peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY); |
||||
EXPECT_NE(property, nullptr); |
||||
EXPECT_EQ(property->type, TSI_PEER_PROPERTY_TYPE_STRING); |
||||
EXPECT_EQ( |
||||
string(property->value.string.data, property->value.string.length), |
||||
string(TSI_X509_CERTIFICATE_TYPE)); |
||||
property = tsi_peer_get_property_by_name( |
||||
peer, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY); |
||||
EXPECT_EQ(property->type, TSI_PEER_PROPERTY_TYPE_STRING); |
||||
return property; |
||||
} |
||||
|
||||
void CheckServer0Peer(tsi_peer* peer) { |
||||
const tsi_peer_property* property = |
||||
CheckBasicAuthenticatedPeerAndGetCommonName(peer); |
||||
EXPECT_EQ( |
||||
string(property->value.string.data, property->value.string.length), |
||||
string("*.test.google.com.au")); |
||||
property = tsi_peer_get_property_by_name( |
||||
peer, TSI_X509_SUBJECT_ALTERNATIVE_NAMES_PEER_PROPERTY); |
||||
EXPECT_EQ(property->type, TSI_PEER_PROPERTY_TYPE_LIST); |
||||
EXPECT_EQ(property->value.list.child_count, 0); |
||||
EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "foo.test.google.com.au")); |
||||
EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "bar.test.google.com.au")); |
||||
EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "bar.test.google.blah")); |
||||
EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "foo.bar.test.google.com.au")); |
||||
EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "test.google.com.au")); |
||||
tsi_peer_destruct(peer); |
||||
} |
||||
|
||||
void CheckServer1Peer(tsi_peer* peer) { |
||||
const tsi_peer_property* property = |
||||
CheckBasicAuthenticatedPeerAndGetCommonName(peer); |
||||
EXPECT_EQ( |
||||
string(property->value.string.data, property->value.string.length), |
||||
string("*.test.google.com")); |
||||
property = tsi_peer_get_property_by_name( |
||||
peer, TSI_X509_SUBJECT_ALTERNATIVE_NAMES_PEER_PROPERTY); |
||||
EXPECT_EQ(property->type, TSI_PEER_PROPERTY_TYPE_LIST); |
||||
EXPECT_EQ(property->value.list.child_count, 3); |
||||
CheckSubjectAltName(property->value.list.children[0], "*.test.google.fr"); |
||||
CheckSubjectAltName(property->value.list.children[1], |
||||
"waterzooi.test.google.be"); |
||||
CheckSubjectAltName(property->value.list.children[2], "*.test.youtube.com"); |
||||
EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "foo.test.google.com")); |
||||
EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "bar.test.google.fr")); |
||||
EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "waterzooi.test.google.be")); |
||||
EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "foo.test.youtube.com")); |
||||
EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "bar.foo.test.google.com")); |
||||
EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "test.google.fr")); |
||||
EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "tartines.test.google.be")); |
||||
EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "tartines.youtube.com")); |
||||
tsi_peer_destruct(peer); |
||||
} |
||||
|
||||
void CheckClientPeer(tsi_peer* peer, bool is_authenticated) { |
||||
if (!is_authenticated) { |
||||
EXPECT_EQ(peer->property_count, |
||||
config_.alpn_mode == ALPN_CLIENT_SERVER_OK ? 1 : 0); |
||||
} else { |
||||
const tsi_peer_property* property = |
||||
CheckBasicAuthenticatedPeerAndGetCommonName(peer); |
||||
EXPECT_EQ( |
||||
string(property->value.string.data, property->value.string.length), |
||||
string("testclient")); |
||||
} |
||||
tsi_peer_destruct(peer); |
||||
} |
||||
|
||||
void SetupHandshakers() override { |
||||
tsi_ssl_handshaker_factory* client_handshaker_factory; |
||||
const unsigned char* client_cert = NULL; |
||||
unsigned int client_cert_size = 0; |
||||
const unsigned char* client_key = NULL; |
||||
unsigned int client_key_size = 0; |
||||
if (config_.do_client_authentication) { |
||||
if (config_.use_bad_client_cert) { |
||||
client_cert = |
||||
reinterpret_cast<const unsigned char*>(badclient_cert_.data()); |
||||
client_cert_size = badclient_cert_.size(); |
||||
client_key = |
||||
reinterpret_cast<const unsigned char*>(badclient_key_.data()); |
||||
client_key_size = badclient_key_.size(); |
||||
} else { |
||||
client_cert = |
||||
reinterpret_cast<const unsigned char*>(client_cert_.data()); |
||||
client_cert_size = client_cert_.size(); |
||||
client_key = reinterpret_cast<const unsigned char*>(client_key_.data()); |
||||
client_key_size = client_key_.size(); |
||||
} |
||||
} |
||||
const unsigned char** client_alpn_protocols(nullptr); |
||||
const unsigned char* client_alpn_protocols_lengths(nullptr); |
||||
uint16_t num_client_alpn_protocols = 0; |
||||
if (config_.alpn_mode == ALPN_CLIENT_NO_SERVER || |
||||
config_.alpn_mode == ALPN_CLIENT_SERVER_OK || |
||||
config_.alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) { |
||||
client_alpn_protocols = |
||||
reinterpret_cast<const unsigned char**>(&client_alpn_protocols_[0]); |
||||
client_alpn_protocols_lengths = &client_alpn_protocols_lengths_[0]; |
||||
num_client_alpn_protocols = client_alpn_protocols_.size(); |
||||
} |
||||
|
||||
EXPECT_EQ(tsi_create_ssl_client_handshaker_factory( |
||||
client_key, client_key_size, client_cert, client_cert_size, |
||||
reinterpret_cast<const unsigned char*>(root_certs_.data()), |
||||
root_certs_.size(), NULL, client_alpn_protocols, |
||||
client_alpn_protocols_lengths, num_client_alpn_protocols, |
||||
&client_handshaker_factory), |
||||
TSI_OK); |
||||
client_handshaker_factory_.reset(client_handshaker_factory); |
||||
|
||||
const unsigned char** server_alpn_protocols(nullptr); |
||||
const unsigned char* server_alpn_protocols_lengths(nullptr); |
||||
uint16_t num_server_alpn_protocols = 0; |
||||
if (config_.alpn_mode == ALPN_SERVER_NO_CLIENT || |
||||
config_.alpn_mode == ALPN_CLIENT_SERVER_OK || |
||||
config_.alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) { |
||||
server_alpn_protocols = |
||||
reinterpret_cast<const unsigned char**>(&server_alpn_protocols_[0]); |
||||
server_alpn_protocols_lengths = &server_alpn_protocols_lengths_[0]; |
||||
num_server_alpn_protocols = server_alpn_protocols_.size(); |
||||
if (config_.alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) { |
||||
// Remove the last element that is common.
|
||||
num_server_alpn_protocols--; |
||||
} |
||||
} |
||||
tsi_ssl_handshaker_factory* server_handshaker_factory; |
||||
EXPECT_EQ( |
||||
tsi_create_ssl_server_handshaker_factory( |
||||
config_.use_bad_server_cert ? &badserver_keys_[0] |
||||
: &server_keys_[0], |
||||
config_.use_bad_server_cert ? &badserver_keys_sizes_[0] |
||||
: &server_keys_sizes_[0], |
||||
config_.use_bad_server_cert ? &badserver_certs_[0] |
||||
: &server_certs_[0], |
||||
config_.use_bad_server_cert ? &badserver_certs_sizes_[0] |
||||
: &server_certs_sizes_[0], |
||||
config_.use_bad_server_cert ? badserver_keys_.size() |
||||
: server_keys_.size(), |
||||
config_.do_client_authentication |
||||
? reinterpret_cast<const unsigned char*>(root_certs_.data()) |
||||
: NULL, |
||||
config_.do_client_authentication ? root_certs_.size() : 0, NULL, |
||||
server_alpn_protocols, server_alpn_protocols_lengths, |
||||
num_server_alpn_protocols, &server_handshaker_factory), |
||||
TSI_OK); |
||||
server_handshaker_factory_.reset(server_handshaker_factory); |
||||
|
||||
tsi_handshaker* client_handshaker; |
||||
EXPECT_EQ(tsi_ssl_handshaker_factory_create_handshaker( |
||||
client_handshaker_factory, config_.subject_name_indication, |
||||
&client_handshaker), |
||||
TSI_OK); |
||||
client_handshaker_.reset(client_handshaker); |
||||
|
||||
tsi_handshaker* server_handshaker; |
||||
EXPECT_EQ(tsi_ssl_handshaker_factory_create_handshaker( |
||||
server_handshaker_factory, NULL, &server_handshaker), |
||||
TSI_OK); |
||||
server_handshaker_.reset(server_handshaker); |
||||
} |
||||
|
||||
void CheckAlpn(const tsi_peer* peer) { |
||||
const tsi_peer_property* alpn_property = |
||||
tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL); |
||||
if (config_.alpn_mode != ALPN_CLIENT_SERVER_OK) { |
||||
EXPECT_EQ(nullptr, alpn_property); |
||||
} else { |
||||
EXPECT_NE(nullptr, alpn_property); |
||||
EXPECT_EQ(TSI_PEER_PROPERTY_TYPE_STRING, alpn_property->type); |
||||
string expected_match("baz"); |
||||
EXPECT_EQ(expected_match, string(alpn_property->value.string.data, |
||||
alpn_property->value.string.length)); |
||||
} |
||||
} |
||||
|
||||
void CheckHandshakeResults() override { |
||||
tsi_peer peer; |
||||
|
||||
bool expect_success = |
||||
!(config_.use_bad_server_cert || |
||||
(config_.use_bad_client_cert && config_.do_client_authentication)); |
||||
tsi_result result = tsi_handshaker_get_result(client_handshaker_.get()); |
||||
EXPECT_NE(result, TSI_HANDSHAKE_IN_PROGRESS); |
||||
if (expect_success) { |
||||
EXPECT_EQ(result, TSI_OK); |
||||
EXPECT_EQ(tsi_handshaker_extract_peer(client_handshaker_.get(), &peer), |
||||
TSI_OK); |
||||
CheckAlpn(&peer); |
||||
// TODO(jboeuf): This is a bit fragile. Maybe revisit.
|
||||
if (config_.subject_name_indication != nullptr) { |
||||
CheckServer1Peer(&peer); |
||||
} else { |
||||
CheckServer0Peer(&peer); |
||||
} |
||||
} else { |
||||
EXPECT_NE(result, TSI_OK); |
||||
EXPECT_NE(tsi_handshaker_extract_peer(client_handshaker_.get(), &peer), |
||||
TSI_OK); |
||||
} |
||||
|
||||
result = tsi_handshaker_get_result(server_handshaker_.get()); |
||||
EXPECT_NE(result, TSI_HANDSHAKE_IN_PROGRESS); |
||||
if (expect_success) { |
||||
EXPECT_EQ(result, TSI_OK); |
||||
EXPECT_EQ(tsi_handshaker_extract_peer(server_handshaker_.get(), &peer), |
||||
TSI_OK); |
||||
CheckAlpn(&peer); |
||||
CheckClientPeer(&peer, config_.do_client_authentication); |
||||
} else { |
||||
EXPECT_NE(result, TSI_OK); |
||||
EXPECT_NE(tsi_handshaker_extract_peer(server_handshaker_.get(), &peer), |
||||
TSI_OK); |
||||
} |
||||
} |
||||
|
||||
const tsi::test::TestConfig* config() override { |
||||
return &config_; |
||||
} |
||||
|
||||
SslTransportSecurityTest() |
||||
: client_alpn_protocols_({"foo", "toto", "baz"}), |
||||
server_alpn_protocols_({"boooo", "far", "baz"}), |
||||
client_alpn_protocols_lengths_({3, 4, 3}), |
||||
server_alpn_protocols_lengths_({5, 3, 3}) { |
||||
CHECK_OK(file::GetContents( |
||||
file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "badserver.key"), |
||||
&badserver_key_, file::Options())); |
||||
CHECK_OK(file::GetContents( |
||||
file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "badserver.pem"), |
||||
&badserver_cert_, file::Options())); |
||||
CHECK_OK(file::GetContents( |
||||
file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "badclient.key"), |
||||
&badclient_key_, file::Options())); |
||||
CHECK_OK(file::GetContents( |
||||
file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "badclient.pem"), |
||||
&badclient_cert_, file::Options())); |
||||
CHECK_OK(file::GetContents( |
||||
file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "server0.key"), |
||||
&server0_key_, file::Options())); |
||||
CHECK_OK(file::GetContents( |
||||
file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "server0.pem"), |
||||
&server0_cert_, file::Options())); |
||||
CHECK_OK(file::GetContents( |
||||
file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "server1.key"), |
||||
&server1_key_, file::Options())); |
||||
CHECK_OK(file::GetContents( |
||||
file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "server1.pem"), |
||||
&server1_cert_, file::Options())); |
||||
CHECK_OK(file::GetContents( |
||||
file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "client.key"), |
||||
&client_key_, file::Options())); |
||||
CHECK_OK(file::GetContents( |
||||
file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "client.pem"), |
||||
&client_cert_, file::Options())); |
||||
CHECK_OK(file::GetContents( |
||||
file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "ca.pem"), |
||||
&root_certs_, file::Options())); |
||||
badserver_keys_.push_back( |
||||
reinterpret_cast<const unsigned char*>(badserver_key_.data())); |
||||
badserver_certs_.push_back( |
||||
reinterpret_cast<const unsigned char*>(badserver_cert_.data())); |
||||
server_keys_.push_back( |
||||
reinterpret_cast<const unsigned char*>(server0_key_.data())); |
||||
server_keys_.push_back( |
||||
reinterpret_cast<const unsigned char*>(server1_key_.data())); |
||||
server_certs_.push_back( |
||||
reinterpret_cast<const unsigned char*>(server0_cert_.data())); |
||||
server_certs_.push_back( |
||||
reinterpret_cast<const unsigned char*>(server1_cert_.data())); |
||||
badserver_keys_sizes_.push_back(badserver_key_.size()); |
||||
badserver_certs_sizes_.push_back(badserver_cert_.size()); |
||||
server_keys_sizes_.push_back(server0_key_.size()); |
||||
server_keys_sizes_.push_back(server1_key_.size()); |
||||
server_certs_sizes_.push_back(server0_cert_.size()); |
||||
server_certs_sizes_.push_back(server1_cert_.size()); |
||||
} |
||||
|
||||
string badserver_key_; |
||||
string badserver_cert_; |
||||
string badclient_key_; |
||||
string badclient_cert_; |
||||
string server0_key_; |
||||
string server0_cert_; |
||||
string server1_key_; |
||||
string server1_cert_; |
||||
string client_key_; |
||||
string client_cert_; |
||||
string root_certs_; |
||||
std::vector<const unsigned char*> badserver_keys_; |
||||
std::vector<const unsigned char*> badserver_certs_; |
||||
std::vector<const unsigned char*> server_keys_; |
||||
std::vector<const unsigned char*> server_certs_; |
||||
std::vector<unsigned int> badserver_keys_sizes_; |
||||
std::vector<unsigned int> badserver_certs_sizes_; |
||||
std::vector<unsigned int> server_keys_sizes_; |
||||
std::vector<unsigned int> server_certs_sizes_; |
||||
TsiSslHandshakerFactoryUniquePtr client_handshaker_factory_; |
||||
TsiSslHandshakerFactoryUniquePtr server_handshaker_factory_; |
||||
std::vector<const char*> client_alpn_protocols_; |
||||
std::vector<const char*> server_alpn_protocols_; |
||||
std::vector<unsigned char> client_alpn_protocols_lengths_; |
||||
std::vector<unsigned char> server_alpn_protocols_lengths_; |
||||
string matched_alpn_; |
||||
SslTestConfig config_; |
||||
}; |
||||
|
||||
|
||||
TEST_F(SslTransportSecurityTest, LoadInvalidRoots) { |
||||
tsi_ssl_handshaker_factory* client_handshaker_factory; |
||||
string invalid_roots("Invalid roots!"); |
||||
EXPECT_EQ( |
||||
TSI_INVALID_ARGUMENT, |
||||
tsi_create_ssl_client_handshaker_factory( |
||||
NULL, 0, NULL, 0, |
||||
reinterpret_cast<const unsigned char*>(invalid_roots.data()), |
||||
invalid_roots.size(), NULL, NULL, 0, 0, &client_handshaker_factory)); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, Handshake) { |
||||
PerformHandshake(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, HandshakeClientAuthentication) { |
||||
config_.do_client_authentication = true; |
||||
PerformHandshake(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, HandshakeSmallBuffer) { |
||||
config_.handshake_buffer_size = 128; |
||||
PerformHandshake(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, HandshakeSNIExactDomain) { |
||||
// server1 cert contains waterzooi.test.google.be in SAN.
|
||||
config_.subject_name_indication = "waterzooi.test.google.be"; |
||||
PerformHandshake(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, HandshakeSNIWildstarDomain) { |
||||
// server1 cert contains *.test.google.fr in SAN.
|
||||
config_.subject_name_indication = "juju.test.google.fr"; |
||||
PerformHandshake(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, BadServerCertFailure) { |
||||
config_.use_bad_server_cert = true; |
||||
PerformHandshake(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, BadClientCertFailure) { |
||||
config_.use_bad_client_cert = true; |
||||
config_.do_client_authentication = true; |
||||
PerformHandshake(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, AlpnClientNoServer) { |
||||
config_.alpn_mode = ALPN_CLIENT_NO_SERVER; |
||||
PerformHandshake(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, AlpnServerNoClient) { |
||||
config_.alpn_mode = ALPN_SERVER_NO_CLIENT; |
||||
PerformHandshake(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, AlpnClientServeMismatch) { |
||||
config_.alpn_mode = ALPN_CLIENT_SERVER_MISMATCH; |
||||
PerformHandshake(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, AlpnClientServerOk) { |
||||
config_.alpn_mode = ALPN_CLIENT_SERVER_OK; |
||||
PerformHandshake(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, PingPong) { |
||||
PingPong(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, RoundTrip) { |
||||
config_.client_message = big_message_; |
||||
config_.server_message = small_message_; |
||||
DoRoundTrip(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, RoundTripSmallMessageBuffer) { |
||||
config_.message_buffer_allocated_size = 42; |
||||
config_.client_message = big_message_; |
||||
config_.server_message = small_message_; |
||||
DoRoundTrip(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, RoundTripSmallProtectedBufferSize) { |
||||
config_.protected_buffer_size = 37; |
||||
config_.client_message = big_message_; |
||||
config_.server_message = small_message_; |
||||
DoRoundTrip(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, RoundTripSmallReadBufferSize) { |
||||
config_.read_buffer_allocated_size = 41; |
||||
config_.client_message = big_message_; |
||||
config_.server_message = small_message_; |
||||
DoRoundTrip(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, RoundTripSmallClientFrames) { |
||||
config_.set_client_max_output_protected_frame_size(39); |
||||
config_.client_message = big_message_; |
||||
config_.server_message = small_message_; |
||||
DoRoundTrip(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, RoundTripSmallServerFrames) { |
||||
config_.set_server_max_output_protected_frame_size(43); |
||||
config_.client_message = small_message_; |
||||
config_.server_message = big_message_; |
||||
DoRoundTrip(); |
||||
} |
||||
|
||||
TEST_F(SslTransportSecurityTest, RoundTripOddBufferSizes) { |
||||
int odd_sizes[] = {33, 67, 135, 271, 523}; |
||||
RandomPermutation<int> permute(odd_sizes, arraysize(odd_sizes), |
||||
random_.get()); |
||||
permute.Permute(); |
||||
LOG(ERROR) << odd_sizes[0] << "\t" << odd_sizes[1] << "\t" << odd_sizes[2] |
||||
<< "\t" << odd_sizes[3] << "\t" << odd_sizes[4]; |
||||
config_.message_buffer_allocated_size = odd_sizes[0]; |
||||
config_.protected_buffer_size = odd_sizes[1]; |
||||
config_.read_buffer_allocated_size = odd_sizes[2]; |
||||
config_.set_client_max_output_protected_frame_size(odd_sizes[3]); |
||||
config_.set_server_max_output_protected_frame_size(odd_sizes[4]); |
||||
config_.client_message = big_message_; |
||||
config_.server_message = small_message_; |
||||
DoRoundTrip(); |
||||
} |
||||
|
||||
} // namespace
|
@ -1,363 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/tsi/transport_security_test_lib.h" |
||||
|
||||
#include <memory> |
||||
|
||||
#include "base/commandlineflags.h" |
||||
#include "src/core/tsi/transport_security_interface.h" |
||||
#include "strings/escaping.h" |
||||
#include "strings/strcat.h" |
||||
#include <gtest/gtest.h> |
||||
#include "util/random/mt_random.h" |
||||
|
||||
namespace { |
||||
|
||||
const char kPingRequest[] = "Ping"; |
||||
const char kPongResponse[] = "Pong"; |
||||
const int kBigMessageSize = 17000; |
||||
|
||||
} // namespace
|
||||
|
||||
namespace tsi { |
||||
namespace test { |
||||
|
||||
TransportSecurityTest::TransportSecurityTest() : random_(new MTRandom()) { |
||||
small_message_ = "Chapi Chapo"; |
||||
big_message_ = RandomString(kBigMessageSize); |
||||
} |
||||
|
||||
string TransportSecurityTest::RandomString(int size) { |
||||
std::unique_ptr<char[]> buffer(new char[size]); |
||||
for (int i = 0; i < size; i++) { |
||||
buffer[i] = random_->Rand8(); |
||||
} |
||||
return string(buffer.get(), size); |
||||
} |
||||
|
||||
void TransportSecurityTest::SendBytesToPeer(bool is_client, unsigned char* buf, |
||||
unsigned int buf_size) { |
||||
string& channel = is_client ? to_server_channel_ : to_client_channel_; |
||||
LOG(INFO) << (is_client ? "Client:" : "Server") << " sending " << buf_size |
||||
<< " bytes to peer."; |
||||
channel.append(reinterpret_cast<const char*>(buf), buf_size); |
||||
} |
||||
|
||||
void TransportSecurityTest::ReadBytesFromPeer(bool is_client, |
||||
unsigned char* buf, |
||||
unsigned int* buf_size) { |
||||
string& channel = is_client ? to_client_channel_ : to_server_channel_; |
||||
unsigned int to_read = |
||||
*buf_size < channel.size() ? *buf_size : channel.size(); |
||||
memcpy(buf, channel.data(), to_read); |
||||
*buf_size = to_read; |
||||
channel.erase(0, to_read); |
||||
LOG(INFO) << (is_client ? "Client:" : "Server") << " read " << to_read |
||||
<< " bytes from peer."; |
||||
} |
||||
|
||||
void TransportSecurityTest::DoHandshakeStep(bool is_client, |
||||
unsigned int buf_allocated_size, |
||||
tsi_handshaker* handshaker, |
||||
string* remaining_bytes) { |
||||
tsi_result result = TSI_OK; |
||||
std::unique_ptr<unsigned char[]> buf(new unsigned char[buf_allocated_size]); |
||||
unsigned int buf_offset; |
||||
unsigned int buf_size; |
||||
// See if we need to send some bytes to the peer.
|
||||
do { |
||||
unsigned int buf_size_to_send = buf_allocated_size; |
||||
result = tsi_handshaker_get_bytes_to_send_to_peer(handshaker, buf.get(), |
||||
&buf_size_to_send); |
||||
if (buf_size_to_send > 0) { |
||||
SendBytesToPeer(is_client, buf.get(), buf_size_to_send); |
||||
} |
||||
} while (result == TSI_INCOMPLETE_DATA); |
||||
if (!tsi_handshaker_is_in_progress(handshaker)) return; |
||||
|
||||
do { |
||||
// Read bytes from the peer.
|
||||
buf_size = buf_allocated_size; |
||||
buf_offset = 0; |
||||
ReadBytesFromPeer(is_client, buf.get(), &buf_size); |
||||
if (buf_size == 0) break; |
||||
|
||||
// Process the bytes from the peer. We have to be careful as these bytes
|
||||
// may contain non-handshake data (protected data). If this is the case,
|
||||
// we will exit from the loop with buf_size > 0.
|
||||
unsigned int consumed_by_handshaker = buf_size; |
||||
result = tsi_handshaker_process_bytes_from_peer(handshaker, buf.get(), |
||||
&consumed_by_handshaker); |
||||
buf_size -= consumed_by_handshaker; |
||||
buf_offset += consumed_by_handshaker; |
||||
} while (result == TSI_INCOMPLETE_DATA); |
||||
|
||||
if (!tsi_handshaker_is_in_progress(handshaker)) { |
||||
remaining_bytes->assign( |
||||
reinterpret_cast<const char*>(buf.get()) + buf_offset, buf_size); |
||||
} |
||||
} |
||||
|
||||
void TransportSecurityTest::PerformHandshake() { |
||||
SetupHandshakers(); |
||||
string remaining_bytes; |
||||
do { |
||||
DoHandshakeStep(true, config()->handshake_buffer_size, |
||||
client_handshaker_.get(), &remaining_bytes); |
||||
EXPECT_EQ(0, remaining_bytes.size()); |
||||
DoHandshakeStep(false, config()->handshake_buffer_size, |
||||
server_handshaker_.get(), &remaining_bytes); |
||||
EXPECT_EQ(0, remaining_bytes.size()); |
||||
} while (tsi_handshaker_is_in_progress(client_handshaker_.get()) || |
||||
tsi_handshaker_is_in_progress(server_handshaker_.get())); |
||||
CheckHandshakeResults(); |
||||
} |
||||
|
||||
void TransportSecurityTest::SendMessageToPeer( |
||||
bool is_client, tsi_frame_protector* protector, const string& message, |
||||
unsigned int protected_buffer_size) { |
||||
std::unique_ptr<unsigned char[]> protected_buffer( |
||||
new unsigned char[protected_buffer_size]); |
||||
unsigned int message_size = message.size(); |
||||
const unsigned char* message_bytes = |
||||
reinterpret_cast<const unsigned char*>(message.data()); |
||||
tsi_result result = TSI_OK; |
||||
while (message_size > 0 && result == TSI_OK) { |
||||
unsigned int protected_buffer_size_to_send = protected_buffer_size; |
||||
unsigned int processed_message_size = message_size; |
||||
result = tsi_frame_protector_protect( |
||||
protector, message_bytes, &processed_message_size, |
||||
protected_buffer.get(), &protected_buffer_size_to_send); |
||||
EXPECT_EQ(TSI_OK, result); |
||||
SendBytesToPeer(is_client, protected_buffer.get(), |
||||
protected_buffer_size_to_send); |
||||
message_bytes += processed_message_size; |
||||
message_size -= processed_message_size; |
||||
|
||||
// Flush if we're done.
|
||||
if (message_size == 0) { |
||||
unsigned int still_pending_size; |
||||
do { |
||||
protected_buffer_size_to_send = protected_buffer_size; |
||||
result = tsi_frame_protector_protect_flush( |
||||
protector, protected_buffer.get(), &protected_buffer_size_to_send, |
||||
&still_pending_size); |
||||
EXPECT_EQ(TSI_OK, result); |
||||
SendBytesToPeer(is_client, protected_buffer.get(), |
||||
protected_buffer_size_to_send); |
||||
} while (still_pending_size > 0 && result == TSI_OK); |
||||
EXPECT_EQ(TSI_OK, result); |
||||
} |
||||
} |
||||
EXPECT_EQ(TSI_OK, result); |
||||
} |
||||
|
||||
void TransportSecurityTest::ReceiveMessageFromPeer( |
||||
bool is_client, tsi_frame_protector* protector, |
||||
unsigned int read_buf_allocated_size, |
||||
unsigned int message_buf_allocated_size, string* message) { |
||||
std::unique_ptr<unsigned char[]> read_buffer( |
||||
new unsigned char[read_buf_allocated_size]); |
||||
unsigned int read_offset = 0; |
||||
unsigned int read_from_peer_size = 0; |
||||
std::unique_ptr<unsigned char[]> message_buffer( |
||||
new unsigned char[message_buf_allocated_size]); |
||||
tsi_result result = TSI_OK; |
||||
bool done = false; |
||||
while (!done && result == TSI_OK) { |
||||
if (read_from_peer_size == 0) { |
||||
read_from_peer_size = read_buf_allocated_size; |
||||
ReadBytesFromPeer(is_client, read_buffer.get(), &read_from_peer_size); |
||||
read_offset = 0; |
||||
} |
||||
if (read_from_peer_size == 0) done = true; |
||||
unsigned int message_buffer_size; |
||||
do { |
||||
message_buffer_size = message_buf_allocated_size; |
||||
unsigned int processed_size = read_from_peer_size; |
||||
result = tsi_frame_protector_unprotect( |
||||
protector, read_buffer.get() + read_offset, &processed_size, |
||||
message_buffer.get(), &message_buffer_size); |
||||
EXPECT_EQ(TSI_OK, result); |
||||
if (message_buffer_size > 0) { |
||||
LOG(INFO) << "Wrote " << message_buffer_size << " bytes to message."; |
||||
message->append(reinterpret_cast<const char*>(message_buffer.get()), |
||||
message_buffer_size); |
||||
} |
||||
read_offset += processed_size; |
||||
read_from_peer_size -= processed_size; |
||||
} while ((read_from_peer_size > 0 || message_buffer_size > 0) && |
||||
result == TSI_OK); |
||||
EXPECT_EQ(TSI_OK, result); |
||||
} |
||||
EXPECT_EQ(TSI_OK, result); |
||||
} |
||||
|
||||
void TransportSecurityTest::DoRoundTrip(const string& request, |
||||
const string& response) { |
||||
PerformHandshake(); |
||||
|
||||
tsi_frame_protector* client_frame_protector; |
||||
tsi_frame_protector* server_frame_protector; |
||||
unsigned int client_max_output_protected_frame_size = |
||||
config()->client_max_output_protected_frame_size(); |
||||
EXPECT_EQ(TSI_OK, |
||||
tsi_handshaker_create_frame_protector( |
||||
client_handshaker_.get(), |
||||
config()->use_client_default_max_output_protected_frame_size() |
||||
? nullptr |
||||
: &client_max_output_protected_frame_size, |
||||
&client_frame_protector)); |
||||
|
||||
unsigned int server_max_output_protected_frame_size = |
||||
config()->server_max_output_protected_frame_size(); |
||||
EXPECT_EQ(TSI_OK, |
||||
tsi_handshaker_create_frame_protector( |
||||
server_handshaker_.get(), |
||||
config()->use_server_default_max_output_protected_frame_size() |
||||
? nullptr |
||||
: &server_max_output_protected_frame_size, |
||||
&server_frame_protector)); |
||||
|
||||
SendMessageToPeer(true, client_frame_protector, request, |
||||
config()->protected_buffer_size); |
||||
string retrieved_request; |
||||
ReceiveMessageFromPeer( |
||||
false, server_frame_protector, config()->read_buffer_allocated_size, |
||||
config()->message_buffer_allocated_size, &retrieved_request); |
||||
EXPECT_EQ(request.size(), retrieved_request.size()); |
||||
EXPECT_EQ(strings::b2a_hex(request), strings::b2a_hex(retrieved_request)); |
||||
|
||||
SendMessageToPeer(false, server_frame_protector, response, |
||||
config()->protected_buffer_size); |
||||
string retrieved_response; |
||||
ReceiveMessageFromPeer( |
||||
true, client_frame_protector, config()->read_buffer_allocated_size, |
||||
config()->message_buffer_allocated_size, &retrieved_response); |
||||
EXPECT_EQ(response.size(), retrieved_response.size()); |
||||
EXPECT_EQ(strings::b2a_hex(response), strings::b2a_hex(retrieved_response)); |
||||
|
||||
tsi_frame_protector_destroy(client_frame_protector); |
||||
tsi_frame_protector_destroy(server_frame_protector); |
||||
} |
||||
|
||||
void TransportSecurityTest::DoRoundTrip() { |
||||
DoRoundTrip(config()->client_message, config()->server_message); |
||||
} |
||||
void TransportSecurityTest::PingPong() { |
||||
PerformHandshake(); |
||||
|
||||
unsigned char to_server[4096]; |
||||
unsigned char to_client[4096]; |
||||
unsigned int max_frame_size = sizeof(to_client); |
||||
tsi_frame_protector* client_frame_protector; |
||||
tsi_frame_protector* server_frame_protector; |
||||
EXPECT_EQ( |
||||
tsi_handshaker_create_frame_protector( |
||||
client_handshaker_.get(), &max_frame_size, &client_frame_protector), |
||||
TSI_OK); |
||||
EXPECT_EQ(max_frame_size, sizeof(to_client)); |
||||
EXPECT_EQ( |
||||
tsi_handshaker_create_frame_protector( |
||||
server_handshaker_.get(), &max_frame_size, &server_frame_protector), |
||||
TSI_OK); |
||||
EXPECT_EQ(max_frame_size, sizeof(to_client)); |
||||
|
||||
// Send Ping.
|
||||
unsigned int ping_length = strlen(kPingRequest); |
||||
unsigned int protected_size = sizeof(to_server); |
||||
EXPECT_EQ(tsi_frame_protector_protect( |
||||
client_frame_protector, |
||||
reinterpret_cast<const unsigned char*>(kPingRequest), |
||||
&ping_length, to_server, &protected_size), |
||||
TSI_OK); |
||||
EXPECT_EQ(ping_length, strlen(kPingRequest)); |
||||
EXPECT_EQ(protected_size, 0); |
||||
protected_size = sizeof(to_server); |
||||
unsigned int still_pending_size; |
||||
EXPECT_EQ( |
||||
tsi_frame_protector_protect_flush(client_frame_protector, to_server, |
||||
&protected_size, &still_pending_size), |
||||
TSI_OK); |
||||
EXPECT_EQ(still_pending_size, 0); |
||||
EXPECT_GT(protected_size, strlen(kPingRequest)); |
||||
|
||||
// Receive Ping.
|
||||
unsigned int unprotected_size = sizeof(to_server); |
||||
unsigned int saved_protected_size = protected_size; |
||||
EXPECT_EQ(tsi_frame_protector_unprotect(server_frame_protector, to_server, |
||||
&protected_size, to_server, |
||||
&unprotected_size), |
||||
TSI_OK); |
||||
EXPECT_EQ(saved_protected_size, protected_size); |
||||
EXPECT_EQ(ping_length, unprotected_size); |
||||
EXPECT_EQ(string(kPingRequest), |
||||
string(reinterpret_cast<const char*>(to_server), unprotected_size)); |
||||
|
||||
// Send back Pong.
|
||||
unsigned int pong_length = strlen(kPongResponse); |
||||
protected_size = sizeof(to_client); |
||||
EXPECT_EQ(tsi_frame_protector_protect( |
||||
server_frame_protector, |
||||
reinterpret_cast<const unsigned char*>(kPongResponse), |
||||
&pong_length, to_client, &protected_size), |
||||
TSI_OK); |
||||
EXPECT_EQ(pong_length, strlen(kPongResponse)); |
||||
EXPECT_EQ(protected_size, 0); |
||||
protected_size = sizeof(to_client); |
||||
EXPECT_EQ( |
||||
tsi_frame_protector_protect_flush(server_frame_protector, to_client, |
||||
&protected_size, &still_pending_size), |
||||
TSI_OK); |
||||
EXPECT_EQ(still_pending_size, 0); |
||||
EXPECT_GT(protected_size, strlen(kPongResponse)); |
||||
|
||||
// Receive Pong.
|
||||
unprotected_size = sizeof(to_server); |
||||
saved_protected_size = protected_size; |
||||
EXPECT_EQ(tsi_frame_protector_unprotect(client_frame_protector, to_client, |
||||
&protected_size, to_client, |
||||
&unprotected_size), |
||||
TSI_OK); |
||||
EXPECT_EQ(saved_protected_size, protected_size); |
||||
EXPECT_EQ(pong_length, unprotected_size); |
||||
EXPECT_EQ(string(kPongResponse), |
||||
string(reinterpret_cast<const char*>(to_client), unprotected_size)); |
||||
|
||||
tsi_frame_protector_destroy(client_frame_protector); |
||||
tsi_frame_protector_destroy(server_frame_protector); |
||||
} |
||||
|
||||
} // namespace test
|
||||
} // namespace tsi
|
@ -1,154 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __TRANSPORT_SECURITY_TEST_LIB_H_ |
||||
#define __TRANSPORT_SECURITY_TEST_LIB_H_ |
||||
|
||||
#include <memory> |
||||
|
||||
#include "base/commandlineflags.h" |
||||
#include "src/core/tsi/transport_security_interface.h" |
||||
#include "strings/strcat.h" |
||||
#include <gtest/gtest.h> |
||||
#include "util/random/mt_random.h" |
||||
|
||||
namespace tsi { |
||||
namespace test { |
||||
|
||||
class TestConfig { |
||||
public: |
||||
TestConfig() |
||||
: client_message("Chapi Chapo"), |
||||
server_message("Chapi Chapo"), |
||||
handshake_buffer_size(4096), |
||||
read_buffer_allocated_size(4096), |
||||
message_buffer_allocated_size(4096), |
||||
protected_buffer_size(16384), |
||||
use_client_default_max_output_protected_frame_size_(true), |
||||
use_server_default_max_output_protected_frame_size_(true), |
||||
client_max_output_protected_frame_size_(0), |
||||
server_max_output_protected_frame_size_(0) {} |
||||
|
||||
void set_client_max_output_protected_frame_size(unsigned int size) { |
||||
use_client_default_max_output_protected_frame_size_ = false; |
||||
client_max_output_protected_frame_size_ = size; |
||||
} |
||||
void set_server_max_output_protected_frame_size(unsigned int size) { |
||||
use_server_default_max_output_protected_frame_size_ = false; |
||||
server_max_output_protected_frame_size_ = size; |
||||
} |
||||
bool use_client_default_max_output_protected_frame_size() const { |
||||
return use_client_default_max_output_protected_frame_size_; |
||||
} |
||||
bool use_server_default_max_output_protected_frame_size() const { |
||||
return use_server_default_max_output_protected_frame_size_; |
||||
} |
||||
unsigned int client_max_output_protected_frame_size() const { |
||||
return client_max_output_protected_frame_size_; |
||||
} |
||||
unsigned int server_max_output_protected_frame_size() const { |
||||
return server_max_output_protected_frame_size_; |
||||
} |
||||
|
||||
string client_message; |
||||
string server_message; |
||||
unsigned int handshake_buffer_size; |
||||
unsigned int read_buffer_allocated_size; |
||||
unsigned int message_buffer_allocated_size; |
||||
unsigned int protected_buffer_size; |
||||
|
||||
private: |
||||
bool use_client_default_max_output_protected_frame_size_; |
||||
bool use_server_default_max_output_protected_frame_size_; |
||||
unsigned int client_max_output_protected_frame_size_; |
||||
unsigned int server_max_output_protected_frame_size_; |
||||
}; |
||||
|
||||
|
||||
struct TsiHandshakerDeleter { |
||||
inline void operator()(tsi_handshaker* ptr) { tsi_handshaker_destroy(ptr); } |
||||
}; |
||||
typedef std::unique_ptr<tsi_handshaker, TsiHandshakerDeleter> |
||||
TsiHandshakerUniquePtr; |
||||
|
||||
class TransportSecurityTest : public ::testing::Test { |
||||
protected: |
||||
TransportSecurityTest(); |
||||
virtual ~TransportSecurityTest() {} |
||||
virtual const TestConfig* config() = 0; |
||||
string RandomString(int size); |
||||
virtual void SetupHandshakers() = 0; |
||||
// An implementation-specific verification of the validity of the handshake.
|
||||
virtual void CheckHandshakeResults() = 0; |
||||
// Do a full handshake.
|
||||
void PerformHandshake(); |
||||
// Send a protected message between the client and server.
|
||||
void SendMessageToPeer(bool is_client, tsi_frame_protector* protector, |
||||
const string& message, |
||||
unsigned int protected_buffer_size); |
||||
void ReceiveMessageFromPeer(bool is_client, tsi_frame_protector* protector, |
||||
unsigned int read_buf_allocated_size, |
||||
unsigned int message_buf_allocated_size, |
||||
string* message); |
||||
|
||||
// A simple test that does a handshake and sends a message back and forth
|
||||
void PingPong(); |
||||
// A complicated test that can be configured by modifying config().
|
||||
void DoRoundTrip(); |
||||
|
||||
TsiHandshakerUniquePtr client_handshaker_; |
||||
TsiHandshakerUniquePtr server_handshaker_; |
||||
|
||||
string small_message_; |
||||
string big_message_; |
||||
std::unique_ptr<RandomBase> random_; |
||||
|
||||
private: |
||||
// Functions to send raw bytes between the client and server.
|
||||
void SendBytesToPeer(bool is_client, unsigned char* buf, |
||||
unsigned int buf_size); |
||||
void ReadBytesFromPeer(bool is_client, unsigned char* buf, |
||||
unsigned int* buf_size); |
||||
// Do a single step of the handshake.
|
||||
void DoHandshakeStep(bool is_client, unsigned int buf_allocated_size, |
||||
tsi_handshaker* handshaker, string* remaining_bytes); |
||||
void DoRoundTrip(const string& request, const string& response); |
||||
|
||||
string to_server_channel_; |
||||
string to_client_channel_; |
||||
}; |
||||
|
||||
} // namespace test
|
||||
} // namespace tsi
|
||||
|
||||
#endif // __TRANSPORT_SECURITY_TEST_LIB_H_
|
@ -0,0 +1,2 @@ |
||||
<%namespace file="vcxproj_defs.include" import="gen_project"/>\ |
||||
${gen_project('gpr_test_util', libs, targets)} |
@ -0,0 +1,162 @@ |
||||
// An integration test service that covers all the method signature permutations |
||||
// of unary/streaming requests/responses. |
||||
syntax = "proto2"; |
||||
|
||||
package grpc.testing; |
||||
|
||||
option java_api_version = 2; |
||||
option cc_api_version = 2; |
||||
option java_package = "com.google.net.stubby.testing.integration"; |
||||
|
||||
enum PayloadType { |
||||
// Compressable text format. |
||||
COMPRESSABLE= 1; |
||||
|
||||
// Uncompressable binary format. |
||||
UNCOMPRESSABLE = 2; |
||||
|
||||
// Randomly chosen from all other formats defined in this enum. |
||||
RANDOM = 3; |
||||
} |
||||
|
||||
message StatsRequest { |
||||
// run number |
||||
optional int32 test_num = 1; |
||||
} |
||||
|
||||
message ServerStats { |
||||
// wall clock time for timestamp |
||||
required double time_now = 1; |
||||
|
||||
// user time used by the server process and threads |
||||
required double time_user = 2; |
||||
|
||||
// server time used by the server process and all threads |
||||
required double time_system = 3; |
||||
|
||||
// RPC count so far |
||||
optional int32 num_rpcs = 4; |
||||
} |
||||
|
||||
message Payload { |
||||
// The type of data in body. |
||||
optional PayloadType type = 1; |
||||
// Primary contents of payload. |
||||
optional bytes body = 2; |
||||
} |
||||
|
||||
message Latencies { |
||||
required double l_50 = 1; |
||||
required double l_90 = 2; |
||||
required double l_99 = 3; |
||||
required double l_999 = 4; |
||||
} |
||||
|
||||
message StartArgs { |
||||
required string server_host = 1; |
||||
required int32 server_port = 2; |
||||
optional bool enable_ssl = 3 [default = false]; |
||||
optional int32 client_threads = 4 [default = 1]; |
||||
optional int32 client_channels = 5 [default = -1]; |
||||
optional int32 num_rpcs = 6 [default = 1]; |
||||
optional int32 payload_size = 7 [default = 1]; |
||||
} |
||||
|
||||
message StartResult { |
||||
required Latencies latencies = 1; |
||||
required int32 num_rpcs = 2; |
||||
required double time_elapsed = 3; |
||||
required double time_user = 4; |
||||
required double time_system = 5; |
||||
} |
||||
|
||||
message SimpleRequest { |
||||
// Desired payload type in the response from the server. |
||||
// If response_type is RANDOM, server randomly chooses one from other formats. |
||||
optional PayloadType response_type = 1 [default=COMPRESSABLE]; |
||||
|
||||
// Desired payload size in the response from the server. |
||||
// If response_type is COMPRESSABLE, this denotes the size before compression. |
||||
optional int32 response_size = 2; |
||||
|
||||
// Optional input payload sent along with the request. |
||||
optional Payload payload = 3; |
||||
} |
||||
|
||||
message SimpleResponse { |
||||
optional Payload payload = 1; |
||||
} |
||||
|
||||
message StreamingInputCallRequest { |
||||
// Optional input payload sent along with the request. |
||||
optional Payload payload = 1; |
||||
|
||||
// Not expecting any payload from the response. |
||||
} |
||||
|
||||
message StreamingInputCallResponse { |
||||
// Aggregated size of payloads received from the client. |
||||
optional int32 aggregated_payload_size = 1; |
||||
} |
||||
|
||||
message ResponseParameters { |
||||
// Desired payload sizes in responses from the server. |
||||
// If response_type is COMPRESSABLE, this denotes the size before compression. |
||||
required int32 size = 1; |
||||
|
||||
// Desired interval between consecutive responses in the response stream in |
||||
// microseconds. |
||||
required int32 interval_us = 2; |
||||
} |
||||
|
||||
message StreamingOutputCallRequest { |
||||
// Desired payload type in the response from the server. |
||||
// If response_type is RANDOM, the payload from each response in the stream |
||||
// might be of different types. This is to simulate a mixed type of payload |
||||
// stream. |
||||
optional PayloadType response_type = 1 [default=COMPRESSABLE]; |
||||
|
||||
repeated ResponseParameters response_parameters = 2; |
||||
|
||||
// Optional input payload sent along with the request. |
||||
optional Payload payload = 3; |
||||
} |
||||
|
||||
message StreamingOutputCallResponse { |
||||
optional Payload payload = 1; |
||||
} |
||||
|
||||
service TestService { |
||||
// Start test with specified workload |
||||
rpc StartTest(StartArgs) returns (Latencies); |
||||
|
||||
// Collect stats from server, ignore request content |
||||
rpc CollectServerStats(StatsRequest) returns (ServerStats); |
||||
|
||||
// One request followed by one response. |
||||
// The server returns the client payload as-is. |
||||
rpc UnaryCall(SimpleRequest) returns (SimpleResponse); |
||||
|
||||
// One request followed by a sequence of responses (streamed download). |
||||
// The server returns the payload with client desired type and sizes. |
||||
rpc StreamingOutputCall(StreamingOutputCallRequest) |
||||
returns (stream StreamingOutputCallResponse); |
||||
|
||||
// A sequence of requests followed by one response (streamed upload). |
||||
// The server returns the aggregated size of client payload as the result. |
||||
rpc StreamingInputCall(stream StreamingInputCallRequest) |
||||
returns (StreamingInputCallResponse); |
||||
|
||||
// A sequence of requests with each request served by the server immediately. |
||||
// As one request could lead to multiple responses, this interface |
||||
// demonstrates the idea of full duplexing. |
||||
rpc FullDuplexCall(stream StreamingOutputCallRequest) |
||||
returns (stream StreamingOutputCallResponse); |
||||
|
||||
// A sequence of requests followed by a sequence of responses. |
||||
// The server buffers all the client requests and then serves them in order. A |
||||
// stream of responses are returned to the client when the server starts with |
||||
// first request. |
||||
rpc HalfDuplexCall(stream StreamingOutputCallRequest) |
||||
returns (stream StreamingOutputCallResponse); |
||||
} |
@ -0,0 +1,82 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup Label="ProjectConfigurations"> |
||||
<ProjectConfiguration Include="Debug|Win32"> |
||||
<Configuration>Debug</Configuration> |
||||
<Platform>Win32</Platform> |
||||
</ProjectConfiguration> |
||||
<ProjectConfiguration Include="Release|Win32"> |
||||
<Configuration>Release</Configuration> |
||||
<Platform>Win32</Platform> |
||||
</ProjectConfiguration> |
||||
</ItemGroup> |
||||
<PropertyGroup Label="Globals"> |
||||
<ProjectGuid>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</ProjectGuid> |
||||
</PropertyGroup> |
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
||||
<ConfigurationType>StaticLibrary</ConfigurationType> |
||||
<UseDebugLibraries>true</UseDebugLibraries> |
||||
<PlatformToolset>v120</PlatformToolset> |
||||
<CharacterSet>Unicode</CharacterSet> |
||||
<IntDir>$(Configuration)\$(ProjectName)\</IntDir> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
||||
<ConfigurationType>StaticLibrary</ConfigurationType> |
||||
<UseDebugLibraries>false</UseDebugLibraries> |
||||
<PlatformToolset>v120</PlatformToolset> |
||||
<WholeProgramOptimization>true</WholeProgramOptimization> |
||||
<CharacterSet>Unicode</CharacterSet> |
||||
<IntDir>$(Configuration)\$(ProjectName)\</IntDir> |
||||
</PropertyGroup> |
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
||||
<ImportGroup Label="ExtensionSettings"> |
||||
</ImportGroup> |
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
<Import Project="global.props" /> |
||||
</ImportGroup> |
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
<Import Project="global.props" /> |
||||
</ImportGroup> |
||||
<PropertyGroup Label="UserMacros" /> |
||||
<PropertyGroup /> |
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
||||
<ClCompile> |
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader> |
||||
<WarningLevel>Level3</WarningLevel> |
||||
<Optimization>Disabled</Optimization> |
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
<SDLCheck>true</SDLCheck> |
||||
</ClCompile> |
||||
<Link> |
||||
<SubSystem>Windows</SubSystem> |
||||
<GenerateDebugInformation>true</GenerateDebugInformation> |
||||
</Link> |
||||
</ItemDefinitionGroup> |
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
||||
<ClCompile> |
||||
<WarningLevel>Level3</WarningLevel> |
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader> |
||||
<Optimization>MaxSpeed</Optimization> |
||||
<FunctionLevelLinking>true</FunctionLevelLinking> |
||||
<IntrinsicFunctions>true</IntrinsicFunctions> |
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
<SDLCheck>true</SDLCheck> |
||||
</ClCompile> |
||||
<Link> |
||||
<SubSystem>Windows</SubSystem> |
||||
<GenerateDebugInformation>true</GenerateDebugInformation> |
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding> |
||||
<OptimizeReferences>true</OptimizeReferences> |
||||
</Link> |
||||
</ItemDefinitionGroup> |
||||
<ItemGroup> |
||||
<ClCompile Include="..\..\test\core\util\test_config.c"> |
||||
</ClCompile> |
||||
</ItemGroup> |
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |
||||
<ImportGroup Label="ExtensionTargets"> |
||||
</ImportGroup> |
||||
</Project> |
Loading…
Reference in new issue