diff --git a/mercurial/error.py b/mercurial/error.py --- a/mercurial/error.py +++ b/mercurial/error.py @@ -212,6 +212,14 @@ """ +class SecurityError(Abort): + """Indicates that some aspect of security failed. + + Examples: Bad server credentials, expired local credentials for network + filesystem, mismatched GPG signature, DoS protection. + """ + + class HookLoadError(Abort): """raised when loading a hook fails, aborting an operation diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -228,6 +228,8 @@ detailed_exit_code = 20 elif isinstance(inst, error.ConfigError): detailed_exit_code = 30 + elif isinstance(inst, error.SecurityError): + detailed_exit_code = 150 elif isinstance(inst, error.CanceledError): detailed_exit_code = 250 ui.error(inst.format()) diff --git a/mercurial/sslutil.py b/mercurial/sslutil.py --- a/mercurial/sslutil.py +++ b/mercurial/sslutil.py @@ -470,7 +470,7 @@ # closed # - see http://bugs.python.org/issue13721 if not sslsocket.cipher(): - raise error.Abort(_(b'ssl connection failed')) + raise error.SecurityError(_(b'ssl connection failed')) sslsocket._hgstate = { b'caloaded': caloaded, @@ -736,10 +736,10 @@ peercert = sock.getpeercert(True) peercert2 = sock.getpeercert() except AttributeError: - raise error.Abort(_(b'%s ssl connection error') % host) + raise error.SecurityError(_(b'%s ssl connection error') % host) if not peercert: - raise error.Abort( + raise error.SecurityError( _(b'%s certificate error: no certificate received') % host ) @@ -801,7 +801,7 @@ else: section = b'hostsecurity' nice = b'%s:%s' % (hash, fmtfingerprint(peerfingerprints[hash])) - raise error.Abort( + raise error.SecurityError( _(b'certificate for %s has unexpected fingerprint %s') % (host, nice), hint=_(b'check %s configuration') % section, @@ -810,7 +810,7 @@ # Security is enabled but no CAs are loaded. We can't establish trust # for the cert so abort. if not sock._hgstate[b'caloaded']: - raise error.Abort( + raise error.SecurityError( _( b'unable to verify security of %s (no loaded CA certificates); ' b'refusing to connect' @@ -826,7 +826,7 @@ msg = _verifycert(peercert2, shost) if msg: - raise error.Abort( + raise error.SecurityError( _(b'%s certificate error: %s') % (host, msg), hint=_( b'set hostsecurity.%s:certfingerprints=%s ' diff --git a/tests/test-https.t b/tests/test-https.t --- a/tests/test-https.t +++ b/tests/test-https.t @@ -125,7 +125,7 @@ $ hg clone https://localhost:$HGPORT/ copy-pull $DISABLECACERTS abort: unable to verify security of localhost (no loaded CA certificates); refusing to connect (see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error or set hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e to trust this server) - [255] + [150] $ hg clone --insecure https://localhost:$HGPORT/ copy-pull warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering @@ -160,7 +160,7 @@ pulling from https://localhost:$HGPORT/ abort: unable to verify security of localhost (no loaded CA certificates); refusing to connect (see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error or set hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e to trust this server) - [255] + [150] $ hg pull --insecure pulling from https://localhost:$HGPORT/ @@ -227,7 +227,7 @@ pulling from https://*:$HGPORT/ (glob) abort: $LOCALIP certificate error: certificate is for localhost (glob) (set hostsecurity.$LOCALIP:certfingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e config setting or use --insecure to connect insecurely) - [255] + [150] $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub.pem" \ > https://$LOCALIP:$HGPORT/ --insecure pulling from https://*:$HGPORT/ (glob) @@ -319,18 +319,18 @@ $ hg --config 'hostfingerprints.localhost=deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, aeadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/ --insecure abort: certificate for localhost has unexpected fingerprint ec:d8:7c:d6:b3:86:d0:4f:c1:b8:b4:1c:9d:8f:5e:16:8e:ef:1c:03 (check hostfingerprint configuration) - [255] + [150] $ hg --config 'hostsecurity.localhost:fingerprints=sha1:deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, sha1:aeadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/ abort: certificate for localhost has unexpected fingerprint sha1:ec:d8:7c:d6:b3:86:d0:4f:c1:b8:b4:1c:9d:8f:5e:16:8e:ef:1c:03 (check hostsecurity configuration) - [255] + [150] - fails when cert doesn't match hostname (port is ignored) $ hg -R copy-pull id https://localhost:$HGPORT1/ --config hostfingerprints.localhost=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03 abort: certificate for localhost has unexpected fingerprint f4:2f:5a:0c:3e:52:5b:db:e7:24:a8:32:1d:18:97:6d:69:b5:87:84 (check hostfingerprint configuration) - [255] + [150] - ignores that certificate doesn't match hostname diff --git a/tests/test-patchbomb-tls.t b/tests/test-patchbomb-tls.t --- a/tests/test-patchbomb-tls.t +++ b/tests/test-patchbomb-tls.t @@ -73,7 +73,7 @@ (verifying remote certificate) abort: unable to verify security of localhost (no loaded CA certificates); refusing to connect (see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error or set hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e to trust this server) - [255] + [150] With global certificates: