Skip to content

Commit

Permalink
Started abstracting out the CryptographyContext stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
jstedfast committed Feb 10, 2024
1 parent c33db55 commit 8cbcf82
Show file tree
Hide file tree
Showing 12 changed files with 1,547 additions and 209 deletions.
148 changes: 74 additions & 74 deletions MimeKit/Cryptography/ApplicationPkcs7Mime.cs

Large diffs are not rendered by default.

73 changes: 42 additions & 31 deletions MimeKit/Cryptography/CryptographyContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
using System;
using System.IO;
using System.Threading;
using System.Reflection;
using System.Threading.Tasks;
using System.Collections.Generic;

Expand All @@ -43,8 +42,8 @@ namespace MimeKit.Cryptography {
public abstract class CryptographyContext : ICryptographyContext
{
const string SubclassAndRegisterFormat = "You need to subclass {0} and then register it with MimeKit.Cryptography.CryptographyContext.Register().";
static Func<SecureMimeContext> SecureMimeContextFactory;
static Func<OpenPgpContext> PgpContextFactory;
static Func<ISecureMimeContext> SecureMimeContextFactory;
static Func<IOpenPgpContext> OpenPgpContextFactory;
static readonly object mutex = new object ();

EncryptionAlgorithm[] encryptionAlgorithmRank;
Expand Down Expand Up @@ -715,7 +714,7 @@ public void Dispose ()
/// There are no supported <see cref="CryptographyContext"/>s that support
/// the specified <paramref name="protocol"/>.
/// </exception>
public static CryptographyContext Create (string protocol)
public static ICryptographyContext Create (string protocol)
{
if (protocol == null)
throw new ArgumentNullException (nameof (protocol));
Expand All @@ -740,8 +739,8 @@ public static CryptographyContext Create (string protocol)
case "application/pgp-encrypted":
case "application/x-pgp-keys":
case "application/pgp-keys":
if (PgpContextFactory != null)
return PgpContextFactory ();
if (OpenPgpContextFactory != null)
return OpenPgpContextFactory ();

throw new NotSupportedException (string.Format (SubclassAndRegisterFormat, "MimeKit.Cryptography.OpenPgpContext or MimeKit.Cryptography.GnuPGContext"));
default:
Expand All @@ -751,20 +750,20 @@ public static CryptographyContext Create (string protocol)
}

/// <summary>
/// Registers a default <see cref="SecureMimeContext"/> or <see cref="OpenPgpContext"/>.
/// Registers a default <see cref="ISecureMimeContext"/> or <see cref="IOpenPgpContext"/>.
/// </summary>
/// <remarks>
/// Registers the specified type as the default <see cref="SecureMimeContext"/> or
/// <see cref="OpenPgpContext"/>.
/// Registers the specified type as the default <see cref="ISecureMimeContext"/> or
/// <see cref="IOpenPgpContext"/> implementation.
/// </remarks>
/// <param name="type">A custom subclass of <see cref="SecureMimeContext"/> or
/// <see cref="OpenPgpContext"/>.</param>
/// <param name="type">A custom class that implements the <see cref="ISecureMimeContext"/> or
/// <see cref="IOpenPgpContext"/> interface.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="type"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <para><paramref name="type"/> is not a subclass of
/// <see cref="SecureMimeContext"/> or <see cref="OpenPgpContext"/>.</para>
/// <para><paramref name="type"/> does not implement the <see cref="ISecureMimeContext"/> or
/// <see cref="IOpenPgpContext"/> interface.</para>
/// <para>-or-</para>
/// <para><paramref name="type"/> does not have a parameterless constructor.</para>
/// </exception>
Expand All @@ -773,36 +772,48 @@ public static void Register (Type type)
if (type == null)
throw new ArgumentNullException (nameof (type));

if (!type.IsClass || type.IsAbstract)
throw new ArgumentException ("The specified type must be a concrete class.", nameof (type));

var ctor = type.GetConstructor (Array.Empty<Type> ());
var args = Array.Empty<object> ();

if (ctor == null)
throw new ArgumentException ("The specified type must have a parameterless constructor.", nameof (type));

if (type.IsSubclassOf (typeof (SecureMimeContext))) {
lock (mutex) {
SecureMimeContextFactory = () => (SecureMimeContext) ctor.Invoke (args);
var interfaces = type.GetInterfaces ();
bool registered = false;

for (int i = 0; i < interfaces.Length; i++) {
if (interfaces[i] == typeof (ISecureMimeContext)) {
lock (mutex) {
SecureMimeContextFactory = () => (ISecureMimeContext) ctor.Invoke (Array.Empty<object> ());
}
registered = true;
}
} else if (type.IsSubclassOf (typeof (OpenPgpContext))) {
lock (mutex) {
PgpContextFactory = () => (OpenPgpContext) ctor.Invoke (args);

if (interfaces[i] == typeof (IOpenPgpContext)) {
lock (mutex) {
OpenPgpContextFactory = () => (IOpenPgpContext) ctor.Invoke (Array.Empty<object> ());
}
registered = true;
}
} else {
throw new ArgumentException ("The specified type must be a subclass of SecureMimeContext or OpenPgpContext.", nameof (type));
}

if (!registered)
throw new ArgumentException ("The specified type must implement the ISecureMimeContext or IOpenPgpContext interface.", nameof (type));
}

/// <summary>
/// Registers a default <see cref="SecureMimeContext"/> factory.
/// Registers a default <see cref="ISecureMimeContext"/> factory.
/// </summary>
/// <remarks>
/// Registers a factory that will return a new instance of the default <see cref="SecureMimeContext"/>.
/// Registers a factory that will return a new instance of the default <see cref="ISecureMimeContext"/>.
/// </remarks>
/// <param name="factory">A factory that creates a new instance of <see cref="SecureMimeContext"/>.</param>
/// <param name="factory">A factory that creates a new instance of <see cref="ISecureMimeContext"/>.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="factory"/> is <c>null</c>.
/// </exception>
public static void Register (Func<SecureMimeContext> factory)
public static void Register (Func<ISecureMimeContext> factory)
{
if (factory == null)
throw new ArgumentNullException (nameof (factory));
Expand All @@ -813,22 +824,22 @@ public static void Register (Func<SecureMimeContext> factory)
}

/// <summary>
/// Registers a default <see cref="OpenPgpContext"/> factory.
/// Registers a default <see cref="IOpenPgpContext"/> factory.
/// </summary>
/// <remarks>
/// Registers a factory that will return a new instance of the default <see cref="OpenPgpContext"/>.
/// Registers a factory that will return a new instance of the default <see cref="IOpenPgpContext"/>.
/// </remarks>
/// <param name="factory">A factory that creates a new instance of <see cref="OpenPgpContext"/>.</param>
/// <param name="factory">A factory that creates a new instance of <see cref="IOpenPgpContext"/>.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="factory"/> is <c>null</c>.
/// </exception>
public static void Register (Func<OpenPgpContext> factory)
public static void Register (Func<IOpenPgpContext> factory)
{
if (factory == null)
throw new ArgumentNullException (nameof (factory));

lock (mutex) {
PgpContextFactory = factory;
OpenPgpContextFactory = factory;
}
}
}
Expand Down
32 changes: 16 additions & 16 deletions MimeKit/Cryptography/IApplicationPkcs7Mime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public interface IApplicationPkcs7Mime : IMimePart
/// Decompress the compressed-data.
/// </summary>
/// <remarks>
/// Decompresses the compressed-data using the specified <see cref="SecureMimeContext"/>.
/// Decompresses the compressed-data using the specified <see cref="ISecureMimeContext"/>.
/// </remarks>
/// <returns>The decompressed <see cref="MimeEntity"/>.</returns>
/// <param name="ctx">The S/MIME context to use for decompressing.</param>
Expand All @@ -72,13 +72,13 @@ public interface IApplicationPkcs7Mime : IMimePart
/// <exception cref="Org.BouncyCastle.Cms.CmsException">
/// An error occurred in the cryptographic message syntax subsystem.
/// </exception>
MimeEntity Decompress (SecureMimeContext ctx, CancellationToken cancellationToken = default);
MimeEntity Decompress (ISecureMimeContext ctx, CancellationToken cancellationToken = default);

/// <summary>
/// Asynchronously decompress the compressed-data.
/// </summary>
/// <remarks>
/// Asynchronously decompresses the compressed-data using the specified <see cref="SecureMimeContext"/>.
/// Asynchronously decompresses the compressed-data using the specified <see cref="ISecureMimeContext"/>.
/// </remarks>
/// <returns>The decompressed <see cref="MimeEntity"/>.</returns>
/// <param name="ctx">The S/MIME context to use for decompressing.</param>
Expand All @@ -98,13 +98,13 @@ public interface IApplicationPkcs7Mime : IMimePart
/// <exception cref="Org.BouncyCastle.Cms.CmsException">
/// An error occurred in the cryptographic message syntax subsystem.
/// </exception>
Task<MimeEntity> DecompressAsync (SecureMimeContext ctx, CancellationToken cancellationToken = default);
Task<MimeEntity> DecompressAsync (ISecureMimeContext ctx, CancellationToken cancellationToken = default);

/// <summary>
/// Decompress the compressed-data.
/// </summary>
/// <remarks>
/// Decompresses the compressed-data using the default <see cref="SecureMimeContext"/>.
/// Decompresses the compressed-data using the default <see cref="ISecureMimeContext"/>.
/// </remarks>
/// <returns>The decompressed <see cref="MimeEntity"/>.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
Expand All @@ -126,7 +126,7 @@ public interface IApplicationPkcs7Mime : IMimePart
/// Asynchronously decompress the compressed-data.
/// </summary>
/// <remarks>
/// Asynchronously decompresses the compressed-data using the default <see cref="SecureMimeContext"/>.
/// Asynchronously decompresses the compressed-data using the default <see cref="ISecureMimeContext"/>.
/// </remarks>
/// <returns>The decompressed <see cref="MimeEntity"/>.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
Expand All @@ -148,7 +148,7 @@ public interface IApplicationPkcs7Mime : IMimePart
/// Decrypt the enveloped-data.
/// </summary>
/// <remarks>
/// Decrypts the enveloped-data using the specified <see cref="SecureMimeContext"/>.
/// Decrypts the enveloped-data using the specified <see cref="ISecureMimeContext"/>.
/// </remarks>
/// <returns>The decrypted <see cref="MimeEntity"/>.</returns>
/// <param name="ctx">The S/MIME context to use for decrypting.</param>
Expand All @@ -168,13 +168,13 @@ public interface IApplicationPkcs7Mime : IMimePart
/// <exception cref="Org.BouncyCastle.Cms.CmsException">
/// An error occurred in the cryptographic message syntax subsystem.
/// </exception>
MimeEntity Decrypt (SecureMimeContext ctx, CancellationToken cancellationToken = default);
MimeEntity Decrypt (ISecureMimeContext ctx, CancellationToken cancellationToken = default);

/// <summary>
/// Asynchronously decrypt the enveloped-data.
/// </summary>
/// <remarks>
/// Asynchronously decrypts the enveloped-data using the specified <see cref="SecureMimeContext"/>.
/// Asynchronously decrypts the enveloped-data using the specified <see cref="ISecureMimeContext"/>.
/// </remarks>
/// <returns>The decrypted <see cref="MimeEntity"/>.</returns>
/// <param name="ctx">The S/MIME context to use for decrypting.</param>
Expand All @@ -194,13 +194,13 @@ public interface IApplicationPkcs7Mime : IMimePart
/// <exception cref="Org.BouncyCastle.Cms.CmsException">
/// An error occurred in the cryptographic message syntax subsystem.
/// </exception>
Task<MimeEntity> DecryptAsync (SecureMimeContext ctx, CancellationToken cancellationToken = default);
Task<MimeEntity> DecryptAsync (ISecureMimeContext ctx, CancellationToken cancellationToken = default);

/// <summary>
/// Decrypt the enveloped-data.
/// </summary>
/// <remarks>
/// Decrypts the enveloped-data using the default <see cref="SecureMimeContext"/>.
/// Decrypts the enveloped-data using the default <see cref="ISecureMimeContext"/>.
/// </remarks>
/// <returns>The decrypted <see cref="MimeEntity"/>.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
Expand All @@ -222,7 +222,7 @@ public interface IApplicationPkcs7Mime : IMimePart
/// Asynchronously decrypt the enveloped-data.
/// </summary>
/// <remarks>
/// Asynchronously decrypts the enveloped-data using the default <see cref="SecureMimeContext"/>.
/// Asynchronously decrypts the enveloped-data using the default <see cref="ISecureMimeContext"/>.
/// </remarks>
/// <returns>The decrypted <see cref="MimeEntity"/>.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
Expand Down Expand Up @@ -263,7 +263,7 @@ public interface IApplicationPkcs7Mime : IMimePart
/// <exception cref="Org.BouncyCastle.Cms.CmsException">
/// An error occurred in the cryptographic message syntax subsystem.
/// </exception>
void Import (SecureMimeContext ctx, CancellationToken cancellationToken = default);
void Import (ISecureMimeContext ctx, CancellationToken cancellationToken = default);

/// <summary>
/// Asynchronously import the certificates contained in the application/pkcs7-mime content.
Expand All @@ -289,7 +289,7 @@ public interface IApplicationPkcs7Mime : IMimePart
/// <exception cref="Org.BouncyCastle.Cms.CmsException">
/// An error occurred in the cryptographic message syntax subsystem.
/// </exception>
Task ImportAsync (SecureMimeContext ctx, CancellationToken cancellationToken = default);
Task ImportAsync (ISecureMimeContext ctx, CancellationToken cancellationToken = default);

/// <summary>
/// Verify the signed-data and return the unencapsulated <see cref="MimeEntity"/>.
Expand Down Expand Up @@ -319,13 +319,13 @@ public interface IApplicationPkcs7Mime : IMimePart
/// <exception cref="Org.BouncyCastle.Cms.CmsException">
/// An error occurred in the cryptographic message syntax subsystem.
/// </exception>
DigitalSignatureCollection Verify (SecureMimeContext ctx, out MimeEntity entity, CancellationToken cancellationToken = default);
DigitalSignatureCollection Verify (ISecureMimeContext ctx, out MimeEntity entity, CancellationToken cancellationToken = default);

/// <summary>
/// Verifies the signed-data and returns the unencapsulated <see cref="MimeEntity"/>.
/// </summary>
/// <remarks>
/// Verifies the signed-data using the default <see cref="SecureMimeContext"/> and returns the
/// Verifies the signed-data using the default <see cref="ISecureMimeContext"/> and returns the
/// unencapsulated <see cref="MimeEntity"/>.
/// </remarks>
/// <returns>The list of digital signatures.</returns>
Expand Down
12 changes: 6 additions & 6 deletions MimeKit/Cryptography/IMultipartEncrypted.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public interface IMultipartEncrypted : IMultipart
/// <para>The multipart is malformed in some way.</para>
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The provided <see cref="OpenPgpContext"/> does not support the protocol parameter.
/// The provided <see cref="IOpenPgpContext"/> does not support the protocol parameter.
/// </exception>
/// <exception cref="PrivateKeyNotFoundException">
/// The private key could not be found to decrypt the encrypted data.
Expand All @@ -71,7 +71,7 @@ public interface IMultipartEncrypted : IMultipart
/// <exception cref="System.UnauthorizedAccessException">
/// 3 bad attempts were made to unlock the secret key.
/// </exception>
MimeEntity Decrypt (OpenPgpContext ctx, out DigitalSignatureCollection signatures, CancellationToken cancellationToken = default);
MimeEntity Decrypt (IOpenPgpContext ctx, out DigitalSignatureCollection signatures, CancellationToken cancellationToken = default);

/// <summary>
/// Decrypts the <see cref="IMultipartEncrypted"/> part.
Expand All @@ -91,7 +91,7 @@ public interface IMultipartEncrypted : IMultipart
/// <para>The multipart is malformed in some way.</para>
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The provided <see cref="OpenPgpContext"/> does not support the protocol parameter.
/// The provided <see cref="IOpenPgpContext"/> does not support the protocol parameter.
/// </exception>
/// <exception cref="PrivateKeyNotFoundException">
/// The private key could not be found to decrypt the encrypted data.
Expand All @@ -107,7 +107,7 @@ public interface IMultipartEncrypted : IMultipart
/// <exception cref="System.UnauthorizedAccessException">
/// 3 bad attempts were made to unlock the secret key.
/// </exception>
MimeEntity Decrypt (OpenPgpContext ctx, CancellationToken cancellationToken = default);
MimeEntity Decrypt (IOpenPgpContext ctx, CancellationToken cancellationToken = default);

/// <summary>
/// Decrypts the <see cref="IMultipartEncrypted"/> part.
Expand All @@ -125,7 +125,7 @@ public interface IMultipartEncrypted : IMultipart
/// <para>The multipart is malformed in some way.</para>
/// </exception>
/// <exception cref="System.NotSupportedException">
/// A suitable <see cref="CryptographyContext"/> for
/// A suitable <see cref="ICryptographyContext"/> for
/// decrypting could not be found.
/// </exception>
/// <exception cref="PrivateKeyNotFoundException">
Expand Down Expand Up @@ -158,7 +158,7 @@ public interface IMultipartEncrypted : IMultipart
/// <para>The multipart is malformed in some way.</para>
/// </exception>
/// <exception cref="System.NotSupportedException">
/// A suitable <see cref="CryptographyContext"/> for
/// A suitable <see cref="ICryptographyContext"/> for
/// decrypting could not be found.
/// </exception>
/// <exception cref="PrivateKeyNotFoundException">
Expand Down
4 changes: 2 additions & 2 deletions MimeKit/Cryptography/IMultipartSigned.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public interface IMultipartSigned : IMultipart
/// <exception cref="Org.BouncyCastle.Cms.CmsException">
/// An error occurred in the cryptographic message syntax subsystem.
/// </exception>
DigitalSignatureCollection Verify (CryptographyContext ctx, CancellationToken cancellationToken = default);
DigitalSignatureCollection Verify (ICryptographyContext ctx, CancellationToken cancellationToken = default);

/// <summary>
/// Verify the multipart/signed part.
Expand Down Expand Up @@ -94,7 +94,7 @@ public interface IMultipartSigned : IMultipart
/// <exception cref="Org.BouncyCastle.Cms.CmsException">
/// An error occurred in the cryptographic message syntax subsystem.
/// </exception>
Task<DigitalSignatureCollection> VerifyAsync (CryptographyContext ctx, CancellationToken cancellationToken = default);
Task<DigitalSignatureCollection> VerifyAsync (ICryptographyContext ctx, CancellationToken cancellationToken = default);

/// <summary>
/// Verify the multipart/signed part.
Expand Down

0 comments on commit 8cbcf82

Please sign in to comment.