Skip to content

Commit 863a203

Browse files
committed
Added support for checking CRLs to BouncyCastleSecureMimeContext
Based on work that @JoeShook had started in pr #1116
1 parent fbf7e17 commit 863a203

22 files changed

+565
-51
lines changed

MimeKit/Cryptography/BouncyCastleSecureMimeContext.cs

+24-26
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ namespace MimeKit.Cryptography {
6767
public abstract class BouncyCastleSecureMimeContext : SecureMimeContext
6868
{
6969
static readonly string RsassaPssOid = PkcsObjectIdentifiers.IdRsassaPss.Id;
70-
71-
HttpClient client;
70+
static readonly HttpClient SharedHttpClient = new HttpClient ();
7271

7372
/// <summary>
7473
/// Initialize a new instance of the <see cref="SecureMimeContext"/> class.
@@ -96,7 +95,6 @@ protected BouncyCastleSecureMimeContext (SecureRandom random)
9695
throw new ArgumentNullException (nameof (random));
9796

9897
RandomNumberGenerator = random;
99-
client = new HttpClient ();
10098
}
10199

102100
/// <summary>
@@ -129,6 +127,17 @@ public bool CheckCertificateRevocation {
129127
get; set;
130128
}
131129

130+
/// <summary>
131+
/// Get the HTTP client to use for downloading CRLs.
132+
/// </summary>
133+
/// <remarks>
134+
/// Gets the HTTP client to use for downloading CRLs.
135+
/// </remarks>
136+
/// <value>The HTTP client used for downloading CRLs.</value>
137+
protected virtual HttpClient HttpClient {
138+
get { return SharedHttpClient; }
139+
}
140+
132141
/// <summary>
133142
/// Get the X.509 certificate matching the specified selector.
134143
/// </summary>
@@ -694,12 +703,11 @@ protected IList<X509Certificate> BuildCertificateChain (X509Certificate certific
694703

695704
var parameters = new PkixBuilderParameters (GetTrustedAnchors (), selector) {
696705
ValidityModel = PkixParameters.PkixValidityModel,
697-
IsRevocationEnabled = CheckCertificateRevocation,
706+
IsRevocationEnabled = false,
698707
Date = DateTime.UtcNow
699708
};
700709
parameters.AddStoreCert (intermediates);
701710
parameters.AddStoreCert (GetIntermediateCertificates ());
702-
parameters.AddStoreCrl (GetCertificateRevocationLists ());
703711

704712
var builder = new PkixCertPathBuilder ();
705713
var result = builder.Build (parameters);
@@ -879,7 +887,7 @@ async Task<bool> DownloadCrlsOverHttpAsync (string location, Stream stream, bool
879887
{
880888
try {
881889
if (doAsync) {
882-
using (var response = await client.GetAsync (location, cancellationToken).ConfigureAwait (false)) {
890+
using (var response = await HttpClient.GetAsync (location, cancellationToken).ConfigureAwait (false)) {
883891
#if NET6_0_OR_GREATER
884892
await response.Content.CopyToAsync (stream, cancellationToken).ConfigureAwait (false);
885893
#else
@@ -888,7 +896,7 @@ async Task<bool> DownloadCrlsOverHttpAsync (string location, Stream stream, bool
888896
}
889897
} else {
890898
#if NET6_0_OR_GREATER
891-
using (var response = client.GetAsync (location, cancellationToken).GetAwaiter ().GetResult ())
899+
using (var response = HttpClient.GetAsync (location, cancellationToken).GetAwaiter ().GetResult ())
892900
response.Content.CopyToAsync (stream, cancellationToken).GetAwaiter ().GetResult ();
893901
#else
894902
cancellationToken.ThrowIfCancellationRequested ();
@@ -1047,8 +1055,10 @@ async Task<DigitalSignatureCollection> GetDigitalSignaturesAsync (CmsSignedDataP
10471055
var certificate = GetCertificate (certificates, signerInfo.SignerID);
10481056
var signature = new SecureMimeDigitalSignature (signerInfo, certificate);
10491057

1050-
if (CheckCertificateRevocation && certificate != null)
1051-
await DownloadCrlsAsync (certificate, doAsync, cancellationToken).ConfigureAwait (false);
1058+
if (CheckCertificateRevocation) {
1059+
foreach (var cert in certificates.EnumerateMatches (null))
1060+
await DownloadCrlsAsync (cert, doAsync, cancellationToken).ConfigureAwait (false);
1061+
}
10521062

10531063
if (certificate != null) {
10541064
Import (certificate, cancellationToken);
@@ -1059,6 +1069,11 @@ async Task<DigitalSignatureCollection> GetDigitalSignaturesAsync (CmsSignedDataP
10591069

10601070
var anchors = GetTrustedAnchors ();
10611071

1072+
if (CheckCertificateRevocation) {
1073+
foreach (var anchor in anchors)
1074+
await DownloadCrlsAsync (anchor.TrustedCert, doAsync, cancellationToken).ConfigureAwait (false);
1075+
}
1076+
10621077
try {
10631078
signature.Chain = BuildCertPath (anchors, certificates, crls, certificate, signature.CreationDate);
10641079
} catch (Exception ex) {
@@ -1832,22 +1847,5 @@ public override Task<MimePart> ExportAsync (IEnumerable<MailboxAddress> mailboxe
18321847
{
18331848
return Task.FromResult (Export (mailboxes, cancellationToken));
18341849
}
1835-
1836-
/// <summary>
1837-
/// Releases all resources used by the <see cref="BouncyCastleSecureMimeContext"/> object.
1838-
/// </summary>
1839-
/// <remarks>Call <see cref="CryptographyContext.Dispose()"/> when you are finished using the <see cref="BouncyCastleSecureMimeContext"/>. The
1840-
/// <see cref="CryptographyContext.Dispose()"/> method leaves the <see cref="BouncyCastleSecureMimeContext"/> in an unusable state. After
1841-
/// calling <see cref="CryptographyContext.Dispose()"/>, you must release all references to the <see cref="BouncyCastleSecureMimeContext"/> so
1842-
/// the garbage collector can reclaim the memory that the <see cref="BouncyCastleSecureMimeContext"/> was occupying.</remarks>
1843-
protected override void Dispose (bool disposing)
1844-
{
1845-
if (disposing && client != null) {
1846-
client.Dispose ();
1847-
client = null;
1848-
}
1849-
1850-
base.Dispose (disposing);
1851-
}
18521850
}
18531851
}

0 commit comments

Comments
 (0)