From 28d7ca654b0a7af965062cb805e2c605e03216d8 Mon Sep 17 00:00:00 2001 From: hiharsh Date: Fri, 10 Mar 2023 20:28:02 -0500 Subject: [PATCH] certificate validation. added an initial rule for checking expiration --- .../validator/CertValidationException.java | 17 +++++ .../attestation/validator/CertValidator.java | 42 +++++++++++ .../validator/CertValidatorRule.java | 10 +++ .../validator/rule/ExpirationRule.java | 26 +++++++ .../validator/rule/ExpirationRuleTest.java | 71 +++++++++++++++++++ 5 files changed, 166 insertions(+) create mode 100644 server/src/main/java/com/google/android/attestation/validator/CertValidationException.java create mode 100644 server/src/main/java/com/google/android/attestation/validator/CertValidator.java create mode 100644 server/src/main/java/com/google/android/attestation/validator/CertValidatorRule.java create mode 100644 server/src/main/java/com/google/android/attestation/validator/rule/ExpirationRule.java create mode 100644 server/src/test/java/com/google/android/attestation/validator/rule/ExpirationRuleTest.java diff --git a/server/src/main/java/com/google/android/attestation/validator/CertValidationException.java b/server/src/main/java/com/google/android/attestation/validator/CertValidationException.java new file mode 100644 index 0000000..e8f7e69 --- /dev/null +++ b/server/src/main/java/com/google/android/attestation/validator/CertValidationException.java @@ -0,0 +1,17 @@ +package com.google.android.attestation.validator; + +/** + * This exception is thrown if the certificate fails any of the validation rule + */ +public class CertValidationException extends Exception { + + private static final long serialVersionUID = 1L; + + public CertValidationException(String msg) { + super(msg); + } + + public CertValidationException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/server/src/main/java/com/google/android/attestation/validator/CertValidator.java b/server/src/main/java/com/google/android/attestation/validator/CertValidator.java new file mode 100644 index 0000000..48825d6 --- /dev/null +++ b/server/src/main/java/com/google/android/attestation/validator/CertValidator.java @@ -0,0 +1,42 @@ +package com.google.android.attestation.validator; + +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; + +/** + * Performs X509 certificate validation. Add required list of validation rules + */ +public class CertValidator implements CertValidatorRule { + private List rules; + + private CertValidator(Builder builder) { + this.rules = builder.rules; + } + + @Override + public void validate(X509Certificate cert) throws CertValidationException { + for (CertValidatorRule validatorRule : rules) { + validatorRule.validate(cert); + } + } + + public static final class Builder { + + private List rules; + + public Builder() { + this.rules = new ArrayList(); + } + + public Builder addRule(CertValidatorRule validatorRule) { + rules.add(validatorRule); + return this; + } + + public CertValidator build() { + return new CertValidator(this); + } + } + +} diff --git a/server/src/main/java/com/google/android/attestation/validator/CertValidatorRule.java b/server/src/main/java/com/google/android/attestation/validator/CertValidatorRule.java new file mode 100644 index 0000000..db4e92b --- /dev/null +++ b/server/src/main/java/com/google/android/attestation/validator/CertValidatorRule.java @@ -0,0 +1,10 @@ +package com.google.android.attestation.validator; + +import java.security.cert.X509Certificate; + +/** + * Identify a validation rule + */ +public interface CertValidatorRule { + void validate(X509Certificate cert) throws CertValidationException; +} diff --git a/server/src/main/java/com/google/android/attestation/validator/rule/ExpirationRule.java b/server/src/main/java/com/google/android/attestation/validator/rule/ExpirationRule.java new file mode 100644 index 0000000..3e31ee4 --- /dev/null +++ b/server/src/main/java/com/google/android/attestation/validator/rule/ExpirationRule.java @@ -0,0 +1,26 @@ +package com.google.android.attestation.validator.rule; + +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509Certificate; + +import com.google.android.attestation.validator.CertValidationException; + +import com.google.android.attestation.validator.CertValidatorRule; + +/** + * check if certificate has expired or is not yet valid + */ +public class ExpirationRule implements CertValidatorRule { + + @Override + public void validate(X509Certificate cert) throws CertValidationException { + + try { + cert.checkValidity(); + } catch (CertificateExpiredException | CertificateNotYetValidException e) { + throw new CertValidationException(e.getMessage(), e); + } + } + +} diff --git a/server/src/test/java/com/google/android/attestation/validator/rule/ExpirationRuleTest.java b/server/src/test/java/com/google/android/attestation/validator/rule/ExpirationRuleTest.java new file mode 100644 index 0000000..f9d1dd2 --- /dev/null +++ b/server/src/test/java/com/google/android/attestation/validator/rule/ExpirationRuleTest.java @@ -0,0 +1,71 @@ +package com.google.android.attestation.validator.rule; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import com.google.android.attestation.validator.CertValidationException; + + +/** Test for {@link ExpirationRule}. */ +@RunWith(JUnit4.class) +public class ExpirationRuleTest { + private static final String expired_badssl_com = "-----BEGIN CERTIFICATE-----\n" + + "MIIFSzCCBDOgAwIBAgIQSueVSfqavj8QDxekeOFpCTANBgkqhkiG9w0BAQsFADCB" + + "kDELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G" + + "A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxNjA0BgNV" + + "BAMTLUNPTU9ETyBSU0EgRG9tYWluIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBD" + + "QTAeFw0xNTA0MDkwMDAwMDBaFw0xNTA0MTIyMzU5NTlaMFkxITAfBgNVBAsTGERv" + + "bWFpbiBDb250cm9sIFZhbGlkYXRlZDEdMBsGA1UECxMUUG9zaXRpdmVTU0wgV2ls" + + "ZGNhcmQxFTATBgNVBAMUDCouYmFkc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD" + + "ggEPADCCAQoCggEBAMIE7PiM7gTCs9hQ1XBYzJMY61yoaEmwIrX5lZ6xKyx2PmzA" + + "S2BMTOqytMAPgLaw+XLJhgL5XEFdEyt/ccRLvOmULlA3pmccYYz2QULFRtMWhyef" + + "dOsKnRFSJiFzbIRMeVXk0WvoBj1IFVKtsyjbqv9u/2CVSndrOfEk0TG23U3AxPxT" + + "uW1CrbV8/q71FdIzSOciccfCFHpsKOo3St/qbLVytH5aohbcabFXRNsKEqveww9H" + + "dFxBIuGa+RuT5q0iBikusbpJHAwnnqP7i/dAcgCskgjZjFeEU4EFy+b+a1SYQCeF" + + "xxC7c3DvaRhBB0VVfPlkPz0sw6l865MaTIbRyoUCAwEAAaOCAdUwggHRMB8GA1Ud" + + "IwQYMBaAFJCvajqUWgvYkOoSVnPfQ7Q6KNrnMB0GA1UdDgQWBBSd7sF7gQs6R2lx" + + "GH0RN5O8pRs/+zAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHSUE" + + "FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwTwYDVR0gBEgwRjA6BgsrBgEEAbIxAQIC" + + "BzArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8uY29tL0NQUzAI" + + "BgZngQwBAgEwVAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL2NybC5jb21vZG9jYS5j" + + "b20vQ09NT0RPUlNBRG9tYWluVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNybDCB" + + "hQYIKwYBBQUHAQEEeTB3ME8GCCsGAQUFBzAChkNodHRwOi8vY3J0LmNvbW9kb2Nh" + + "LmNvbS9DT01PRE9SU0FEb21haW5WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3J0" + + "MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wIwYDVR0RBBww" + + "GoIMKi5iYWRzc2wuY29tggpiYWRzc2wuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBq" + + "evHa/wMHcnjFZqFPRkMOXxQhjHUa6zbgH6QQFezaMyV8O7UKxwE4PSf9WNnM6i1p" + + "OXy+l+8L1gtY54x/v7NMHfO3kICmNnwUW+wHLQI+G1tjWxWrAPofOxkt3+IjEBEH" + + "fnJ/4r+3ABuYLyw/zoWaJ4wQIghBK4o+gk783SHGVnRwpDTysUCeK1iiWQ8dSO/r" + + "ET7BSp68ZVVtxqPv1dSWzfGuJ/ekVxQ8lEEFeouhN0fX9X3c+s5vMaKwjOrMEpsi" + + "8TRwz311SotoKQwe6Zaoz7ASH1wq7mcvf71z81oBIgxw+s1F73hczg36TuHvzmWf" + + "RwxPuzZEaFZcVlmtqoq8\n" + + "-----END CERTIFICATE-----"; + + public static X509Certificate loadCertFromString(String certStr) throws CertificateException { + CertificateFactory factory = CertificateFactory.getInstance("X509"); + return (X509Certificate) factory + .generateCertificate(new ByteArrayInputStream(expired_badssl_com.getBytes(StandardCharsets.UTF_8))); + } + + @Test + public void testCertificateExpired() throws CertificateException { + X509Certificate cert = loadCertFromString(expired_badssl_com); + var rule = new ExpirationRule(); + + try { + rule.validate(cert); + Assert.fail("CertificateException expected."); + } catch (CertValidationException e) { + + } + } + +}