From a043f2b787be0ddb8e3d0a19bd7c34d767b7a789 Mon Sep 17 00:00:00 2001 From: anhefti Date: Mon, 9 May 2022 15:00:12 +0200 Subject: [PATCH] SEBSERV-304 fixed --- .../sebconfig/SEBConfigEncryptionContext.java | 2 + .../impl/AbstractCertificateCryptor.java | 53 ++++++++++++++----- .../impl/CertificateAsymetricKeyCryptor.java | 15 ++++-- .../impl/CertificateSymetricKeyCryptor.java | 13 +++-- .../impl/ClientConfigServiceImpl.java | 9 ++-- .../sebconfig/impl/ExamConfigIO.java | 6 +++ .../impl/SEBConfigEncryptionServiceImpl.java | 49 ++++++++++++++--- 7 files changed, 115 insertions(+), 32 deletions(-) diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/SEBConfigEncryptionContext.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/SEBConfigEncryptionContext.java index 729070f3..9e711d12 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/SEBConfigEncryptionContext.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/SEBConfigEncryptionContext.java @@ -36,4 +36,6 @@ public interface SEBConfigEncryptionContext { * @throws UnsupportedOperationException if not supported */ Certificate getCertificate(); + String getCertificateAlias(); + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/AbstractCertificateCryptor.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/AbstractCertificateCryptor.java index 84eb9115..b049cff1 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/AbstractCertificateCryptor.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/AbstractCertificateCryptor.java @@ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl; import java.io.IOException; import java.io.InputStream; +import java.security.PrivateKey; import java.security.cert.Certificate; import java.util.Arrays; import java.util.Enumeration; @@ -21,7 +22,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Certificates; +import ch.ethz.seb.sebserver.gbl.util.Cryptor; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.CertificateService; +import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigEncryptionContext; +import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl.SEBConfigEncryptionServiceImpl.EncryptionContext; public abstract class AbstractCertificateCryptor { @@ -32,25 +36,38 @@ public abstract class AbstractCertificateCryptor { protected static final int KEY_LENGTH_SIZE = 4; protected final CertificateService certificateService; + protected final Cryptor cryptor; + + public AbstractCertificateCryptor( + final CertificateService certificateService, + final Cryptor cryptor) { - public AbstractCertificateCryptor(final CertificateService certificateService) { this.certificateService = certificateService; + this.cryptor = cryptor; } - protected Certificate getCertificateByPublicKeyHash(final Long institutionId, final byte[] publicKeyHash) { + protected SEBConfigEncryptionContext getCertificateByPublicKeyHash( + final SEBConfigEncryptionContext sebConfigEncryptionContext, + final byte[] publicKeyHash) { + try { final Certificates certs = this.certificateService - .getCertificates(institutionId) + .getCertificates(sebConfigEncryptionContext.institutionId()) .getOrThrow(); @SuppressWarnings("unchecked") final Enumeration engineAliases = certs.keyStore.engineAliases(); while (engineAliases.hasMoreElements()) { - final Certificate certificate = certs.keyStore.engineGetCertificate(engineAliases.nextElement()); + final String alias = engineAliases.nextElement(); + final Certificate certificate = certs.keyStore.engineGetCertificate(alias); final byte[] otherPublicKeyHash = generatePublicKeyHash(certificate); if (Arrays.equals(otherPublicKeyHash, publicKeyHash)) { - return certificate; + return EncryptionContext.contextOf( + sebConfigEncryptionContext.institutionId(), + sebConfigEncryptionContext.getStrategy(), + certificate, + alias); } } @@ -85,21 +102,33 @@ public abstract class AbstractCertificateCryptor { final String algorithm = cert.getPublicKey().getAlgorithm(); final Cipher encryptCipher = Cipher.getInstance(algorithm); - encryptCipher.init(Cipher.ENCRYPT_MODE, cert.getPublicKey()); + encryptCipher.init(Cipher.ENCRYPT_MODE, cert); return encryptCipher.doFinal(data, 0, length); } - protected byte[] decryptWithCert(final Certificate cert, final byte[] encryptedData) throws Exception { - return decryptWithCert(cert, encryptedData, encryptedData.length); + protected byte[] decryptWithCert( + final SEBConfigEncryptionContext sebConfigEncryptionContext, + final byte[] encryptedData) throws Exception { + + return decryptWithCert(sebConfigEncryptionContext, encryptedData, encryptedData.length); } protected byte[] decryptWithCert( - final Certificate cert, - final byte[] encryptedData, final int length) throws Exception { + final SEBConfigEncryptionContext sebConfigEncryptionContext, + final byte[] encryptedData, + final int length) throws Exception { - final String algorithm = cert.getPublicKey().getAlgorithm(); + final Certificate certificate = sebConfigEncryptionContext.getCertificate(); + final String certificateAlias = sebConfigEncryptionContext.getCertificateAlias(); + final String algorithm = certificate.getPublicKey().getAlgorithm(); final Cipher encryptCipher = Cipher.getInstance(algorithm); - encryptCipher.init(Cipher.DECRYPT_MODE, cert.getPublicKey()); + final Certificates certificates = this.certificateService + .getCertificates(sebConfigEncryptionContext.institutionId()) + .getOrThrow(); + final PrivateKey privateKey = this.cryptor + .getPrivateKey(certificates.keyStore, certificateAlias) + .getOrThrow(); + encryptCipher.init(Cipher.DECRYPT_MODE, privateKey); return encryptCipher.doFinal(encryptedData, 0, length); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateAsymetricKeyCryptor.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateAsymetricKeyCryptor.java index 159a03fa..e6181dea 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateAsymetricKeyCryptor.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateAsymetricKeyCryptor.java @@ -20,6 +20,7 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; +import ch.ethz.seb.sebserver.gbl.util.Cryptor; import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.CertificateService; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigCryptor; @@ -37,8 +38,11 @@ public class CertificateAsymetricKeyCryptor extends AbstractCertificateCryptor i private static final Set STRATEGIES = Utils.immutableSetOf( Strategy.PUBLIC_KEY_HASH); - public CertificateAsymetricKeyCryptor(final CertificateService certificateService) { - super(certificateService); + public CertificateAsymetricKeyCryptor( + final CertificateService certificateService, + final Cryptor cryptor) { + + super(certificateService, cryptor); } @Override @@ -94,9 +98,10 @@ public class CertificateAsymetricKeyCryptor extends AbstractCertificateCryptor i try { final byte[] publicKeyHash = parsePublicKeyHash(input); - final Certificate certificate = getCertificateByPublicKeyHash( - context.institutionId(), + final SEBConfigEncryptionContext sebConfigEncryptionContext = getCertificateByPublicKeyHash( + context, publicKeyHash); + final Certificate certificate = sebConfigEncryptionContext.getCertificate(); if (certificate == null) { throw new RuntimeException("No matching certificate found to decrypt the configuration"); @@ -106,7 +111,7 @@ public class CertificateAsymetricKeyCryptor extends AbstractCertificateCryptor i int readBytes = input.read(buffer, 0, buffer.length); while (readBytes > 0) { - final byte[] encryptedBlock = decryptWithCert(certificate, buffer, readBytes); + final byte[] encryptedBlock = decryptWithCert(sebConfigEncryptionContext, buffer, readBytes); output.write(encryptedBlock, 0, encryptedBlock.length); readBytes = input.read(buffer, 0, buffer.length); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateSymetricKeyCryptor.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateSymetricKeyCryptor.java index 19362bea..e91f0d40 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateSymetricKeyCryptor.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateSymetricKeyCryptor.java @@ -29,6 +29,7 @@ import org.springframework.stereotype.Component; import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; +import ch.ethz.seb.sebserver.gbl.util.Cryptor; import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.CertificateService; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigCryptor; @@ -60,9 +61,10 @@ public class CertificateSymetricKeyCryptor extends AbstractCertificateCryptor im public CertificateSymetricKeyCryptor( final PasswordEncryptor passwordEncryptor, final PasswordDecryptor passwordDecryptor, - final CertificateService certificateService) { + final CertificateService certificateService, + final Cryptor cryptor) { - super(certificateService); + super(certificateService, cryptor); this.passwordEncryptor = passwordEncryptor; this.passwordDecryptor = passwordDecryptor; } @@ -120,16 +122,17 @@ public class CertificateSymetricKeyCryptor extends AbstractCertificateCryptor im try { final byte[] publicKeyHash = parsePublicKeyHash(input); - final Certificate certificate = getCertificateByPublicKeyHash( - context.institutionId(), + final SEBConfigEncryptionContext sebConfigEncryptionContext = getCertificateByPublicKeyHash( + context, publicKeyHash); + final Certificate certificate = sebConfigEncryptionContext.getCertificate(); if (certificate == null) { throw new RuntimeException("No matching certificate found to decrypt the configuration"); } final byte[] encryptedKey = getEncryptedKey(input); - final byte[] symetricKey = decryptWithCert(certificate, encryptedKey); + final byte[] symetricKey = decryptWithCert(sebConfigEncryptionContext, encryptedKey); final CharSequence symetricKeyBase64 = Base64.getEncoder().encodeToString(symetricKey); this.passwordDecryptor.decrypt(output, input, symetricKeyBase64); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ClientConfigServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ClientConfigServiceImpl.java index 7f065a9c..ae10d83f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ClientConfigServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ClientConfigServiceImpl.java @@ -293,9 +293,9 @@ public class ClientConfigServiceImpl implements ClientConfigService { private SEBConfigEncryptionContext buildCertificateEncryptionContext(final SEBClientConfig config) { - final Certificate certificate = this.certificateDAO.getCertificate( - config.institutionId, - String.valueOf(config.getEncryptCertificateAlias())) + final String alias = String.valueOf(config.getEncryptCertificateAlias()); + final Certificate certificate = this.certificateDAO + .getCertificate(config.institutionId, alias) .getOrThrow(); return EncryptionContext.contextOf( @@ -303,7 +303,8 @@ public class ClientConfigServiceImpl implements ClientConfigService { (config.encryptCertificateAsym) ? SEBConfigEncryptionService.Strategy.PUBLIC_KEY_HASH : SEBConfigEncryptionService.Strategy.PUBLIC_KEY_HASH_SYMMETRIC_KEY, - certificate); + certificate, + alias); } private SEBConfigEncryptionContext buildPasswordEncryptionContext(final SEBClientConfig config) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigIO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigIO.java index 9e77af50..0adc714e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigIO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ExamConfigIO.java @@ -15,6 +15,7 @@ import java.io.OutputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.io.SequenceInputStream; +import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -50,6 +51,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.AttributeValueConverter; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.AttributeValueConverterService; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConfigurationFormat; +import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigEncryptionService.Strategy; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ZipService; @Lazy @@ -243,6 +245,10 @@ public class ExamConfigIO { throw new IllegalArgumentException("Failed to verify Zip type from input stream. Header size mismatch."); } + if (Arrays.equals(Strategy.PLAIN_TEXT.header, zipHeader)) { + return unzip(input); + } + final boolean isZipped = Byte.toUnsignedInt(zipHeader[0]) == Constants.GZIP_ID1 && Byte.toUnsignedInt(zipHeader[1]) == Constants.GZIP_ID2 && Byte.toUnsignedInt(zipHeader[2]) == Constants.GZIP_CM; diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/SEBConfigEncryptionServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/SEBConfigEncryptionServiceImpl.java index a8b916a9..e94da6c4 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/SEBConfigEncryptionServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/SEBConfigEncryptionServiceImpl.java @@ -150,6 +150,34 @@ public final class SEBConfigEncryptionServiceImpl implements SEBConfigEncryption .getOrThrow() .decrypt(pout, newIn, context); +// if (strategy == Strategy.PLAIN_TEXT) { +// +// getEncryptor(strategy) +// .getOrThrow() +// .decrypt(pout, newIn, context); +// +// } else if ((strategy == Strategy.PASSWORD_PSWD || strategy == Strategy.PASSWORD_PWCC)) { +// if (StringUtils.isBlank(context.getPassword())) { +// return new AsyncResult<>(new APIMessage.APIMessageException( +// APIMessage.ErrorMessage.MISSING_PASSWORD.of("Missing Password"))); +// } else { +// +// // then decrypt stream with password +// getEncryptor(strategy) +// .getOrThrow() +// .decrypt(pout, newIn, context); +// } +// } else { +// +// // then decrypt stream with certificate +// getEncryptor(strategy) +// .getOrThrow() +// .decrypt( +// pout, +// newIn, +// EncryptionContext.contextOf(context.institutionId(), strategy, null, null)); +// } + IOUtils.copyLarge(pin, output); return new AsyncResult<>(null); @@ -194,17 +222,20 @@ public final class SEBConfigEncryptionServiceImpl implements SEBConfigEncryption public final Strategy strategy; public final CharSequence password; public final Certificate certificate; + public final String certificateAlias; private EncryptionContext( final Long institutionId, final Strategy strategy, final CharSequence password, - final Certificate certificate) { + final Certificate certificate, + final String certificateAlias) { this.institutionId = institutionId; this.strategy = strategy; this.password = password; this.certificate = certificate; + this.certificateAlias = certificateAlias; } @Override @@ -227,22 +258,28 @@ public final class SEBConfigEncryptionServiceImpl implements SEBConfigEncryption return this.certificate; } + @Override + public String getCertificateAlias() { + return this.certificateAlias; + } + static SEBConfigEncryptionContext contextOf( final Long institutionId, final Strategy strategy, final CharSequence password) { checkPasswordBased(strategy); - return new EncryptionContext(institutionId, strategy, password, null); + return new EncryptionContext(institutionId, strategy, password, null, null); } static SEBConfigEncryptionContext contextOf( final Long institutionId, final Strategy strategy, - final Certificate certificate) { + final Certificate certificate, + final String certificateAlias) { checkCertificateBased(strategy); - return new EncryptionContext(institutionId, strategy, null, certificate); + return new EncryptionContext(institutionId, strategy, null, certificate, certificateAlias); } static void checkPasswordBased(final Strategy strategy) { @@ -259,14 +296,14 @@ public final class SEBConfigEncryptionServiceImpl implements SEBConfigEncryption public static SEBConfigEncryptionContext contextOfPlainText(final Long institutionId) { - return new EncryptionContext(institutionId, Strategy.PLAIN_TEXT, null, null); + return new EncryptionContext(institutionId, Strategy.PLAIN_TEXT, null, null, null); } public static SEBConfigEncryptionContext contextOf( final Long institutionId, final CharSequence password) { - return new EncryptionContext(institutionId, null, password, null); + return new EncryptionContext(institutionId, null, password, null, null); } }