bug 1003448 - HTTP/2 Alternate Service and Opportunistic Security [1/2 PSM] r=keeler
--- a/netwerk/socket/nsISSLSocketControl.idl
+++ b/netwerk/socket/nsISSLSocketControl.idl
@@ -10,17 +10,17 @@ interface nsIInterfaceRequestor;
interface nsIX509Cert;
%{C++
template<class T> class nsTArray;
class nsCString;
%}
[ref] native nsCStringTArrayRef(nsTArray<nsCString>);
-[scriptable, builtinclass, uuid(89b819dc-31b0-4d09-915a-66f8a3703483)]
+[scriptable, builtinclass, uuid(f160ec31-01f3-47f2-b542-0e12a647b07f)]
interface nsISSLSocketControl : nsISupports {
attribute nsIInterfaceRequestor notificationCallbacks;
void proxyStartSSL();
void StartTLS();
/* NPN (Next Protocol Negotiation) is a mechanism for
negotiating the protocol to be spoken inside the SSL
@@ -48,16 +48,21 @@ interface nsISSLSocketControl : nsISuppo
* a desired NPN negotiated protocol of npnProtocol can use the socket
* associated with this object instead of making a new one.
*/
boolean joinConnection(
in ACString npnProtocol, /* e.g. "spdy/2" */
in ACString hostname,
in long port);
+ /* Determine if existing connection should be trusted to convey information about
+ * a hostname.
+ */
+ boolean isAcceptableForHost(in ACString hostname);
+
/* The Key Exchange Algorithm is used when determining whether or
not to do false start and whether or not HTTP/2 can be used.
After a handshake is complete it can be read from KEAUsed,
before a handshake is started it may be set through KEAExpected.
The values correspond to the SSLKEAType enum in NSS or the
KEY_EXCHANGE_UNKNOWN constant defined below.
@@ -98,10 +103,31 @@ interface nsISSLSocketControl : nsISuppo
[infallible] readonly attribute short MACAlgorithmUsed;
/**
* If set before the server requests a client cert (assuming it does so at
* all), then this cert will be presented to the server, instead of asking
* the user or searching the set of rememebered user cert decisions.
*/
attribute nsIX509Cert clientCert;
+
+ /**
+ * If you wish to verify the host certificate using a different name than
+ * was used for the tcp connection, but without using proxy semantics, you
+ * can set authenticationName and authenticationPort
+ */
+ attribute ACString authenticationName;
+ [infallible] attribute long authenticationPort;
+
+ /**
+ * set bypassAuthentication to true if the server certificate checks should
+ * not be enforced. This is to enable non-secure transport over TLS.
+ */
+ [infallible] attribute boolean bypassAuthentication;
+
+ /*
+ * failedVerification is true if any enforced certificate checks have failed.
+ * Connections that have not yet tried to verify, have verifications bypassed,
+ * or are using acceptable exceptions will all return false.
+ */
+ [infallible] readonly attribute boolean failedVerification;
};
--- a/security/manager/ssl/src/SSLServerCertVerification.cpp
+++ b/security/manager/ssl/src/SSLServerCertVerification.cpp
@@ -395,16 +395,26 @@ CertErrorRunnable::CheckCertOverrides()
unused << mFdForLogging;
if (!NS_IsMainThread()) {
NS_ERROR("CertErrorRunnable::CheckCertOverrides called off main thread");
return new SSLServerCertVerificationResult(mInfoObject,
mDefaultErrorCodeToReport);
}
+ nsCOMPtr<nsISSLSocketControl> sslSocketControl = do_QueryInterface(
+ NS_ISUPPORTS_CAST(nsITransportSecurityInfo*, mInfoObject));
+ if (sslSocketControl &&
+ sslSocketControl->GetBypassAuthentication()) {
+ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
+ ("[%p][%p] Bypass Auth in CheckCertOverrides\n",
+ mFdForLogging, this));
+ return new SSLServerCertVerificationResult(mInfoObject, 0);
+ }
+
int32_t port;
mInfoObject->GetPort(&port);
nsAutoCString hostWithPortString(mInfoObject->GetHostName());
hostWithPortString.Append(':');
hostWithPortString.AppendInt(port);
uint32_t remaining_display_errors = mCollectedErrors;
@@ -484,18 +494,16 @@ CertErrorRunnable::CheckCertOverrides()
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
("[%p][%p] Certificate error was not overridden\n",
mFdForLogging, this));
// Ok, this is a full stop.
// First, deliver the technical details of the broken SSL status.
// Try to get a nsIBadCertListener2 implementation from the socket consumer.
- nsCOMPtr<nsISSLSocketControl> sslSocketControl = do_QueryInterface(
- NS_ISUPPORTS_CAST(nsITransportSecurityInfo*, mInfoObject));
if (sslSocketControl) {
nsCOMPtr<nsIInterfaceRequestor> cb;
sslSocketControl->GetNotificationCallbacks(getter_AddRefs(cb));
if (cb) {
nsCOMPtr<nsIBadCertListener2> bcl = do_GetInterface(cb);
if (bcl) {
nsIInterfaceRequestor* csi
= static_cast<nsIInterfaceRequestor*>(mInfoObject);
--- a/security/manager/ssl/src/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/src/nsNSSIOLayer.cpp
@@ -127,21 +127,23 @@ nsNSSSocketInfo::nsNSSSocketInfo(SharedS
mNPNCompleted(false),
mFalseStartCallbackCalled(false),
mFalseStarted(false),
mIsFullHandshake(false),
mHandshakeCompleted(false),
mJoined(false),
mSentClientCert(false),
mNotedTimeUntilReady(false),
+ mFailedVerification(false),
mKEAUsed(nsISSLSocketControl::KEY_EXCHANGE_UNKNOWN),
mKEAExpected(nsISSLSocketControl::KEY_EXCHANGE_UNKNOWN),
mKEAKeyBits(0),
mSSLVersionUsed(nsISSLSocketControl::SSL_VERSION_UNKNOWN),
mMACAlgorithmUsed(nsISSLSocketControl::SSL_MAC_UNKNOWN),
+ mBypassAuthentication(false),
mProviderFlags(providerFlags),
mSocketCreationTimestamp(TimeStamp::Now()),
mPlaintextBytesRead(0),
mClientCert(nullptr)
{
mTLSVersionRange.min = 0;
mTLSVersionRange.max = 0;
}
@@ -222,16 +224,62 @@ nsNSSSocketInfo::GetClientCert(nsIX509Ce
NS_IMETHODIMP
nsNSSSocketInfo::SetClientCert(nsIX509Cert* aClientCert)
{
mClientCert = aClientCert;
return NS_OK;
}
NS_IMETHODIMP
+nsNSSSocketInfo::GetBypassAuthentication(bool* arg)
+{
+ *arg = mBypassAuthentication;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNSSSocketInfo::SetBypassAuthentication(bool arg)
+{
+ mBypassAuthentication = arg;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNSSSocketInfo::GetFailedVerification(bool* arg)
+{
+ *arg = mFailedVerification;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNSSSocketInfo::GetAuthenticationName(nsACString& aAuthenticationName)
+{
+ aAuthenticationName = GetHostName();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNSSSocketInfo::SetAuthenticationName(const nsACString& aAuthenticationName)
+{
+ return SetHostName(PromiseFlatCString(aAuthenticationName).get());
+}
+
+NS_IMETHODIMP
+nsNSSSocketInfo::GetAuthenticationPort(int32_t* aAuthenticationPort)
+{
+ return GetPort(aAuthenticationPort);
+}
+
+NS_IMETHODIMP
+nsNSSSocketInfo::SetAuthenticationPort(int32_t aAuthenticationPort)
+{
+ return SetPort(aAuthenticationPort);
+}
+
+NS_IMETHODIMP
nsNSSSocketInfo::GetRememberClientAuthCertificate(bool* aRemember)
{
NS_ENSURE_ARG_POINTER(aRemember);
*aRemember = mRememberClientAuthCertificate;
return NS_OK;
}
NS_IMETHODIMP
@@ -373,31 +421,18 @@ nsNSSSocketInfo::GetNegotiatedNPN(nsACSt
if (!mNPNCompleted)
return NS_ERROR_NOT_CONNECTED;
aNegotiatedNPN = mNegotiatedNPN;
return NS_OK;
}
NS_IMETHODIMP
-nsNSSSocketInfo::JoinConnection(const nsACString& npnProtocol,
- const nsACString& hostname,
- int32_t port,
- bool* _retval)
+nsNSSSocketInfo::IsAcceptableForHost(const nsACString& hostname, bool* _retval)
{
- *_retval = false;
-
- // Different ports may not be joined together
- if (port != GetPort())
- return NS_OK;
-
- // Make sure NPN has been completed and matches requested npnProtocol
- if (!mNPNCompleted || !mNegotiatedNPN.Equals(npnProtocol))
- return NS_OK;
-
// If this is the same hostname then the certicate status does not
// need to be considered. They are joinable.
if (hostname.Equals(GetHostName())) {
*_retval = true;
return NS_OK;
}
// Before checking the server certificate we need to make sure the
@@ -457,22 +492,46 @@ nsNSSSocketInfo::JoinConnection(const ns
mozilla::pkix::Now(),
nullptr, hostnameFlat.get(),
false, flags, nullptr,
nullptr);
if (rv != SECSuccess) {
return NS_OK;
}
- // All tests pass - this is joinable
- mJoined = true;
+ // All tests pass
*_retval = true;
return NS_OK;
}
+NS_IMETHODIMP
+nsNSSSocketInfo::JoinConnection(const nsACString& npnProtocol,
+ const nsACString& hostname,
+ int32_t port,
+ bool* _retval)
+{
+ *_retval = false;
+
+ // Different ports may not be joined together
+ if (port != GetPort())
+ return NS_OK;
+
+ // Make sure NPN has been completed and matches requested npnProtocol
+ if (!mNPNCompleted || !mNegotiatedNPN.Equals(npnProtocol))
+ return NS_OK;
+
+ IsAcceptableForHost(hostname, _retval);
+
+ if (*_retval) {
+ // All tests pass - this is joinable
+ mJoined = true;
+ }
+ return NS_OK;
+}
+
bool
nsNSSSocketInfo::GetForSTARTTLS()
{
return mForSTARTTLS;
}
void
nsNSSSocketInfo::SetForSTARTTLS(bool aForSTARTTLS)
@@ -627,16 +686,17 @@ nsNSSSocketInfo::SetCertVerificationResu
if (errorCode == 0) {
NS_ERROR("SSL_AuthCertificateComplete didn't set error code");
errorCode = PR_INVALID_STATE_ERROR;
}
}
}
if (errorCode) {
+ mFailedVerification = true;
SetCanceled(errorCode, errorMessageType);
}
if (mPlaintextBytesRead && !errorCode) {
Telemetry::Accumulate(Telemetry::SSL_BYTES_BEFORE_CERT_CALLBACK,
AssertedCast<uint32_t>(mPlaintextBytesRead));
}
--- a/security/manager/ssl/src/nsNSSIOLayer.h
+++ b/security/manager/ssl/src/nsNSSIOLayer.h
@@ -108,16 +108,32 @@ public:
void SetSSLVersionUsed(int16_t version)
{
mSSLVersionUsed = version;
}
void SetMACAlgorithmUsed(int16_t mac) { mMACAlgorithmUsed = mac; }
+ inline bool GetBypassAuthentication()
+ {
+ bool result = false;
+ mozilla::DebugOnly<nsresult> rv = GetBypassAuthentication(&result);
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
+ return result;
+ }
+
+ inline int32_t GetAuthenticationPort()
+ {
+ int32_t result = -1;
+ mozilla::DebugOnly<nsresult> rv = GetAuthenticationPort(&result);
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
+ return result;
+ }
+
protected:
virtual ~nsNSSSocketInfo();
private:
PRFileDesc* mFd;
CertVerificationState mCertVerificationState;
@@ -134,24 +150,26 @@ private:
bool mNPNCompleted;
bool mFalseStartCallbackCalled;
bool mFalseStarted;
bool mIsFullHandshake;
bool mHandshakeCompleted;
bool mJoined;
bool mSentClientCert;
bool mNotedTimeUntilReady;
+ bool mFailedVerification;
// mKEA* are used in false start and http/2 detetermination
// Values are from nsISSLSocketControl
int16_t mKEAUsed;
int16_t mKEAExpected;
uint32_t mKEAKeyBits;
int16_t mSSLVersionUsed;
int16_t mMACAlgorithmUsed;
+ bool mBypassAuthentication;
uint32_t mProviderFlags;
mozilla::TimeStamp mSocketCreationTimestamp;
uint64_t mPlaintextBytesRead;
nsCOMPtr<nsIX509Cert> mClientCert;
};