diff --git a/src/dk.gov.oiosi/security/validation/CertificateValidator.cs b/src/dk.gov.oiosi/security/validation/CertificateValidator.cs index 7f2c99d86b98dcd009c259f14367cec9444abb8a..de54f23b6f8c24cd3ca6030b48ab9bda05c27d37 100644 --- a/src/dk.gov.oiosi/security/validation/CertificateValidator.cs +++ b/src/dk.gov.oiosi/security/validation/CertificateValidator.cs @@ -35,7 +35,6 @@ using System.Security.Cryptography.X509Certificates; namespace dk.gov.oiosi.security.validation { - /// /// Class to validate X509 certificates /// @@ -58,28 +57,36 @@ namespace dk.gov.oiosi.security.validation /// The certificate to be validated public static void ValidateCertificate(X509Certificate2 certificate) { - // first we check the activation and expire date - those cast the most specifict errors - CheckCertificateActivated(certificate); - CheckCertificateExpired(certificate); + try + { + // first we check the activation and expire date - those cast the most specifict errors + CheckCertificateActivated(certificate); + CheckCertificateExpired(certificate); - X509Chain chain = CreateChain(certificate); + X509Chain chain = CreateChain(certificate); - //Modified chain validation of the certificate. We are not interested in Ctl lists - foreach (X509ChainStatus status in chain.ChainStatus) - { - switch (status.Status) + //Modified chain validation of the certificate. We are not interested in Ctl lists + foreach (X509ChainStatus status in chain.ChainStatus) { - case X509ChainStatusFlags.CtlNotSignatureValid: - case X509ChainStatusFlags.CtlNotTimeValid: - case X509ChainStatusFlags.CtlNotValidForUsage: - case X509ChainStatusFlags.NoError: - case X509ChainStatusFlags.RevocationStatusUnknown: - case X509ChainStatusFlags.OfflineRevocation: - break; - default: - throw new CertificateFailedChainValidationException(status, certificate.Subject); + switch (status.Status) + { + case X509ChainStatusFlags.CtlNotSignatureValid: + case X509ChainStatusFlags.CtlNotTimeValid: + case X509ChainStatusFlags.CtlNotValidForUsage: + case X509ChainStatusFlags.NoError: + case X509ChainStatusFlags.RevocationStatusUnknown: + case X509ChainStatusFlags.OfflineRevocation: + break; + default: + throw new CertificateFailedChainValidationException(status, certificate.Subject); + } } } + catch (Exception ex) + { + ex.Data.Add("Certificate", certificate); + throw ex; + } } /// @@ -99,54 +106,61 @@ namespace dk.gov.oiosi.security.validation /// that the root certificate exists in the certificate chain. public static void ValidateCertificate(X509Certificate2 certificate, X509Certificate2 rootCertificate) { - CheckCertificateActivated(certificate); - CheckCertificateExpired(certificate); + try + { + CheckCertificateActivated(certificate); + CheckCertificateExpired(certificate); - X509Chain chain = CreateChain(certificate); + X509Chain chain = CreateChain(certificate); - //Modified chain validation of the certificate. We are not interested in Ctl lists - foreach (X509ChainStatus status in chain.ChainStatus) - { - switch (status.Status) + //Modified chain validation of the certificate. We are not interested in Ctl lists + foreach (X509ChainStatus status in chain.ChainStatus) { - case X509ChainStatusFlags.CtlNotSignatureValid: - case X509ChainStatusFlags.CtlNotTimeValid: - case X509ChainStatusFlags.CtlNotValidForUsage: - case X509ChainStatusFlags.NoError: - case X509ChainStatusFlags.RevocationStatusUnknown: - case X509ChainStatusFlags.OfflineRevocation: - break; - default: - throw new CertificateFailedChainValidationException(status, certificate.Subject); + switch (status.Status) + { + case X509ChainStatusFlags.CtlNotSignatureValid: + case X509ChainStatusFlags.CtlNotTimeValid: + case X509ChainStatusFlags.CtlNotValidForUsage: + case X509ChainStatusFlags.NoError: + case X509ChainStatusFlags.RevocationStatusUnknown: + case X509ChainStatusFlags.OfflineRevocation: + break; + default: + throw new CertificateFailedChainValidationException(status, certificate.Subject); + } } - } - // Check if the certificate has the default root certificate as its root - bool rootIsInChain = false; - string rootThumbprint = rootCertificate.Thumbprint.ToLower(); + // Check if the certificate has the default root certificate as its root + bool rootIsInChain = false; + string rootThumbprint = rootCertificate.Thumbprint.ToLower(); - if (certificate.Thumbprint.ToLower() != rootThumbprint) - { - foreach (X509ChainElement chainElem in chain.ChainElements) + if (certificate.Thumbprint.ToLower() != rootThumbprint) { - if (chainElem.Certificate.Thumbprint.ToLower() == rootThumbprint) + foreach (X509ChainElement chainElem in chain.ChainElements) { - rootIsInChain = true; - break; + if (chainElem.Certificate.Thumbprint.ToLower() == rootThumbprint) + { + rootIsInChain = true; + break; + } } } - } - else - { - throw new CertificateFailedChainValidationException("The root certificate and certificate must be different", certificate.Subject); - } + else + { + throw new CertificateFailedChainValidationException("The root certificate and certificate must be different", certificate.Subject); + } - if (rootIsInChain == false) + if (rootIsInChain == false) + { + throw new CertificateFailedChainValidationException("The specified root certificate was not part of the certificate chain", certificate.Subject); + } + } + catch(Exception ex) { - throw new CertificateFailedChainValidationException("The specified root certificate was not part of the certificate chain", certificate.Subject); + ex.Data.Add("Certificate", certificate); + ex.Data.Add("RootCertificate", rootCertificate); + throw ex; } - - } /// diff --git a/test/dk.gov.oiosi.test.unit/security/ldap/LdapCertificateLookupTest.cs b/test/dk.gov.oiosi.test.unit/security/ldap/LdapCertificateLookupTest.cs index 3bcaf0435bb9f6750e9014e88d0d141b61138d2f..abfbdf0319626e70d5a65726932de2f057b65811 100644 --- a/test/dk.gov.oiosi.test.unit/security/ldap/LdapCertificateLookupTest.cs +++ b/test/dk.gov.oiosi.test.unit/security/ldap/LdapCertificateLookupTest.cs @@ -38,18 +38,28 @@ namespace dk.gov.oiosi.test.unit.security.ldap } [Test] - [Ignore("Need ok certificate chain")] public void TestLdapTestServerFoces2Subject() { - CertificateSubject certSubject = new CertificateSubject(TestConstants.TEST_CERTIFICATE_SUBJECT_FUNCTION); - var ldapCertificateLookup = new LdapCertificateLookup(this._ldapSettings); - X509Certificate2 cert = ldapCertificateLookup.GetCertificate(certSubject); + var certSubject = new CertificateSubject(TestConstants.TEST_CERTIFICATE_SUBJECT_FUNCTION); + + X509Certificate2 cert = null; + + try + { + cert = ldapCertificateLookup.GetCertificate(certSubject); + } + catch (CertificateValidationException ex) + { + // We managed to connect and get a certificate. For some (possibly local) reason it didn't + // pass validation but that is not important for this test. + cert = (X509Certificate2)ex.Data["Certificate"]; + } // java: assertEquals("Wrong cert. found...", BigInteger.valueOf(1538079514), cert.getSerialNumber()); var expectedSerialNumber = new BigInteger("1538079514").ToString(16); // i.e. as hex-string var actualSerialNumber = cert.GetSerialNumberString(); - Assert.AreEqual(expectedSerialNumber.ToUpperInvariant(), actualSerialNumber.ToUpperInvariant(), + Assert.AreEqual(expectedSerialNumber.ToUpperInvariant(), actualSerialNumber.ToUpperInvariant(), message: "Wrong cert. found..."); // java: assertEquals("Wrong end date found...", "2022-12-16T14:31:07 UTC", DateUtil.formatDate(cert.getNotAfter())); @@ -59,18 +69,28 @@ namespace dk.gov.oiosi.test.unit.security.ldap } [Test] - [Ignore("Need ok certificate chain")] public void TestGetMitIdCertificateFromTestLdap() { + var ldapCertificateLookup = new LdapCertificateLookup(this._ldapSettings); var certSubject = "C=DK, OID.2.5.4.97=NTRDK-90087822, O=Testorganisation nr. 90087822, SERIALNUMBER=UI:DK-8b230ff4-5f3d-4264-801a-7aac66bd51bd, CN=Nemhandel-DEV-OCES-cert-2"; - var ldapCertificateLookup = new LdapCertificateLookup(this._ldapSettings); - X509Certificate2 cert = ldapCertificateLookup.GetCertificate(new CertificateSubject(certSubject)); + X509Certificate2 cert = null; + + try + { + cert = ldapCertificateLookup.GetCertificate(new CertificateSubject(certSubject)); + } + catch (CertificateValidationException ex) + { + // We managed to connect and get a certificate. For some (possibly local) reason it didn't + // pass validation but that is not important for this test. + cert = (X509Certificate2)ex.Data["Certificate"]; + } // java: assertEquals("Wrong cert. found...", "344676415080031272949370873805706101461479077746", result.getSerialNumber().toString()); - var expectedSerialNumber = new BigInteger("3c5fd332f87ba522fd39e31ec5710d1009ec3772").ToString(16); // i.e. as hex-string + var expectedSerialNumber = new BigInteger("344676415080031272949370873805706101461479077746").ToString(16); // i.e. as hex-string var actualSerialNumber = cert.GetSerialNumberString(); - Assert.AreEqual( expectedSerialNumber.ToUpperInvariant(), actualSerialNumber.ToUpperInvariant(), + Assert.AreEqual(expectedSerialNumber.ToUpperInvariant(), actualSerialNumber.ToUpperInvariant(), message: "Wrong cert. found..."); // java: assertEquals("Wrong expire date found...", "2024-02-16T08:57:31 UTC", DateUtil.formatDate(result.getNotAfter()));