seb-win-refactoring/SafeExamBrowser.Configuration/Cryptography/CertificateStore.cs

123 lines
3.4 KiB
C#
Raw Normal View History

/*
* Copyright (c) 2024 ETH Zürich, IT Services
*
* 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();
}
}
}
}