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 */
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.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<String> 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);
}

View file

@ -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<Strategy> 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);
}

View file

@ -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);

View file

@ -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) {

View file

@ -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;

View file

@ -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);
}
}