Skip to content

Commit 66fdf3f

Browse files
authored
Merge pull request #28 from MobileID-Strong-Authentication/develop
Release 1.5.7, Introduced impl. for new dtbd format, fix in isDefined in GeofencingAdditionalServices
2 parents 9850dea + fdf2bf2 commit 66fdf3f

File tree

14 files changed

+336
-113
lines changed

14 files changed

+336
-113
lines changed

mid-java-client-core/pom.xml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<parent>
77
<groupId>ch.mobileid.mid-java-client</groupId>
88
<artifactId>mid-java-client-parent</artifactId>
9-
<version>1.5.6</version>
9+
<version>1.5.7</version>
1010
</parent>
1111

1212
<artifactId>mid-java-client-core</artifactId>
@@ -31,6 +31,15 @@
3131
<groupId>org.bouncycastle</groupId>
3232
<artifactId>bcpkix-jdk18on</artifactId>
3333
</dependency>
34+
<dependency>
35+
<groupId>com.fasterxml.jackson.core</groupId>
36+
<artifactId>jackson-databind</artifactId>
37+
</dependency>
38+
<dependency>
39+
<groupId>org.apache.commons</groupId>
40+
<artifactId>commons-text</artifactId>
41+
<version>1.12.0</version>
42+
</dependency>
3443
</dependencies>
3544

3645
</project>

mid-java-client-core/src/main/java/ch/swisscom/mid/client/impl/SignatureValidatorImpl.java

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
import ch.swisscom.mid.client.SignatureValidator;
44
import ch.swisscom.mid.client.config.ConfigurationException;
55
import ch.swisscom.mid.client.config.SignatureValidationConfiguration;
6+
import ch.swisscom.mid.client.model.DataToBeSignedTXNResponseType;
67
import ch.swisscom.mid.client.model.SignatureValidationFailureReason;
78
import ch.swisscom.mid.client.model.SignatureValidationResult;
89
import ch.swisscom.mid.client.model.Traceable;
10+
import com.fasterxml.jackson.core.JsonProcessingException;
11+
import com.fasterxml.jackson.databind.DeserializationFeature;
12+
import com.fasterxml.jackson.databind.ObjectMapper;
913
import org.bouncycastle.cert.X509CertificateHolder;
1014
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
1115
import org.bouncycastle.cms.CMSException;
@@ -32,6 +36,7 @@
3236
import java.util.regex.Pattern;
3337

3438
import static ch.swisscom.mid.client.utils.Utils.*;
39+
import static org.apache.commons.text.StringEscapeUtils.unescapeJava;
3540

3641
/**
3742
* Default implementation of {@link SignatureValidator}.
@@ -43,15 +48,22 @@ public class SignatureValidatorImpl implements SignatureValidator {
4348
private static final Logger log = LoggerFactory.getLogger(Loggers.SIGNATURE_VALIDATOR);
4449

4550
private final KeyStore validationTrustStore;
51+
private ObjectMapper jacksonMapper;
4652

4753
public SignatureValidatorImpl(SignatureValidationConfiguration config) {
4854
Security.addProvider(new BouncyCastleProvider());
4955
this.validationTrustStore = loadValidationTruststore(config);
56+
57+
jacksonMapper = new ObjectMapper();
58+
jacksonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
5059
}
5160

5261
public SignatureValidatorImpl(KeyStore validationTrustStore) {
5362
Security.addProvider(new BouncyCastleProvider());
5463
this.validationTrustStore = validationTrustStore;
64+
65+
jacksonMapper = new ObjectMapper();
66+
jacksonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
5567
}
5668

5769
@Override
@@ -143,14 +155,45 @@ public SignatureValidationResult validateSignature(String base64SignatureContent
143155
}
144156
} catch (OperatorCreationException | CMSException e) {
145157
log.warn("Failed to validate the signature against the signer info " +
146-
"during the signature CMS content validation{}", printTrace(trace), e);
158+
"during the signature CMS content validation{}", printTrace(trace), e);
147159
result.setValidationException(e);
148160
result.setValidationFailureReason(SignatureValidationFailureReason.SIGNATURE_VALIDATION_FAILED);
149161
return result;
150162
}
151163

152164
// verify the DTBS from the request vs the one from the response
153-
if (requestedDtbs.equals(result.getSignedDtbs())) {
165+
if (result.getSignedDtbs() == null) {
166+
log.info("Failed to match the DTBS texts, requested=[{}] vs signed=[{}]{}", requestedDtbs, result.getSignedDtbs(), printTrace(trace));
167+
result.setValidationFailureReason(SignatureValidationFailureReason.DATA_TO_BE_SIGNED_NOT_MATCHING);
168+
return result;
169+
}
170+
if (requestedDtbs.startsWith("{")) {
171+
result.setDtbsMatching(false);
172+
try {
173+
// parse item
174+
String[] dtbsArray = requestedDtbs.split("\"dtbd\":");
175+
String reqDtbsValueStr = "";
176+
if (dtbsArray.length > 0) {
177+
String reqDtbsValueRaw = dtbsArray[1];
178+
reqDtbsValueStr = reqDtbsValueRaw.substring(0, reqDtbsValueRaw.length() - 1);
179+
}
180+
// fix response DTBS string
181+
String escResultDtbs = unescapeJava(result.getSignedDtbs()
182+
.replace("\"format_version\"", "\\\"format_version\\\"")
183+
.replace("\"content_string\"", "\\\"content_string\\\"")
184+
.replace("\"[", "[")
185+
.replace("]\"", "]"));
186+
187+
DataToBeSignedTXNResponseType resDtbs = jacksonMapper.readValue(escResultDtbs, DataToBeSignedTXNResponseType.class);
188+
String finalResDtbs = jacksonMapper.writeValueAsString(resDtbs.getDtbd());
189+
result.setDtbsMatching(reqDtbsValueStr.equals(finalResDtbs));
190+
} catch (JsonProcessingException e) {
191+
log.info("Failed to match the DTBS texts, requested=[{}] vs signed=[{}]{}", requestedDtbs, result.getSignedDtbs(), printTrace(trace));
192+
result.setValidationFailureReason(SignatureValidationFailureReason.DATA_TO_BE_SIGNED_NOT_MATCHING);
193+
}
194+
return result;
195+
196+
} else if (requestedDtbs.equals(result.getSignedDtbs())) {
154197
result.setDtbsMatching(true);
155198
} else {
156199
log.info("Failed to match the DTBS texts, requested=[{}] vs signed=[{}]{}", requestedDtbs, result.getSignedDtbs(), printTrace(trace));
@@ -225,23 +268,23 @@ private KeyStore loadValidationTruststore(SignatureValidationConfiguration confi
225268
if (config.getTrustStoreFile() != null) {
226269
try (InputStream is = new FileInputStream(config.getTrustStoreFile())) {
227270
trustStore.load(is, config.getTrustStorePassword() == null ?
228-
null : config.getTrustStorePassword().toCharArray());
271+
null : config.getTrustStorePassword().toCharArray());
229272
}
230273
} else if (config.getTrustStoreClasspathFile() != null) {
231274
try (InputStream is = this.getClass().getResourceAsStream(config.getTrustStoreClasspathFile())) {
232275
trustStore.load(is, config.getTrustStorePassword() == null ?
233-
null : config.getTrustStorePassword().toCharArray());
276+
null : config.getTrustStorePassword().toCharArray());
234277
}
235278
} else {
236279
try (InputStream is = new ByteArrayInputStream(config.getTrustStoreBytes())) {
237280
trustStore.load(is, config.getTrustStorePassword() == null ?
238-
null : config.getTrustStorePassword().toCharArray());
281+
null : config.getTrustStorePassword().toCharArray());
239282
}
240283
}
241284
return trustStore;
242285
} catch (Exception e) {
243286
throw new ConfigurationException("Failed to initialize the digital signature validation truststore " +
244-
"(Mobile ID CMS signature validator)", e);
287+
"(Mobile ID CMS signature validator)", e);
245288
}
246289
}
247290
}

mid-java-client-core/src/main/java/ch/swisscom/mid/client/model/DataToBeSigned.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package ch.swisscom.mid.client.model;
1717

18+
import static ch.swisscom.mid.client.utils.Utils.dataIsTXNApprovalRequestType;
1819
import static ch.swisscom.mid.client.utils.Utils.dataNotEmpty;
1920

2021
public class DataToBeSigned {
@@ -61,14 +62,17 @@ public void validateYourself() {
6162
dataNotEmpty(data, "The data in the DataToBeSigned cannot be null or empty");
6263
dataNotEmpty(encoding, "The encoding in the DataToBeSigned cannot be null or empty (set it to \"UTF-8\", for example)");
6364
dataNotEmpty(mimeType, "The mime type in the DataToBeSigned cannot be null or empty (set it to \"text/plain\", for example)");
65+
if (mimeType.equalsIgnoreCase("application/vnd.mobileid.txn-approval")) {
66+
dataIsTXNApprovalRequestType(data, "The DataToBeSigned format is not valid for mime type 'application/vnd.mobileid.txn-approval'");
67+
}
6468
}
6569

6670
@Override
6771
public String toString() {
6872
return "DataToBeSigned{" +
69-
"data='" + data + '\'' +
70-
", encoding='" + encoding + '\'' +
71-
", mimeType='" + mimeType + '\'' +
72-
'}';
73+
"data='" + data + '\'' +
74+
", encoding='" + encoding + '\'' +
75+
", mimeType='" + mimeType + '\'' +
76+
'}';
7377
}
7478
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package ch.swisscom.mid.client.model;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
import java.util.Map;
8+
9+
10+
public class DataToBeSignedTXNResponseType {
11+
@JsonProperty("format_version")
12+
private String formatVersion;
13+
14+
@JsonProperty("content_string")
15+
private List<Map<String, String>> dtbd = new ArrayList<>();
16+
17+
public DataToBeSignedTXNResponseType() {
18+
}
19+
20+
public DataToBeSignedTXNResponseType(String formatVersion, List<Map<String, String>> dtbd) {
21+
this.formatVersion = formatVersion;
22+
this.dtbd = dtbd;
23+
}
24+
25+
public String getFormatVersion() {
26+
return formatVersion;
27+
}
28+
29+
public void setFormatVersion(String formatVersion) {
30+
this.formatVersion = formatVersion;
31+
}
32+
33+
public List<Map<String, String>> getDtbd() {
34+
return dtbd;
35+
}
36+
37+
public void setDtbd(List<Map<String, String>> dtbd) {
38+
this.dtbd = dtbd;
39+
}
40+
41+
@Override
42+
public String toString() {
43+
return "DataToBeSignedTXNResponseType{" +
44+
"formatVersion='" + formatVersion + '\'' +
45+
", content_string=" + dtbd +
46+
'}';
47+
}
48+
}

mid-java-client-core/src/main/java/ch/swisscom/mid/client/model/GeofencingAdditionalService.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021 Swisscom (Schweiz) AG
2+
* Copyright 2021-2025 Swisscom (Schweiz) AG
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -88,10 +88,12 @@ public void setMaxAccuracyMeters(String maxAccuracyMeters) {
8888

8989

9090
public boolean isDefined() {
91-
if (countryWhiteList != null && !countryWhiteList.isEmpty()) return true;
92-
if(countryBlackList!=null && !countryBlackList.isEmpty()) return true;
93-
if (minDeviceConfidence != null && !minDeviceConfidence.isEmpty() && !minDeviceConfidence.equalsIgnoreCase("0")) return true;
94-
if (minLocationConfidence != null && !minLocationConfidence.isEmpty() && !minLocationConfidence.equalsIgnoreCase("0")) return true;
91+
if (countryWhiteList != null && !countryWhiteList.isEmpty()) return true;
92+
if (countryBlackList != null && !countryBlackList.isEmpty()) return true;
93+
if (minDeviceConfidence != null && !minDeviceConfidence.isEmpty() && !minDeviceConfidence.equalsIgnoreCase("0"))
94+
return true;
95+
if (minLocationConfidence != null && !minLocationConfidence.isEmpty() && !minLocationConfidence.equalsIgnoreCase("0"))
96+
return true;
9597
if (maxAccuracyMeters != null && !maxAccuracyMeters.isEmpty()) return true;
9698
if (maxTimestampMinutes != null && !maxTimestampMinutes.isEmpty()) return true;
9799
return false;

mid-java-client-core/src/main/java/ch/swisscom/mid/client/model/StatusCode.java

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021 Swisscom (Schweiz) AG
2+
* Copyright 2021-2025 Swisscom (Schweiz) AG
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,57 +15,58 @@
1515
*/
1616
package ch.swisscom.mid.client.model;
1717

18+
import ch.swisscom.mid.client.impl.Loggers;
1819
import org.slf4j.Logger;
1920
import org.slf4j.LoggerFactory;
2021

21-
import ch.swisscom.mid.client.impl.Loggers;
22-
2322
public enum StatusCode implements DocumentedEnum {
2423

2524
REQUEST_OK(100, false, "The request from the AP has been accepted."),
2625
WRONG_PARAM(101, true, "The AP’s request contains wrong parameters."),
2726
MISSING_PARAM(102, true, "The AP’s request has missing parameters."),
2827
WRONG_DATA_LENGTH(103, true, "The AP’s request contains a DTBD message "
29-
+ "that is exceeding the max. allowed length."),
28+
+ "that is exceeding the max. allowed length."),
3029
UNAUTHORIZED_ACCESS(104, true, "AP is not authorized to access the Mobile ID API. "
31-
+ "This is typically due to a wrong AP_ID value or missing X509 client certificate."),
30+
+ "This is typically due to a wrong AP_ID value or missing X509 client certificate."),
3231
UNKNOWN_CLIENT(105, true, "The MSISDN value is unknown to the MID service. "
33-
+ "There is no Mobile ID user with that MSISDN value."),
32+
+ "There is no Mobile ID user with that MSISDN value."),
3433
INAPPROPRIATE_DATA(107, true, "The AP’s request was not accepted due to inappropriate data. "
35-
+ "Typically, the DTBD message does not contain the mandatory prefix string "
36-
+ "(see section 2.19 of the Reference Guide) that is a unique string for each AP."),
34+
+ "Typically, the DTBD message does not contain the mandatory prefix string "
35+
+ "(see section 2.19 of the Reference Guide) that is a unique string for each AP."),
3736
INCOMPATIBLE_INTERFACE(108, true, "The AP’s request contains bad data. "
38-
+ "Typically, a wrong MajorVersion or MinorVersion value has been set in the request."),
37+
+ "Typically, a wrong MajorVersion or MinorVersion value has been set in the request."),
3938
UNSUPPORTED_PROFILE(109, true, "Either the AP has specified an MSS signature profile value "
40-
+ "that the MSSP does not support or the AP is not authorized to use the "
41-
+ "Signature Profile. See section 3.2.1 of the Reference Guide."),
39+
+ "that the MSSP does not support or the AP is not authorized to use the "
40+
+ "Signature Profile. See section 3.2.1 of the Reference Guide."),
4241
EXPIRED_TRANSACTION(208, true, "The transaction timed out. The AP may try again."),
4342
OTA_ERROR(209, true, "A Problem related to the MSSP internal Over-The-Air (OTA) communication "
44-
+ "with the Mobile ID user’s SIM. "
45-
+ "Typically, there is a temporary problem with SMS communication."),
43+
+ "with the Mobile ID user’s SIM. "
44+
+ "Typically, there is a temporary problem with SMS communication."),
4645
USER_CANCEL(401, true, "The user cancelled the request at the mobile phone."),
4746
PIN_NR_BLOCKED(402, true, "The Mobile ID PIN of the SIM method is blocked. "
48-
+ "The user must reactivate the Mobile ID SIM card on the Mobile ID selfcare portal."),
47+
+ "The user must reactivate the Mobile ID SIM card on the Mobile ID selfcare portal."),
4948
CARD_BLOCKED(403, true, "The Mobile ID user is currently suspended. "
50-
+ "Please contact Swisscom Support."),
49+
+ "Please contact Swisscom Support."),
5150
NO_KEY_FOUND(404, true, "The Mobile ID user exists but is not in an active state. "
52-
+ "The user must activate the account on the Mobile ID selfcare portal."),
51+
+ "The user must activate the account on the Mobile ID selfcare portal."),
5352
PB_SIGNATURE_PROCESS(406, true, "A signature transaction is already on-going. "
54-
+ "Please try again later."),
53+
+ "Please try again later."),
5554
NO_CERT_FOUND(422, true, "The Mobile ID user exists but is not in an active state. "
56-
+ "The user must activate the account on the Mobile ID selfcare portal."),
55+
+ "The user must activate the account on the Mobile ID selfcare portal."),
56+
GEOFENCING_POLICY_VIOLATION(450, true, "Geo policy for referenced AP ID was violated. "
57+
+ "Please try again later or contact Swisscom Support, if the problem persists."),
5758
SIGNATURE(500, false, "The MSS Signature transaction was successful."),
5859
REVOKED_CERTIFICATE(501, false, "The Mobile ID user’s509 certificate has been revoked. "
59-
+ "The user must re-activate the account on the Mobile ID selfcare portal."),
60+
+ "The user must re-activate the account on the Mobile ID selfcare portal."),
6061
VALID_SIGNATURE(502, false, "The MSS Signature transaction was successful."),
6162
INVALID_SIGNATURE(503, false, "The MSS Signature transaction failed due to invalid signature data. "
62-
+ "The user must re-activate the account on the Mobile ID selfcare portal."),
63+
+ "The user must re-activate the account on the Mobile ID selfcare portal."),
6364
OUTSTANDING_TRANSACTION(504, false, "The MSS Signature transaction is outstanding. "
64-
+ "The AP must try again later."),
65+
+ "The AP must try again later."),
6566
CONNECTION_REFUSED(780, true, "The connection to the service was refused. "
66-
+ "The client did not present a valid TLS certificate"),
67+
+ "The client did not present a valid TLS certificate"),
6768
INTERNAL_ERROR(900, true, "An internal error on MSSP has occurred. "
68-
+ "Please try again later or contact Swisscom Support, if the problem persists.");
69+
+ "Please try again later or contact Swisscom Support, if the problem persists.");
6970

7071
private static final Logger log = LoggerFactory.getLogger(Loggers.CLIENT);
7172

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package ch.swisscom.mid.client.model;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
import java.util.Map;
8+
9+
public class TXNApprovalReqType {
10+
11+
@JsonProperty("type")
12+
private String type;
13+
14+
@JsonProperty("dtbd")
15+
private List<Map<String, String>> dtbd = new ArrayList<>();
16+
17+
public TXNApprovalReqType() {
18+
}
19+
20+
public TXNApprovalReqType(String type, List<Map<String, String>> dtbd) {
21+
this.type = type;
22+
this.dtbd = dtbd;
23+
}
24+
25+
@Override
26+
public String toString() {
27+
return "TXNApprovalReqType{" +
28+
"type='" + type + '\'' +
29+
", dtbd=" + dtbd +
30+
'}';
31+
}
32+
33+
public void setType(String type) {
34+
this.type = type;
35+
}
36+
37+
public void setDtbd(List<Map<String, String>> dtbd) {
38+
this.dtbd = dtbd;
39+
}
40+
41+
public String getType() {
42+
return type;
43+
}
44+
45+
public List<Map<String, String>> getDtbd() {
46+
return dtbd;
47+
}
48+
}

0 commit comments

Comments
 (0)