diff --git a/domain/src/main/java/org/cryptomator/domain/exception/license/DesktopSupporterCertificateException.java b/domain/src/main/java/org/cryptomator/domain/exception/license/DesktopSupporterCertificateException.java
new file mode 100644
index 00000000..261da226
--- /dev/null
+++ b/domain/src/main/java/org/cryptomator/domain/exception/license/DesktopSupporterCertificateException.java
@@ -0,0 +1,9 @@
+package org.cryptomator.domain.exception.license;
+
+public class DesktopSupporterCertificateException extends LicenseNotValidException {
+
+ public DesktopSupporterCertificateException(final String license) {
+ super(license);
+ }
+
+}
diff --git a/domain/src/main/java/org/cryptomator/domain/usecases/DoLicenseCheck.java b/domain/src/main/java/org/cryptomator/domain/usecases/DoLicenseCheck.java
index 0d71c7ba..dd624e06 100644
--- a/domain/src/main/java/org/cryptomator/domain/usecases/DoLicenseCheck.java
+++ b/domain/src/main/java/org/cryptomator/domain/usecases/DoLicenseCheck.java
@@ -4,6 +4,7 @@ import com.google.common.io.BaseEncoding;
import org.cryptomator.domain.exception.BackendException;
import org.cryptomator.domain.exception.FatalBackendException;
+import org.cryptomator.domain.exception.license.DesktopSupporterCertificateException;
import org.cryptomator.domain.exception.license.LicenseNotValidException;
import org.cryptomator.domain.exception.license.NoLicenseAvailableException;
import org.cryptomator.domain.repository.UpdateCheckRepository;
@@ -20,10 +21,19 @@ import java.security.spec.X509EncodedKeySpec;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.security.SignatureException;
@UseCase
public class DoLicenseCheck {
+ private static final String ANDROID_PUB_KEY = "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBcnb81CfNeL3qBVFMx/yRfm1Y1yib" + //
+ "ajIJkV1s82AQt+mOl4+Kub64wq1OCgBVwWUlKwqgnyF39nmkoXEjakRPFngBzg2J" + //
+ "zo4UR0B7OYmn0uGf3K+zQfxKnNMxGVPtlzE8j9Nqz/dm2YvYLLVwvTSDQX/GaxoP" + //
+ "/EH84Hupw2wuU7qAaFU=";
+ private static final String DESKTOP_SUPPORTER_CERTIFICATE_PUB_KEY = "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQB7NfnqiZbg2KTmoflmZ71PbXru7oW" + //
+ "fmnV2yv3eDjlDfGruBrqz9TtXBZV/eYWt31xu1osIqaT12lKBvZ511aaAkIBeOEV" + //
+ "gwcBIlJr6kUw7NKzeJt7r2rrsOyQoOG2nWc/Of/NBqA3mIZRHk5Aq1YupFdD26QE" + //
+ "r0DzRyj4ixPIt38CQB8=";
private final UpdateCheckRepository updateCheckRepository;
private String license;
@@ -34,17 +44,13 @@ public class DoLicenseCheck {
public LicenseCheck execute() throws BackendException {
license = useLicenseOrRetrieveFromDb(license);
-
try {
- final Claims claims = Jwts //
- .parserBuilder() //
- .setSigningKey(getPublicKey()) //
- .build() //
- .parseClaimsJws(license) //
- .getBody();
-
+ final Claims claims = Jwts.parserBuilder().setSigningKey(getPublicKey(ANDROID_PUB_KEY)).build().parseClaimsJws(license).getBody();
return claims::getSubject;
} catch (JwtException | FatalBackendException e) {
+ if (e instanceof SignatureException && isDesktopSupporterCertificate(license)) {
+ throw new DesktopSupporterCertificateException(license);
+ }
throw new LicenseNotValidException(license);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new FatalBackendException(e);
@@ -56,28 +62,29 @@ public class DoLicenseCheck {
updateCheckRepository.setLicense(license);
} else {
license = updateCheckRepository.getLicense();
-
if (license == null) {
throw new NoLicenseAvailableException();
}
}
-
return license;
}
- private ECPublicKey getPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
- final byte[] publicKey = BaseEncoding //
- .base64() //
- .decode("MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBcnb81CfNeL3qBVFMx/yRfm1Y1yib" + //
- "ajIJkV1s82AQt+mOl4+Kub64wq1OCgBVwWUlKwqgnyF39nmkoXEjakRPFngBzg2J" + //
- "zo4UR0B7OYmn0uGf3K+zQfxKnNMxGVPtlzE8j9Nqz/dm2YvYLLVwvTSDQX/GaxoP" + //
- "/EH84Hupw2wuU7qAaFU=");
-
- Key key = KeyFactory.getInstance("EC").generatePublic(new X509EncodedKeySpec(publicKey));
+ private ECPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
+ final X509EncodedKeySpec keySpec = new X509EncodedKeySpec(BaseEncoding.base64().decode(publicKey));
+ Key key = KeyFactory.getInstance("EC").generatePublic(keySpec);
if (key instanceof ECPublicKey) {
return (ECPublicKey) key;
} else {
throw new FatalBackendException("Key not an EC public key.");
}
}
+
+ private boolean isDesktopSupporterCertificate(String license) {
+ try {
+ Jwts.parserBuilder().setSigningKey(getPublicKey(DESKTOP_SUPPORTER_CERTIFICATE_PUB_KEY)).build().parseClaimsJws(license);
+ return true;
+ } catch (JwtException | NoSuchAlgorithmException | InvalidKeySpecException e) {
+ return false;
+ }
+ }
}
diff --git a/presentation/src/main/java/org/cryptomator/presentation/exception/ExceptionHandlers.kt b/presentation/src/main/java/org/cryptomator/presentation/exception/ExceptionHandlers.kt
index 4e67acd6..024d3bbb 100644
--- a/presentation/src/main/java/org/cryptomator/presentation/exception/ExceptionHandlers.kt
+++ b/presentation/src/main/java/org/cryptomator/presentation/exception/ExceptionHandlers.kt
@@ -13,6 +13,7 @@ import org.cryptomator.domain.exception.NoSuchCloudFileException
import org.cryptomator.domain.exception.UnableToDecryptWebdavPasswordException
import org.cryptomator.domain.exception.VaultAlreadyExistException
import org.cryptomator.domain.exception.authentication.AuthenticationException
+import org.cryptomator.domain.exception.license.DesktopSupporterCertificateException
import org.cryptomator.domain.exception.license.LicenseNotValidException
import org.cryptomator.domain.exception.license.NoLicenseAvailableException
import org.cryptomator.domain.exception.update.GeneralUpdateErrorException
@@ -25,7 +26,6 @@ import org.cryptomator.domain.exception.vaultconfig.VaultVersionMismatchExceptio
import org.cryptomator.presentation.R
import org.cryptomator.presentation.ui.activity.view.View
import org.cryptomator.presentation.util.ResourceHelper
-import java.util.ArrayList
import java.util.Collections
import javax.inject.Inject
import timber.log.Timber
@@ -48,6 +48,7 @@ class ExceptionHandlers @Inject constructor(private val context: Context, defaul
staticHandler(NoSuchCloudFileException::class.java, R.string.error_no_such_file)
staticHandler(IllegalFileNameException::class.java, R.string.error_export_illegal_file_name)
staticHandler(UnableToDecryptWebdavPasswordException::class.java, R.string.error_failed_to_decrypt_webdav_password)
+ staticHandler(DesktopSupporterCertificateException::class.java, R.string.dialog_enter_license_not_valid_content_desktop_supporter_certificate)
staticHandler(LicenseNotValidException::class.java, R.string.dialog_enter_license_not_valid_content)
staticHandler(NoLicenseAvailableException::class.java, R.string.dialog_enter_license_no_content)
staticHandler(HashMismatchUpdateCheckException::class.java, R.string.error_hash_mismatch_update)
diff --git a/presentation/src/main/res/values/strings.xml b/presentation/src/main/res/values/strings.xml
index 03d574f8..8af0409d 100644
--- a/presentation/src/main/res/values/strings.xml
+++ b/presentation/src/main/res/values/strings.xml
@@ -447,6 +447,7 @@
Provide a valid license
We detected that you installed Cryptomator without using Google Play Store. Provide a valid license, which can be purchased on https://cryptomator.org/android/
The provided license isn\'t valid. Make sure you entered it correctly.
+ The provided key is a desktop supporter certificate. Please enter a valid license.
No license provided. Please enter a valid license.
@string/dialog_unable_to_share_positive_button
Exit