Skip to content

Commit 771955a

Browse files
NFC-46 Move cert validation first, fix keyUsage logic, compare Authority Key Identifiers, and normalize subject DN comparison. Move trust validator batch creation into SubjectCertificateValidatorBatch. Reuse ObjectReader for WebEidAuthToken parsing
1 parent 970edc2 commit 771955a

File tree

9 files changed

+120
-58
lines changed

9 files changed

+120
-58
lines changed

src/main/java/eu/webeid/security/validator/AuthTokenV11Validator.java

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,17 @@
88
import eu.webeid.security.validator.certvalidators.SubjectCertificateValidatorBatch;
99
import eu.webeid.security.validator.ocsp.OcspClient;
1010
import eu.webeid.security.validator.ocsp.OcspServiceProvider;
11+
import org.bouncycastle.asn1.x500.X500Name;
12+
import org.bouncycastle.asn1.x500.style.RFC4519Style;
13+
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
14+
import org.bouncycastle.asn1.x509.Extension;
15+
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
1116

17+
import javax.security.auth.x500.X500Principal;
1218
import java.security.cert.CertStore;
1319
import java.security.cert.TrustAnchor;
1420
import java.security.cert.X509Certificate;
21+
import java.util.Arrays;
1522
import java.util.List;
1623
import java.util.Set;
1724

@@ -27,7 +34,6 @@ class AuthTokenV11Validator extends AuthTokenV1Validator {
2734
"SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512"
2835
);
2936
private static final int KEY_USAGE_NON_REPUDIATION = 1;
30-
private static final int KEY_USAGE_DIGITAL_SIGNATURE = 0;
3137

3238
public AuthTokenV11Validator(
3339
SubjectCertificateValidatorBatch simpleSubjectCertificateValidators,
@@ -56,6 +62,8 @@ public boolean supports(String format) {
5662

5763
@Override
5864
public X509Certificate validate(WebEidAuthToken token, String currentChallengeNonce) throws AuthTokenException {
65+
final X509Certificate subjectCertificate = validateV1(token, currentChallengeNonce);
66+
5967
if (token.getFormat() == null || !token.getFormat().startsWith(SUPPORTED_PREFIX)) {
6068
throw new AuthTokenParseException("Only token format '" + SUPPORTED_PREFIX + "' is supported by this validator");
6169
}
@@ -66,19 +74,23 @@ public X509Certificate validate(WebEidAuthToken token, String currentChallengeNo
6674

6775
validateSupportedSignatureAlgorithms(token.getSupportedSignatureAlgorithms());
6876

69-
final X509Certificate subjectCertificate = validateV1(token, currentChallengeNonce);
7077
final X509Certificate signingCertificate = CertificateLoader.decodeCertificateFromBase64(token.getUnverifiedSigningCertificate());
7178

72-
if (!subjectCertificate.getSubjectX500Principal().equals(signingCertificate.getSubjectX500Principal())) {
79+
if (!subjectAndSigningCertificateSubjectsMatch(subjectCertificate.getSubjectX500Principal(), signingCertificate.getSubjectX500Principal())) {
7380
throw new AuthTokenParseException("Signing certificate subject does not match authentication certificate subject");
7481
}
7582

76-
if (!subjectCertificate.getIssuerX500Principal().equals(signingCertificate.getIssuerX500Principal())) {
77-
throw new AuthTokenParseException("Signing and authentication certificates are not issued by the same authority");
83+
byte[] subjectCertificateAuthorityKeyIdentifier = getAuthorityKeyIdentifier(subjectCertificate);
84+
byte[] signingCertificateAuthorityKeyIdentifier = getAuthorityKeyIdentifier(signingCertificate);
85+
86+
if (subjectCertificateAuthorityKeyIdentifier.length == 0
87+
|| signingCertificateAuthorityKeyIdentifier.length == 0
88+
|| !Arrays.equals(subjectCertificateAuthorityKeyIdentifier, signingCertificateAuthorityKeyIdentifier)) {
89+
throw new AuthTokenParseException("Signing certificate is not issued by the same issuing authority as the authentication certificate");
7890
}
7991

8092
boolean[] keyUsage = signingCertificate.getKeyUsage();
81-
if (keyUsage == null || (keyUsage.length > KEY_USAGE_NON_REPUDIATION && !keyUsage[KEY_USAGE_NON_REPUDIATION] && !keyUsage[KEY_USAGE_DIGITAL_SIGNATURE])) {
93+
if (keyUsage == null || keyUsage.length <= KEY_USAGE_NON_REPUDIATION || !keyUsage[KEY_USAGE_NON_REPUDIATION]) {
8294
throw new AuthTokenParseException("Signing certificate not suitable for signing");
8395
}
8496

@@ -101,6 +113,28 @@ private static void validateSupportedSignatureAlgorithms(List<SupportedSignature
101113
}
102114
}
103115

116+
private static boolean subjectAndSigningCertificateSubjectsMatch(
117+
X500Principal authenticationCertificateSubject,
118+
X500Principal signingCertificateSubject) {
119+
X500Name authName = X500Name.getInstance(RFC4519Style.INSTANCE, authenticationCertificateSubject.getEncoded());
120+
X500Name signName = X500Name.getInstance(RFC4519Style.INSTANCE, signingCertificateSubject.getEncoded());
121+
return authName.equals(signName);
122+
}
123+
124+
private static byte[] getAuthorityKeyIdentifier(X509Certificate certificate) throws AuthTokenParseException {
125+
try {
126+
byte[] authorityKeyIdentifierExtension = certificate.getExtensionValue(Extension.authorityKeyIdentifier.getId());
127+
if (authorityKeyIdentifierExtension == null) {
128+
return new byte[0];
129+
}
130+
AuthorityKeyIdentifier authorityKeyIdentifier =
131+
AuthorityKeyIdentifier.getInstance(JcaX509ExtensionUtils.parseExtensionValue(authorityKeyIdentifierExtension));
132+
return authorityKeyIdentifier.getKeyIdentifier();
133+
} catch (Exception e) {
134+
throw new AuthTokenParseException("Failed to parse Authority Key Identifier", e);
135+
}
136+
}
137+
104138
protected X509Certificate validateV1(WebEidAuthToken token, String currentChallengeNonce) throws AuthTokenException {
105139
return super.validate(token, currentChallengeNonce);
106140
}

src/main/java/eu/webeid/security/validator/AuthTokenV1Validator.java

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
import eu.webeid.security.certificate.CertificateLoader;
55
import eu.webeid.security.exceptions.AuthTokenException;
66
import eu.webeid.security.exceptions.AuthTokenParseException;
7-
import eu.webeid.security.validator.certvalidators.SubjectCertificateNotRevokedValidator;
8-
import eu.webeid.security.validator.certvalidators.SubjectCertificateTrustedValidator;
97
import eu.webeid.security.validator.certvalidators.SubjectCertificateValidatorBatch;
108
import eu.webeid.security.validator.ocsp.OcspClient;
119
import eu.webeid.security.validator.ocsp.OcspServiceProvider;
@@ -67,7 +65,7 @@ public X509Certificate validate(WebEidAuthToken token, String currentChallengeNo
6765

6866
simpleSubjectCertificateValidators.executeFor(subjectCertificate);
6967

70-
createCertTrustValidators(
68+
SubjectCertificateValidatorBatch.forTrustValidation(
7169
configuration,
7270
trustedCACertificateAnchors,
7371
trustedCACertificateCertStore,
@@ -86,34 +84,4 @@ public X509Certificate validate(WebEidAuthToken token, String currentChallengeNo
8684

8785
return subjectCertificate;
8886
}
89-
90-
/**
91-
* Creates the certificate trust validators batch.
92-
* As SubjectCertificateTrustedValidator has mutable state that SubjectCertificateNotRevokedValidator depends on,
93-
* they cannot be reused/cached in an instance variable in a multi-threaded environment. Hence, they are
94-
* re-created for each validation run for thread safety.
95-
*
96-
* @return certificate trust validator batch
97-
*/
98-
public static SubjectCertificateValidatorBatch createCertTrustValidators(
99-
AuthTokenValidationConfiguration configuration,
100-
Set<TrustAnchor> trustedCACertificateAnchors,
101-
CertStore trustedCACertificateCertStore,
102-
OcspClient ocspClient,
103-
OcspServiceProvider ocspServiceProvider
104-
) {
105-
final SubjectCertificateTrustedValidator certTrustedValidator =
106-
new SubjectCertificateTrustedValidator(trustedCACertificateAnchors, trustedCACertificateCertStore);
107-
108-
return SubjectCertificateValidatorBatch.createFrom(
109-
certTrustedValidator::validateCertificateTrusted
110-
).addOptional(configuration.isUserCertificateRevocationCheckWithOcspEnabled(),
111-
new SubjectCertificateNotRevokedValidator(
112-
certTrustedValidator,
113-
ocspClient, ocspServiceProvider,
114-
configuration.getAllowedOcspResponseTimeSkew(),
115-
configuration.getMaxOcspResponseThisUpdateAge()
116-
)::validateCertificateNotRevoked
117-
);
118-
}
11987
}

src/main/java/eu/webeid/security/validator/AuthTokenValidationConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Collection<X509Certificate> getTrustedCACertificates() {
8787
return trustedCACertificates;
8888
}
8989

90-
boolean isUserCertificateRevocationCheckWithOcspEnabled() {
90+
public boolean isUserCertificateRevocationCheckWithOcspEnabled() {
9191
return isUserCertificateRevocationCheckWithOcspEnabled;
9292
}
9393

src/main/java/eu/webeid/security/validator/AuthTokenValidator.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
* Parses and validates the provided Web eID authentication token.
3838
*/
3939
public interface AuthTokenValidator {
40+
String CURRENT_TOKEN_FORMAT_VERSION = "web-eid:1.1";
41+
42+
ObjectReader TOKEN_READER = new ObjectMapper().readerFor(WebEidAuthToken.class);
4043

4144
/**
4245
* Returns whether this validator supports validation of the given token format.
@@ -62,8 +65,7 @@ default WebEidAuthToken parse(String authToken) throws AuthTokenException {
6265
throw new AuthTokenParseException("Auth token is too long");
6366
}
6467

65-
ObjectReader reader = new ObjectMapper().readerFor(WebEidAuthToken.class);
66-
WebEidAuthToken token = reader.readValue(authToken);
68+
WebEidAuthToken token = TOKEN_READER.readValue(authToken);
6769
if (token == null) {
6870
throw new AuthTokenParseException("Web eID authentication token is null");
6971
}

src/main/java/eu/webeid/security/validator/certvalidators/SubjectCertificateValidatorBatch.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,17 @@
2323
package eu.webeid.security.validator.certvalidators;
2424

2525
import eu.webeid.security.exceptions.AuthTokenException;
26+
import eu.webeid.security.validator.AuthTokenValidationConfiguration;
27+
import eu.webeid.security.validator.ocsp.OcspClient;
28+
import eu.webeid.security.validator.ocsp.OcspServiceProvider;
2629

30+
import java.security.cert.CertStore;
31+
import java.security.cert.TrustAnchor;
2732
import java.security.cert.X509Certificate;
2833
import java.util.ArrayList;
2934
import java.util.Collections;
3035
import java.util.List;
36+
import java.util.Set;
3137

3238
public final class SubjectCertificateValidatorBatch {
3339

@@ -55,4 +61,34 @@ public SubjectCertificateValidatorBatch addOptional(boolean condition, SubjectCe
5561
private SubjectCertificateValidatorBatch(List<SubjectCertificateValidator> validatorList) {
5662
this.validatorList = validatorList;
5763
}
64+
65+
/**
66+
* Creates the certificate trust validators batch.
67+
* As SubjectCertificateTrustedValidator has mutable state that SubjectCertificateNotRevokedValidator depends on,
68+
* they cannot be reused/cached in an instance variable in a multi-threaded environment. Hence, they are
69+
* re-created for each validation run for thread safety.
70+
*
71+
* @return certificate trust validator batch
72+
*/
73+
public static SubjectCertificateValidatorBatch forTrustValidation(
74+
AuthTokenValidationConfiguration configuration,
75+
Set<TrustAnchor> trustedCACertificateAnchors,
76+
CertStore trustedCACertificateCertStore,
77+
OcspClient ocspClient,
78+
OcspServiceProvider ocspServiceProvider) {
79+
80+
final SubjectCertificateTrustedValidator certTrustedValidator =
81+
new SubjectCertificateTrustedValidator(trustedCACertificateAnchors, trustedCACertificateCertStore);
82+
83+
return SubjectCertificateValidatorBatch.createFrom(
84+
certTrustedValidator::validateCertificateTrusted
85+
).addOptional(configuration.isUserCertificateRevocationCheckWithOcspEnabled(),
86+
new SubjectCertificateNotRevokedValidator(
87+
certTrustedValidator,
88+
ocspClient, ocspServiceProvider,
89+
configuration.getAllowedOcspResponseTimeSkew(),
90+
configuration.getMaxOcspResponseThisUpdateAge()
91+
)::validateCertificateNotRevoked
92+
);
93+
}
5894
}

src/test/java/eu/webeid/security/testutil/AbstractTestWithValidator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public abstract class AbstractTestWithValidator {
4646

4747
public static final String VALID_V11_AUTH_TOKEN = "{\"algorithm\":\"ES384\"," +
4848
"\"unverifiedCertificate\":\"MIIEBDCCA2WgAwIBAgIQY5OGshxoPMFg+Wfc0gFEaTAKBggqhkjOPQQDBDBgMQswCQYDVQQGEwJFRTEbMBkGA1UECgwSU0sgSUQgU29sdXRpb25zIEFTMRcwFQYDVQRhDA5OVFJFRS0xMDc0NzAxMzEbMBkGA1UEAwwSVEVTVCBvZiBFU1RFSUQyMDE4MB4XDTIxMDcyMjEyNDMwOFoXDTI2MDcwOTIxNTk1OVowfzELMAkGA1UEBhMCRUUxKjAoBgNVBAMMIUrDlUVPUkcsSkFBSy1LUklTVEpBTiwzODAwMTA4NTcxODEQMA4GA1UEBAwHSsOVRU9SRzEWMBQGA1UEKgwNSkFBSy1LUklTVEpBTjEaMBgGA1UEBRMRUE5PRUUtMzgwMDEwODU3MTgwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQmwEKsJTjaMHSaZj19hb9EJaJlwbKc5VFzmlGMFSJVk4dDy+eUxa5KOA7tWXqzcmhh5SYdv+MxcaQKlKWLMa36pfgv20FpEDb03GCtLqjLTRZ7649PugAQ5EmAqIic29CjggHDMIIBvzAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIDiDBHBgNVHSAEQDA+MDIGCysGAQQBg5EhAQIBMCMwIQYIKwYBBQUHAgEWFWh0dHBzOi8vd3d3LnNrLmVlL0NQUzAIBgYEAI96AQIwHwYDVR0RBBgwFoEUMzgwMDEwODU3MThAZWVzdGkuZWUwHQYDVR0OBBYEFPlp/ceABC52itoqppEmbf71TJz6MGEGCCsGAQUFBwEDBFUwUzBRBgYEAI5GAQUwRzBFFj9odHRwczovL3NrLmVlL2VuL3JlcG9zaXRvcnkvY29uZGl0aW9ucy1mb3ItdXNlLW9mLWNlcnRpZmljYXRlcy8TAkVOMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAfBgNVHSMEGDAWgBTAhJkpxE6fOwI09pnhClYACCk+ezBzBggrBgEFBQcBAQRnMGUwLAYIKwYBBQUHMAGGIGh0dHA6Ly9haWEuZGVtby5zay5lZS9lc3RlaWQyMDE4MDUGCCsGAQUFBzAChilodHRwOi8vYy5zay5lZS9UZXN0X29mX0VTVEVJRDIwMTguZGVyLmNydDAKBggqhkjOPQQDBAOBjAAwgYgCQgDCAgybz0u3W+tGI+AX+PiI5CrE9ptEHO5eezR1Jo4j7iGaO0i39xTGUB+NSC7P6AQbyE/ywqJjA1a62jTLcS9GHAJCARxN4NO4eVdWU3zVohCXm8WN3DWA7XUcn9TZiLGQ29P4xfQZOXJi/z4PNRRsR4plvSNB3dfyBvZn31HhC7my8woi\"," +
49-
"\"unverifiedSigningCertificate\":\"MIIEBDCCA2WgAwIBAgIQY5OGshxoPMFg+Wfc0gFEaTAKBggqhkjOPQQDBDBgMQswCQYDVQQGEwJFRTEbMBkGA1UECgwSU0sgSUQgU29sdXRpb25zIEFTMRcwFQYDVQRhDA5OVFJFRS0xMDc0NzAxMzEbMBkGA1UEAwwSVEVTVCBvZiBFU1RFSUQyMDE4MB4XDTIxMDcyMjEyNDMwOFoXDTI2MDcwOTIxNTk1OVowfzELMAkGA1UEBhMCRUUxKjAoBgNVBAMMIUrDlUVPUkcsSkFBSy1LUklTVEpBTiwzODAwMTA4NTcxODEQMA4GA1UEBAwHSsOVRU9SRzEWMBQGA1UEKgwNSkFBSy1LUklTVEpBTjEaMBgGA1UEBRMRUE5PRUUtMzgwMDEwODU3MTgwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQmwEKsJTjaMHSaZj19hb9EJaJlwbKc5VFzmlGMFSJVk4dDy+eUxa5KOA7tWXqzcmhh5SYdv+MxcaQKlKWLMa36pfgv20FpEDb03GCtLqjLTRZ7649PugAQ5EmAqIic29CjggHDMIIBvzAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIDiDBHBgNVHSAEQDA+MDIGCysGAQQBg5EhAQIBMCMwIQYIKwYBBQUHAgEWFWh0dHBzOi8vd3d3LnNrLmVlL0NQUzAIBgYEAI96AQIwHwYDVR0RBBgwFoEUMzgwMDEwODU3MThAZWVzdGkuZWUwHQYDVR0OBBYEFPlp/ceABC52itoqppEmbf71TJz6MGEGCCsGAQUFBwEDBFUwUzBRBgYEAI5GAQUwRzBFFj9odHRwczovL3NrLmVlL2VuL3JlcG9zaXRvcnkvY29uZGl0aW9ucy1mb3ItdXNlLW9mLWNlcnRpZmljYXRlcy8TAkVOMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAfBgNVHSMEGDAWgBTAhJkpxE6fOwI09pnhClYACCk+ezBzBggrBgEFBQcBAQRnMGUwLAYIKwYBBQUHMAGGIGh0dHA6Ly9haWEuZGVtby5zay5lZS9lc3RlaWQyMDE4MDUGCCsGAQUFBzAChilodHRwOi8vYy5zay5lZS9UZXN0X29mX0VTVEVJRDIwMTguZGVyLmNydDAKBggqhkjOPQQDBAOBjAAwgYgCQgDCAgybz0u3W+tGI+AX+PiI5CrE9ptEHO5eezR1Jo4j7iGaO0i39xTGUB+NSC7P6AQbyE/ywqJjA1a62jTLcS9GHAJCARxN4NO4eVdWU3zVohCXm8WN3DWA7XUcn9TZiLGQ29P4xfQZOXJi/z4PNRRsR4plvSNB3dfyBvZn31HhC7my8woi\"," +
49+
"\"unverifiedSigningCertificate\":\"MIID6zCCA02gAwIBAgIQT7j6zk6pmVRcyspLo5SqejAKBggqhkjOPQQDBDBgMQswCQYDVQQGEwJFRTEbMBkGA1UECgwSU0sgSUQgU29sdXRpb25zIEFTMRcwFQYDVQRhDA5OVFJFRS0xMDc0NzAxMzEbMBkGA1UEAwwSVEVTVCBvZiBFU1RFSUQyMDE4MB4XDTE5MDUwMjEwNDUzMVoXDTI5MDUwMjEwNDUzMVowfzELMAkGA1UEBhMCRUUxFjAUBgNVBCoMDUpBQUstS1JJU1RKQU4xEDAOBgNVBAQMB0rDlUVPUkcxKjAoBgNVBAMMIUrDlUVPUkcsSkFBSy1LUklTVEpBTiwzODAwMTA4NTcxODEaMBgGA1UEBRMRUE5PRUUtMzgwMDEwODU3MTgwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASkwENR8GmCpEs6OshDWDfIiKvGuyNMOD2rjIQW321AnZD3oIsqD0svBMNEJJj9Dlvq/47TYDObIa12KAU5IuOBfJs2lrFdSXZjaM+a5TWT3O2JTM36YDH2GcMe/eisepejggGrMIIBpzAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIGQDBIBgNVHSAEQTA/MDIGCysGAQQBg5EhAQIBMCMwIQYIKwYBBQUHAgEWFWh0dHBzOi8vd3d3LnNrLmVlL0NQUzAJBgcEAIvsQAECMB0GA1UdDgQWBBTVX3s48Spy/Es2TcXgkRvwUn2YcjCBigYIKwYBBQUHAQMEfjB8MAgGBgQAjkYBATAIBgYEAI5GAQQwEwYGBACORgEGMAkGBwQAjkYBBgEwUQYGBACORgEFMEcwRRY/aHR0cHM6Ly9zay5lZS9lbi9yZXBvc2l0b3J5L2NvbmRpdGlvbnMtZm9yLXVzZS1vZi1jZXJ0aWZpY2F0ZXMvEwJFTjAfBgNVHSMEGDAWgBTAhJkpxE6fOwI09pnhClYACCk+ezBzBggrBgEFBQcBAQRnMGUwLAYIKwYBBQUHMAGGIGh0dHA6Ly9haWEuZGVtby5zay5lZS9lc3RlaWQyMDE4MDUGCCsGAQUFBzAChilodHRwOi8vYy5zay5lZS9UZXN0X29mX0VTVEVJRDIwMTguZGVyLmNydDAKBggqhkjOPQQDBAOBiwAwgYcCQgGBr+Jbo1GeqgWdIwgMo7SA29AP38JxNm2HWq2Qb+kIHpusAK574Co1K5D4+Mk7/ITTuXQaET5WphHoN7tdAciTaQJBAn0zBigYyVPYSTO68HM6hmlwTwi/KlJDdXW/2NsMjSqofFFJXpGvpxk2CTqSRCjcavxLPnkasTbNROYSJcmM8Xc=\"," +
5050
"\"supportedSignatureAlgorithms\":[{\"cryptoAlgorithm\":\"RSA\",\"hashFunction\":\"SHA-256\",\"paddingScheme\":\"PKCS1.5\"}]," +
5151
"\"appVersion\":\"https://web-eid.eu/web-eid-mobile-app/releases/v1.0.0\"," +
5252
"\"signature\":\"0Ov7ME6pTY1K2GXMj8Wxov/o2fGIMEds8OMY5dKdkB0nrqQX7fG1E5mnsbvyHpMDecMUH6Yg+p1HXdgB/lLqOcFZjt/OVXPjAAApC5d1YgRYATDcxsR1zqQwiNcHdmWn\"," +

src/test/java/eu/webeid/security/validator/AuthTokenCertificateTest.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import eu.webeid.security.validator.certvalidators.SubjectCertificateValidatorBatch;
4646
import eu.webeid.security.validator.ocsp.OcspClient;
4747
import eu.webeid.security.validator.ocsp.OcspServiceProvider;
48+
import org.bouncycastle.asn1.x509.Extension;
4849
import org.junit.jupiter.api.AfterEach;
4950
import org.junit.jupiter.api.BeforeEach;
5051
import org.junit.jupiter.api.Disabled;
@@ -351,9 +352,15 @@ void whenValidV11Token_thenValidationSucceeds() {
351352

352353
@Test
353354
void whenV11SigningCertificateFieldIsMissing_thenValidationFails() throws Exception {
354-
final WebEidAuthToken token = replaceTokenField(V11_AUTH_TOKEN, "\"unverifiedSigningCertificate\":\"X5C\",", "");
355-
assertThatThrownBy(() -> validator
356-
.validate(token, VALID_CHALLENGE_NONCE))
355+
ObjectMapper mapper = new ObjectMapper();
356+
ObjectNode node = (ObjectNode) mapper.readTree(V11_AUTH_TOKEN);
357+
node.remove("unverifiedSigningCertificate");
358+
WebEidAuthToken token = OBJECT_READER.readValue(node.toString());
359+
360+
AuthTokenV11Validator spyValidator = spyAuthTokenV11Validator();
361+
doReturn(mock(X509Certificate.class)).when(spyValidator).validateV1(any(), any());
362+
363+
assertThatThrownBy(() -> spyValidator.validate(token, VALID_CHALLENGE_NONCE))
357364
.isInstanceOf(AuthTokenParseException.class)
358365
.hasMessage("'unverifiedSigningCertificate' field is missing, null or empty for format 'web-eid:1.1'");
359366
}
@@ -420,7 +427,7 @@ void whenV11SigningCertificateNotIssuedBySameAuthority_thenValidationFails() thr
420427

421428
assertThatThrownBy(() -> spyValidator.validate(parsedToken, VALID_CHALLENGE_NONCE))
422429
.isInstanceOf(AuthTokenParseException.class)
423-
.hasMessage("Signing and authentication certificates are not issued by the same authority");
430+
.hasMessage("Signing certificate is not issued by the same issuing authority as the authentication certificate");
424431
}
425432
}
426433

@@ -434,7 +441,9 @@ void whenV11SigningCertificateNotSuitableForSigning_thenValidationFails() throws
434441
X509Certificate signingCert = mock(X509Certificate.class);
435442
when(signingCert.getSubjectX500Principal()).thenReturn(realSubjectCert.getSubjectX500Principal());
436443
when(signingCert.getIssuerX500Principal()).thenReturn(realSubjectCert.getIssuerX500Principal());
437-
when(signingCert.getKeyUsage()).thenReturn(new boolean[]{false, false});
444+
when(signingCert.getExtensionValue(Extension.authorityKeyIdentifier.getId()))
445+
.thenReturn(realSubjectCert.getExtensionValue(Extension.authorityKeyIdentifier.getId()));
446+
when(signingCert.getKeyUsage()).thenReturn(new boolean[]{true, false});
438447

439448
try (MockedStatic<CertificateLoader> mocked = mockStatic(CertificateLoader.class)) {
440449
mocked.when(() -> CertificateLoader.decodeCertificateFromBase64(parsedToken.getUnverifiedCertificate()))

0 commit comments

Comments
 (0)