SEBSERV-304 fixed

This commit is contained in:
anhefti 2022-05-09 15:00:12 +02:00
parent d9b03e7894
commit a043f2b787
7 changed files with 115 additions and 32 deletions

View file

@ -36,4 +36,6 @@ public interface SEBConfigEncryptionContext {
* @throws UnsupportedOperationException if not supported */ * @throws UnsupportedOperationException if not supported */
Certificate getCertificate(); Certificate getCertificate();
String getCertificateAlias();
} }

View file

@ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.security.PrivateKey;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.util.Arrays; import java.util.Arrays;
import java.util.Enumeration; import java.util.Enumeration;
@ -21,7 +22,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Certificates; 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.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 { public abstract class AbstractCertificateCryptor {
@ -32,25 +36,38 @@ public abstract class AbstractCertificateCryptor {
protected static final int KEY_LENGTH_SIZE = 4; protected static final int KEY_LENGTH_SIZE = 4;
protected final CertificateService certificateService; 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.certificateService = certificateService;
this.cryptor = cryptor;
} }
protected Certificate getCertificateByPublicKeyHash(final Long institutionId, final byte[] publicKeyHash) { protected SEBConfigEncryptionContext getCertificateByPublicKeyHash(
final SEBConfigEncryptionContext sebConfigEncryptionContext,
final byte[] publicKeyHash) {
try { try {
final Certificates certs = this.certificateService final Certificates certs = this.certificateService
.getCertificates(institutionId) .getCertificates(sebConfigEncryptionContext.institutionId())
.getOrThrow(); .getOrThrow();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final Enumeration<String> engineAliases = certs.keyStore.engineAliases(); final Enumeration<String> engineAliases = certs.keyStore.engineAliases();
while (engineAliases.hasMoreElements()) { 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); final byte[] otherPublicKeyHash = generatePublicKeyHash(certificate);
if (Arrays.equals(otherPublicKeyHash, publicKeyHash)) { 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 String algorithm = cert.getPublicKey().getAlgorithm();
final Cipher encryptCipher = Cipher.getInstance(algorithm); 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); return encryptCipher.doFinal(data, 0, length);
} }
protected byte[] decryptWithCert(final Certificate cert, final byte[] encryptedData) throws Exception { protected byte[] decryptWithCert(
return decryptWithCert(cert, encryptedData, encryptedData.length); final SEBConfigEncryptionContext sebConfigEncryptionContext,
final byte[] encryptedData) throws Exception {
return decryptWithCert(sebConfigEncryptionContext, encryptedData, encryptedData.length);
} }
protected byte[] decryptWithCert( protected byte[] decryptWithCert(
final Certificate cert, final SEBConfigEncryptionContext sebConfigEncryptionContext,
final byte[] encryptedData, final int length) throws Exception { 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); 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); return encryptCipher.doFinal(encryptedData, 0, length);
} }

View file

@ -20,6 +20,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; 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.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.CertificateService; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.CertificateService;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigCryptor; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigCryptor;
@ -37,8 +38,11 @@ public class CertificateAsymetricKeyCryptor extends AbstractCertificateCryptor i
private static final Set<Strategy> STRATEGIES = Utils.immutableSetOf( private static final Set<Strategy> STRATEGIES = Utils.immutableSetOf(
Strategy.PUBLIC_KEY_HASH); Strategy.PUBLIC_KEY_HASH);
public CertificateAsymetricKeyCryptor(final CertificateService certificateService) { public CertificateAsymetricKeyCryptor(
super(certificateService); final CertificateService certificateService,
final Cryptor cryptor) {
super(certificateService, cryptor);
} }
@Override @Override
@ -94,9 +98,10 @@ public class CertificateAsymetricKeyCryptor extends AbstractCertificateCryptor i
try { try {
final byte[] publicKeyHash = parsePublicKeyHash(input); final byte[] publicKeyHash = parsePublicKeyHash(input);
final Certificate certificate = getCertificateByPublicKeyHash( final SEBConfigEncryptionContext sebConfigEncryptionContext = getCertificateByPublicKeyHash(
context.institutionId(), context,
publicKeyHash); publicKeyHash);
final Certificate certificate = sebConfigEncryptionContext.getCertificate();
if (certificate == null) { if (certificate == null) {
throw new RuntimeException("No matching certificate found to decrypt the configuration"); 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); int readBytes = input.read(buffer, 0, buffer.length);
while (readBytes > 0) { while (readBytes > 0) {
final byte[] encryptedBlock = decryptWithCert(certificate, buffer, readBytes); final byte[] encryptedBlock = decryptWithCert(sebConfigEncryptionContext, buffer, readBytes);
output.write(encryptedBlock, 0, encryptedBlock.length); output.write(encryptedBlock, 0, encryptedBlock.length);
readBytes = input.read(buffer, 0, buffer.length); readBytes = input.read(buffer, 0, buffer.length);
} }

View file

@ -29,6 +29,7 @@ import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; 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.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.CertificateService; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.CertificateService;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigCryptor; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigCryptor;
@ -60,9 +61,10 @@ public class CertificateSymetricKeyCryptor extends AbstractCertificateCryptor im
public CertificateSymetricKeyCryptor( public CertificateSymetricKeyCryptor(
final PasswordEncryptor passwordEncryptor, final PasswordEncryptor passwordEncryptor,
final PasswordDecryptor passwordDecryptor, final PasswordDecryptor passwordDecryptor,
final CertificateService certificateService) { final CertificateService certificateService,
final Cryptor cryptor) {
super(certificateService); super(certificateService, cryptor);
this.passwordEncryptor = passwordEncryptor; this.passwordEncryptor = passwordEncryptor;
this.passwordDecryptor = passwordDecryptor; this.passwordDecryptor = passwordDecryptor;
} }
@ -120,16 +122,17 @@ public class CertificateSymetricKeyCryptor extends AbstractCertificateCryptor im
try { try {
final byte[] publicKeyHash = parsePublicKeyHash(input); final byte[] publicKeyHash = parsePublicKeyHash(input);
final Certificate certificate = getCertificateByPublicKeyHash( final SEBConfigEncryptionContext sebConfigEncryptionContext = getCertificateByPublicKeyHash(
context.institutionId(), context,
publicKeyHash); publicKeyHash);
final Certificate certificate = sebConfigEncryptionContext.getCertificate();
if (certificate == null) { if (certificate == null) {
throw new RuntimeException("No matching certificate found to decrypt the configuration"); throw new RuntimeException("No matching certificate found to decrypt the configuration");
} }
final byte[] encryptedKey = getEncryptedKey(input); final byte[] encryptedKey = getEncryptedKey(input);
final byte[] symetricKey = decryptWithCert(certificate, encryptedKey); final byte[] symetricKey = decryptWithCert(sebConfigEncryptionContext, encryptedKey);
final CharSequence symetricKeyBase64 = Base64.getEncoder().encodeToString(symetricKey); final CharSequence symetricKeyBase64 = Base64.getEncoder().encodeToString(symetricKey);
this.passwordDecryptor.decrypt(output, input, symetricKeyBase64); this.passwordDecryptor.decrypt(output, input, symetricKeyBase64);

View file

@ -293,9 +293,9 @@ public class ClientConfigServiceImpl implements ClientConfigService {
private SEBConfigEncryptionContext buildCertificateEncryptionContext(final SEBClientConfig config) { private SEBConfigEncryptionContext buildCertificateEncryptionContext(final SEBClientConfig config) {
final Certificate certificate = this.certificateDAO.getCertificate( final String alias = String.valueOf(config.getEncryptCertificateAlias());
config.institutionId, final Certificate certificate = this.certificateDAO
String.valueOf(config.getEncryptCertificateAlias())) .getCertificate(config.institutionId, alias)
.getOrThrow(); .getOrThrow();
return EncryptionContext.contextOf( return EncryptionContext.contextOf(
@ -303,7 +303,8 @@ public class ClientConfigServiceImpl implements ClientConfigService {
(config.encryptCertificateAsym) (config.encryptCertificateAsym)
? SEBConfigEncryptionService.Strategy.PUBLIC_KEY_HASH ? SEBConfigEncryptionService.Strategy.PUBLIC_KEY_HASH
: SEBConfigEncryptionService.Strategy.PUBLIC_KEY_HASH_SYMMETRIC_KEY, : SEBConfigEncryptionService.Strategy.PUBLIC_KEY_HASH_SYMMETRIC_KEY,
certificate); certificate,
alias);
} }
private SEBConfigEncryptionContext buildPasswordEncryptionContext(final SEBClientConfig config) { private SEBConfigEncryptionContext buildPasswordEncryptionContext(final SEBClientConfig config) {

View file

@ -15,6 +15,7 @@ import java.io.OutputStream;
import java.io.PipedInputStream; import java.io.PipedInputStream;
import java.io.PipedOutputStream; import java.io.PipedOutputStream;
import java.io.SequenceInputStream; import java.io.SequenceInputStream;
import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; 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.AttributeValueConverter;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.AttributeValueConverterService; 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.ConfigurationFormat;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigEncryptionService.Strategy;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ZipService; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ZipService;
@Lazy @Lazy
@ -243,6 +245,10 @@ public class ExamConfigIO {
throw new IllegalArgumentException("Failed to verify Zip type from input stream. Header size mismatch."); 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 final boolean isZipped = Byte.toUnsignedInt(zipHeader[0]) == Constants.GZIP_ID1
&& Byte.toUnsignedInt(zipHeader[1]) == Constants.GZIP_ID2 && Byte.toUnsignedInt(zipHeader[1]) == Constants.GZIP_ID2
&& Byte.toUnsignedInt(zipHeader[2]) == Constants.GZIP_CM; && Byte.toUnsignedInt(zipHeader[2]) == Constants.GZIP_CM;

View file

@ -150,6 +150,34 @@ public final class SEBConfigEncryptionServiceImpl implements SEBConfigEncryption
.getOrThrow() .getOrThrow()
.decrypt(pout, newIn, context); .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); IOUtils.copyLarge(pin, output);
return new AsyncResult<>(null); return new AsyncResult<>(null);
@ -194,17 +222,20 @@ public final class SEBConfigEncryptionServiceImpl implements SEBConfigEncryption
public final Strategy strategy; public final Strategy strategy;
public final CharSequence password; public final CharSequence password;
public final Certificate certificate; public final Certificate certificate;
public final String certificateAlias;
private EncryptionContext( private EncryptionContext(
final Long institutionId, final Long institutionId,
final Strategy strategy, final Strategy strategy,
final CharSequence password, final CharSequence password,
final Certificate certificate) { final Certificate certificate,
final String certificateAlias) {
this.institutionId = institutionId; this.institutionId = institutionId;
this.strategy = strategy; this.strategy = strategy;
this.password = password; this.password = password;
this.certificate = certificate; this.certificate = certificate;
this.certificateAlias = certificateAlias;
} }
@Override @Override
@ -227,22 +258,28 @@ public final class SEBConfigEncryptionServiceImpl implements SEBConfigEncryption
return this.certificate; return this.certificate;
} }
@Override
public String getCertificateAlias() {
return this.certificateAlias;
}
static SEBConfigEncryptionContext contextOf( static SEBConfigEncryptionContext contextOf(
final Long institutionId, final Long institutionId,
final Strategy strategy, final Strategy strategy,
final CharSequence password) { final CharSequence password) {
checkPasswordBased(strategy); checkPasswordBased(strategy);
return new EncryptionContext(institutionId, strategy, password, null); return new EncryptionContext(institutionId, strategy, password, null, null);
} }
static SEBConfigEncryptionContext contextOf( static SEBConfigEncryptionContext contextOf(
final Long institutionId, final Long institutionId,
final Strategy strategy, final Strategy strategy,
final Certificate certificate) { final Certificate certificate,
final String certificateAlias) {
checkCertificateBased(strategy); checkCertificateBased(strategy);
return new EncryptionContext(institutionId, strategy, null, certificate); return new EncryptionContext(institutionId, strategy, null, certificate, certificateAlias);
} }
static void checkPasswordBased(final Strategy strategy) { static void checkPasswordBased(final Strategy strategy) {
@ -259,14 +296,14 @@ public final class SEBConfigEncryptionServiceImpl implements SEBConfigEncryption
public static SEBConfigEncryptionContext contextOfPlainText(final Long institutionId) { 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( public static SEBConfigEncryptionContext contextOf(
final Long institutionId, final Long institutionId,
final CharSequence password) { final CharSequence password) {
return new EncryptionContext(institutionId, null, password, null); return new EncryptionContext(institutionId, null, password, null, null);
} }
} }