Skip to content

Commit e576f05

Browse files
committed
Add XML parser for retrieving country-specific LOTL URLs
DEVSIX-9242
1 parent 8664ec0 commit e576f05

File tree

13 files changed

+345
-92
lines changed

13 files changed

+345
-92
lines changed

commons/src/sharpenconfig/java/com/itextpdf/commons/SharpenConfigMapping.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,9 @@ public void applyMappingConfiguration(MappingConfigurator configurator) {
148148
configurator.mapMethod("com.itextpdf.commons.utils.DateTimeUtil.addDaysToDate", "AddDays");
149149
configurator.mapMethod("com.itextpdf.commons.utils.DateTimeUtil.addYearsToDate", "AddYears");
150150
configurator.mapMethod("com.itextpdf.commons.utils.DateTimeUtil.getCurrentTimeDate", "GetCurrentUtcTime");
151-
151+
configurator.mapMethod("java.time.LocalDateTime.of", "iText.Commons.Utils.DateTimeUtil.CreateDateTime");
152+
153+
configurator.mapMethod("java.nio.file.Files.newInputStream", "iText.Commons.Utils.FileUtil.GetInputStreamForFile");
152154

153155
configurator.mapType("com.itextpdf.commons.bouncycastle.asn1.x509.ITBSCertificate", "iText.Commons.Bouncycastle.Asn1.X509.ITbsCertificateStructure");
154156
configurator.mapType("com.itextpdf.commons.bouncycastle.asn1.IASN1OutputStream", "iText.Commons.Bouncycastle.Asn1.IDerOutputStream");

sharpenConfiguration.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@
468468
<fileset reason="XML validation is different in .NET">
469469
<file path="com/itextpdf/signatures/validation/XmlValidationUtils.java" />
470470
<file path="com/itextpdf/signatures/validation/CertificateSelector.java" />
471+
<file path="com/itextpdf/signatures/validation/xml/XmlSaxProcessor.java" />
471472
</fileset>
472473
<file path="com/itextpdf/signatures/ProviderDigest.java"/>
473474
<fileset reason="ProviderDigest class exists only on Java.">
@@ -541,11 +542,9 @@
541542
</fileset>
542543
<fileset reason="Different xml SAX reading implementation on .NET and java">
543544
<file path="com/itextpdf/signatures/validation/AbstractXmlCertificateHandler.java"/>
544-
<file path="com/itextpdf/signatures/validation/XmlCertificateRetriever.java"/>
545545
</fileset>
546546
<fileset reason="LocalDateTime and DateTime have different constructors and parsing">
547547
<file path="com/itextpdf/signatures/validation/ServiceStatusInfo.java"/>
548-
<file path="com/itextpdf/signatures/validation/XmlCertificateRetrieverTest.java"/>
549548
</fileset>
550549
<!-- jsoup -->
551550
<file path="com/itextpdf/styledxmlparser/jsoup/PortUtil.java" />

sign/src/main/java/com/itextpdf/signatures/exceptions/SignExceptionMessageConstant.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ public final class SignExceptionMessageConstant {
114114
public static final String CMS_CERTIFICATE_NOT_FOUND = "Signer certificate not found in list of certificates";
115115
public static final String CMS_MISSING_CERTIFICATES =
116116
"The certificate set must at least contains the signer certificate";
117-
public static final String FAILED_TO_READ_CERTIFICATE_BYTES_FROM_XML = "Failed to read certificate binary data from {0}.";
118117
public static final String FAILED_TO_RETRIEVE_CERTIFICATE = "Failed to retrieve certificates from binary data";
119118
public static final String FAILED_TO_GET_EU_LOTL = "Failed to get European List of Trusted Lists (LOTL) from {0}.";
120119

sign/src/main/java/com/itextpdf/signatures/validation/AbstractXmlCertificateHandler.java

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@ This file is part of the iText (R) project.
2828
import com.itextpdf.commons.bouncycastle.cert.jcajce.IJcaX509CertificateConverter;
2929
import com.itextpdf.kernel.exceptions.PdfException;
3030
import com.itextpdf.signatures.exceptions.SignExceptionMessageConstant;
31-
import org.xml.sax.helpers.DefaultHandler;
32-
import org.xml.sax.Attributes;
31+
import com.itextpdf.signatures.validation.xml.IDefaultXmlHandler;
3332

3433
import java.io.IOException;
3534
import java.security.cert.Certificate;
3635
import java.security.cert.CertificateException;
3736
import java.util.Base64;
37+
import java.util.HashMap;
3838
import java.util.List;
3939

40-
abstract class AbstractXmlCertificateHandler extends DefaultHandler {
40+
abstract class AbstractXmlCertificateHandler implements IDefaultXmlHandler {
4141

4242
private static final IBouncyCastleFactory BOUNCY_CASTLE_FACTORY = BouncyCastleFactoryCreator.getFactory();
4343

@@ -48,15 +48,6 @@ abstract class AbstractXmlCertificateHandler extends DefaultHandler {
4848

4949
abstract List<Certificate> getCertificateList();
5050

51-
@Override
52-
public void startElement(String uri, String localName, String qName, Attributes attributes) {}
53-
54-
@Override
55-
public void endElement(String uri, String localName, String qName) {}
56-
57-
@Override
58-
public void characters(char[] ch, int start, int length) {}
59-
6051
Certificate getCertificateFromEncodedData(String certificateString) {
6152
try {
6253
byte[] bytes = Base64.getDecoder().decode(certificateString);

sign/src/main/java/com/itextpdf/signatures/validation/XmlCertificateRetriever.java

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,40 +22,26 @@ This file is part of the iText (R) project.
2222
*/
2323
package com.itextpdf.signatures.validation;
2424

25-
import com.itextpdf.commons.utils.MessageFormatUtil;
26-
import com.itextpdf.kernel.exceptions.PdfException;
27-
import com.itextpdf.kernel.utils.XmlProcessorCreator;
28-
import com.itextpdf.signatures.exceptions.SignExceptionMessageConstant;
29-
import org.xml.sax.SAXException;
30-
import org.xml.sax.XMLReader;
25+
import com.itextpdf.signatures.validation.xml.XmlSaxProcessor;
3126

32-
import java.io.IOException;
27+
import java.io.InputStream;
3328
import java.security.cert.Certificate;
3429
import java.util.List;
3530

3631

3732
class XmlCertificateRetriever {
3833

39-
private AbstractXmlCertificateHandler handler;
34+
private final AbstractXmlCertificateHandler handler;
4035

4136
XmlCertificateRetriever(AbstractXmlCertificateHandler handler) {
4237
this.handler = handler;
4338
}
4439

45-
List<Certificate> getCertificates(String path) {
40+
List<Certificate> getCertificates(InputStream inputStream) {
4641
if (!handler.getCertificateList().isEmpty()) {
4742
handler.clear();
4843
}
49-
50-
XMLReader reader = XmlProcessorCreator.createSafeXMLReader(true, false);
51-
reader.setContentHandler(handler);
52-
try {
53-
reader.parse(path);
54-
} catch (IOException | SAXException e) {
55-
throw new PdfException(MessageFormatUtil.format(
56-
SignExceptionMessageConstant.FAILED_TO_READ_CERTIFICATE_BYTES_FROM_XML, path), e);
57-
}
58-
44+
new XmlSaxProcessor().process(inputStream,handler);
5945
return handler.getCertificateList();
6046
}
6147

sign/src/main/java/com/itextpdf/signatures/validation/XmlCountryCertificateHandler.java

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,39 +23,38 @@ This file is part of the iText (R) project.
2323
package com.itextpdf.signatures.validation;
2424

2525

26-
import org.xml.sax.Attributes;
27-
2826
import java.security.cert.Certificate;
2927
import java.util.ArrayList;
28+
import java.util.HashMap;
3029
import java.util.List;
3130

3231
class XmlCountryCertificateHandler extends AbstractXmlCertificateHandler {
3332

3433
private static final List<String> INFORMATION_TAGS = new ArrayList<>();
3534

36-
private StringBuilder information;
37-
38-
private final List<Certificate> certificateList = new ArrayList<>();
39-
40-
private CountryServiceContext currentServiceContext = null;
41-
42-
private ServiceStatusInfo currentServiceStatusInfo = null;
43-
44-
private final List<CountryServiceContext> serviceContextList = new ArrayList<>();
45-
4635
static {
4736
INFORMATION_TAGS.add(XmlTagConstants.SERVICE_TYPE);
4837
INFORMATION_TAGS.add(XmlTagConstants.SERVICE_STATUS);
4938
INFORMATION_TAGS.add(XmlTagConstants.X509CERTIFICATE);
5039
INFORMATION_TAGS.add(XmlTagConstants.SERVICE_STATUS_STARTING_TIME);
5140
}
5241

42+
private final List<Certificate> certificateList = new ArrayList<>();
43+
private final List<CountryServiceContext> serviceContextList = new ArrayList<>();
44+
private StringBuilder information;
45+
private CountryServiceContext currentServiceContext = null;
46+
private ServiceStatusInfo currentServiceStatusInfo = null;
47+
5348
XmlCountryCertificateHandler() {
5449
//empty constructor
5550
}
5651

52+
private static String removeWhitespacesAndBreakLines(String data) {
53+
return data.replace(" ", "").replace("\n", "");
54+
}
55+
5756
@Override
58-
public void startElement(String uri, String localName, String qName, Attributes attributes) {
57+
public void startElement(String uri, String localName, String qName, HashMap<String, String> attributes) {
5958
if (XmlTagConstants.TSP_SERVICE.equals(localName)) {
6059
startProvider();
6160
} else if (XmlTagConstants.SERVICE_HISTORY_INSTANCE.equals(localName)
@@ -154,8 +153,4 @@ void clear() {
154153
certificateList.clear();
155154
serviceContextList.clear();
156155
}
157-
158-
private static String removeWhitespacesAndBreakLines(String data) {
159-
return data.replace(" ", "").replace("\n", "");
160-
}
161156
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package com.itextpdf.signatures.validation;
2+
3+
import com.itextpdf.signatures.validation.xml.IDefaultXmlHandler;
4+
import com.itextpdf.signatures.validation.xml.XmlSaxProcessor;
5+
6+
import java.io.InputStream;
7+
import java.util.ArrayList;
8+
import java.util.HashMap;
9+
import java.util.List;
10+
11+
/**
12+
* This class is used to retrieve the list of countries and their corresponding TSL (Trusted List) locations
13+
* from an XML file.
14+
*/
15+
final class XmlCountryRetriever {
16+
17+
18+
/**
19+
* Default constructor for XmlCountryRetriever.
20+
* Creates an instance of {@code XmlCountryRetriever}.
21+
*/
22+
public XmlCountryRetriever() {
23+
// Empty constructor
24+
}
25+
26+
/**
27+
* This method reads an XML file containing country-specific TSL locations and returns a list of
28+
* {@code CountrySpecificLotl} objects.
29+
*
30+
* @param data the InputStream of the XML data containing country-specific TSL locations
31+
* @return a list of CountrySpecificLotl objects, each containing the scheme territory and TSL location.
32+
*/
33+
public List<CountrySpecificLotl> getAllCountriesLotlFilesLocation(InputStream data) {
34+
TSLLocationExtractor tslLocationExtractor = new TSLLocationExtractor();
35+
new XmlSaxProcessor().process(data, tslLocationExtractor);
36+
return tslLocationExtractor.tslLocations;
37+
}
38+
39+
/**
40+
* This class represents a country-specific TSL (Trusted List) location.
41+
* It contains the scheme territory and the TSL location URL.
42+
*/
43+
public static final class CountrySpecificLotl {
44+
45+
private final String schemeTerritory;
46+
private final String tslLocation;
47+
private final String mimeType;
48+
49+
50+
CountrySpecificLotl(String schemeTerritory, String tslLocation, String mimeType) {
51+
this.schemeTerritory = schemeTerritory;
52+
this.tslLocation = tslLocation;
53+
this.mimeType = mimeType;
54+
}
55+
56+
/**
57+
* Returns the scheme territory of this country-specific TSL.
58+
*
59+
* @return The scheme territory
60+
*/
61+
public String getSchemeTerritory() {
62+
return schemeTerritory;
63+
}
64+
65+
/**
66+
* Returns the TSL location URL of this country-specific TSL.
67+
*
68+
* @return The TSL location URL
69+
*/
70+
public String getTslLocation() {
71+
return tslLocation;
72+
}
73+
74+
/**
75+
* Returns the MIME type of the TSL location.
76+
*
77+
* @return The MIME type of the TSL location
78+
*/
79+
public String getMimeType() {
80+
return mimeType;
81+
}
82+
83+
@Override
84+
public String toString() {
85+
return "CountrySpecificLotl{" + "schemeTerritory='" +
86+
schemeTerritory + '\'' + ", tslLocation='" + tslLocation + '\'' +
87+
", mimeType='" + mimeType + '\'' +
88+
'}';
89+
}
90+
}
91+
92+
93+
private static final class TSLLocationExtractor implements IDefaultXmlHandler {
94+
private static final String MIME_TYPE_ETSI_TSL = "application/vnd.etsi.tsl+xml";
95+
final List<CountrySpecificLotl> tslLocations = new ArrayList<>();
96+
String parsingState = null;
97+
String schemeTerritory = null;
98+
String tslLocation = null;
99+
String mimeType = null;
100+
101+
102+
TSLLocationExtractor() {
103+
//Empty constructor
104+
}
105+
106+
private static boolean isXmlLink(CountrySpecificLotl data) {
107+
return MIME_TYPE_ETSI_TSL.equals(data.getMimeType());
108+
}
109+
110+
@Override
111+
public void startElement(String uri, String localName, String qName, HashMap<String, String> attributes) {
112+
parsingState = localName;
113+
}
114+
115+
@Override
116+
public void endElement(String uri, String localName, String qName) {
117+
if (XmlTagConstants.OTHER_TSL_POINTER.equals(localName)) {
118+
CountrySpecificLotl data = new CountrySpecificLotl(schemeTerritory, tslLocation, mimeType);
119+
if (isXmlLink(data)) {
120+
tslLocations.add(data);
121+
}
122+
resetState();
123+
}
124+
}
125+
126+
@Override
127+
public void characters(char[] ch, int start, int length) {
128+
if (parsingState == null) {
129+
return;
130+
}
131+
String value = new String(ch, start, length).trim();
132+
if (value.isEmpty()) {
133+
return;
134+
}
135+
switch (parsingState) {
136+
case XmlTagConstants.SCHEME_TERRITORY:
137+
schemeTerritory = value;
138+
break;
139+
case XmlTagConstants.TSLLOCATION:
140+
tslLocation = value;
141+
break;
142+
case XmlTagConstants.MIME_TYPE:
143+
mimeType = value;
144+
break;
145+
default:
146+
}
147+
}
148+
149+
private void resetState() {
150+
schemeTerritory = null;
151+
tslLocation = null;
152+
parsingState = null;
153+
mimeType = null;
154+
}
155+
}
156+
}

sign/src/main/java/com/itextpdf/signatures/validation/XmlDefaultCertificateHandler.java

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,27 @@ This file is part of the iText (R) project.
2222
*/
2323
package com.itextpdf.signatures.validation;
2424

25-
import org.xml.sax.Attributes;
26-
2725
import java.security.cert.Certificate;
2826
import java.util.ArrayList;
27+
import java.util.HashMap;
2928
import java.util.List;
3029

3130
class XmlDefaultCertificateHandler extends AbstractXmlCertificateHandler {
3231

33-
private StringBuilder information;
34-
3532
private final List<Certificate> certificateList = new ArrayList<>();
36-
3733
private final List<SimpleServiceContext> serviceContextList = new ArrayList<>();
34+
private StringBuilder information;
3835

3936
XmlDefaultCertificateHandler() {
4037
//empty constructor
4138
}
4239

40+
private static String removeWhitespacesAndBreakLines(String data) {
41+
return data.replace(" ", "").replace("\n", "");
42+
}
43+
4344
@Override
44-
public void startElement(String uri, String localName, String qName, Attributes attributes) {
45+
public void startElement(String uri, String localName, String qName, HashMap<String, String> attributes) {
4546
if (XmlTagConstants.X509CERTIFICATE.equals(localName)) {
4647
information = new StringBuilder();
4748
}
@@ -87,8 +88,4 @@ void clear() {
8788
certificateList.clear();
8889
serviceContextList.clear();
8990
}
90-
91-
private static String removeWhitespacesAndBreakLines(String data) {
92-
return data.replace(" ", "").replace("\n", "");
93-
}
9491
}

0 commit comments

Comments
 (0)