Skip to content

Commit 85d0d20

Browse files
NFC-115 Implement minimal multiple signing certification solution
Signed-off-by: Sander Kondratjev <sander.kondratjev@nortal.com>
1 parent 32fde8f commit 85d0d20

15 files changed

Lines changed: 212 additions & 63 deletions

File tree

example/src/main/java/eu/webeid/example/security/WebEidAuthentication.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
package eu.webeid.example.security;
2424

2525
import eu.webeid.security.authtoken.SupportedSignatureAlgorithm;
26+
import eu.webeid.security.authtoken.UnverifiedSigningCertificate;
2627
import eu.webeid.security.certificate.CertificateData;
2728
import org.springframework.lang.Nullable;
2829
import org.springframework.security.core.Authentication;
@@ -48,11 +49,17 @@ private WebEidAuthentication(String principalName, String idCode, String signing
4849
this.supportedSignatureAlgorithms = supportedSignatureAlgorithms;
4950
}
5051

51-
public static Authentication fromCertificate(X509Certificate userCertificate, @Nullable String signingCertificate, @Nullable List<SupportedSignatureAlgorithm> supportedSignatureAlgorithms, List<GrantedAuthority> authorities) throws CertificateEncodingException {
52+
public static Authentication fromCertificate(X509Certificate userCertificate, @Nullable UnverifiedSigningCertificate signingCertificate, List<GrantedAuthority> authorities) throws CertificateEncodingException {
5253
final String principalName = getPrincipalNameFromCertificate(userCertificate);
5354
final String idCode = CertificateData.getSubjectIdCode(userCertificate)
5455
.orElseThrow(() -> new CertificateEncodingException("Certificate does not contain subject ID code"));
55-
return new WebEidAuthentication(principalName, idCode, signingCertificate, supportedSignatureAlgorithms, authorities);
56+
return new WebEidAuthentication(
57+
principalName,
58+
idCode,
59+
signingCertificate != null ? signingCertificate.getCertificate() : null,
60+
signingCertificate != null ? signingCertificate.getSupportedSignatureAlgorithms() : null,
61+
authorities
62+
);
5663
}
5764

5865
private static String getPrincipalNameFromCertificate(X509Certificate userCertificate) throws CertificateEncodingException {

example/src/main/java/eu/webeid/example/security/WebEidAuthenticationProvider.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.springframework.security.core.authority.SimpleGrantedAuthority;
3939
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
4040
import org.springframework.stereotype.Component;
41+
import org.springframework.util.CollectionUtils;
4142

4243
import java.security.cert.CertificateEncodingException;
4344
import java.security.cert.X509Certificate;
@@ -76,14 +77,10 @@ public Authentication authenticate(Authentication auth) throws AuthenticationExc
7677
try {
7778
final String nonce = challengeNonceStore.getAndRemove().getBase64EncodedNonce();
7879
final X509Certificate userCertificate = tokenValidator.validate(authToken, nonce);
79-
final String signingCertificate = requireSigningCert
80-
? authToken.getUnverifiedSigningCertificate()
80+
final var signingCertificate = requireSigningCert && !CollectionUtils.isEmpty(authToken.getUnverifiedSigningCertificates())
81+
? authToken.getUnverifiedSigningCertificates().getFirst() // NOTE: Handling multiple signing certificates is out of scope of this example.
8182
: null;
82-
final List<SupportedSignatureAlgorithm> supportedSignatureAlgorithms = requireSigningCert
83-
? authToken.getSupportedSignatureAlgorithms()
84-
: null;
85-
86-
return WebEidAuthentication.fromCertificate(userCertificate, signingCertificate, supportedSignatureAlgorithms, authorities);
83+
return WebEidAuthentication.fromCertificate(userCertificate, signingCertificate, authorities);
8784
} catch (AuthTokenException e) {
8885
throw new AuthenticationServiceException("Web eID token validation failed", e);
8986
} catch (CertificateEncodingException e) {

example/src/test/java/eu/webeid/example/security/WebEidAuthenticationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class WebEidAuthenticationTest {
3838
@Test
3939
void whenOrganizationCertificate_thenSucceeds() throws Exception {
4040
final X509Certificate certificate = CertificateLoader.decodeCertificateFromBase64(ORGANIZATION_CERT);
41-
final Authentication authentication = WebEidAuthentication.fromCertificate(certificate, null, null, Collections.emptyList());
41+
final Authentication authentication = WebEidAuthentication.fromCertificate(certificate, null, Collections.emptyList());
4242
assertThat(authentication.getPrincipal()).isEqualTo("Testijad.ee isikutuvastus");
4343
}
4444

example/src/test/java/eu/webeid/example/testutil/ObjectMother.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,11 @@ public class ObjectMother {
6868
VALID_WEB_EID_1_1AUTH_TOKEN = MAPPER.readValue(
6969
"{\"algorithm\":\"ES384\"," +
7070
"\"unverifiedCertificate\":\"MIIEBDCCA2WgAwIBAgIQY5OGshxoPMFg+Wfc0gFEaTAKBggqhkjOPQQDBDBgMQswCQYDVQQGEwJFRTEbMBkGA1UECgwSU0sgSUQgU29sdXRpb25zIEFTMRcwFQYDVQRhDA5OVFJFRS0xMDc0NzAxMzEbMBkGA1UEAwwSVEVTVCBvZiBFU1RFSUQyMDE4MB4XDTIxMDcyMjEyNDMwOFoXDTI2MDcwOTIxNTk1OVowfzELMAkGA1UEBhMCRUUxKjAoBgNVBAMMIUrDlUVPUkcsSkFBSy1LUklTVEpBTiwzODAwMTA4NTcxODEQMA4GA1UEBAwHSsOVRU9SRzEWMBQGA1UEKgwNSkFBSy1LUklTVEpBTjEaMBgGA1UEBRMRUE5PRUUtMzgwMDEwODU3MTgwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQmwEKsJTjaMHSaZj19hb9EJaJlwbKc5VFzmlGMFSJVk4dDy+eUxa5KOA7tWXqzcmhh5SYdv+MxcaQKlKWLMa36pfgv20FpEDb03GCtLqjLTRZ7649PugAQ5EmAqIic29CjggHDMIIBvzAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIDiDBHBgNVHSAEQDA+MDIGCysGAQQBg5EhAQIBMCMwIQYIKwYBBQUHAgEWFWh0dHBzOi8vd3d3LnNrLmVlL0NQUzAIBgYEAI96AQIwHwYDVR0RBBgwFoEUMzgwMDEwODU3MThAZWVzdGkuZWUwHQYDVR0OBBYEFPlp/ceABC52itoqppEmbf71TJz6MGEGCCsGAQUFBwEDBFUwUzBRBgYEAI5GAQUwRzBFFj9odHRwczovL3NrLmVlL2VuL3JlcG9zaXRvcnkvY29uZGl0aW9ucy1mb3ItdXNlLW9mLWNlcnRpZmljYXRlcy8TAkVOMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAfBgNVHSMEGDAWgBTAhJkpxE6fOwI09pnhClYACCk+ezBzBggrBgEFBQcBAQRnMGUwLAYIKwYBBQUHMAGGIGh0dHA6Ly9haWEuZGVtby5zay5lZS9lc3RlaWQyMDE4MDUGCCsGAQUFBzAChilodHRwOi8vYy5zay5lZS9UZXN0X29mX0VTVEVJRDIwMTguZGVyLmNydDAKBggqhkjOPQQDBAOBjAAwgYgCQgDCAgybz0u3W+tGI+AX+PiI5CrE9ptEHO5eezR1Jo4j7iGaO0i39xTGUB+NSC7P6AQbyE/ywqJjA1a62jTLcS9GHAJCARxN4NO4eVdWU3zVohCXm8WN3DWA7XUcn9TZiLGQ29P4xfQZOXJi/z4PNRRsR4plvSNB3dfyBvZn31HhC7my8woi\"," +
71-
"\"unverifiedSigningCertificate\":\"MIID6zCCA02gAwIBAgIQT7j6zk6pmVRcyspLo5SqejAKBggqhkjOPQQDBDBgMQswCQYDVQQGEwJFRTEbMBkGA1UECgwSU0sgSUQgU29sdXRpb25zIEFTMRcwFQYDVQRhDA5OVFJFRS0xMDc0NzAxMzEbMBkGA1UEAwwSVEVTVCBvZiBFU1RFSUQyMDE4MB4XDTE5MDUwMjEwNDUzMVoXDTI5MDUwMjEwNDUzMVowfzELMAkGA1UEBhMCRUUxFjAUBgNVBCoMDUpBQUstS1JJU1RKQU4xEDAOBgNVBAQMB0rDlUVPUkcxKjAoBgNVBAMMIUrDlUVPUkcsSkFBSy1LUklTVEpBTiwzODAwMTA4NTcxODEaMBgGA1UEBRMRUE5PRUUtMzgwMDEwODU3MTgwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASkwENR8GmCpEs6OshDWDfIiKvGuyNMOD2rjIQW321AnZD3oIsqD0svBMNEJJj9Dlvq/47TYDObIa12KAU5IuOBfJs2lrFdSXZjaM+a5TWT3O2JTM36YDH2GcMe/eisepejggGrMIIBpzAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIGQDBIBgNVHSAEQTA/MDIGCysGAQQBg5EhAQIBMCMwIQYIKwYBBQUHAgEWFWh0dHBzOi8vd3d3LnNrLmVlL0NQUzAJBgcEAIvsQAECMB0GA1UdDgQWBBTVX3s48Spy/Es2TcXgkRvwUn2YcjCBigYIKwYBBQUHAQMEfjB8MAgGBgQAjkYBATAIBgYEAI5GAQQwEwYGBACORgEGMAkGBwQAjkYBBgEwUQYGBACORgEFMEcwRRY/aHR0cHM6Ly9zay5lZS9lbi9yZXBvc2l0b3J5L2NvbmRpdGlvbnMtZm9yLXVzZS1vZi1jZXJ0aWZpY2F0ZXMvEwJFTjAfBgNVHSMEGDAWgBTAhJkpxE6fOwI09pnhClYACCk+ezBzBggrBgEFBQcBAQRnMGUwLAYIKwYBBQUHMAGGIGh0dHA6Ly9haWEuZGVtby5zay5lZS9lc3RlaWQyMDE4MDUGCCsGAQUFBzAChilodHRwOi8vYy5zay5lZS9UZXN0X29mX0VTVEVJRDIwMTguZGVyLmNydDAKBggqhkjOPQQDBAOBiwAwgYcCQgGBr+Jbo1GeqgWdIwgMo7SA29AP38JxNm2HWq2Qb+kIHpusAK574Co1K5D4+Mk7/ITTuXQaET5WphHoN7tdAciTaQJBAn0zBigYyVPYSTO68HM6hmlwTwi/KlJDdXW/2NsMjSqofFFJXpGvpxk2CTqSRCjcavxLPnkasTbNROYSJcmM8Xc=\"," +
72-
"\"supportedSignatureAlgorithms\":[{\"cryptoAlgorithm\":\"RSA\",\"hashFunction\":\"SHA-256\",\"paddingScheme\":\"PKCS1.5\"}]," +
73-
"\"issuerApp\":\"https://web-eid.eu/web-eid-mobile-app/releases/v1.0.0\"," +
71+
"\"unverifiedSigningCertificates\":[{" +
72+
"\"certificate\":\"MIID6zCCA02gAwIBAgIQT7j6zk6pmVRcyspLo5SqejAKBggqhkjOPQQDBDBgMQswCQYDVQQGEwJFRTEbMBkGA1UECgwSU0sgSUQgU29sdXRpb25zIEFTMRcwFQYDVQRhDA5OVFJFRS0xMDc0NzAxMzEbMBkGA1UEAwwSVEVTVCBvZiBFU1RFSUQyMDE4MB4XDTE5MDUwMjEwNDUzMVoXDTI5MDUwMjEwNDUzMVowfzELMAkGA1UEBhMCRUUxFjAUBgNVBCoMDUpBQUstS1JJU1RKQU4xEDAOBgNVBAQMB0rDlUVPUkcxKjAoBgNVBAMMIUrDlUVPUkcsSkFBSy1LUklTVEpBTiwzODAwMTA4NTcxODEaMBgGA1UEBRMRUE5PRUUtMzgwMDEwODU3MTgwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASkwENR8GmCpEs6OshDWDfIiKvGuyNMOD2rjIQW321AnZD3oIsqD0svBMNEJJj9Dlvq/47TYDObIa12KAU5IuOBfJs2lrFdSXZjaM+a5TWT3O2JTM36YDH2GcMe/eisepejggGrMIIBpzAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIGQDBIBgNVHSAEQTA/MDIGCysGAQQBg5EhAQIBMCMwIQYIKwYBBQUHAgEWFWh0dHBzOi8vd3d3LnNrLmVlL0NQUzAJBgcEAIvsQAECMB0GA1UdDgQWBBTVX3s48Spy/Es2TcXgkRvwUn2YcjCBigYIKwYBBQUHAQMEfjB8MAgGBgQAjkYBATAIBgYEAI5GAQQwEwYGBACORgEGMAkGBwQAjkYBBgEwUQYGBACORgEFMEcwRRY/aHR0cHM6Ly9zay5lZS9lbi9yZXBvc2l0b3J5L2NvbmRpdGlvbnMtZm9yLXVzZS1vZi1jZXJ0aWZpY2F0ZXMvEwJFTjAfBgNVHSMEGDAWgBTAhJkpxE6fOwI09pnhClYACCk+ezBzBggrBgEFBQcBAQRnMGUwLAYIKwYBBQUHMAGGIGh0dHA6Ly9haWEuZGVtby5zay5lZS9lc3RlaWQyMDE4MDUGCCsGAQUFBzAChilodHRwOi8vYy5zay5lZS9UZXN0X29mX0VTVEVJRDIwMTguZGVyLmNydDAKBggqhkjOPQQDBAOBiwAwgYcCQgGBr+Jbo1GeqgWdIwgMo7SA29AP38JxNm2HWq2Qb+kIHpusAK574Co1K5D4+Mk7/ITTuXQaET5WphHoN7tdAciTaQJBAn0zBigYyVPYSTO68HM6hmlwTwi/KlJDdXW/2NsMjSqofFFJXpGvpxk2CTqSRCjcavxLPnkasTbNROYSJcmM8Xc=\"," +
73+
"\"supportedSignatureAlgorithms\":[{\"cryptoAlgorithm\":\"RSA\",\"hashFunction\":\"SHA-256\",\"paddingScheme\":\"PKCS1.5\"}]" +
74+
"}]," +
75+
"\"appVersion\":\"https://web-eid.eu/web-eid-mobile-app/releases/v1.0.0\"," +
7476
"\"signature\":\"0Ov7ME6pTY1K2GXMj8Wxov/o2fGIMEds8OMY5dKdkB0nrqQX7fG1E5mnsbvyHpMDecMUH6Yg+p1HXdgB/lLqOcFZjt/OVXPjAAApC5d1YgRYATDcxsR1zqQwiNcHdmWn\"," +
7577
"\"format\":\"web-eid:1.1\"}",
7678
WebEidAuthToken.class);

src/main/java/eu/webeid/security/authtoken/SupportedSignatureAlgorithm.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222

2323
package eu.webeid.security.authtoken;
2424

25+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
26+
27+
@JsonIgnoreProperties(ignoreUnknown = true)
2528
public class SupportedSignatureAlgorithm {
2629
private String cryptoAlgorithm;
2730
private String hashFunction;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright (c) 2020-2025 Estonian Information System Authority
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
23+
package eu.webeid.security.authtoken;
24+
25+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
26+
27+
import java.util.List;
28+
29+
@JsonIgnoreProperties(ignoreUnknown = true)
30+
public class UnverifiedSigningCertificate {
31+
32+
private String certificate;
33+
private List<SupportedSignatureAlgorithm> supportedSignatureAlgorithms;
34+
35+
public String getCertificate() {
36+
return certificate;
37+
}
38+
39+
public void setCertificate(String certificate) {
40+
this.certificate = certificate;
41+
}
42+
43+
public List<SupportedSignatureAlgorithm> getSupportedSignatureAlgorithms() {
44+
return supportedSignatureAlgorithms;
45+
}
46+
47+
public void setSupportedSignatureAlgorithms(List<SupportedSignatureAlgorithm> supportedSignatureAlgorithms) {
48+
this.supportedSignatureAlgorithms = supportedSignatureAlgorithms;
49+
}
50+
}

src/main/java/eu/webeid/security/authtoken/WebEidAuthToken.java

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ public class WebEidAuthToken {
3434
private String algorithm;
3535
private String format;
3636

37-
private String unverifiedSigningCertificate;
38-
private List<SupportedSignatureAlgorithm> supportedSignatureAlgorithms;
37+
private List<UnverifiedSigningCertificate> unverifiedSigningCertificates;
3938

4039
public String getUnverifiedCertificate() {
4140
return unverifiedCertificate;
@@ -69,19 +68,11 @@ public void setFormat(String format) {
6968
this.format = format;
7069
}
7170

72-
public String getUnverifiedSigningCertificate() {
73-
return unverifiedSigningCertificate;
71+
public List<UnverifiedSigningCertificate> getUnverifiedSigningCertificates() {
72+
return unverifiedSigningCertificates;
7473
}
7574

76-
public void setUnverifiedSigningCertificate(String unverifiedSigningCertificate) {
77-
this.unverifiedSigningCertificate = unverifiedSigningCertificate;
78-
}
79-
80-
public List<SupportedSignatureAlgorithm> getSupportedSignatureAlgorithms() {
81-
return supportedSignatureAlgorithms;
82-
}
83-
84-
public void setSupportedSignatureAlgorithms(List<SupportedSignatureAlgorithm> supportedSignatureAlgorithms) {
85-
this.supportedSignatureAlgorithms = supportedSignatureAlgorithms;
75+
public void setUnverifiedSigningCertificates(List<UnverifiedSigningCertificate> unverifiedSigningCertificates) {
76+
this.unverifiedSigningCertificates = unverifiedSigningCertificates;
8677
}
8778
}

src/main/java/eu/webeid/security/validator/versionvalidators/AuthTokenVersion11Validator.java

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
package eu.webeid.security.validator.versionvalidators;
2424

2525
import eu.webeid.security.authtoken.SupportedSignatureAlgorithm;
26+
import eu.webeid.security.authtoken.UnverifiedSigningCertificate;
2627
import eu.webeid.security.authtoken.WebEidAuthToken;
2728
import eu.webeid.security.certificate.CertificateLoader;
2829
import eu.webeid.security.exceptions.AuthTokenException;
@@ -45,6 +46,7 @@
4546
import java.security.cert.CertificateNotYetValidException;
4647
import java.security.cert.TrustAnchor;
4748
import java.security.cert.X509Certificate;
49+
import java.util.ArrayList;
4850
import java.util.Arrays;
4951
import java.util.List;
5052
import java.util.Set;
@@ -90,37 +92,57 @@ protected String getSupportedFormatPrefix() {
9092
@Override
9193
public X509Certificate validate(WebEidAuthToken token, String currentChallengeNonce) throws AuthTokenException {
9294
final X509Certificate subjectCertificate = validateV1(token, currentChallengeNonce);
93-
final X509Certificate signingCertificate = validateSigningCertificateExists(token);
94-
validateSupportedSignatureAlgorithms(token.getSupportedSignatureAlgorithms());
95-
validateSameSubject(subjectCertificate, signingCertificate);
96-
validateSameIssuer(subjectCertificate, signingCertificate);
97-
validateSigningCertificateValidity(signingCertificate);
98-
validateKeyUsage(signingCertificate);
95+
final List<X509Certificate> signingCertificates = validateSigningCertificates(token);
96+
for (X509Certificate signingCertificate : signingCertificates) {
97+
validateSameSubject(subjectCertificate, signingCertificate);
98+
validateSameIssuer(subjectCertificate, signingCertificate);
99+
validateSigningCertificateValidity(signingCertificate);
100+
validateKeyUsage(signingCertificate);
101+
}
99102

100103
return subjectCertificate;
101104
}
102105

103-
private static void validateSupportedSignatureAlgorithms(List<SupportedSignatureAlgorithm> algorithms) throws AuthTokenParseException {
106+
private static void validateSupportedSignatureAlgorithms(UnverifiedSigningCertificate cert) throws AuthTokenParseException {
107+
List<SupportedSignatureAlgorithm> algorithms = cert.getSupportedSignatureAlgorithms();
108+
104109
if (algorithms == null || algorithms.isEmpty()) {
105110
throw new AuthTokenParseException("'supportedSignatureAlgorithms' field is missing");
106111
}
107112

108-
boolean hasInvalid = algorithms.stream().anyMatch(supportedSignatureAlgorithm ->
109-
!SUPPORTED_SIGNING_CRYPTO_ALGORITHMS.contains(supportedSignatureAlgorithm.getCryptoAlgorithm()) ||
110-
!SUPPORTED_SIGNING_HASH_FUNCTIONS.contains(supportedSignatureAlgorithm.getHashFunction()) ||
111-
!SUPPORTED_SIGNING_PADDING_SCHEMES.contains(supportedSignatureAlgorithm.getPaddingScheme())
113+
boolean hasInvalid = algorithms.stream().anyMatch(algorithm ->
114+
algorithm == null ||
115+
algorithm.getCryptoAlgorithm() == null ||
116+
algorithm.getHashFunction() == null ||
117+
algorithm.getPaddingScheme() == null ||
118+
!SUPPORTED_SIGNING_CRYPTO_ALGORITHMS.contains(algorithm.getCryptoAlgorithm()) ||
119+
!SUPPORTED_SIGNING_HASH_FUNCTIONS.contains(algorithm.getHashFunction()) ||
120+
!SUPPORTED_SIGNING_PADDING_SCHEMES.contains(algorithm.getPaddingScheme())
112121
);
113122

114123
if (hasInvalid) {
115124
throw new AuthTokenParseException("Unsupported signature algorithm");
116125
}
117126
}
118127

119-
private static X509Certificate validateSigningCertificateExists(WebEidAuthToken token) throws AuthTokenParseException, CertificateDecodingException {
120-
if (isNullOrEmpty(token.getUnverifiedSigningCertificate())) {
121-
throw new AuthTokenParseException("'unverifiedSigningCertificate' field is missing, null or empty for format 'web-eid:1.1'");
128+
private static List<X509Certificate> validateSigningCertificates(WebEidAuthToken token) throws AuthTokenParseException, CertificateDecodingException {
129+
List<UnverifiedSigningCertificate> signingCertificates = token.getUnverifiedSigningCertificates();
130+
131+
if (signingCertificates == null || signingCertificates.isEmpty()) {
132+
throw new AuthTokenParseException("'unverifiedSigningCertificates' field is missing, null or empty for format 'web-eid:1.1'");
133+
}
134+
135+
List<X509Certificate> result = new ArrayList<>();
136+
137+
for (UnverifiedSigningCertificate certificate : signingCertificates) {
138+
if (certificate == null || isNullOrEmpty(certificate.getCertificate())) {
139+
throw new AuthTokenParseException("'unverifiedSigningCertificates' contains a null or empty entry for format 'web-eid:1.1'");
140+
}
141+
validateSupportedSignatureAlgorithms(certificate);
142+
result.add(CertificateLoader.decodeCertificateFromBase64(certificate.getCertificate()));
122143
}
123-
return CertificateLoader.decodeCertificateFromBase64(token.getUnverifiedSigningCertificate());
144+
145+
return result;
124146
}
125147

126148
private static void validateSameSubject(X509Certificate subjectCertificate, X509Certificate signingCertificate)

src/main/java/eu/webeid/security/validator/versionvalidators/AuthTokenVersion1Validator.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ protected String getSupportedFormatPrefix() {
7878

7979
@Override
8080
public X509Certificate validate(WebEidAuthToken token, String currentChallengeNonce) throws AuthTokenException {
81+
if (isExactV10Format(token.getFormat()) && token.getUnverifiedSigningCertificates() != null) {
82+
throw new AuthTokenParseException(
83+
"'unverifiedSigningCertificates' field is not allowed for format '" + token.getFormat() + "'"
84+
);
85+
}
86+
8187
if (token.getUnverifiedCertificate() == null || token.getUnverifiedCertificate().isEmpty()) {
8288
throw new AuthTokenParseException("'unverifiedCertificate' field is missing, null or empty");
8389
}
@@ -105,4 +111,8 @@ public X509Certificate validate(WebEidAuthToken token, String currentChallengeNo
105111

106112
return subjectCertificate;
107113
}
114+
115+
private static boolean isExactV10Format(String format) {
116+
return V1_SUPPORTED_TOKEN_FORMAT_PREFIX.equals(format) || "web-eid:1.0".equals(format);
117+
}
108118
}

0 commit comments

Comments
 (0)