Skip to content

Commit

Permalink
Merge pull request #7 from slovensko-digital/sync-autogram-v2.2.2
Browse files Browse the repository at this point in the history
Sync core logic from Autogram v2.2.2
  • Loading branch information
celuchmarek authored Jul 2, 2024
2 parents 582ac16 + 258e794 commit d67d1a5
Show file tree
Hide file tree
Showing 22 changed files with 1,048 additions and 677 deletions.
2 changes: 1 addition & 1 deletion .run/Main.run.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<option name="ALTERNATIVE_JRE_PATH" value="$PROJECT_DIR$/target/jdkCache/LIBERICA_jdk17.0.10+13_linux_amd64-full" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
<option name="MAIN_CLASS_NAME" value="digital.slovensko.avm.Main" />
<module name="autogram" />
<module name="avm" />
<option name="PROGRAM_PARAMETERS" value="-p 7200" />
<option name="VM_PARAMETERS" value="--add-exports jdk.crypto.cryptoki/sun.security.pkcs11.wrapper=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED --add-opens jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED --add-exports java.base/sun.security.x509=ALL-UNNAMED" />
<method v="2">
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/digital/slovensko/avm/core/AVM.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
import eu.europa.esig.dss.model.DSSDocument;
import eu.europa.esig.dss.pdfa.PDFAStructureValidator;
import eu.europa.esig.dss.spi.x509.tsp.TSPSource;
import eu.europa.esig.dss.validation.reports.Reports;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;

Expand All @@ -27,9 +27,9 @@ public AVM(TSPSource tspSource, boolean plainXmlEnabled) {
this.plainXmlEnabled = plainXmlEnabled;
}

public Reports checkAndValidateSignatures(DSSDocument document) {
var reports = SignatureValidator.getInstance().getSignatureValidationReport(document);
if (reports.getSimpleReport().getSignatureIdList().isEmpty())
public ValidationReports checkAndValidateSignatures(SigningJob job) {
var reports = SignatureValidator.getInstance().getSignatureValidationReport(job);
if (!reports.haveSignatures())
return null;

return reports;
Expand All @@ -40,8 +40,8 @@ public boolean checkPDFACompliance(SigningJob job) {
return result.isCompliant();
}

public void initializeSignatureValidator(ScheduledExecutorService scheduledExecutorService, ExecutorService cachedExecutorService) {
SignatureValidator.getInstance().initialize(cachedExecutorService);
public void initializeSignatureValidator(ScheduledExecutorService scheduledExecutorService, ExecutorService cachedExecutorService, List<String> tlCountries) {
SignatureValidator.getInstance().initialize(cachedExecutorService, tlCountries);

scheduledExecutorService.scheduleAtFixedRate(() -> SignatureValidator.getInstance().refresh(),
480, 480, java.util.concurrent.TimeUnit.MINUTES);
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/digital/slovensko/avm/core/AutogramMimeType.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public record AutogramMimeType(
String extension
) implements MimeType {
public static final AutogramMimeType XML_DATACONTAINER = new AutogramMimeType("application/vnd.gov.sk.xmldatacontainer+xml", null);
public static final AutogramMimeType XML_DATACONTAINER_WITH_CHARSET = new AutogramMimeType("application/vnd.gov.sk.xmldatacontainer+xml; charset=UTF-8", null);
public static final AutogramMimeType TEXT_WITH_CHARSET = new AutogramMimeType("text/plain; charset=UTF-8", null);
public static final AutogramMimeType APPLICATION_XML = new AutogramMimeType("application/xml", null);

@Override
Expand Down Expand Up @@ -41,10 +43,18 @@ public static boolean isXML(MimeType mimeType) {
}

public static boolean isXDC(MimeType mimeType) {
return mimeType.equals(XML_DATACONTAINER);
return mimeType.equals(XML_DATACONTAINER) || mimeType.equals(XML_DATACONTAINER_WITH_CHARSET);
}

public static boolean isPDF(MimeType mimeType) {
return mimeType.equals(MimeTypeEnum.PDF);
}

public static boolean isTxt(MimeType mimeType) {
return mimeType.equals(MimeTypeEnum.TEXT) || mimeType.equals(TEXT_WITH_CHARSET);
}

public static boolean isImage(MimeType mimeType) {
return mimeType.equals(MimeTypeEnum.PNG) || mimeType.equals(MimeTypeEnum.JPEG);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ private DSSDocument createVisualization() throws IOException, ParserConfiguratio
if (documentToDisplay.getMimeType().equals(MimeTypeEnum.HTML))
return documentToDisplay;

if (documentToDisplay.getMimeType().equals(MimeTypeEnum.TEXT))
if (isTxt(documentToDisplay.getMimeType()))
return documentToDisplay;

if (documentToDisplay.getMimeType().equals(MimeTypeEnum.PDF))
if (isPDF(documentToDisplay.getMimeType()))
return documentToDisplay;

if (documentToDisplay.getMimeType().equals(MimeTypeEnum.JPEG) || documentToDisplay.getMimeType().equals(MimeTypeEnum.PNG))
if (isImage(documentToDisplay.getMimeType()))
return transformImageToHTML(documentToDisplay);

return null;
Expand All @@ -97,8 +97,6 @@ private boolean isTranformationAvailable(String transformation) {
}

private boolean isDocumentSupportingTransformation(DSSDocument document) {
return document.getMimeType().equals(AutogramMimeType.XML_DATACONTAINER)
|| document.getMimeType().equals(AutogramMimeType.APPLICATION_XML)
|| document.getMimeType().equals(MimeTypeEnum.XML);
return isXDC(document.getMimeType()) || isXML(document.getMimeType());
}
}
30 changes: 22 additions & 8 deletions src/main/java/digital/slovensko/avm/core/SignatureValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;

import javax.xml.parsers.ParserConfigurationException;
Expand All @@ -16,6 +17,8 @@

import digital.slovensko.avm.util.DSSUtils;
import digital.slovensko.avm.util.XMLUtils;
import eu.europa.esig.dss.simplereport.SimpleReport;
import eu.europa.esig.dss.tsl.function.TLPredicateFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.InputSource;
Expand All @@ -40,6 +43,8 @@
import eu.europa.esig.dss.validation.SignedDocumentValidator;
import eu.europa.esig.dss.validation.reports.Reports;

import static digital.slovensko.avm.util.DSSUtils.createDocumentValidator;

public class SignatureValidator {
private static final String LOTL_URL = "https://ec.europa.eu/tools/lotl/eu-lotl.xml";
private static final String OJ_URL = "https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=uriserv:OJ.C_.2019.276.01.0001.01.ENG";
Expand Down Expand Up @@ -71,7 +76,7 @@ public synchronized void refresh() {
validationJob.offlineRefresh();
}

public synchronized void initialize(ExecutorService executorService) {
public synchronized void initialize(ExecutorService executorService, List<String> tlCountries) {
SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
logger.debug("Initializing signature validator at {}", formatter.format(new Date()));

Expand All @@ -82,6 +87,7 @@ public synchronized void initialize(ExecutorService executorService) {
lotlSource.setSigningCertificatesAnnouncementPredicate(new OfficialJournalSchemeInformationURI(OJ_URL));
lotlSource.setUrl(LOTL_URL);
lotlSource.setPivotSupport(true);
lotlSource.setTlPredicate(TLPredicateFactory.createEUTLCountryCodePredicate(tlCountries.toArray(new String[0])));

var offlineFileLoader = new FileCacheDataLoader();
offlineFileLoader.setCacheExpirationTime(21600000);
Expand Down Expand Up @@ -121,12 +127,12 @@ private CertificateSource getJournalCertificateSource() throws AssertionError {
}
}

public synchronized Reports getSignatureValidationReport(DSSDocument document) {
var documentValidator = DSSUtils.createDocumentValidator(document);
public synchronized ValidationReports getSignatureValidationReport(SigningJob job) {
var documentValidator = createDocumentValidator(job.getDocument());
if (documentValidator == null)
return null;
return new ValidationReports(null, job);

return validate(documentValidator);
return new ValidationReports(validate(documentValidator), job);
}

public static String getSignatureValidationReportHTML(Reports signatureValidationReport) {
Expand All @@ -153,16 +159,16 @@ public static String getSignatureValidationReportHTML(Reports signatureValidatio
}

public static ValidationReports getSignatureCheckReport(SigningJob job) {
var validator = DSSUtils.createDocumentValidator(job.getDocument());
var validator = createDocumentValidator(job.getDocument());
if (validator == null)
return new ValidationReports(null, job);

validator.setCertificateVerifier(new CommonCertificateVerifier());
return new ValidationReports(validator.validateDocument(), job);
}

public static SignatureLevel getSignedDocumentSignatureLevel(DSSDocument document) {
var validator = DSSUtils.createDocumentValidator(document);
public static SimpleReport getSignedDocumentSimpleReport(DSSDocument document) {
var validator = createDocumentValidator(document);
if (validator == null)
return null;

Expand All @@ -171,10 +177,18 @@ public static SignatureLevel getSignedDocumentSignatureLevel(DSSDocument documen
if (report.getSignatureIdList().size() == 0)
return null;

return report;
}

public static SignatureLevel getSignedDocumentSignatureLevel(SimpleReport report) {
if (report == null)
return null;

return report.getSignatureFormat(report.getSignatureIdList().get(0));
}

public synchronized boolean areTLsLoaded() {
// TODO: consider validation turned off as well
return validationJob.getSummary().getNumberOfProcessedTLs() > 0;
}
}
52 changes: 33 additions & 19 deletions src/main/java/digital/slovensko/avm/core/SigningJob.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package digital.slovensko.avm.core;

import java.io.File;
import java.security.cert.CertificateException;
import java.util.Base64;
import java.util.Date;

import digital.slovensko.avm.core.eforms.EFormUtils;
import digital.slovensko.avm.core.eforms.XDCBuilder;
import digital.slovensko.avm.core.eforms.XDCValidator;
import digital.slovensko.avm.core.eforms.xdc.XDCBuilder;
import digital.slovensko.avm.core.errors.AutogramException;
import digital.slovensko.avm.core.errors.CryptographicSignatureVerificationException;
import digital.slovensko.avm.core.errors.DataToSignMismatchException;
Expand All @@ -17,15 +15,19 @@
import eu.europa.esig.dss.cades.signature.CAdESService;
import eu.europa.esig.dss.enumerations.ASiCContainerType;
import eu.europa.esig.dss.enumerations.SignatureForm;
import eu.europa.esig.dss.enumerations.SignatureLevel;
import eu.europa.esig.dss.jades.signature.JAdESService;
import eu.europa.esig.dss.model.*;
import eu.europa.esig.dss.pades.PAdESSignatureParameters;
import eu.europa.esig.dss.pades.signature.PAdESService;
import eu.europa.esig.dss.signature.AbstractSignatureService;
import eu.europa.esig.dss.validation.CertificateVerifier;
import eu.europa.esig.dss.validation.CommonCertificateVerifier;
import eu.europa.esig.dss.xades.signature.XAdESService;

import static digital.slovensko.avm.core.AutogramMimeType.*;
import static digital.slovensko.avm.util.DSSUtils.createDocumentValidator;
import static digital.slovensko.avm.util.DSSUtils.getXdcfFilename;

public class SigningJob {
private final DSSDocument document;
Expand All @@ -52,20 +54,33 @@ public SignedDocument signDocument(DataToSignStructure dataToSignStructure, Stri
bLevelParameters.setSigningDate(new Date(dataToSignStructure.signingTime()));
signatureParameters.setBLevelParams(bLevelParameters);

if (signatureParameters.getSignatureLevel().equals(SignatureLevel.PAdES_BASELINE_T)) {
service.setTspSource(getParameters().getTspSource());
((PAdESSignatureParameters)signatureParameters).setContentSize(9472*2);
}

var dataToSign = service.getDataToSign(document, signatureParameters);
if (!new String(Base64.getEncoder().encode(dataToSign.getBytes())).equals(dataToSignStructure.dataToSign()))
throw new DataToSignMismatchException();

DSSDocument doc;
try {
var doc = service.signDocument(document, signatureParameters, signatureValue);
doc = service.signDocument(document, signatureParameters, signatureValue);
doc.setName(generatePrettyName(doc.getName(), document.getName()));
return new SignedDocument(doc, token);
} catch (DSSException e) {
if (e.getMessage().contains("Cryptographic signature verification has failed"))
throw new CryptographicSignatureVerificationException();

throw e;
}

var documentValidator = createDocumentValidator(doc);
documentValidator.setCertificateVerifier(commonCertificateVerifier);
var reports = documentValidator.validateDocument().getSimpleReport();
if (!reports.isValid(reports.getSignatureIdList().get(reports.getSignatureIdList().size() - 1)))
throw new CryptographicSignatureVerificationException();

return new SignedDocument(doc, token);
}

private static String generatePrettyName(String newName, String originalName) {
Expand Down Expand Up @@ -110,27 +125,26 @@ public DataToSignStructure buildDataToSign(String signingCertificate) throws Cer
bLevelParameters.setSigningDate(signingTime);
signatureParameters.setBLevelParams(bLevelParameters);

if (signatureParameters.getSignatureLevel().equals(SignatureLevel.PAdES_BASELINE_T)) {
service.setTspSource(getParameters().getTspSource());
((PAdESSignatureParameters)signatureParameters).setContentSize(9472*2);
}

var dataToSign = Base64.getEncoder().encode(service.getDataToSign(document, signatureParameters).getBytes());

return new DataToSignStructure(new String(dataToSign), signingTime.getTime(), signingCertificate);
}

public static FileDocument createDSSFileDocumentFromFile(File file) {
var fileDocument = new FileDocument(file);
private static SigningJob build(DSSDocument document, SigningParameters params) {
if (params.shouldCreateXdc() && !isXDC(document.getMimeType()) && !isAsice(document.getMimeType()))
document = XDCBuilder.transform(params, document.getName(), EFormUtils.getXmlFromDocument(document));

if (isXDC(fileDocument.getMimeType()) || isXML(fileDocument.getMimeType()) && XDCValidator.isXDCContent(fileDocument))
fileDocument.setMimeType(AutogramMimeType.XML_DATACONTAINER);
if (isTxt(document.getMimeType()))
document.setMimeType(AutogramMimeType.TEXT_WITH_CHARSET);

return fileDocument;
}

private static SigningJob build(DSSDocument document, SigningParameters params) {
if (params.shouldCreateXdc()) {
var mimeType = document.getMimeType();
if (!isXDC(mimeType) && !isAsice(mimeType)) {
document = XDCBuilder.transform(params, document.getName(), EFormUtils.getXmlFromDocument(document));
document.setMimeType(AutogramMimeType.XML_DATACONTAINER);
}
if (isXDC(document.getMimeType())) {
document.setMimeType(AutogramMimeType.XML_DATACONTAINER_WITH_CHARSET);
document.setName(getXdcfFilename(document.getName()));
}

return new SigningJob(document, params);
Expand Down
Loading

0 comments on commit d67d1a5

Please sign in to comment.