Skip to content

Commit daf6f6a

Browse files
committed
feat(token): remove site cert hash validation, rename fields according to final spec
WE2-586 Signed-off-by: Mart Somermaa <[email protected]>
1 parent fa76e2a commit daf6f6a

16 files changed

+37
-168
lines changed

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

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,17 @@
2727
@JsonIgnoreProperties(ignoreUnknown = true)
2828
public class WebEidAuthToken {
2929

30-
private String certificate;
30+
private String untrustedCertificate;
3131
private String signature;
3232
private String algorithm;
33-
private String version;
34-
private boolean useOriginCertHash;
33+
private String format;
3534

36-
public String getCertificate() {
37-
return certificate;
35+
public String getUntrustedCertificate() {
36+
return untrustedCertificate;
3837
}
3938

40-
public void setCertificate(String certificate) {
41-
this.certificate = certificate;
39+
public void setUntrustedCertificate(String untrustedCertificate) {
40+
this.untrustedCertificate = untrustedCertificate;
4241
}
4342

4443
public String getSignature() {
@@ -57,20 +56,12 @@ public void setAlgorithm(String algorithm) {
5756
this.algorithm = algorithm;
5857
}
5958

60-
public String getVersion() {
61-
return version;
59+
public String getFormat() {
60+
return format;
6261
}
6362

64-
public void setVersion(String version) {
65-
this.version = version;
66-
}
67-
68-
public boolean getUseOriginCertHash() {
69-
return useOriginCertHash;
70-
}
71-
72-
public void setUseOriginCertHash(boolean useOriginCertHash) {
73-
this.useOriginCertHash = useOriginCertHash;
63+
public void setFormat(String format) {
64+
this.format = format;
7465
}
7566

7667
}

src/main/java/eu/webeid/security/certificate/CertificateLoader.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.security.cert.X509Certificate;
3333
import java.util.ArrayList;
3434
import java.util.List;
35+
import java.util.Objects;
3536

3637
import static eu.webeid.security.util.Base64Decoder.decodeBase64;
3738

@@ -52,6 +53,7 @@ public static X509Certificate[] loadCertificatesFromResources(String... resource
5253
}
5354

5455
public static X509Certificate decodeCertificateFromBase64(String certificateInBase64) throws CertificateDecodingException {
56+
Objects.requireNonNull(certificateInBase64, "certificateInBase64");
5557
try (final InputStream targetStream = new ByteArrayInputStream(decodeBase64(certificateInBase64))) {
5658
return (X509Certificate) CertificateFactory
5759
.getInstance("X509")

src/main/java/eu/webeid/security/challenge/ChallengeNonceGeneratorBuilder.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
package eu.webeid.security.challenge;
2424

2525
import eu.webeid.security.util.DateAndTime;
26-
import eu.webeid.security.validator.AuthTokenValidator;
2726

2827
import java.security.SecureRandom;
2928
import java.time.Duration;

src/main/java/eu/webeid/security/exceptions/TokenSignatureValidationException.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,8 @@
2727
*/
2828
public class TokenSignatureValidationException extends TokenValidationException {
2929

30-
public static final String MESSAGE = "Token signature validation has failed";
31-
3230
public TokenSignatureValidationException() {
33-
super(MESSAGE);
31+
super("Token signature validation has failed");
3432
}
3533

3634
}

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public AuthTokenSignatureValidator(URI siteOrigin) {
5959
}
6060

6161
// This method is based on the relevant subset of JJWT's DefaultJwtParser.parse().
62-
public void validate(String algorithm, String signature, PublicKey publicKey, String currentChallengeNonce, byte[] originCertHash) throws TokenValidationException {
62+
public void validate(String algorithm, String signature, PublicKey publicKey, String currentChallengeNonce) throws TokenValidationException {
6363
requireNotEmpty(algorithm, "algorithm");
6464
requireNotEmpty(signature, "signature");
6565
Objects.requireNonNull(publicKey);
@@ -88,9 +88,7 @@ public void validate(String algorithm, String signature, PublicKey publicKey, St
8888
final byte[] decodedSignature = decodeBase64(signature);
8989

9090
final byte[] nonceHash = sha256Digest(currentChallengeNonce);
91-
final byte[] concatSignedFields = originCertHash == null ?
92-
Bytes.concat(originHash, nonceHash) :
93-
Bytes.concat(originHash, nonceHash, originCertHash);
91+
final byte[] concatSignedFields = Bytes.concat(originHash, nonceHash);
9492

9593
// Note that in case of ECDSA, the eID card outputs raw R||S, but JCA's SHA384withECDSA signature
9694
// validation implementation requires the signature in DER encoding.

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

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ public final class AuthTokenValidationConfiguration {
5050
private boolean isUserCertificateRevocationCheckWithOcspEnabled = true;
5151
private Duration ocspRequestTimeout = Duration.ofSeconds(5);
5252
private DesignatedOcspServiceConfiguration designatedOcspServiceConfiguration;
53-
private byte[] siteCertificateSha256Hash;
5453
// Don't allow Estonian Mobile-ID policy by default.
5554
private Collection<ASN1ObjectIdentifier> disallowedSubjectCertificatePolicies = Sets.newHashSet(
5655
SubjectCertificatePolicies.ESTEID_SK_2015_MOBILE_ID_POLICY_V1,
@@ -70,7 +69,6 @@ private AuthTokenValidationConfiguration(AuthTokenValidationConfiguration other)
7069
this.isUserCertificateRevocationCheckWithOcspEnabled = other.isUserCertificateRevocationCheckWithOcspEnabled;
7170
this.ocspRequestTimeout = other.ocspRequestTimeout;
7271
this.designatedOcspServiceConfiguration = other.designatedOcspServiceConfiguration;
73-
this.siteCertificateSha256Hash = other.siteCertificateSha256Hash;
7472
this.disallowedSubjectCertificatePolicies = Collections.unmodifiableSet(new HashSet<>(other.disallowedSubjectCertificatePolicies));
7573
this.nonceDisabledOcspUrls = Collections.unmodifiableSet(new HashSet<>(other.nonceDisabledOcspUrls));
7674
}
@@ -111,14 +109,6 @@ public void setDesignatedOcspServiceConfiguration(DesignatedOcspServiceConfigura
111109
this.designatedOcspServiceConfiguration = designatedOcspServiceConfiguration;
112110
}
113111

114-
public void setSiteCertificateSha256Hash(byte[] siteCertificateSha256Hash) {
115-
this.siteCertificateSha256Hash = siteCertificateSha256Hash;
116-
}
117-
118-
public byte[] getSiteCertificateSha256Hash() {
119-
return siteCertificateSha256Hash;
120-
}
121-
122112
public Collection<ASN1ObjectIdentifier> getDisallowedSubjectCertificatePolicies() {
123113
return disallowedSubjectCertificatePolicies;
124114
}
@@ -139,10 +129,6 @@ void validate() {
139129
if (trustedCACertificates.isEmpty()) {
140130
throw new IllegalArgumentException("At least one trusted certificate authority must be provided");
141131
}
142-
// If given, a SHA256 hash must be 32 bytes long.
143-
if (siteCertificateSha256Hash!= null && siteCertificateSha256Hash.length != 32) {
144-
throw new IllegalArgumentException("Site certificate SHA-256 hash must be 32 bytes long");
145-
}
146132
requirePositiveDuration(ocspRequestTimeout, "OCSP request timeout");
147133
}
148134

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

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -152,24 +152,6 @@ public AuthTokenValidatorBuilder withDesignatedOcspServiceConfiguration(Designat
152152
return this;
153153
}
154154

155-
/**
156-
* Sets the site certificate hash, i.e. the SHA-256 hash of the HTTPS certificate
157-
* that the site is using.
158-
* <p>
159-
* When the experimental origin certificate validation support is enabled, then
160-
* the origin certificate hash is used along with the origin and challenge nonce hashes
161-
* during authentication token signature calculation. In this case the site certificate hash
162-
* must be provided in configuration to verify the signature.
163-
*
164-
* @param certificateSha256Hash SHA-256 hash of the HTTPS certificate that the site is using
165-
* @return the builder instance for method chaining.
166-
*/
167-
public AuthTokenValidatorBuilder withSiteCertificateSha256Hash(byte[] certificateSha256Hash) {
168-
configuration.setSiteCertificateSha256Hash(certificateSha256Hash);
169-
LOG.debug("Site certificate hash validation is enabled, hash is {}", certificateSha256Hash);
170-
return this;
171-
}
172-
173155
/**
174156
* Validates the configuration and builds the {@link AuthTokenValidator} object with it.
175157
* The returned {@link AuthTokenValidator} object is immutable/thread-safe.

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

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import org.slf4j.Logger;
3333
import org.slf4j.LoggerFactory;
3434
import eu.webeid.security.authtoken.WebEidAuthToken;
35-
import eu.webeid.security.exceptions.SiteCertificateHashNotConfiguredException;
3635
import eu.webeid.security.exceptions.TokenParseException;
3736
import eu.webeid.security.exceptions.TokenValidationException;
3837
import eu.webeid.security.validator.certvalidators.SubjectCertificateExpiryValidator;
@@ -149,19 +148,14 @@ private WebEidAuthToken parseToken(String authToken) throws TokenParseException
149148
}
150149

151150
private X509Certificate validateToken(WebEidAuthToken token, String currentChallengeNonce) throws TokenValidationException {
152-
if (!Objects.equals(token.getVersion(), CURRENT_TOKEN_FORMAT_VERSION)) {
153-
throw new TokenParseException("Only token version '" + CURRENT_TOKEN_FORMAT_VERSION +
151+
if (token.getFormat() == null || !token.getFormat().startsWith(CURRENT_TOKEN_FORMAT_VERSION)) {
152+
throw new TokenParseException("Only token format version '" + CURRENT_TOKEN_FORMAT_VERSION +
154153
"' is currently supported");
155154
}
156-
// When the token signature contains the experimental origin certificate hash,
157-
// the hash must be provided in the configuration.
158-
if (token.getUseOriginCertHash() && configuration.getSiteCertificateSha256Hash() == null) {
159-
throw new SiteCertificateHashNotConfiguredException();
160-
}
161-
if (token.getCertificate() == null || token.getCertificate().isEmpty()) {
155+
if (token.getUntrustedCertificate() == null || token.getUntrustedCertificate().isEmpty()) {
162156
throw new TokenParseException("'certificate' field is missing, null or empty");
163157
}
164-
final X509Certificate subjectCertificate = CertificateLoader.decodeCertificateFromBase64(token.getCertificate());
158+
final X509Certificate subjectCertificate = CertificateLoader.decodeCertificateFromBase64(token.getUntrustedCertificate());
165159

166160
simpleSubjectCertificateValidators.executeFor(subjectCertificate);
167161
getCertTrustValidators().executeFor(subjectCertificate);
@@ -172,10 +166,7 @@ private X509Certificate validateToken(WebEidAuthToken token, String currentChall
172166
authTokenSignatureValidator.validate(token.getAlgorithm(),
173167
token.getSignature(),
174168
subjectCertificate.getPublicKey(),
175-
currentChallengeNonce,
176-
token.getUseOriginCertHash() ?
177-
configuration.getSiteCertificateSha256Hash() :
178-
null);
169+
currentChallengeNonce);
179170

180171
return subjectCertificate;
181172
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@
3535
public abstract class AbstractTestWithValidator {
3636

3737
public static final String VALID_AUTH_TOKEN = "{\"algorithm\":\"ES384\"," +
38-
"\"certificate\":\"MIIEAzCCA2WgAwIBAgIQHWbVWxCkcYxbzz9nBzGrDzAKBggqhkjOPQQDBDBgMQswCQYDVQQGEwJFRTEbMBkGA1UECgwSU0sgSUQgU29sdXRpb25zIEFTMRcwFQYDVQRhDA5OVFJFRS0xMDc0NzAxMzEbMBkGA1UEAwwSVEVTVCBvZiBFU1RFSUQyMDE4MB4XDTE4MTAyMzE1MzM1OVoXDTIzMTAyMjIxNTk1OVowfzELMAkGA1UEBhMCRUUxKjAoBgNVBAMMIUrDlUVPUkcsSkFBSy1LUklTVEpBTiwzODAwMTA4NTcxODEQMA4GA1UEBAwHSsOVRU9SRzEWMBQGA1UEKgwNSkFBSy1LUklTVEpBTjEaMBgGA1UEBRMRUE5PRUUtMzgwMDEwODU3MTgwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQ/u+9IncarVpgrACN6aRgUiT9lWC9H7llnxoEXe8xoCI982Md8YuJsVfRdeG5jwVfXe0N6KkHLFRARspst8qnACULkqFNat/Kj+XRwJ2UANeJ3Gl5XBr+tnLNuDf/UiR6jggHDMIIBvzAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIDiDBHBgNVHSAEQDA+MDIGCysGAQQBg5EhAQIBMCMwIQYIKwYBBQUHAgEWFWh0dHBzOi8vd3d3LnNrLmVlL0NQUzAIBgYEAI96AQIwHwYDVR0RBBgwFoEUMzgwMDEwODU3MThAZWVzdGkuZWUwHQYDVR0OBBYEFOTddHnA9rJtbLwhBNyn0xZTQGCMMGEGCCsGAQUFBwEDBFUwUzBRBgYEAI5GAQUwRzBFFj9odHRwczovL3NrLmVlL2VuL3JlcG9zaXRvcnkvY29uZGl0aW9ucy1mb3ItdXNlLW9mLWNlcnRpZmljYXRlcy8TAkVOMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAfBgNVHSMEGDAWgBTAhJkpxE6fOwI09pnhClYACCk+ezBzBggrBgEFBQcBAQRnMGUwLAYIKwYBBQUHMAGGIGh0dHA6Ly9haWEuZGVtby5zay5lZS9lc3RlaWQyMDE4MDUGCCsGAQUFBzAChilodHRwOi8vYy5zay5lZS9UZXN0X29mX0VTVEVJRDIwMTguZGVyLmNydDAKBggqhkjOPQQDBAOBiwAwgYcCQgHYElkX4vn821JR41akI/lpexCnJFUf4GiOMbTfzAxpZma333R8LNrmI4zbzDp03hvMTzH49g1jcbGnaCcbboS8DAJBObenUp++L5VqldHwKAps61nM4V+TiLqD0jILnTzl+pV+LexNL3uGzUfvvDNLHnF9t6ygi8+Bsjsu3iHHyM1haKM=\"," +
39-
"\"issuerApp\":\"https://web-eid.eu/web-eid-app/releases/2.0.0+0\"," +
38+
"\"untrustedCertificate\":\"MIIEAzCCA2WgAwIBAgIQHWbVWxCkcYxbzz9nBzGrDzAKBggqhkjOPQQDBDBgMQswCQYDVQQGEwJFRTEbMBkGA1UECgwSU0sgSUQgU29sdXRpb25zIEFTMRcwFQYDVQRhDA5OVFJFRS0xMDc0NzAxMzEbMBkGA1UEAwwSVEVTVCBvZiBFU1RFSUQyMDE4MB4XDTE4MTAyMzE1MzM1OVoXDTIzMTAyMjIxNTk1OVowfzELMAkGA1UEBhMCRUUxKjAoBgNVBAMMIUrDlUVPUkcsSkFBSy1LUklTVEpBTiwzODAwMTA4NTcxODEQMA4GA1UEBAwHSsOVRU9SRzEWMBQGA1UEKgwNSkFBSy1LUklTVEpBTjEaMBgGA1UEBRMRUE5PRUUtMzgwMDEwODU3MTgwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQ/u+9IncarVpgrACN6aRgUiT9lWC9H7llnxoEXe8xoCI982Md8YuJsVfRdeG5jwVfXe0N6KkHLFRARspst8qnACULkqFNat/Kj+XRwJ2UANeJ3Gl5XBr+tnLNuDf/UiR6jggHDMIIBvzAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIDiDBHBgNVHSAEQDA+MDIGCysGAQQBg5EhAQIBMCMwIQYIKwYBBQUHAgEWFWh0dHBzOi8vd3d3LnNrLmVlL0NQUzAIBgYEAI96AQIwHwYDVR0RBBgwFoEUMzgwMDEwODU3MThAZWVzdGkuZWUwHQYDVR0OBBYEFOTddHnA9rJtbLwhBNyn0xZTQGCMMGEGCCsGAQUFBwEDBFUwUzBRBgYEAI5GAQUwRzBFFj9odHRwczovL3NrLmVlL2VuL3JlcG9zaXRvcnkvY29uZGl0aW9ucy1mb3ItdXNlLW9mLWNlcnRpZmljYXRlcy8TAkVOMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAfBgNVHSMEGDAWgBTAhJkpxE6fOwI09pnhClYACCk+ezBzBggrBgEFBQcBAQRnMGUwLAYIKwYBBQUHMAGGIGh0dHA6Ly9haWEuZGVtby5zay5lZS9lc3RlaWQyMDE4MDUGCCsGAQUFBzAChilodHRwOi8vYy5zay5lZS9UZXN0X29mX0VTVEVJRDIwMTguZGVyLmNydDAKBggqhkjOPQQDBAOBiwAwgYcCQgHYElkX4vn821JR41akI/lpexCnJFUf4GiOMbTfzAxpZma333R8LNrmI4zbzDp03hvMTzH49g1jcbGnaCcbboS8DAJBObenUp++L5VqldHwKAps61nM4V+TiLqD0jILnTzl+pV+LexNL3uGzUfvvDNLHnF9t6ygi8+Bsjsu3iHHyM1haKM=\"," +
39+
"\"appVersion\":\"https://web-eid.eu/web-eid-app/releases/2.0.0+0\"," +
4040
"\"signature\":\"arx164xRiwhIQDINe0J+ZxJWZFOQTx0PBtOaWaxAe7gofEIHRIbV1w0sOCYBJnvmvMem9hU4nc2+iJx2x8poYck4Z6eI3GwtiksIec3XQ9ZIk1n/XchXnmPn3GYV+HzJ\"," +
41-
"\"version\":\"web-eid:1\"}";
41+
"\"format\":\"web-eid:1\"}";
4242
public static final String VALID_CHALLENGE_NONCE = "12345678123456781234567812345678912356789123";
4343

4444
protected AuthTokenValidator validator;

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

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,17 +84,6 @@ public static AuthTokenValidator getAuthTokenValidatorWithDisallowedESTEIDPolicy
8484
.build();
8585
}
8686

87-
public static AuthTokenValidator getAuthTokenValidatorWithCertHashCheck() throws CertificateException, JceException, IOException, CertificateDecodingException {
88-
return getAuthTokenValidatorWithCertHashCheck(getRiaSiteCertificateSha256Hash());
89-
}
90-
91-
public static AuthTokenValidator getAuthTokenValidatorWithCertHashCheck(byte[] certHash) throws CertificateException, JceException, IOException, CertificateDecodingException {
92-
return getAuthTokenValidatorBuilder(TOKEN_ORIGIN_URL, getCACertificates())
93-
.withSiteCertificateSha256Hash(certHash)
94-
.withoutUserCertificateRevocationCheckWithOcsp()
95-
.build();
96-
}
97-
9887
private static AuthTokenValidatorBuilder getAuthTokenValidatorBuilder(String uri, X509Certificate[] certificates) {
9988
return new AuthTokenValidatorBuilder()
10089
.withSiteOrigin(URI.create(uri))

0 commit comments

Comments
 (0)