diff --git a/NetSSL_OpenSSL/src/HTTPSStreamFactory.cpp b/NetSSL_OpenSSL/src/HTTPSStreamFactory.cpp index 371c2bde1..0f23d2408 100644 --- a/NetSSL_OpenSSL/src/HTTPSStreamFactory.cpp +++ b/NetSSL_OpenSSL/src/HTTPSStreamFactory.cpp @@ -75,17 +75,25 @@ HTTPSStreamFactory::~HTTPSStreamFactory() std::istream* HTTPSStreamFactory::open(const URI& uri) { - poco_assert (uri.getScheme() == "https"); + poco_assert (uri.getScheme() == "https" || uri.getScheme() == "http"); URI resolvedURI(uri); + URI proxyUri; HTTPClientSession* pSession = 0; try { + bool retry = false; int redirects = 0; do { - pSession = new HTTPSClientSession(resolvedURI.getHost(), resolvedURI.getPort()); - pSession->setProxy(_proxyHost, _proxyPort); + if (resolvedURI.getScheme() != "http") + pSession = new HTTPSClientSession(resolvedURI.getHost(), resolvedURI.getPort()); + else + pSession = new HTTPClientSession(resolvedURI.getHost(), resolvedURI.getPort()); + if (proxyUri.empty()) + pSession->setProxy(_proxyHost, _proxyPort); + else + pSession->setProxy(proxyUri.getHost(), proxyUri.getPort()); std::string path = resolvedURI.getPathAndQuery(); if (path.empty()) path = "/"; HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1); @@ -94,20 +102,38 @@ std::istream* HTTPSStreamFactory::open(const URI& uri) std::istream& rs = pSession->receiveResponse(res); bool moved = (res.getStatus() == HTTPResponse::HTTP_MOVED_PERMANENTLY || res.getStatus() == HTTPResponse::HTTP_FOUND || - res.getStatus() == HTTPResponse::HTTP_SEE_OTHER); + res.getStatus() == HTTPResponse::HTTP_SEE_OTHER || + res.getStatus() == HTTPResponse::HTTP_TEMPORARY_REDIRECT); if (moved) { resolvedURI.resolve(res.get("Location")); - delete pSession; + //throw URIRedirection(resolvedURI.toString()); + delete pSession; pSession = 0; ++redirects; + retry = true; } else if (res.getStatus() == HTTPResponse::HTTP_OK) { return new HTTPResponseStream(rs, pSession); } - else throw HTTPException(res.getReason(), uri.toString()); + else if (res.getStatus() == HTTPResponse::HTTP_USEPROXY && !retry) + { + //The requested resource MUST be accessed through the proxy + //given by the Location field. The Location field gives the + //URI of the proxy. The recipient is expected to repeat this + //single request via the proxy. 305 responses MUST only be generated by origin servers. + // only use for one single request! + proxyUri.resolve(res.get("Location")); + delete pSession; pSession = 0; + retry = true; //only allow useproxy once + } + else + { + delete pSession; pSession = 0; + throw HTTPException(res.getReason(), uri.toString()); + } } - while (redirects < MAX_REDIRECTS); + while (retry && redirects < MAX_REDIRECTS); throw HTTPException("Too many redirects", uri.toString()); } catch (...) diff --git a/NetSSL_OpenSSL/src/SecureSocketImpl.cpp b/NetSSL_OpenSSL/src/SecureSocketImpl.cpp index e80722727..944d95b87 100644 --- a/NetSSL_OpenSSL/src/SecureSocketImpl.cpp +++ b/NetSSL_OpenSSL/src/SecureSocketImpl.cpp @@ -48,6 +48,7 @@ #include "Poco/RegularExpression.h" #include #include +#include using Poco::IOException; @@ -66,6 +67,9 @@ namespace Poco { namespace Net { +static void getCertNames (X509*, std::string& commonName, std::set& DNSNames); + + SecureSocketImpl::SecureSocketImpl():_pBIO(0), _pSSL(0) { } @@ -420,43 +424,10 @@ long SecureSocketImpl::postConnectionCheck(SSLManager::ContextPtr pContext, X509 return X509_V_ERR_APPLICATION_VERIFICATION; } - bool ok = false; - - if ((extcount = X509_get_ext_count(cert)) > 0) - { - for (int i = 0; i < extcount && !ok; ++i) - { - const char* extstr = 0; - X509_EXTENSION* ext; - ext = X509_get_ext(cert, i); - extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext))); - - if (!strcmp(extstr, "subjectAltName")) - { - X509V3_EXT_METHOD* meth = X509V3_EXT_get(ext); - if (!meth) - break; - -#if OPENSSL_VERSION_NUMBER >= 0x00908000 - const unsigned char* pData = ext->value->data; - const unsigned char** ppData = &pData; -#else - unsigned char* pData = ext->value->data; - unsigned char** ppData = &pData; -#endif - STACK_OF(CONF_VALUE)* val = meth->i2v(meth, meth->d2i(0, ppData, ext->value->length), 0); - - for (int j = 0; j < sk_CONF_VALUE_num(val) && !ok; ++j) - { - CONF_VALUE* nval = sk_CONF_VALUE_value(val, j); - if (!strcmp(nval->name, "DNS") && !strcmp(nval->value, host)) - { - ok = true; - } - } - } - } - } + std::string commonName; + std::set dnsNames; + getCertNames(cert, commonName, dnsNames); + bool ok = (dnsNames.find(hostName) != dnsNames.end()); char data[256]; if (!ok && (subj = X509_get_subject_name(cert)) && X509_NAME_get_text_by_NID(subj, NID_commonName, data, 256) > 0) @@ -618,4 +589,48 @@ bool SecureSocketImpl::matchByAlias(const std::string& alias, const HostEntry& h } +static void +getCertNames (X509 *certificate, + std::string& common_name, + std::set& DNS_names) +{ + DNS_names.clear (); + common_name.clear (); + if (certificate == 0) + { + return; + } + + if (STACK_OF (GENERAL_NAME) * names = static_cast + (X509_get_ext_d2i (certificate, NID_subject_alt_name, 0, 0))) + { + for (int i = 0; i < sk_GENERAL_NAME_num (names); ++i) + { + const GENERAL_NAME *name = sk_GENERAL_NAME_value (names, i); + if (name->type == GEN_DNS) + { + const char *data = reinterpret_cast + (ASN1_STRING_data (name->d.ia5)); + size_t len = ASN1_STRING_length (name->d.ia5); + DNS_names.insert (std::string (data, len)); + } + } + GENERAL_NAMES_free (names); + } + + if (X509_NAME * subj = X509_get_subject_name (certificate)) + { + char buffer[256]; + X509_NAME_get_text_by_NID (subj, NID_commonName, + buffer, sizeof buffer); + common_name = std::string (buffer); + if (DNS_names.empty ()) + { + DNS_names.insert (common_name); + } + } +} + + } } // namespace Poco::Net diff --git a/NetSSL_OpenSSL/testsuite/src/HTTPSClientSessionTest.cpp b/NetSSL_OpenSSL/testsuite/src/HTTPSClientSessionTest.cpp index d5d45cee2..956b1bb5f 100644 --- a/NetSSL_OpenSSL/testsuite/src/HTTPSClientSessionTest.cpp +++ b/NetSSL_OpenSSL/testsuite/src/HTTPSClientSessionTest.cpp @@ -31,6 +31,7 @@ #include "HTTPSClientSessionTest.h" +#include "HTTPSClientTestSuite.h" #include "CppUnit/TestCaller.h" #include "CppUnit/TestSuite.h" #include "Poco/Net/HTTPSClientSession.h" @@ -336,7 +337,7 @@ void HTTPSClientSessionTest::testKeepAlive() void HTTPSClientSessionTest::testProxy() { HTTPSTestServer srv; - HTTPSClientSession s("wwws.appinf.com"); + HTTPSClientSession s(TESTSERVERNAME); s.setProxy("proxy.aon.at", 8080); HTTPRequest request(HTTPRequest::HTTP_GET, "/"); s.sendRequest(request); @@ -351,7 +352,7 @@ void HTTPSClientSessionTest::testProxy() void HTTPSClientSessionTest::testConnectNB() { SecureStreamSocket sock; - sock.connectNB(SocketAddress("server.com", 443)); + sock.connectNB(SocketAddress(TESTSERVERNAME, 443)); char buf[512]; std::string msg("GET / HTTP/1.0\r\n\r\n"); sock.sendBytes(msg.c_str(), (int)msg.length()); diff --git a/NetSSL_OpenSSL/testsuite/src/HTTPSClientTestSuite.h b/NetSSL_OpenSSL/testsuite/src/HTTPSClientTestSuite.h index 9d81014ff..9f6f94db6 100644 --- a/NetSSL_OpenSSL/testsuite/src/HTTPSClientTestSuite.h +++ b/NetSSL_OpenSSL/testsuite/src/HTTPSClientTestSuite.h @@ -39,6 +39,8 @@ #include "CppUnit/TestSuite.h" +#define TESTSERVERNAME "secure.appinf.com" + class HTTPSClientTestSuite { public: diff --git a/NetSSL_OpenSSL/testsuite/src/HTTPSStreamFactoryTest.cpp b/NetSSL_OpenSSL/testsuite/src/HTTPSStreamFactoryTest.cpp index 1d3126143..e33932532 100644 --- a/NetSSL_OpenSSL/testsuite/src/HTTPSStreamFactoryTest.cpp +++ b/NetSSL_OpenSSL/testsuite/src/HTTPSStreamFactoryTest.cpp @@ -31,6 +31,7 @@ #include "HTTPSStreamFactoryTest.h" +#include "HTTPSClientTestSuite.h" #include "CppUnit/TestCaller.h" #include "CppUnit/TestSuite.h" #include "Poco/Net/HTTPSStreamFactory.h" @@ -103,7 +104,7 @@ void HTTPSStreamFactoryTest::testProxy() { HTTPSTestServer server; HTTPSStreamFactory factory("proxy.aon.at", 8080); - URI uri("https://wwws.appinf.com/"); + URI uri(std::string("https://") + TESTSERVERNAME + "/"); std::auto_ptr pStr(factory.open(uri)); std::ostringstream ostr; StreamCopier::copyStream(*pStr.get(), ostr);