-
-
Notifications
You must be signed in to change notification settings - Fork 372
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Abstract DKIM/ARC support into interfaces
The idea here is to provide the DKIM interfaces in the core MimeKit package, but provide the BouncyCastle implementation of said interfaces in a future MimeKit.Cryptography package. Partial fix for issue #820
- Loading branch information
Showing
25 changed files
with
1,362 additions
and
237 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// | ||
// BouncyCastleDkimKey.cs | ||
// | ||
// Author: Jeffrey Stedfast <[email protected]> | ||
// | ||
// Copyright (c) 2013-2024 .NET Foundation and Contributors | ||
// | ||
// Permission is hereby granted, free of charge, to any person obtaining a copy | ||
// of this software and associated documentation files (the "Software"), to deal | ||
// in the Software without restriction, including without limitation the rights | ||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
// copies of the Software, and to permit persons to whom the Software is | ||
// furnished to do so, subject to the following conditions: | ||
// | ||
// The above copyright notice and this permission notice shall be included in | ||
// all copies or substantial portions of the Software. | ||
// | ||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
// THE SOFTWARE. | ||
// | ||
|
||
using System; | ||
|
||
using Org.BouncyCastle.Crypto; | ||
using Org.BouncyCastle.Crypto.Digests; | ||
using Org.BouncyCastle.Crypto.Signers; | ||
|
||
namespace MimeKit.Cryptography { | ||
/// <summary> | ||
/// A base class for <see cref="BouncyCastleDkimPublicKey"/> and <see cref="BouncyCastleDkimPrivateKey" />. | ||
/// </summary> | ||
/// <remarks> | ||
/// A base class for <see cref="BouncyCastleDkimPublicKey"/> and <see cref="BouncyCastleDkimPrivateKey" />. | ||
/// </remarks> | ||
public abstract class BouncyCastleDkimKey | ||
{ | ||
/// <summary> | ||
/// Get the private key. | ||
/// </summary> | ||
/// <remarks> | ||
/// Gets the private key. | ||
/// </remarks> | ||
public AsymmetricKeyParameter Key { | ||
get; protected set; | ||
} | ||
|
||
/// <summary> | ||
/// Create a DKIM signature context. | ||
/// </summary> | ||
/// <remarks> | ||
/// Creates a DKIM signature context. | ||
/// </remarks> | ||
/// <param name="algorithm">The DKIM signature algorithm.</param> | ||
/// <param name="sign">If set to <c>true</c>, the context will be used for signing; otherwise, it will be used for verifying.</param> | ||
/// <returns>The DKIM signature context.</returns> | ||
/// <exception cref="NotSupportedException"> | ||
/// The specified <paramref name="algorithm"/> is not supported. | ||
/// </exception> | ||
protected IDkimSignatureContext CreateSignatureContext (DkimSignatureAlgorithm algorithm, bool sign) | ||
{ | ||
ISigner signer; | ||
|
||
switch (algorithm) { | ||
case DkimSignatureAlgorithm.RsaSha1: | ||
signer = new RsaDigestSigner (new Sha1Digest ()); | ||
break; | ||
case DkimSignatureAlgorithm.RsaSha256: | ||
signer = new RsaDigestSigner (new Sha256Digest ()); | ||
break; | ||
case DkimSignatureAlgorithm.Ed25519Sha256: | ||
signer = new Ed25519DigestSigner (new Sha256Digest ()); | ||
break; | ||
default: | ||
throw new NotSupportedException ($"{algorithm} is not supported."); | ||
} | ||
|
||
signer.Init (sign, Key); | ||
|
||
return new BouncyCastleDkimSignatureContext (signer); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
// | ||
// BouncyCastleDkimPrivateKey.cs | ||
// | ||
// Author: Jeffrey Stedfast <[email protected]> | ||
// | ||
// Copyright (c) 2013-2024 .NET Foundation and Contributors | ||
// | ||
// Permission is hereby granted, free of charge, to any person obtaining a copy | ||
// of this software and associated documentation files (the "Software"), to deal | ||
// in the Software without restriction, including without limitation the rights | ||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
// copies of the Software, and to permit persons to whom the Software is | ||
// furnished to do so, subject to the following conditions: | ||
// | ||
// The above copyright notice and this permission notice shall be included in | ||
// all copies or substantial portions of the Software. | ||
// | ||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
// THE SOFTWARE. | ||
// | ||
|
||
using System; | ||
using System.IO; | ||
|
||
using Org.BouncyCastle.Crypto; | ||
using Org.BouncyCastle.OpenSsl; | ||
|
||
namespace MimeKit.Cryptography { | ||
/// <summary> | ||
/// A DKIM private key implemented using BouncyCastle. | ||
/// </summary> | ||
/// <remarks> | ||
/// A DKIM private key implemented using BouncyCastle. | ||
/// </remarks> | ||
public class BouncyCastleDkimPrivateKey : BouncyCastleDkimKey, IDkimPrivateKey | ||
{ | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="BouncyCastleDkimPrivateKey"/> class. | ||
/// </summary> | ||
/// <remarks> | ||
/// Creates a new <see cref="BouncyCastleDkimPrivateKey"/>. | ||
/// </remarks> | ||
/// <param name="key">The private key.</param> | ||
/// <exception cref="System.ArgumentNullException"> | ||
/// <paramref name="key"/> is <c>null</c>. | ||
/// </exception> | ||
/// <exception cref="System.ArgumentException"> | ||
/// <paramref name="key"/> is not a private key. | ||
/// </exception> | ||
public BouncyCastleDkimPrivateKey (AsymmetricKeyParameter key) | ||
{ | ||
if (key is null) | ||
throw new ArgumentNullException (nameof (key)); | ||
|
||
if (!key.IsPrivate) | ||
throw new ArgumentException ("The key must be a private key.", nameof (key)); | ||
|
||
Key = key; | ||
} | ||
|
||
/// <summary> | ||
/// Create a DKIM signature context suitable for signing. | ||
/// </summary> | ||
/// <remarks> | ||
/// Creates a DKIM signature context suitable for signing. | ||
/// </remarks> | ||
/// <param name="algorithm">The DKIM signature algorithm.</param> | ||
/// <returns>The DKIM signature context.</returns> | ||
/// <exception cref="System.NotSupportedException"> | ||
/// The specified <paramref name="algorithm"/> is not supported. | ||
/// </exception> | ||
public IDkimSignatureContext CreateSigningContext (DkimSignatureAlgorithm algorithm) | ||
{ | ||
return CreateSignatureContext (algorithm, true); | ||
} | ||
|
||
static AsymmetricKeyParameter LoadPrivateKey (Stream stream) | ||
{ | ||
AsymmetricKeyParameter key = null; | ||
|
||
using (var reader = new StreamReader (stream)) { | ||
var pem = new PemReader (reader); | ||
|
||
var keyObject = pem.ReadObject (); | ||
|
||
if (keyObject is AsymmetricCipherKeyPair pair) { | ||
key = pair.Private; | ||
} else if (keyObject is AsymmetricKeyParameter param) { | ||
key = param; | ||
} | ||
} | ||
|
||
if (key == null || !key.IsPrivate) | ||
throw new FormatException ("Private key not found."); | ||
|
||
return key; | ||
} | ||
|
||
/// <summary> | ||
/// Load a private key from the specified stream. | ||
/// </summary> | ||
/// <remarks> | ||
/// Loads a private key from the specified stream. | ||
/// </remarks> | ||
/// <param name="stream">A stream containing the private DKIM key data.</param> | ||
/// <returns>A <see cref="BouncyCastleDkimPrivateKey"/>.</returns> | ||
/// <exception cref="System.ArgumentNullException"> | ||
/// <paramref name="stream"/> is <c>null</c>. | ||
/// </exception> | ||
/// <exception cref="System.FormatException"> | ||
/// The stream did not contain a private key in PEM format. | ||
/// </exception> | ||
/// <exception cref="System.IO.IOException"> | ||
/// An I/O error occurred. | ||
/// </exception> | ||
public static BouncyCastleDkimPrivateKey Load (Stream stream) | ||
{ | ||
if (stream is null) | ||
throw new ArgumentNullException (nameof (stream)); | ||
|
||
var key = LoadPrivateKey (stream); | ||
|
||
return new BouncyCastleDkimPrivateKey (key); | ||
} | ||
|
||
/// <summary> | ||
/// Load a private key from the specified file. | ||
/// </summary> | ||
/// <remarks> | ||
/// Loads a private key from the specified file. | ||
/// </remarks> | ||
/// <param name="fileName">A file containing the private DKIM key data.</param> | ||
/// <returns>A <see cref="BouncyCastleDkimPrivateKey"/>.</returns> | ||
/// <exception cref="System.ArgumentNullException"> | ||
/// <paramref name="fileName"/> is <c>null</c>. | ||
/// </exception> | ||
/// <exception cref="System.FormatException"> | ||
/// The stream did not contain a private key in PEM format. | ||
/// </exception> | ||
/// <exception cref="System.IO.IOException"> | ||
/// An I/O error occurred. | ||
/// </exception> | ||
public static BouncyCastleDkimPrivateKey Load (string fileName) | ||
{ | ||
if (fileName is null) | ||
throw new ArgumentNullException (nameof (fileName)); | ||
|
||
using (var stream = File.OpenRead (fileName)) | ||
return Load (stream); | ||
} | ||
} | ||
} |
Oops, something went wrong.