Bug 954534 - Use toolkit untrusted cert dialog for "SSL Handshake failed" errors: chat/ part, r=florian.

This commit is contained in:
Patrick Cloke 2013-04-10 18:56:57 -04:00
Родитель 3ee5cdae24
Коммит 7c994c36f0
5 изменённых файлов: 68 добавлений и 13 удалений

Просмотреть файл

@ -103,6 +103,11 @@ interface prplIAccount: nsISupports {
/* When a connection error occurred, this value indicates the type of error */ /* When a connection error occurred, this value indicates the type of error */
readonly attribute short connectionErrorReason; readonly attribute short connectionErrorReason;
/* When a certificate error occurs, the host/port that caused a
* SSL/certificate error when connecting to it. This is only valid when
* connectionErrorReason is one of ERROR_CERT_*. */
readonly attribute AUTF8String connectionTarget;
/* Possible connection error reasons: /* Possible connection error reasons:
ERROR_NETWORK_ERROR and ERROR_ENCRYPTION_ERROR are not fatal and ERROR_NETWORK_ERROR and ERROR_ENCRYPTION_ERROR are not fatal and
should enable the automatic reconnection feature. */ should enable the automatic reconnection feature. */

Просмотреть файл

@ -52,6 +52,40 @@ const GenericAccountPrototype = {
_connectionErrorReason: Ci.prplIAccount.NO_ERROR, _connectionErrorReason: Ci.prplIAccount.NO_ERROR,
get connectionErrorReason() this._connectionErrorReason, get connectionErrorReason() this._connectionErrorReason,
handleBadCertificate: function(aSocket, aIsSslError) {
this._connectionTarget = aSocket.host + ":" + aSocket.port;
if (aIsSslError)
return Ci.prplIAccount.ERROR_ENCRYPTION_ERROR;
let sslStatus = aSocket.sslStatus;
if (!sslStatus)
return Ci.prplIAccount.ERROR_CERT_NOT_PROVIDED;
if (sslStatus.isUntrusted) {
if (sslStatus.serverCert instanceof Ci.nsIX509Cert3 &&
sslStatus.serverCert.isSelfSigned)
return Ci.prplIAccount.ERROR_CERT_SELF_SIGNED;
return Ci.prplIAccount.ERROR_CERT_UNTRUSTED;
}
if (sslStatus.isNotValidAtThisTime) {
if (sslStatus.serverCert instanceof Ci.nsIX509Cert3 &&
sslStatus.serverCert.validity.notBefore < Date.now() * 1000)
return Ci.prplIAccount.ERROR_CERT_NOT_ACTIVATED;
return Ci.prplIAccount.ERROR_CERT_EXPIRED;
}
if (sslStatus.isDomainMismatch)
return Ci.prplIAccount.ERROR_CERT_HOSTNAME_MISMATCH;
// XXX ERROR_CERT_FINGERPRINT_MISMATCH
return Ci.prplIAccount.ERROR_CERT_OTHER_ERROR;
},
_connectionTarget: "",
get connectionTarget() this._connectionTarget,
reportConnected: function() { reportConnected: function() {
this.imAccount.observe(this, "account-connected", null); this.imAccount.observe(this, "account-connected", null);
}, },

Просмотреть файл

@ -35,6 +35,7 @@
* connectTimeout (default is no timeout) * connectTimeout (default is no timeout)
* readWriteTimeout (default is no timeout) * readWriteTimeout (default is no timeout)
* isConnected * isConnected
* sslStatus
* *
* Users should "subclass" this object, i.e. set their .__proto__ to be it. And * Users should "subclass" this object, i.e. set their .__proto__ to be it. And
* then implement: * then implement:
@ -42,7 +43,7 @@
* onConnectionHeard() * onConnectionHeard()
* onConnectionTimedOut() * onConnectionTimedOut()
* onConnectionReset() * onConnectionReset()
* onBadCertificate(AString aNSSErrorMessage) * onBadCertificate(boolean aIsSslError, AString aNSSErrorMessage)
* onConnectionClosed() * onConnectionClosed()
* onDataReceived(String <data>) * onDataReceived(String <data>)
* <length handled> = onBinaryDataReceived(ArrayBuffer <data>) * <length handled> = onBinaryDataReceived(ArrayBuffer <data>)
@ -131,6 +132,9 @@ const Socket = {
connectTimeout: 0, connectTimeout: 0,
readWriteTimeout: 0, readWriteTimeout: 0,
// A nsISSLStatus instance giving details about the certificate error.
sslStatus: null,
/* /*
***************************************************************************** *****************************************************************************
******************************* Public methods ****************************** ******************************* Public methods ******************************
@ -402,12 +406,16 @@ const Socket = {
this.onConnectionReset(); this.onConnectionReset();
else if (aStatus == NS_ERROR_NET_TIMEOUT) else if (aStatus == NS_ERROR_NET_TIMEOUT)
this.onConnectionTimedOut(); this.onConnectionTimedOut();
else if (aStatus) { else if (!Components.isSuccessCode(aStatus)) {
let nssErrorsService = let nssErrorsService =
Cc["@mozilla.org/nss_errors_service;1"].getService(Ci.nsINSSErrorsService); Cc["@mozilla.org/nss_errors_service;1"].getService(Ci.nsINSSErrorsService);
if (aStatus <= nssErrorsService.getXPCOMFromNSSError(nssErrorsService.NSS_SEC_ERROR_BASE) && if ((aStatus <= nssErrorsService.getXPCOMFromNSSError(nssErrorsService.NSS_SEC_ERROR_BASE) &&
aStatus >= nssErrorsService.getXPCOMFromNSSError(nssErrorsService.NSS_SEC_ERROR_LIMIT - 1)) { aStatus >= nssErrorsService.getXPCOMFromNSSError(nssErrorsService.NSS_SEC_ERROR_LIMIT - 1)) ||
this.onBadCertificate(nssErrorsService.getErrorMessage(aStatus)); (aStatus <= nssErrorsService.getXPCOMFromNSSError(nssErrorsService.NSS_SSL_ERROR_BASE) &&
aStatus >= nssErrorsService.getXPCOMFromNSSError(nssErrorsService.NSS_SSL_ERROR_LIMIT - 1))) {
this.onBadCertificate(nssErrorsService.getErrorClass(aStatus) ==
nssErrorsService.ERROR_CLASS_SSL_PROTOCOL,
nssErrorsService.getErrorMessage(aStatus));
return; return;
} }
} }
@ -419,12 +427,18 @@ const Socket = {
*/ */
// Called when there's an error, return true to suppress the modal alert. // Called when there's an error, return true to suppress the modal alert.
// Whatever this function returns, NSS will close the connection. // Whatever this function returns, NSS will close the connection.
notifyCertProblem: function(aSocketInfo, aStatus, aTargetSite) true, notifyCertProblem: function(aSocketInfo, aStatus, aTargetSite) {
this.sslStatus = aStatus;
return true;
},
/* /*
* nsISSLErrorListener * nsISSLErrorListener
*/ */
notifySSLError: function(aSocketInfo, aError, aTargetSite) true, notifySSLError: function(aSocketInfo, aError, aTargetSite) {
this.sslStatus = null;
return true;
},
/* /*
* nsITransportEventSink methods * nsITransportEventSink methods

Просмотреть файл

@ -674,10 +674,11 @@ ircSocket.prototype = {
this._account.gotDisconnected(Ci.prplIAccount.ERROR_NETWORK_ERROR, this._account.gotDisconnected(Ci.prplIAccount.ERROR_NETWORK_ERROR,
_("connection.error.timeOut")); _("connection.error.timeOut"));
}, },
onBadCertificate: function(aNSSErrorMessage) { onBadCertificate: function(aIsSslError, aNSSErrorMessage) {
this.ERROR("bad certificate: " + aNSSErrorMessage); this.ERROR("Bad certificate or SSL connection for " + this._account.name +
this._account.gotDisconnected(Ci.prplIAccount.ERROR_CERT_OTHER_ERROR, ":\n" + aNSSErrorMessage);
aNSSErrorMessage); let error = this._account.handleBadCertificate(this, aIsSslError);
this._account.gotDisconnected(error, aNSSErrorMessage);
}, },
get DEBUG() this._account.DEBUG, get DEBUG() this._account.DEBUG,

Просмотреть файл

@ -196,8 +196,9 @@ XMPPSession.prototype = {
onConnectionClosed: function() { onConnectionClosed: function() {
this._networkError(_("connection.error.serverClosedConnection")); this._networkError(_("connection.error.serverClosedConnection"));
}, },
onBadCertificate: function(aNSSErrorMessage) { onBadCertificate: function(aIsSslError, aNSSErrorMessage) {
this.onError(Ci.prplIAccount.ERROR_CERT_OTHER_ERROR, aNSSErrorMessage); let error = this._account.handleBadCertificate(this, aIsSslError);
this.onError(error, aNSSErrorMessage);
}, },
onConnectionReset: function() { onConnectionReset: function() {
this._networkError(_("connection.error.resetByPeer")); this._networkError(_("connection.error.resetByPeer"));