mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2026-10-05 19:18:26 +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.*;
|
||||||
import java.security.cert.*;
|
import java.security.cert.*;
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class TcpOverTlsTransport extends TcpTransport {
|
public class TcpOverTlsTransport extends TcpTransport {
|
||||||
private static final Logger log = LoggerFactory.getLogger(TcpOverTlsTransport.class);
|
private static final Logger log = LoggerFactory.getLogger(TcpOverTlsTransport.class);
|
||||||
public static final int PAD_TO_MULTIPLE_OF_BYTES = 96;
|
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 SSLSocketFactory sslSocketFactory;
|
||||||
protected final boolean usingCaTrust;
|
protected final boolean usingCaTrust;
|
||||||
@@ -112,9 +116,9 @@ public class TcpOverTlsTransport extends TcpTransport {
|
|||||||
return getTrustManagers(null, host);
|
return getTrustManagers(null, host);
|
||||||
}
|
}
|
||||||
//Allow expired certificates for private servers where users may not have the expertise to renew
|
//Allow expired certificates for private servers where users may not have the expertise to renew
|
||||||
} catch(CertificateException e) {
|
} catch(CertificateNotYetValidException e) {
|
||||||
crtFile.delete();
|
//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
|
||||||
return getTrustManagers(null, host);
|
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 {
|
try {
|
||||||
Certificate[] certs = event.getPeerCertificates();
|
Certificate[] certs = event.getPeerCertificates();
|
||||||
if(certs.length > 0) {
|
if(certs.length > 0) {
|
||||||
if(isCaSigned(certs)) {
|
if(isCaValidated(certs, server)) {
|
||||||
Storage.saveCaCertificate(server.getHost(), certs[0]);
|
Storage.saveCaCertificate(server.getHost(), certs[0]);
|
||||||
} else {
|
} else {
|
||||||
Storage.saveCertificate(server.getHost(), certs[0]);
|
Storage.saveCertificate(server.getHost(), certs[0]);
|
||||||
@@ -171,7 +175,7 @@ public class TcpOverTlsTransport extends TcpTransport {
|
|||||||
return tmf.getTrustManagers();
|
return tmf.getTrustManagers();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isCaSigned(Certificate[] certs) {
|
private static boolean isCaValidated(Certificate[] certs, HostAndPort server) {
|
||||||
try {
|
try {
|
||||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||||
tmf.init((KeyStore)null);
|
tmf.init((KeyStore)null);
|
||||||
@@ -195,12 +199,40 @@ public class TcpOverTlsTransport extends TcpTransport {
|
|||||||
|
|
||||||
String authType = x509Certs[0].getPublicKey().getAlgorithm().equals("EC") ? "ECDHE_ECDSA" : "RSA";
|
String authType = x509Certs[0].getPublicKey().getAlgorithm().equals("EC") ? "ECDHE_ECDSA" : "RSA";
|
||||||
defaultTm.checkServerTrusted(x509Certs, authType);
|
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) {
|
} catch(Exception e) {
|
||||||
return false;
|
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
|
@Override
|
||||||
protected int getDefaultPort() {
|
protected int getDefaultPort() {
|
||||||
return Protocol.SSL.getDefaultPort();
|
return Protocol.SSL.getDefaultPort();
|
||||||
|
|||||||
Reference in New Issue
Block a user