From 56784b684a141fadb037e8b76752177a2e3b4e9c Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Fri, 16 Dec 2022 12:06:05 +0200 Subject: [PATCH] allow expired certificates for electrum servers so long as they have been previously used or explicitly approved --- .../com/sparrowwallet/sparrow/AppServices.java | 12 ++++++++++-- .../sparrow/net/TcpOverTlsTransport.java | 11 ++++++++++- .../net/UnknownCertificateExpiredException.java | 17 +++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/sparrowwallet/sparrow/net/UnknownCertificateExpiredException.java diff --git a/src/main/java/com/sparrowwallet/sparrow/AppServices.java b/src/main/java/com/sparrowwallet/sparrow/AppServices.java index 644c11db..15e464dc 100644 --- a/src/main/java/com/sparrowwallet/sparrow/AppServices.java +++ b/src/main/java/com/sparrowwallet/sparrow/AppServices.java @@ -290,8 +290,7 @@ public class AppServices { connectionService.setRestartOnFailure(false); } - if(failEvent.getSource().getException() instanceof TlsServerException && failEvent.getSource().getException().getCause() != null) { - TlsServerException tlsServerException = (TlsServerException)failEvent.getSource().getException(); + if(failEvent.getSource().getException() instanceof TlsServerException tlsServerException && failEvent.getSource().getException().getCause() != null) { connectionService.setRestartOnFailure(false); if(tlsServerException.getCause().getMessage().contains("PKIX path building failed")) { File crtFile = Config.get().getElectrumServerCert(); @@ -315,6 +314,15 @@ public class AppServices { } } } + } else if(tlsServerException.getCause().getCause() instanceof UnknownCertificateExpiredException expiredException) { + Optional optButton = AppServices.showErrorDialog("SSL Handshake Failed", "The certificate provided by the server at " + tlsServerException.getServer().getHost() + " has expired. " + + tlsServerException.getMessage() + "." + + "\n\nDo you still want to proceed?", ButtonType.NO, ButtonType.YES); + if(optButton.isPresent() && optButton.get() == ButtonType.YES) { + Storage.saveCertificate(tlsServerException.getServer().getHost(), expiredException.getCertificate()); + Platform.runLater(() -> restartService(connectionService)); + return; + } } } diff --git a/src/main/java/com/sparrowwallet/sparrow/net/TcpOverTlsTransport.java b/src/main/java/com/sparrowwallet/sparrow/net/TcpOverTlsTransport.java index 25a6e8d7..38504747 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/TcpOverTlsTransport.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/TcpOverTlsTransport.java @@ -57,7 +57,13 @@ public class TcpOverTlsTransport extends TcpTransport { throw new CertificateException("No server certificate provided"); } - certs[0].checkValidity(); + try { + certs[0].checkValidity(); + } catch(CertificateExpiredException e) { + if(Storage.getCertificateFile(server.getHost()) == null) { + throw new UnknownCertificateExpiredException(e.getMessage(), certs[0]); + } + } } } }; @@ -68,6 +74,9 @@ public class TcpOverTlsTransport extends TcpTransport { try { X509Certificate x509Certificate = (X509Certificate)certificate; x509Certificate.checkValidity(); + } catch(CertificateExpiredException e) { + //Allow expired certificates so long as they have been previously used or explicitly approved + //These will usually be self-signed certificates that users may not have the expertise to renew } catch(CertificateException e) { crtFile.delete(); return getTrustManagers(null); diff --git a/src/main/java/com/sparrowwallet/sparrow/net/UnknownCertificateExpiredException.java b/src/main/java/com/sparrowwallet/sparrow/net/UnknownCertificateExpiredException.java new file mode 100644 index 00000000..22bc4957 --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/net/UnknownCertificateExpiredException.java @@ -0,0 +1,17 @@ +package com.sparrowwallet.sparrow.net; + +import java.security.cert.Certificate; +import java.security.cert.CertificateExpiredException; + +public class UnknownCertificateExpiredException extends CertificateExpiredException { + private final Certificate certificate; + + public UnknownCertificateExpiredException(String message, Certificate certificate) { + super(message); + this.certificate = certificate; + } + + public Certificate getCertificate() { + return certificate; + } +}