mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2026-08-09 08:14:43 +00:00
only save certificates passing hostname verification as ca validated, and retain not yet valid certificates
This commit is contained in:
@@ -14,10 +14,14 @@ import java.net.InetSocketAddress;
|
||||
import java.security.*;
|
||||
import java.security.cert.*;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class TcpOverTlsTransport extends TcpTransport {
|
||||
private static final Logger log = LoggerFactory.getLogger(TcpOverTlsTransport.class);
|
||||
public static final int PAD_TO_MULTIPLE_OF_BYTES = 96;
|
||||
private static final int GENERAL_NAME_DNS = 2;
|
||||
private static final int GENERAL_NAME_IP_ADDRESS = 7;
|
||||
|
||||
protected final SSLSocketFactory sslSocketFactory;
|
||||
protected final boolean usingCaTrust;
|
||||
@@ -112,9 +116,9 @@ public class TcpOverTlsTransport extends TcpTransport {
|
||||
return getTrustManagers(null, host);
|
||||
}
|
||||
//Allow expired certificates for private servers where users may not have the expertise to renew
|
||||
} catch(CertificateException e) {
|
||||
crtFile.delete();
|
||||
return getTrustManagers(null, host);
|
||||
} catch(CertificateNotYetValidException e) {
|
||||
//A certificate that was valid when saved or configured can only appear to be not yet valid if the system clock is incorrect - retain it
|
||||
log.warn("Certificate for " + host + " at " + crtFile.getAbsolutePath() + " is not yet valid, check the system clock is correct");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +144,7 @@ public class TcpOverTlsTransport extends TcpTransport {
|
||||
try {
|
||||
Certificate[] certs = event.getPeerCertificates();
|
||||
if(certs.length > 0) {
|
||||
if(isCaSigned(certs)) {
|
||||
if(isCaValidated(certs, server)) {
|
||||
Storage.saveCaCertificate(server.getHost(), certs[0]);
|
||||
} else {
|
||||
Storage.saveCertificate(server.getHost(), certs[0]);
|
||||
@@ -171,7 +175,7 @@ public class TcpOverTlsTransport extends TcpTransport {
|
||||
return tmf.getTrustManagers();
|
||||
}
|
||||
|
||||
private static boolean isCaSigned(Certificate[] certs) {
|
||||
private static boolean isCaValidated(Certificate[] certs, HostAndPort server) {
|
||||
try {
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init((KeyStore)null);
|
||||
@@ -195,12 +199,40 @@ public class TcpOverTlsTransport extends TcpTransport {
|
||||
|
||||
String authType = x509Certs[0].getPublicKey().getAlgorithm().equals("EC") ? "ECDHE_ECDSA" : "RSA";
|
||||
defaultTm.checkServerTrusted(x509Certs, authType);
|
||||
return true;
|
||||
|
||||
//Match the hostname as CA validated connections do, so that a certificate saved here can be validated when it is used
|
||||
return Protocol.isOnionAddress(server) || matchesHostname(x509Certs[0], server.getHost());
|
||||
} catch(Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean matchesHostname(X509Certificate cert, String host) throws CertificateParsingException {
|
||||
Collection<List<?>> subjectAltNames = cert.getSubjectAlternativeNames();
|
||||
if(subjectAltNames == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(List<?> subjectAltName : subjectAltNames) {
|
||||
if(subjectAltName.size() > 1 && subjectAltName.get(0) instanceof Integer type && subjectAltName.get(1) instanceof String name) {
|
||||
if((type == GENERAL_NAME_DNS && matchesDnsName(name, host)) || (type == GENERAL_NAME_IP_ADDRESS && name.equalsIgnoreCase(host))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean matchesDnsName(String dnsName, String host) {
|
||||
if(dnsName.startsWith("*.")) {
|
||||
int index = host.indexOf('.');
|
||||
return index > 0 && host.substring(index + 1).equalsIgnoreCase(dnsName.substring(2));
|
||||
}
|
||||
|
||||
return dnsName.equalsIgnoreCase(host);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDefaultPort() {
|
||||
return Protocol.SSL.getDefaultPort();
|
||||
|
||||
Reference in New Issue
Block a user