seb-win-refactoring/SafeExamBrowser.Configuration/Cryptography/CertificateStore.cs
2021-02-03 00:45:33 +01:00

122 lines
3.4 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using SafeExamBrowser.Configuration.ConfigurationData;
using SafeExamBrowser.Configuration.Contracts.Cryptography;
using SafeExamBrowser.Logging.Contracts;
namespace SafeExamBrowser.Configuration.Cryptography
{
public class CertificateStore : ICertificateStore
{
private ILogger logger;
private readonly X509Store[] stores = new[]
{
new X509Store(StoreLocation.CurrentUser),
new X509Store(StoreLocation.LocalMachine),
new X509Store(StoreName.TrustedPeople)
};
public CertificateStore(ILogger logger)
{
this.logger = logger;
}
public bool TryGetCertificateWith(byte[] keyHash, out X509Certificate2 certificate)
{
certificate = default(X509Certificate2);
using (var algorithm = new SHA1CryptoServiceProvider())
{
foreach (var store in stores)
{
try
{
store.Open(OpenFlags.ReadOnly);
foreach (var current in store.Certificates)
{
var publicKey = current.PublicKey.EncodedKeyValue.RawData;
var publicKeyHash = algorithm.ComputeHash(publicKey);
if (publicKeyHash.SequenceEqual(keyHash))
{
certificate = current;
return true;
}
}
}
finally
{
store.Close();
}
}
}
return false;
}
public void ExtractAndImportIdentities(IDictionary<string, object> data)
{
const int IDENTITY_CERTIFICATE = 1;
var hasCertificates = data.TryGetValue(Keys.Network.Certificates.EmbeddedCertificates, out var value);
if (hasCertificates && value is IList<IDictionary<string, object>> certificates)
{
var toRemove = new List<IDictionary<string, object>>();
foreach (var certificate in certificates)
{
var hasData = certificate.TryGetValue(Keys.Network.Certificates.CertificateData, out var dataValue);
var hasType = certificate.TryGetValue(Keys.Network.Certificates.CertificateType, out var typeValue);
var isIdentity = typeValue is int type && type == IDENTITY_CERTIFICATE;
if (hasData && hasType && isIdentity && dataValue is byte[] certificateData)
{
ImportIdentityCertificate(certificateData, new X509Store(StoreLocation.CurrentUser));
ImportIdentityCertificate(certificateData, new X509Store(StoreName.TrustedPeople, StoreLocation.LocalMachine));
toRemove.Add(certificate);
}
}
toRemove.ForEach(c => certificates.Remove(c));
}
}
private void ImportIdentityCertificate(byte[] certificateData, X509Store store)
{
try
{
var certificate = new X509Certificate2();
certificate.Import(certificateData, "Di𝈭l𝈖Ch𝈒ah𝉇t𝈁a𝉈Hai1972", X509KeyStorageFlags.UserKeySet | X509KeyStorageFlags.PersistKeySet);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
logger.Info($"Successfully imported identity certificate into {store.Location}.{store.Name}.");
}
catch (Exception e)
{
logger.Error($"Failed to import identity certificate into {store.Location}.{store.Name}!", e);
}
finally
{
store.Close();
}
}
}
}