diff options
Diffstat (limited to 'cpp/src/IceSSL/WinRTTransceiverI.cpp')
-rwxr-xr-x | cpp/src/IceSSL/WinRTTransceiverI.cpp | 182 |
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) { } |