From 4849ab6c8b4d9443544cfffe108d6ca26660127d Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Mon, 9 Nov 2015 10:46:58 +0100 Subject: [PATCH] BHttpRequest: add SSL certificate exception management. When an HTTPS request uses an SSL certificate that OpenSSL considers untrusted, and the user decides to continue anyway, add the certificate to an exception list. Match certificates against this list and don't ask the user again if they are already there. Fixes #12004. Thanks to markh for the initial patch and peeking into the WebKit code! --- headers/os/net/Certificate.h | 2 +- headers/os/net/UrlContext.h | 7 ++++- src/kits/network/libnetapi/Certificate.cpp | 8 ++--- src/kits/network/libnetapi/HttpRequest.cpp | 13 +++++--- src/kits/network/libnetapi/UrlContext.cpp | 36 +++++++++++++++++++++- 5 files changed, 55 insertions(+), 11 deletions(-) diff --git a/headers/os/net/Certificate.h b/headers/os/net/Certificate.h index fe064520d8..cb3bee4ee0 100644 --- a/headers/os/net/Certificate.h +++ b/headers/os/net/Certificate.h @@ -29,7 +29,7 @@ public: BString String() const; - bool operator==(const BCertificate& other); + bool operator==(const BCertificate& other) const; private: friend class BSecureSocket::Private; diff --git a/headers/os/net/UrlContext.h b/headers/os/net/UrlContext.h index d561ef5115..514c523ea4 100644 --- a/headers/os/net/UrlContext.h +++ b/headers/os/net/UrlContext.h @@ -1,5 +1,5 @@ /* - * Copyright 2010-2014 Haiku Inc. All rights reserved. + * Copyright 2010-2015 Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. */ @@ -8,6 +8,7 @@ #define _B_URL_CONTEXT_H_ +#include #include #include #include @@ -30,6 +31,7 @@ public: void AddAuthentication(const BUrl& url, const BHttpAuthentication& authentication); void SetProxy(BString host, uint16 port); + void AddCertificateException(const BCertificate& certificate); // Context accessors BNetworkCookieJar& GetCookieJar(); @@ -37,12 +39,15 @@ public: bool UseProxy(); BString GetProxyHost(); uint16 GetProxyPort(); + bool HasCertificateException(const BCertificate& certificate); private: BNetworkCookieJar fCookieJar; typedef BPrivate::SynchronizedHashMap BHttpAuthenticationMap; BHttpAuthenticationMap* fAuthenticationMap; + typedef BObjectList BCertificateSet; + BCertificateSet fCertificates; BString fProxyHost; uint16 fProxyPort; diff --git a/src/kits/network/libnetapi/Certificate.cpp b/src/kits/network/libnetapi/Certificate.cpp index ac2296b049..957790ddb9 100644 --- a/src/kits/network/libnetapi/Certificate.cpp +++ b/src/kits/network/libnetapi/Certificate.cpp @@ -60,7 +60,7 @@ BCertificate::BCertificate(Private* data) BCertificate::BCertificate(const BCertificate& other) { - fPrivate = new(std::nothrow) BCertificate::Private(other.fPrivate); + fPrivate = new(std::nothrow) BCertificate::Private(other.fPrivate->fX509); } @@ -151,7 +151,7 @@ BCertificate::String() const bool -BCertificate::operator==(const BCertificate& other) +BCertificate::operator==(const BCertificate& other) const { return X509_cmp(fPrivate->fX509, other.fPrivate->fX509) == 0; } @@ -168,7 +168,7 @@ BCertificate::Private::Private(X509* data) BCertificate::Private::~Private() { - sk_X509_pop_free(fX509, X509_free); + X509_free(fX509); } @@ -247,7 +247,7 @@ BCertificate::String() const bool -BCertificate::operator==(const BCertificate& other) +BCertificate::operator==(const BCertificate& other) const { return false; } diff --git a/src/kits/network/libnetapi/HttpRequest.cpp b/src/kits/network/libnetapi/HttpRequest.cpp index 972c5ccbea..3c3625007f 100644 --- a/src/kits/network/libnetapi/HttpRequest.cpp +++ b/src/kits/network/libnetapi/HttpRequest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2010-2014 Haiku Inc. All rights reserved. + * Copyright 2010-2015 Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -1083,9 +1083,14 @@ bool BHttpRequest::_CertificateVerificationFailed(BCertificate& certificate, const char* message) { - if (fListener != NULL) { - return fListener->CertificateVerificationFailed(this, certificate, - message); + if (fContext->HasCertificateException(certificate)) + return true; + + if (fListener != NULL + && fListener->CertificateVerificationFailed(this, certificate, message)) { + // User asked us to continue anyway, let's add a temporary exception for this certificate + fContext->AddCertificateException(certificate); + return true; } return false; diff --git a/src/kits/network/libnetapi/UrlContext.cpp b/src/kits/network/libnetapi/UrlContext.cpp index 6a9f6e1028..4a7970a664 100644 --- a/src/kits/network/libnetapi/UrlContext.cpp +++ b/src/kits/network/libnetapi/UrlContext.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2010 Haiku Inc. All rights reserved. + * Copyright 2010-2015 Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Christophe Huriaux, c.huriaux@gmail.com + * Adrien Destugues, pulkomandy@pulkomandy.tk */ @@ -19,6 +20,7 @@ BUrlContext::BUrlContext() : fCookieJar(), fAuthenticationMap(NULL), + fCertificates(20, true), fProxyHost(), fProxyPort(0) { @@ -84,6 +86,16 @@ BUrlContext::SetProxy(BString host, uint16 port) } +void +BUrlContext::AddCertificateException(const BCertificate& certificate) +{ + BCertificate* copy = new(std::nothrow) BCertificate(certificate); + if (copy != NULL) { + fCertificates.AddItem(copy); + } +} + + // #pragma mark Context accessors @@ -133,3 +145,25 @@ BUrlContext::GetProxyPort() { return fProxyPort; } + + +bool +BUrlContext::HasCertificateException(const BCertificate& certificate) +{ + struct Equals: public UnaryPredicate { + Equals(const BCertificate& itemToMatch) + : + fItemToMatch(itemToMatch) + { + } + + int operator()(const BCertificate* item) const + { + return *item == fItemToMatch; + } + + const BCertificate& fItemToMatch; + } comparator(certificate); + + return fCertificates.FindIf(comparator) != NULL; +}