Show specific message if desktop supporter cert entered as license key

This commit is contained in:
Julian Raufelder 2022-02-24 15:43:11 +01:00
parent 71dc76b157
commit e1a5ff7007
No known key found for this signature in database
GPG Key ID: 17EE71F6634E381D
4 changed files with 38 additions and 20 deletions

View File

@ -0,0 +1,9 @@
package org.cryptomator.domain.exception.license;
public class DesktopSupporterCertificateException extends LicenseNotValidException {
public DesktopSupporterCertificateException(final String license) {
super(license);
}
}

View File

@ -4,6 +4,7 @@ import com.google.common.io.BaseEncoding;
import org.cryptomator.domain.exception.BackendException; import org.cryptomator.domain.exception.BackendException;
import org.cryptomator.domain.exception.FatalBackendException; 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.LicenseNotValidException;
import org.cryptomator.domain.exception.license.NoLicenseAvailableException; import org.cryptomator.domain.exception.license.NoLicenseAvailableException;
import org.cryptomator.domain.repository.UpdateCheckRepository; import org.cryptomator.domain.repository.UpdateCheckRepository;
@ -20,10 +21,19 @@ import java.security.spec.X509EncodedKeySpec;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException; import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.SignatureException;
@UseCase @UseCase
public class DoLicenseCheck { 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 final UpdateCheckRepository updateCheckRepository;
private String license; private String license;
@ -34,17 +44,13 @@ public class DoLicenseCheck {
public LicenseCheck execute() throws BackendException { public LicenseCheck execute() throws BackendException {
license = useLicenseOrRetrieveFromDb(license); license = useLicenseOrRetrieveFromDb(license);
try { try {
final Claims claims = Jwts // final Claims claims = Jwts.parserBuilder().setSigningKey(getPublicKey(ANDROID_PUB_KEY)).build().parseClaimsJws(license).getBody();
.parserBuilder() //
.setSigningKey(getPublicKey()) //
.build() //
.parseClaimsJws(license) //
.getBody();
return claims::getSubject; return claims::getSubject;
} catch (JwtException | FatalBackendException e) { } catch (JwtException | FatalBackendException e) {
if (e instanceof SignatureException && isDesktopSupporterCertificate(license)) {
throw new DesktopSupporterCertificateException(license);
}
throw new LicenseNotValidException(license); throw new LicenseNotValidException(license);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) { } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new FatalBackendException(e); throw new FatalBackendException(e);
@ -56,28 +62,29 @@ public class DoLicenseCheck {
updateCheckRepository.setLicense(license); updateCheckRepository.setLicense(license);
} else { } else {
license = updateCheckRepository.getLicense(); license = updateCheckRepository.getLicense();
if (license == null) { if (license == null) {
throw new NoLicenseAvailableException(); throw new NoLicenseAvailableException();
} }
} }
return license; return license;
} }
private ECPublicKey getPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException { private ECPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
final byte[] publicKey = BaseEncoding // final X509EncodedKeySpec keySpec = new X509EncodedKeySpec(BaseEncoding.base64().decode(publicKey));
.base64() // Key key = KeyFactory.getInstance("EC").generatePublic(keySpec);
.decode("MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBcnb81CfNeL3qBVFMx/yRfm1Y1yib" + //
"ajIJkV1s82AQt+mOl4+Kub64wq1OCgBVwWUlKwqgnyF39nmkoXEjakRPFngBzg2J" + //
"zo4UR0B7OYmn0uGf3K+zQfxKnNMxGVPtlzE8j9Nqz/dm2YvYLLVwvTSDQX/GaxoP" + //
"/EH84Hupw2wuU7qAaFU=");
Key key = KeyFactory.getInstance("EC").generatePublic(new X509EncodedKeySpec(publicKey));
if (key instanceof ECPublicKey) { if (key instanceof ECPublicKey) {
return (ECPublicKey) key; return (ECPublicKey) key;
} else { } else {
throw new FatalBackendException("Key not an EC public key."); 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;
}
}
} }

View File

@ -13,6 +13,7 @@ import org.cryptomator.domain.exception.NoSuchCloudFileException
import org.cryptomator.domain.exception.UnableToDecryptWebdavPasswordException import org.cryptomator.domain.exception.UnableToDecryptWebdavPasswordException
import org.cryptomator.domain.exception.VaultAlreadyExistException import org.cryptomator.domain.exception.VaultAlreadyExistException
import org.cryptomator.domain.exception.authentication.AuthenticationException 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.LicenseNotValidException
import org.cryptomator.domain.exception.license.NoLicenseAvailableException import org.cryptomator.domain.exception.license.NoLicenseAvailableException
import org.cryptomator.domain.exception.update.GeneralUpdateErrorException 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.R
import org.cryptomator.presentation.ui.activity.view.View import org.cryptomator.presentation.ui.activity.view.View
import org.cryptomator.presentation.util.ResourceHelper import org.cryptomator.presentation.util.ResourceHelper
import java.util.ArrayList
import java.util.Collections import java.util.Collections
import javax.inject.Inject import javax.inject.Inject
import timber.log.Timber 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(NoSuchCloudFileException::class.java, R.string.error_no_such_file)
staticHandler(IllegalFileNameException::class.java, R.string.error_export_illegal_file_name) staticHandler(IllegalFileNameException::class.java, R.string.error_export_illegal_file_name)
staticHandler(UnableToDecryptWebdavPasswordException::class.java, R.string.error_failed_to_decrypt_webdav_password) 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(LicenseNotValidException::class.java, R.string.dialog_enter_license_not_valid_content)
staticHandler(NoLicenseAvailableException::class.java, R.string.dialog_enter_license_no_content) staticHandler(NoLicenseAvailableException::class.java, R.string.dialog_enter_license_no_content)
staticHandler(HashMismatchUpdateCheckException::class.java, R.string.error_hash_mismatch_update) staticHandler(HashMismatchUpdateCheckException::class.java, R.string.error_hash_mismatch_update)

View File

@ -447,6 +447,7 @@
<string name="dialog_enter_license_title">Provide a valid license</string> <string name="dialog_enter_license_title">Provide a valid license</string>
<string name="dialog_enter_license_content">We detected that you installed Cryptomator without using Google Play Store. Provide a valid license, which can be purchased on <a href="https://cryptomator.org/android/">https://cryptomator.org/android/</a></string> <string name="dialog_enter_license_content">We detected that you installed Cryptomator without using Google Play Store. Provide a valid license, which can be purchased on <a href="https://cryptomator.org/android/">https://cryptomator.org/android/</a></string>
<string name="dialog_enter_license_not_valid_content">The provided license isn\'t valid. Make sure you entered it correctly.</string> <string name="dialog_enter_license_not_valid_content">The provided license isn\'t valid. Make sure you entered it correctly.</string>
<string name="dialog_enter_license_not_valid_content_desktop_supporter_certificate">The provided key is a desktop supporter certificate. Please enter a valid license.</string>
<string name="dialog_enter_license_no_content">No license provided. Please enter a valid license.</string> <string name="dialog_enter_license_no_content">No license provided. Please enter a valid license.</string>
<string name="dialog_enter_license_ok_button" translatable="false">@string/dialog_unable_to_share_positive_button</string> <string name="dialog_enter_license_ok_button" translatable="false">@string/dialog_unable_to_share_positive_button</string>
<string name="dialog_enter_license_decline_button">Exit</string> <string name="dialog_enter_license_decline_button">Exit</string>