/// <summary> /// Verifies if the ETK contains a token that is still valid and can be trusted. /// </summary> /// <remarks> /// <para> /// This method checks if the certificate in the ETK is issued by a trusted party. Trust means /// the root certificate is trusted by the computer it is running on and all /// validation checks, including revocation, are successful. Root /// certificates are trusted by the computer if present in the /// <see cref="StoreName.Root"/> store. /// </para> /// <para> /// This method no longer validates the signer of the ETK token due lack of signing time in the ETK. /// The encryption certificate inside the ETK is still completely verified, this means there isn't a reduction in /// security compared to the previous implementation. /// </para> /// </remarks> /// <param name="checkRevocation"><c>true</c>to check if the certificates that issued the encryption cert aren't revoked</param> /// <returns>Detailed information about the encryption certificate status</returns> public CertificateSecurityInformation Verify(bool checkRevocation) { IList <CertificateList> crls; IList <BasicOcspResponse> ocps; //Get encryption cert BC::X509Certificate encCert = DotNetUtilities.FromX509Certificate(ToCertificate()); trace.TraceEvent(TraceEventType.Information, 0, "Verifying ETK: {0}", encCert.SubjectDN.ToString()); //Check the certificate IX509Store certs = raw.GetCertificates("COLLECTION"); if (checkRevocation) { crls = new List <CertificateList>(); ocps = new List <BasicOcspResponse>(); } else { crls = null; ocps = null; } CertificateSecurityInformation certInfo = encCert.Verify(DateTime.UtcNow, new int[] { 2, 3 }, EteeActiveConfig.Unseal.MinimumEncryptionKeySize.AsymmerticRecipientKey, certs, ref crls, ref ocps); if (!(encCert.GetPublicKey() is RsaKeyParameters)) { certInfo.securityViolations.Add(CertSecurityViolation.NotValidKeyType); trace.TraceEvent(TraceEventType.Warning, 0, "Only RSA keys can be used for sealing"); } return(certInfo); }
public void InvalidEncKeyUsage() { EncryptionToken receiver = new EncryptionToken(Utils.ReadFully(GetAbsoluteTestFilePath("etk/invalid_encrkey_usage.etk"))); CertificateSecurityInformation info = receiver.Verify(); Console.WriteLine(info.ToString()); Assert.IsNotNull(info.ToString()); Assert.AreEqual(ETEE::Status.TrustStatus.None, info.TrustStatus); Assert.AreEqual(ValidationStatus.Invalid, info.ValidationStatus); Assert.IsTrue(info.SecurityViolations.Contains(CertSecurityViolation.NotValidForUsage)); }
public void ExpiredEnc() { EncryptionToken receiver = new EncryptionToken(Utils.ReadFully(GetAbsoluteTestFilePath("etk/expired_encr.etk"))); CertificateSecurityInformation info = receiver.Verify(); Console.WriteLine(info.ToString()); Assert.IsNotNull(info.ToString()); Assert.AreEqual(ETEE::Status.TrustStatus.Unsure, info.TrustStatus); Assert.AreEqual(ValidationStatus.Invalid, info.ValidationStatus); Assert.IsTrue(info.SecurityViolations.Contains(CertSecurityViolation.NotTimeValid)); }
public void Bob2() { EncryptionToken receiver = new EncryptionToken(Utils.ReadFully(GetAbsoluteTestFilePath("etk/Bob2_public_key.etk"))); CertificateSecurityInformation info = receiver.Verify(); Console.WriteLine(info.ToString()); Assert.IsNotNull(info.ToString()); Assert.AreEqual(ETEE::Status.TrustStatus.Unsure, info.TrustStatus); Assert.AreEqual(ValidationStatus.Valid, info.ValidationStatus); Assert.IsTrue(info.SecurityViolations.Contains(CertSecurityViolation.IssuerTrustUnknown)); Assert.IsTrue(info.IssuerInfo.SecurityViolations.Contains(CertSecurityViolation.RevocationStatusUnknown)); }
public void MixedKeyAlgorithm() { EncryptionToken receiver = new EncryptionToken(Utils.ReadFully(GetAbsoluteTestFilePath("etk/invalid_key_algorithm.etk"))); CertificateSecurityInformation info = receiver.Verify(); Console.WriteLine(info.ToString()); Assert.IsNotNull(info.ToString()); Assert.AreEqual(ETEE::Status.TrustStatus.None, info.TrustStatus); Assert.AreEqual(ValidationStatus.Valid, info.ValidationStatus); Assert.IsTrue(info.SecurityViolations.Contains(CertSecurityViolation.UntrustedIssuer)); Assert.IsTrue(info.IssuerInfo.SecurityViolations.Contains(CertSecurityViolation.NotValidKeySize)); }
public void NotYetAuth() { EncryptionToken receiver = new EncryptionToken(Utils.ReadFully(GetAbsoluteTestFilePath("etk/not_yet_auth.etk"))); CertificateSecurityInformation info = receiver.Verify(); Console.WriteLine(info.ToString()); Assert.IsNotNull(info.ToString()); Assert.AreEqual(ETEE::Status.TrustStatus.None, info.TrustStatus); Assert.AreEqual(ValidationStatus.Valid, info.ValidationStatus); Assert.IsTrue(info.SecurityViolations.Contains(CertSecurityViolation.UntrustedIssuer)); Assert.IsTrue(info.IssuerInfo.SecurityViolations.Contains(CertSecurityViolation.NotTimeValid)); }
public void DifferentDN() { EncryptionToken receiver = new EncryptionToken(Utils.ReadFully(GetAbsoluteTestFilePath("etk/auth_and_encr_not_same_DN.etk"))); CertificateSecurityInformation info = receiver.Verify(); Console.WriteLine(info.ToString()); Assert.IsNotNull(info.ToString()); Assert.AreEqual(ETEE::Status.TrustStatus.None, info.TrustStatus); //Assert.AreEqual(ValidationStatus.Unsure, info.ValidationStatus); Assert.IsTrue(info.SecurityViolations.Contains(CertSecurityViolation.UntrustedIssuer)); Assert.IsTrue(info.IssuerInfo.SecurityViolations.Contains(CertSecurityViolation.InvalidBasicConstraints)); }
public void ValidButScrambledDN() { EncryptionToken receiver = new EncryptionToken(Utils.ReadFully(GetAbsoluteTestFilePath("etk/valid_but_scrambledDN.etk"))); CertificateSecurityInformation info = receiver.Verify(); Console.WriteLine(info.ToString()); Assert.IsNotNull(info.ToString()); Assert.AreEqual(ETEE::Status.TrustStatus.None, info.TrustStatus); Assert.AreEqual(ValidationStatus.Valid, info.ValidationStatus); Assert.IsTrue(info.SecurityViolations.Contains(CertSecurityViolation.UntrustedIssuer)); Assert.IsTrue(info.IssuerInfo.SecurityViolations.Contains(CertSecurityViolation.NotValidForUsage)); }
public void InvalidKeySize() { EncryptionToken receiver = new EncryptionToken(Utils.ReadFully(GetAbsoluteTestFilePath("etk/invalid_key_size.etk"))); CertificateSecurityInformation info = receiver.Verify(); Console.WriteLine(info.ToString()); Assert.IsNotNull(info.ToString()); Assert.AreEqual(ETEE::Status.TrustStatus.None, info.TrustStatus); Assert.AreEqual(ValidationStatus.Invalid, info.ValidationStatus); Assert.IsTrue(info.SecurityViolations.Contains(CertSecurityViolation.NotValidKeySize)); //This is no longer the case because we allow eID with 1024 bit keys. //Assert.IsTrue(info.IssuerInfo.SecurityViolations.Contains(CertSecurityViolation.NotValidKeySize)); }
public void kgss() { if (DateTime.Now > new DateTime(2015, 4, 22)) { Assert.Inconclusive("KGSS token must be updated"); } EncryptionToken receiver = new EncryptionToken(Utils.ReadFully(GetAbsoluteTestFilePath("etk/kgss.etk"))); CertificateSecurityInformation info = receiver.Verify(); Console.WriteLine(info.ToString()); Assert.IsNotNull(info.ToString()); Assert.AreEqual(ETEE::Status.TrustStatus.Full, info.TrustStatus); Assert.AreEqual(ValidationStatus.Valid, info.ValidationStatus); }
public static CertificateSecurityInformation VerifyEnc(Org.BouncyCastle.X509.X509Certificate encCert, Org.BouncyCastle.X509.X509Certificate authCert, DateTime date, IX509Store certs, bool checkRevocation) { CertificateSecurityInformation result = new CertificateSecurityInformation(); result.Certificate = new X509Certificate2(encCert.GetEncoded()); //check validity try { encCert.CheckValidity(date); } catch (CertificateExpiredException) { result.securityViolations.Add(CertSecurityViolation.NotTimeValid); } catch (CertificateNotYetValidException) { result.securityViolations.Add(CertSecurityViolation.NotTimeValid); } //check key usage int[] keyUsageIndexes = new int[] { 2, 3 }; foreach (int i in keyUsageIndexes) { if (!encCert.GetKeyUsage()[i]) { result.securityViolations.Add(CertSecurityViolation.NotValidForUsage); trace.TraceEvent(TraceEventType.Warning, 0, "The key usage did not have the correct usage flag set"); } } //check issuer/subject if (!encCert.IssuerDN.Equivalent(encCert.SubjectDN, false)) result.securityViolations.Add(CertSecurityViolation.HasNotPermittedNameConstraint); //check key size if (!VerifyKeySize(encCert.GetPublicKey(), EteeActiveConfig.Unseal.MinimumEncryptionKeySize.AsymmerticRecipientKey)) result.securityViolations.Add(CertSecurityViolation.NotValidKeySize); //check key type if (!(encCert.GetPublicKey() is RsaKeyParameters)) result.securityViolations.Add(CertSecurityViolation.NotValidKeyType); if (authCert != null) { //check signature try { encCert.Verify(authCert.GetPublicKey()); } catch (InvalidKeyException) { result.securityViolations.Add(CertSecurityViolation.NotSignatureValid); } //Validate result.IssuerInfo = VerifyBoth(authCert, date, certs, new List<CertificateList>(0), new List<BasicOcspResponse>(0), checkRevocation, false); } else { //We assume that we have the authCert in case it's of a 3rd person, we don't care if its or own encryption cert (we only care for the validity) } return result; }
private static CertificateSecurityInformation Verify(Org.BouncyCastle.X509.X509Certificate cert, DateTime date, IX509Store certs, IList<CertificateList> crls, IList<BasicOcspResponse> ocsps, bool checkRevocation, bool checkTime) { CertificateSecurityInformation result = new CertificateSecurityInformation(); AsymmetricKeyParameter key = cert.GetPublicKey(); //check key type if (!(key is RsaKeyParameters)) { result.securityViolations.Add(CertSecurityViolation.NotValidKeyType); trace.TraceEvent(TraceEventType.Warning, 0, "The key should be RSA but was {0}", key.GetType()); } //check key size if (!VerifyKeySize(key, EteeActiveConfig.Unseal.MinimumSignatureKeySize)) { result.securityViolations.Add(CertSecurityViolation.NotValidKeySize); trace.TraceEvent(TraceEventType.Warning, 0, "The key was smaller then {0}", EteeActiveConfig.Unseal.MinimumSignatureKeySize); } X509Certificate2Collection extraStore = new X509Certificate2Collection(); foreach (Org.BouncyCastle.X509.X509Certificate obj in certs.GetMatches(null)) { extraStore.Add(new X509Certificate2(obj.GetEncoded())); } Chain chain; if (checkRevocation) chain = new X509Certificate2(cert.GetEncoded()).BuildChain(date, extraStore, ref crls, ref ocsps, checkTime ? DateTime.UtcNow : date); else chain = new X509Certificate2(cert.GetEncoded()).BuildBasicChain(date, extraStore); CertificateSecurityInformation dest = null; foreach (ChainElement ce in chain.ChainElements) { if (dest == null) { dest = result; } else { dest.IssuerInfo = new CertificateSecurityInformation(); dest = dest.IssuerInfo; } dest.Certificate = ce.Certificate; foreach (X509ChainStatus status in ce.ChainElementStatus.Where(x => x.Status != X509ChainStatusFlags.NoError)) { dest.securityViolations.Add((CertSecurityViolation)Enum.Parse(typeof(CertSecurityViolation), Enum.GetName(typeof(X509ChainStatusFlags), status.Status))); } } if (chain.ChainStatus.Count(x => x.Status == X509ChainStatusFlags.PartialChain) > 0) { result.securityViolations.Add(CertSecurityViolation.IssuerTrustUnknown); } trace.TraceEvent(TraceEventType.Verbose, 0, "Verified certificate {0} for date {1}", cert.SubjectDN.ToString(), date); return result; }
public static CertificateSecurityInformation Verify(this Org.BouncyCastle.X509.X509Certificate cert, DateTime date, int[] keyUsageIndexes, int minimumKeySize, IX509Store certs, ref IList <CertificateList> crls, ref IList <BasicOcspResponse> ocsps) { CertificateSecurityInformation result = new CertificateSecurityInformation(); result.Certificate = new X509Certificate2(cert.GetEncoded()); //check key size AsymmetricKeyParameter key = cert.GetPublicKey(); if (!VerifyKeySize(key, minimumKeySize)) { result.securityViolations.Add(CertSecurityViolation.NotValidKeySize); trace.TraceEvent(TraceEventType.Warning, 0, "The key was smaller then {0}", minimumKeySize); } //check key usages foreach (int i in keyUsageIndexes) { if (!cert.GetKeyUsage()[i]) { result.securityViolations.Add(CertSecurityViolation.NotValidForUsage); trace.TraceEvent(TraceEventType.Warning, 0, "The key usage did not have the correct usage flag {0} set", i); } } //build extra store X509Certificate2Collection extraStore = new X509Certificate2Collection(); foreach (Org.BouncyCastle.X509.X509Certificate obj in certs.GetMatches(null)) { extraStore.Add(new X509Certificate2(obj.GetEncoded())); } CertificateSecurityInformation dest = result; CertificateSecurityInformation previous = null; Org.BouncyCastle.X509.X509Certificate issuer = cert.ValidateAndGetDerivedIssuer(certs); if (issuer != null) { trace.TraceEvent(TraceEventType.Verbose, 0, "Detected eHealth variant of proxy certificate"); //check proxy certificate, is it still valid? if (!cert.IsValid(date)) { dest.securityViolations.Add(CertSecurityViolation.NotTimeValid); trace.TraceEvent(TraceEventType.Warning, 0, "The proxy certificate is expired or not yet valid, {0} not between {1}-{2}", date, cert.NotBefore, cert.NotAfter); } //The issuer signature of the proxy certificate is already checked... //check issuer previous = dest; dest = new CertificateSecurityInformation(); dest.Certificate = new X509Certificate2(issuer.GetEncoded()); //check key size of the issuer key = issuer.GetPublicKey(); if (!VerifyKeySize(key, minimumKeySize)) { dest.securityViolations.Add(CertSecurityViolation.NotValidKeySize); trace.TraceEvent(TraceEventType.Warning, 0, "The key of the issuer was smaller then {0}", minimumKeySize); } //check key usage of the issuer foreach (int i in new int[] { 0, 1 }) { if (!issuer.GetKeyUsage()[i]) { dest.securityViolations.Add(CertSecurityViolation.NotValidForUsage); trace.TraceEvent(TraceEventType.Warning, 0, "The key usage of the issuer did not have the correct usage flag set"); } } } //check the chain Chain chain; if (crls != null || ocsps != null) { chain = dest.Certificate.BuildChain(date, extraStore, crls, ocsps); } else { chain = dest.Certificate.BuildChain(date, extraStore); } //process the chain foreach (ChainElement ce in chain.ChainElements) { //connect the prepared link if (previous != null) { previous.IssuerInfo = dest; } //update the link dest.Certificate = ce.Certificate; foreach (X509ChainStatus status in ce.ChainElementStatus.Where(x => x.Status != X509ChainStatusFlags.NoError)) { dest.securityViolations.Add((CertSecurityViolation)Enum.Parse(typeof(CertSecurityViolation), Enum.GetName(typeof(X509ChainStatusFlags), status.Status))); } //prepare the next link previous = dest; dest = new CertificateSecurityInformation(); } if (chain.ChainStatus.Count(x => x.Status == X509ChainStatusFlags.PartialChain) > 0) { result.securityViolations.Add(CertSecurityViolation.IssuerTrustUnknown); } trace.TraceEvent(TraceEventType.Verbose, 0, "Verified certificate {0} for date {1}", cert.SubjectDN.ToString(), date); return(result); }