summaryrefslogtreecommitdiff
path: root/cpp/src/IceSSL/WinRTTransceiverI.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/IceSSL/WinRTTransceiverI.cpp')
-rwxr-xr-xcpp/src/IceSSL/WinRTTransceiverI.cpp182
1 files changed, 180 insertions, 2 deletions
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 <IceSSL/WinRTTransceiverI.h>
#include <IceSSL/Instance.h>
#include <IceSSL/SSLEngine.h>
+#include <Ice/Logger.h>
+#include <ppltasks.h>
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<StreamSocket^>(_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<CertificateChain^> p;
+
+ create_task(fd->Information->ServerCertificate->BuildChainAsync(
+ fd->Information->ServerIntermediateCertificates, params)).then(
+ [&](task<CertificateChain^> 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<IceSSL::NativeConnectionInfo>(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<StreamSocket^>(_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<StreamSocket^>(_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)
{
}