Merge branch 'release/1.16.1'

This commit is contained in:
Armin Schrenk
2025-04-30 14:04:43 +02:00
4 changed files with 202 additions and 3 deletions
@@ -83,6 +83,9 @@
</content_rating>
<releases>
<release date="2025-04-30" version="1.16.1">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.16.1</url>
</release>
<release date="2025-04-29" version="1.16.0">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.16.0</url>
</release>
+2 -2
View File
@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.cryptomator</groupId>
<artifactId>cryptomator</artifactId>
<version>1.16.0</version>
<version>1.16.1</version>
<name>Cryptomator Desktop App</name>
<organization>
@@ -36,7 +36,7 @@
<cryptomator.cryptofs.version>2.9.0</cryptomator.cryptofs.version>
<cryptomator.integrations.version>1.5.1</cryptomator.integrations.version>
<cryptomator.integrations.win.version>1.3.0</cryptomator.integrations.win.version>
<cryptomator.integrations.mac.version>1.3.0</cryptomator.integrations.mac.version>
<cryptomator.integrations.mac.version>1.3.2</cryptomator.integrations.mac.version>
<cryptomator.integrations.linux.version>1.5.3</cryptomator.integrations.linux.version>
<cryptomator.fuse.version>5.0.5</cryptomator.fuse.version>
<cryptomator.webdav.version>2.0.10</cryptomator.webdav.version>
@@ -0,0 +1,185 @@
package org.cryptomator.networking;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.KeyStoreSpi;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.concurrent.atomic.AtomicInteger;
public class CombinedKeyStoreSpi extends KeyStoreSpi {
private final KeyStore primary;
private final KeyStore fallback;
public static CombinedKeyStoreSpi create(KeyStore primary, KeyStore fallback) {
checkIfLoaded(primary);
checkIfLoaded(fallback);
return new CombinedKeyStoreSpi(primary, fallback);
}
private static void checkIfLoaded(KeyStore s) {
try {
s.aliases();
} catch (KeyStoreException e) {
throw new IllegalArgumentException("Keystore %s is not loaded.".formatted(s.getType()));
}
}
private CombinedKeyStoreSpi(KeyStore primary, KeyStore fallback) {
this.primary = primary;
this.fallback = fallback;
}
@Override
public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException {
try {
Key key = primary.getKey(alias, password);
if (key == null) {
key = fallback.getKey(alias, password);
}
return key;
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public Certificate[] engineGetCertificateChain(String alias) {
try {
Certificate[] chain = primary.getCertificateChain(alias);
if (chain == null) {
chain = fallback.getCertificateChain(alias);
}
return chain;
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public Certificate engineGetCertificate(String alias) {
try {
Certificate cert = primary.getCertificate(alias);
if (cert == null) {
cert = fallback.getCertificate(alias);
}
return cert;
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public Date engineGetCreationDate(String alias) {
try {
Date date = primary.getCreationDate(alias);
if (date == null) {
date = fallback.getCreationDate(alias);
}
return date;
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain) throws KeyStoreException {
throw new UnsupportedOperationException("Read-only KeyStore");
}
@Override
public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException {
throw new UnsupportedOperationException("Read-only KeyStore");
}
@Override
public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
throw new UnsupportedOperationException("Read-only KeyStore");
}
@Override
public void engineDeleteEntry(String alias) throws KeyStoreException {
throw new UnsupportedOperationException("Read-only KeyStore");
}
@Override
public Enumeration<String> engineAliases() {
var aliases = new LinkedHashSet<String>();
try {
primary.aliases().asIterator().forEachRemaining(aliases::add);
fallback.aliases().asIterator().forEachRemaining(aliases::add);
return Collections.enumeration(aliases);
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public boolean engineContainsAlias(String alias) {
try {
return primary.containsAlias(alias) || fallback.containsAlias(alias);
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public int engineSize() {
var aliases = engineAliases();
var i = new AtomicInteger(0);
aliases.asIterator().forEachRemaining(_ -> i.incrementAndGet());
return i.get();
}
@Override
public boolean engineIsKeyEntry(String alias) {
try {
return primary.isKeyEntry(alias) || fallback.isKeyEntry(alias);
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public boolean engineIsCertificateEntry(String alias) {
try {
return primary.isCertificateEntry(alias) || fallback.isCertificateEntry(alias);
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public String engineGetCertificateAlias(Certificate cert) {
try {
String alias = primary.getCertificateAlias(cert);
if (alias == null) {
alias = fallback.getCertificateAlias(cert);
}
return alias;
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public void engineStore(OutputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException {
throw new UnsupportedOperationException("Read-only KeyStore");
}
@Override
public void engineLoad(InputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException {
// Nothing to do; the real keystores are already loaded.
}
}
@@ -6,6 +6,7 @@ import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.cert.CertificateException;
/**
@@ -16,6 +17,16 @@ public class SSLContextWithMacKeychain extends SSLContextDifferentTrustStoreBase
@Override
KeyStore getTruststore() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
return KeyStore.getInstance("KeychainStore-ROOT");
var userKeyStore = KeyStore.getInstance("KeychainStore");
var systemRootKeyStore = KeyStore.getInstance("KeychainStore-ROOT");
userKeyStore.load(null);
systemRootKeyStore.load(null);
try {
CombinedKeyStoreSpi spi = CombinedKeyStoreSpi.create(userKeyStore, systemRootKeyStore);
Provider dummyProvider = new Provider("CombinedKeyStoreProvider", "1.0", "Provides a combined, read-only KeyStore") {};
return new KeyStore(spi, dummyProvider, "CombinedKeyStoreProvider") {};
} catch (IllegalArgumentException e) {
throw new KeyStoreException(e);
}
}
}