From 2c9a7b1d54dc95c1b6307643e6fbfc89dc02607e Mon Sep 17 00:00:00 2001 From: Jose Date: Mon, 7 Nov 2016 12:01:27 +0100 Subject: UWP ssl improvements --- .../msbuild/iceuwp++11/iceuwp++11.vcxproj.filters | 9 +- cpp/src/IceSSL/Certificate.cpp | 94 +++++++++-- cpp/src/IceSSL/SSLEngine.cpp | 24 +++ cpp/src/IceSSL/SSLEngine.h | 18 +- cpp/src/IceSSL/Util.cpp | 135 +++++++++++++++ cpp/src/IceSSL/Util.h | 3 + cpp/src/IceSSL/WinRTEngine.cpp | 37 ++++- cpp/src/IceSSL/WinRTTransceiverI.cpp | 182 ++++++++++++++++++++- cpp/src/IceSSL/WinRTTransceiverI.h | 2 + .../msbuild/icessluwp++11/icessluwp++11.vcxproj | 4 - .../icessluwp++11/icessluwp++11.vcxproj.filters | 16 +- 11 files changed, 479 insertions(+), 45 deletions(-) (limited to 'cpp/src') diff --git a/cpp/src/Ice/msbuild/iceuwp++11/iceuwp++11.vcxproj.filters b/cpp/src/Ice/msbuild/iceuwp++11/iceuwp++11.vcxproj.filters index 5a48cd6767d..84cf9cc5098 100644 --- a/cpp/src/Ice/msbuild/iceuwp++11/iceuwp++11.vcxproj.filters +++ b/cpp/src/Ice/msbuild/iceuwp++11/iceuwp++11.vcxproj.filters @@ -1087,7 +1087,6 @@ Source Files - Source Files @@ -1100,6 +1099,12 @@ Source Files + + Source Files + + + Source Files + @@ -1924,4 +1929,4 @@ Header Files\x64\Release - + \ No newline at end of file diff --git a/cpp/src/IceSSL/Certificate.cpp b/cpp/src/IceSSL/Certificate.cpp index 8ecfd8c0dc0..3f4eb05bed9 100755 --- a/cpp/src/IceSSL/Certificate.cpp +++ b/cpp/src/IceSSL/Certificate.cpp @@ -28,6 +28,9 @@ # pragma GCC diagnostic ignored "-Wold-style-cast" #elif defined(ICE_USE_SECURE_TRANSPORT) # include +#elif defined(ICE_OS_WINRT) +# include +# include #endif #ifdef __SUNPRO_CC @@ -49,6 +52,15 @@ using namespace std; using namespace Ice; using namespace IceSSL; +#ifdef ICE_OS_WINRT +using namespace concurrency; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Storage; +using namespace Windows::Storage::Streams; +using namespace Windows::Security::Cryptography; +#endif + #if defined(ICE_USE_SECURE_TRANSPORT) || defined(ICE_USE_SCHANNEL) // @@ -599,19 +611,19 @@ vector > certificateAltNames(Windows::Security::Cryptography::Certificates::SubjectAlternativeNameInfo^ subAltNames) { vector > altNames; - for (auto iter = subAltNames->EmailName->First(); iter->HasCurrent; iter->MoveNext()) + for(auto iter = subAltNames->EmailName->First(); iter->HasCurrent; iter->MoveNext()) { altNames.push_back(make_pair(AltNameEmail, wstringToString(iter->Current->Data()))); } - for (auto iter = subAltNames->DnsName->First(); iter->HasCurrent; iter->MoveNext()) + for(auto iter = subAltNames->DnsName->First(); iter->HasCurrent; iter->MoveNext()) { altNames.push_back(make_pair(AltNameDNS, wstringToString(iter->Current->Data()))); } - for (auto iter = subAltNames->Url->First(); iter->HasCurrent; iter->MoveNext()) + for(auto iter = subAltNames->Url->First(); iter->HasCurrent; iter->MoveNext()) { altNames.push_back(make_pair(AltNameURL, wstringToString(iter->Current->Data()))); } - for (auto iter = subAltNames->IPAddress->First(); iter->HasCurrent; iter->MoveNext()) + for(auto iter = subAltNames->IPAddress->First(); iter->HasCurrent; iter->MoveNext()) { altNames.push_back(make_pair(AltNAmeIP, wstringToString(iter->Current->Data()))); } @@ -1035,7 +1047,7 @@ Certificate::Certificate(X509CertificateRef cert) : _cert(cert) throw IceUtil::IllegalArgumentException(__FILE__, __LINE__, "Invalid certificate reference"); } -#ifdef ICE_USE_SCHANNEL +#if defined(ICE_USE_SCHANNEL) _certInfo = 0; try { @@ -1055,9 +1067,7 @@ Certificate::Certificate(X509CertificateRef cert) : _cert(cert) _cert = 0; throw; } -#endif - -#if defined(ICE_USE_SECURE_TRANSPORT_IOS) +#elif defined(ICE_USE_SECURE_TRANSPORT_IOS) _subject = NULL; _issuer = NULL; #endif @@ -1125,8 +1135,39 @@ Certificate::load(const string& file) BIO_free(cert); return ICE_MAKE_SHARED(Certificate, x); #elif defined(ICE_OS_WINRT) - // TODO - return ICE_NULLPTR; + promise> result; + create_task(StorageFile::GetFileFromApplicationUriAsync( + ref new Uri(ref new String(stringToWstring(file).c_str())))).then([](StorageFile^ file) + { + return FileIO::ReadBufferAsync(file); + }, + task_continuation_context::use_arbitrary()).then([&result, &file](task previous) + { + try + { + result.set_value(make_shared(ref new Certificates::Certificate(previous.get()))); + } + catch(Platform::Exception^ ex) + { + try + { + if(HRESULT_CODE(ex->HResult) == ERROR_FILE_NOT_FOUND) + { + throw CertificateReadException(__FILE__, __LINE__, "certificate file not found:\n" + file); + } + else + { + throw Ice::SyscallException(__FILE__, __LINE__, ex->HResult); + } + } + catch(...) + { + result.set_exception(current_exception()); + } + } + }, + task_continuation_context::use_arbitrary()); + return result.get_future().get(); #else # error "Unknown platform" #endif @@ -1198,8 +1239,25 @@ Certificate::decode(const string& encoding) BIO_free(cert); return ICE_MAKE_SHARED(Certificate, x); #elif defined(ICE_OS_WINRT) - // TODO - return ICE_NULLPTR; + string::size_type size, startpos, endpos = 0; + startpos = encoding.find("-----BEGIN CERTIFICATE-----", endpos); + if (startpos != string::npos) + { + startpos += sizeof("-----BEGIN CERTIFICATE-----"); + endpos = encoding.find("-----END CERTIFICATE-----", startpos); + size = endpos - startpos; + } + else + { + startpos = 0; + endpos = string::npos; + size = encoding.size(); + } + + vector data(IceInternal::Base64::decode(string(&encoding[startpos], size))); + auto writer = ref new DataWriter(); + writer->WriteBytes(Platform::ArrayReference(&data[0], data.size())); + return make_shared(ref new Certificates::Certificate(writer->DetachBuffer())); #else # error "Unknown platform" #endif @@ -1461,7 +1519,7 @@ Certificate::encode() const #elif defined(ICE_OS_WINRT) auto reader = Windows::Storage::Streams::DataReader::FromBuffer(_cert->GetCertificateBlob()); std::vector data(reader->UnconsumedBufferLength); - if (!data.empty()) + if(!data.empty()) { reader->ReadBytes(Platform::ArrayReference(&data[0], static_cast(data.size()))); } @@ -1646,9 +1704,9 @@ Certificate::getSubjectDN() const } else { - string s = "CN="; - s += fromCFString(UniqueRef(SecCertificateCopySubjectSummary(_cert)).get()); - return DistinguishedName(s); + ostringstream os; + os << "CN=" << fromCFString(UniqueRef(SecCertificateCopySubjectSummary(_cert)).get()); + return DistinguishedName(os.str()); } #elif defined(ICE_USE_SECURE_TRANSPORT_MACOS) return getX509Name(_cert, kSecOIDX509V1SubjectName); @@ -1657,7 +1715,9 @@ Certificate::getSubjectDN() const #elif defined(ICE_USE_OPENSSL) return DistinguishedName(RFC2253::parseStrict(convertX509NameToString(X509_get_subject_name(_cert)))); #elif defined(ICE_OS_WINRT) - return DistinguishedName(wstringToString(_cert->Subject->Data())); + ostringstream os; + os << "CN=" << wstringToString(_cert->Subject->Data()); + return DistinguishedName(os.str()); #else # error "Unknown platform" #endif diff --git a/cpp/src/IceSSL/SSLEngine.cpp b/cpp/src/IceSSL/SSLEngine.cpp index ed286df2b5b..4f8f927495f 100644 --- a/cpp/src/IceSSL/SSLEngine.cpp +++ b/cpp/src/IceSSL/SSLEngine.cpp @@ -291,3 +291,27 @@ IceSSL::SSLEngine::verifyPeer(const string& address, const NativeConnectionInfoP throw ex; } } + +bool +IceSSL::SSLEngine::getCheckCertName() const +{ + return _checkCertName; +} + +int +IceSSL::SSLEngine::getVerifyPeer() const +{ + return _verifyPeer; +} + +int +IceSSL::SSLEngine::securityTraceLevel() const +{ + return _securityTraceLevel; +} + +std::string +IceSSL::SSLEngine::securityTraceCategory() const +{ + return _securityTraceCategory; +} diff --git a/cpp/src/IceSSL/SSLEngine.h b/cpp/src/IceSSL/SSLEngine.h index 25748c71c78..c8b84fcd31b 100644 --- a/cpp/src/IceSSL/SSLEngine.h +++ b/cpp/src/IceSSL/SSLEngine.h @@ -40,6 +40,8 @@ # include # include # undef SECURITY_WIN32 +#elif defined(ICE_OS_WINRT) +# include #endif namespace IceSSL @@ -81,10 +83,10 @@ public: std::string getPassword() const; void setPassword(const std::string& password); - bool getCheckCertName() const { return _checkCertName; } - int getVerifyPeer() const { return _verifyPeer; } - int securityTraceLevel() const { return _securityTraceLevel; } - std::string securityTraceCategory() const { return _securityTraceCategory; } + bool getCheckCertName() const; + int getVerifyPeer() const; + int securityTraceLevel() const; + std::string securityTraceCategory() const; private: @@ -234,6 +236,13 @@ public: virtual void initialize(); virtual bool initialized() const; virtual void destroy(); + virtual std::shared_ptr certificate(); + +private: + + std::shared_ptr _certificate; + bool _initialized; + std::mutex _mutex; }; #else // OpenSSL @@ -263,7 +272,6 @@ private: enum Protocols { SSLv3 = 0x01, TLSv1_0 = 0x02, TLSv1_1 = 0x04, TLSv1_2 = 0x08 }; int parseProtocols(const Ice::StringSeq&) const; - bool _initialized; SSL_CTX* _ctx; std::string _defaultDir; diff --git a/cpp/src/IceSSL/Util.cpp b/cpp/src/IceSSL/Util.cpp index 5b592797842..67a81e09740 100755 --- a/cpp/src/IceSSL/Util.cpp +++ b/cpp/src/IceSSL/Util.cpp @@ -23,6 +23,11 @@ #include #include +#ifdef ICE_OS_WINRT +# include +#endif +using namespace IceUtilInternal; + #ifdef ICE_USE_OPENSSL # include // @@ -36,6 +41,17 @@ using namespace Ice; using namespace IceUtil; using namespace IceSSL; +#ifdef ICE_OS_WINRT +using namespace concurrency; +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::Storage; +using namespace Windows::Storage::Streams; +using namespace Windows::Security::Cryptography; +using namespace Windows::Security::Cryptography::Core; +using namespace Windows::Security::Cryptography::Certificates; +#endif #ifdef ICE_CPP11_MAPPING IceSSL::CertificateVerifier::CertificateVerifier(std::function&)> v) : @@ -1677,6 +1693,125 @@ IceSSL::findCertificates(const string& location, const string& name, const strin } return certs; } +#elif defined (ICE_OS_WINRT) +IVectorView^ +IceSSL::findCertificates(const string& name, const string& value) +{ + CertificateQuery^ query = ref new CertificateQuery(); + query->StoreName = ref new String(stringToWstring(name).c_str()); + query->IncludeDuplicates = true; + + if(value != "*") + { + if(value.find(':', 0) == string::npos) + { + throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: no key in `" + value + "'"); + } + size_t start = 0; + size_t pos; + while((pos = value.find(':', start)) != string::npos) + { + string field = IceUtilInternal::toUpper(IceUtilInternal::trim(value.substr(start, pos - start))); + if(field != "ISSUER" && field != "THUMBPRINT" && field != "FRIENDLYNAME") + { + throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: unknown key in `" + value + "'"); + } + + start = pos + 1; + while(start < value.size() && (value[start] == ' ' || value[start] == '\t')) + { + ++start; + } + + if(start == value.size()) + { + throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: missing argument in `" + value + "'"); + } + + string arg; + if(value[start] == '"' || value[start] == '\'') + { + size_t end = start; + ++end; + while(end < value.size()) + { + if(value[end] == value[start] && value[end - 1] != '\\') + { + break; + } + ++end; + } + if(end == value.size() || value[end] != value[start]) + { + throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: unmatched quote in `" + value + "'"); + } + ++start; + arg = value.substr(start, end - start); + start = end + 1; + } + else + { + size_t end = value.find_first_of(" \t", start); + if(end == string::npos) + { + arg = value.substr(start); + start = value.size(); + } + else + { + arg = value.substr(start, end - start); + start = end + 1; + } + } + + if(field == "ISSUER") + { + query->IssuerName = ref new String(stringToWstring(arg).c_str()); + } + else if(field == "FRIENDLYNAME") + { + query->FriendlyName = ref new String(stringToWstring(arg).c_str()); + } + else if(field == "THUMBPRINT") + { + vector buffer; + if(!parseBytes(arg, buffer)) + { + throw PluginInitializationException(__FILE__, __LINE__, + "IceSSL: invalid `IceSSL.FindCert' property: can't decode the value"); + } + query->Thumbprint = ref new Array(&buffer[0], static_cast(buffer.size())); + } + } + } + + std::promise^> p; + HRESULT error = 0; + create_task(CertificateStores::FindAllAsync(query)).then( + [&](task^> previous) + { + try + { + p.set_value(previous.get()); + } + catch(Platform::Exception^ err) + { + try + { + Ice::SyscallException ex(__FILE__, __LINE__); + ex.error = err->HResult; + throw ex; + } + catch(...) + { + p.set_exception(current_exception()); + } + } + }, + task_continuation_context::use_arbitrary()); + + return p.get_future().get(); +} #endif void diff --git a/cpp/src/IceSSL/Util.h b/cpp/src/IceSSL/Util.h index 1ff3b12aab5..59ff813a1a8 100644 --- a/cpp/src/IceSSL/Util.h +++ b/cpp/src/IceSSL/Util.h @@ -202,6 +202,9 @@ CFArrayRef findCertificateChain(const std::string&, const std::string&, const st #elif defined(ICE_USE_SCHANNEL) std::vector findCertificates(const std::string&, const std::string&, const std::string&, std::vector&); +#elif defined(ICE_OS_WINRT) +Windows::Foundation::Collections::IVectorView^ +findCertificates(const std::string&, const std::string&); #endif // diff --git a/cpp/src/IceSSL/WinRTEngine.cpp b/cpp/src/IceSSL/WinRTEngine.cpp index a6dc675c581..651fd2ace53 100755 --- a/cpp/src/IceSSL/WinRTEngine.cpp +++ b/cpp/src/IceSSL/WinRTEngine.cpp @@ -12,26 +12,59 @@ #ifdef ICE_OS_WINRT #include +#include +#include #include +#include + IceUtil::Shared* IceSSL::upCast(IceSSL::WinRTEngine* p) { return p; } +using namespace std; using namespace IceSSL; WinRTEngine::WinRTEngine(const Ice::CommunicatorPtr& communicator) : SSLEngine(communicator) { - } void WinRTEngine::initialize() { + lock_guard lock(_mutex); + if(_initialized) + { + return; + } + + SSLEngine::initialize(); + + const auto properties = communicator()->getProperties(); + + // + // Load client certificate + // + string findCert = properties->getProperty("IceSSL.FindCert"); + if(!findCert.empty()) + { + auto certs = findCertificates(properties->getPropertyWithDefault("IceSSL.CertStore", "My"), findCert); + if(certs->Size > 0) + { + _certificate = make_shared(certs->GetAt(0)); + } + } + _initialized = true; } bool WinRTEngine::initialized() const { - return true; + return _initialized; +} + +shared_ptr +WinRTEngine::certificate() +{ + return _certificate; } void diff --git a/cpp/src/IceSSL/WinRTTransceiverI.cpp b/cpp/src/IceSSL/WinRTTransceiverI.cpp index d9bca2912a9..6aad729e957 100755 --- a/cpp/src/IceSSL/WinRTTransceiverI.cpp +++ b/cpp/src/IceSSL/WinRTTransceiverI.cpp @@ -14,14 +14,94 @@ #include #include #include +#include +#include using namespace std; using namespace Ice; using namespace IceSSL; +using namespace concurrency; using namespace Platform; using namespace Windows::Networking; using namespace Windows::Networking::Sockets; +using namespace Windows::Foundation::Collections; +using namespace Windows::Security::Cryptography::Certificates; + +namespace +{ + +std::string +validationResultToString(ChainValidationResult result) +{ + switch (result) + { + case ChainValidationResult::Success: + { + return "The certificate chain was verified."; + } + case ChainValidationResult::Untrusted: + { + return "A certificate in the chain is not trusted."; + } + case ChainValidationResult::Revoked: + { + return "A certificate in the chain has been revoked."; + } + case ChainValidationResult::Expired: + { + return "A certificate in the chain has expired."; + } + case ChainValidationResult::IncompleteChain: + { + return "The certificate chain is missing one or more certificates."; + } + case ChainValidationResult::InvalidSignature: + { + return "The signature of a certificate in the chain cannot be verified."; + } + case ChainValidationResult::WrongUsage: + { + return "A certificate in the chain is being used for a purpose other than one specified by its CA."; + } + case ChainValidationResult::InvalidName: + { + return "A certificate in the chain has a name that is not valid. The name is either not included in " + "the permitted list or is explicitly excluded."; + } + case ChainValidationResult::InvalidCertificateAuthorityPolicy: + { + return "A certificate in the chain has a policy that is not valid."; + } + case ChainValidationResult::BasicConstraintsError: + { + return "The basic constraint extension of a certificate in the chain has not been observed."; + } + case ChainValidationResult::UnknownCriticalExtension: + { + return "A certificate in the chain contains an unknown extension that is marked \"critical\"."; + } + case ChainValidationResult::RevocationInformationMissing: + { + return "No installed or registered DLL was found to verify revocation."; + } + case ChainValidationResult::RevocationFailure: + { + return "Unable to connect to the revocation server."; + } + case ChainValidationResult::OtherErrors: + { + return "An unexpected error occurred while validating the certificate chain."; + } + default: + { + assert(false); + return ""; + } + } +} + +} IceInternal::NativeInfoPtr IceSSL::TransceiverI::getNativeInfo() @@ -50,6 +130,89 @@ IceSSL::TransceiverI::initialize(IceInternal::Buffer& readBuffer, IceInternal::B else if(!_upgraded) { _upgraded = true; + try + { + auto fd = safe_cast(_delegate->getNativeInfo()->fd()); + if (fd->Information->ServerCertificate) + { + // + // Build the certificate chain + // + auto params = ref new ChainBuildingParameters(); + params->AuthorityInformationAccessEnabled = false; + params->CurrentTimeValidationEnabled = true; + params->NetworkRetrievalEnabled = false; + params->RevocationCheckEnabled = false; + + promise p; + + create_task(fd->Information->ServerCertificate->BuildChainAsync( + fd->Information->ServerIntermediateCertificates, params)).then( + [&](task previous) + { + try + { + p.set_value(previous.get()); + } + catch (Platform::Exception^ ex) + { + try + { + throw SyscallException(__FILE__, __LINE__, ex->HResult); + } + catch(...) + { + p.set_exception(current_exception()); + } + } + }); + + _chain = p.get_future().get(); + + ChainValidationResult result = _chain->Validate(); + // + // Ignore InvalidName errors here SSLEngine::verifyPeer already checks that + // using IceSSL.CheckCertName settings. + // + if(result != ChainValidationResult::InvalidName && result != ChainValidationResult::Success) + { + if(_engine->getVerifyPeer() == 0) + { + if(_instance->traceLevel() >= 1) + { + _instance->logger()->trace(_instance->traceCategory(), + "IceSSL: ignoring certificate verification failure\n" + + validationResultToString(result)); + } + } + else + { + throw SecurityException(__FILE__, __LINE__, + "IceSSL: certificate validation error:\n" + validationResultToString(result)); + } + } + else + { + _verified = true; + } + } + else if((!_incoming && _engine->getVerifyPeer() > 0) || (_incoming && _engine->getVerifyPeer() == 2)) + { + // + // Clients require server certificate if VerifyPeer > 0 and servers require client + // certificate if VerifyPeer == 2 + // + throw SecurityException(__FILE__, __LINE__, "IceSSL: certificate required"); + } + + _engine->verifyPeer(_host, dynamic_pointer_cast(getInfo()), toString()); + } + catch(Platform::Exception^ ex) + { + ostringstream os; + os << "IceSSL: certificate verification failure:\n" << wstringToString(ex->Message->Data()); + throw SecurityException(__FILE__, __LINE__, os.str()); + } } return IceInternal::SocketOperationNone; } @@ -85,6 +248,18 @@ IceSSL::TransceiverI::startWrite(IceInternal::Buffer& buf) { StreamSocket^ stream = safe_cast(_delegate->getNativeInfo()->fd()); HostName^ host = ref new HostName(ref new String(IceUtil::stringToWstring(_host).c_str())); + + // + // We ignre SSL invalid name errors at this point, the certificate name will be later verify + // by SSLEngine veryPeer implementation. + // + stream->Control->IgnorableServerCertificateErrors->Append(ChainValidationResult::InvalidName); + + if(_engine->certificate()) + { + stream->Control->ClientCertificate = _engine->certificate()->getCert(); + } + try { Windows::Foundation::IAsyncAction^ action = stream->UpgradeToSslAsync(SocketProtectionLevel::Tls12, host); @@ -151,11 +326,13 @@ IceSSL::TransceiverI::getInfo() const StreamSocket^ stream = safe_cast(_delegate->getNativeInfo()->fd()); info->nativeCerts.push_back(ICE_MAKE_SHARED(Certificate, stream->Information->ServerCertificate)); info->certs.push_back(info->nativeCerts.back()->encode()); - for(auto iter = stream->Information->ServerIntermediateCertificates->First(); iter->HasCurrent; iter->MoveNext()) + auto certs = _chain ? _chain->GetCertificates(true) : stream->Information->ServerIntermediateCertificates; + for(auto iter = certs->First(); iter->HasCurrent; iter->MoveNext()) { info->nativeCerts.push_back(ICE_MAKE_SHARED(Certificate, iter->Current)); info->certs.push_back(info->nativeCerts.back()->encode()); } + info->verified = _verified; info->adapterName = _adapterName; info->incoming = _incoming; info->underlying = _delegate->getInfo(); @@ -184,7 +361,8 @@ IceSSL::TransceiverI::TransceiverI(const InstancePtr& instance, _incoming(incoming), _delegate(delegate), _connected(false), - _upgraded(false) + _upgraded(false), + _verified(false) { } diff --git a/cpp/src/IceSSL/WinRTTransceiverI.h b/cpp/src/IceSSL/WinRTTransceiverI.h index 29d285175a6..71429198022 100755 --- a/cpp/src/IceSSL/WinRTTransceiverI.h +++ b/cpp/src/IceSSL/WinRTTransceiverI.h @@ -67,6 +67,8 @@ private: bool _connected; bool _upgraded; + bool _verified; + Windows::Security::Cryptography::Certificates::CertificateChain^ _chain; }; typedef IceUtil::Handle TransceiverIPtr; diff --git a/cpp/src/IceSSL/msbuild/icessluwp++11/icessluwp++11.vcxproj b/cpp/src/IceSSL/msbuild/icessluwp++11/icessluwp++11.vcxproj index 6b376e66034..8e4a2dd18fb 100644 --- a/cpp/src/IceSSL/msbuild/icessluwp++11/icessluwp++11.vcxproj +++ b/cpp/src/IceSSL/msbuild/icessluwp++11/icessluwp++11.vcxproj @@ -318,10 +318,6 @@ true true - - - - diff --git a/cpp/src/IceSSL/msbuild/icessluwp++11/icessluwp++11.vcxproj.filters b/cpp/src/IceSSL/msbuild/icessluwp++11/icessluwp++11.vcxproj.filters index 17f262f778e..e3eed3add57 100644 --- a/cpp/src/IceSSL/msbuild/icessluwp++11/icessluwp++11.vcxproj.filters +++ b/cpp/src/IceSSL/msbuild/icessluwp++11/icessluwp++11.vcxproj.filters @@ -144,21 +144,11 @@ Source Files - + + Source Files + - - Header Files - - - Header Files - - - Header Files - - - Header Files - Header Files\Win32\Debug -- cgit v1.2.3