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