Skip to content

Commit

Permalink
Added OpenPgpContext.SignKey() and unit tests
Browse files Browse the repository at this point in the history
Completes issue #315
  • Loading branch information
jstedfast committed Sep 2, 2017
1 parent bf95e24 commit a039327
Show file tree
Hide file tree
Showing 14 changed files with 168 additions and 17 deletions.
66 changes: 49 additions & 17 deletions MimeKit/Cryptography/OpenPgpContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1114,30 +1114,62 @@ public void GenerateKeyPair (MailboxAddress mailbox, string password, DateTime?
Import (generator.GeneratePublicKeyRing ());
}

//public void SignPublicKey (PgpSecretKey secretKey, PgpPublicKey publicKey, DigestAlgorithm digestAlgo = DigestAlgorithm.Sha1)
//{
// if (secretKey == null)
// throw new ArgumentNullException (nameof (secretKey));
/// <summary>
/// Sign a public key.
/// </summary>
/// <remarks>
/// <para>Signs a public key using the specified secret key.</para>
/// <para>Most OpenPGP implementations use <see cref="OpenPgpKeyCertification.GenericCertification"/>
/// to make their "key signatures". Some implementations are known to use the other
/// certification types, but few differentiate between them.</para>
/// </remarks>
/// <param name="secretKey">The secret key to use for signing.</param>
/// <param name="publicKey">The public key to sign.</param>
/// <param name="digestAlgo">The digest algorithm.</param>
/// <param name="certification">The certification to give the signed key.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="secretKey"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="publicKey"/> is <c>null</c>.</para>
/// </exception>
public void SignKey (PgpSecretKey secretKey, PgpPublicKey publicKey, DigestAlgorithm digestAlgo = DigestAlgorithm.Sha1, OpenPgpKeyCertification certification = OpenPgpKeyCertification.GenericCertification)
{
if (secretKey == null)
throw new ArgumentNullException (nameof (secretKey));

// if (publicKey == null)
// throw new ArgumentNullException (nameof (publicKey));
if (publicKey == null)
throw new ArgumentNullException (nameof (publicKey));

// var privateKey = GetPrivateKey (secretKey);
// var signatureGenerator = new PgpSignatureGenerator (secretKey.PublicKey.Algorithm, GetHashAlgorithm (digestAlgo));
var privateKey = GetPrivateKey (secretKey);
var signatureGenerator = new PgpSignatureGenerator (secretKey.PublicKey.Algorithm, GetHashAlgorithm (digestAlgo));

// signatureGenerator.InitSign (PgpSignature.CasualCertification, privateKey);
// signatureGenerator.GenerateOnePassVersion (false);
signatureGenerator.InitSign ((int) certification, privateKey);
signatureGenerator.GenerateOnePassVersion (false);

// var subpacketGenerator = new PgpSignatureSubpacketGenerator ();
// var subpacketVector = subpacketGenerator.Generate ();
var subpacketGenerator = new PgpSignatureSubpacketGenerator ();
var subpacketVector = subpacketGenerator.Generate ();

// signatureGenerator.SetHashedSubpackets (subpacketVector);
signatureGenerator.SetHashedSubpackets (subpacketVector);

// var signedKey = PgpPublicKey.AddCertification (publicKey, signatureGenerator.Generate ());
// var keyring = new PgpPublicKeyRing (signedKey.GetEncoded ());
var signedKey = PgpPublicKey.AddCertification (publicKey, signatureGenerator.Generate ());
PgpPublicKeyRing keyring = null;

// Import (keyring);
//}
foreach (var ring in EnumeratePublicKeyRings ()) {
foreach (PgpPublicKey key in ring.GetPublicKeys ()) {
if (key.KeyId == publicKey.KeyId) {
PublicKeyRingBundle = PgpPublicKeyRingBundle.RemovePublicKeyRing (PublicKeyRingBundle, ring);
keyring = PgpPublicKeyRing.InsertPublicKey (ring, signedKey);
break;
}
}
}

if (keyring == null)
keyring = new PgpPublicKeyRing (signedKey.GetEncoded ());

PublicKeyRingBundle = PgpPublicKeyRingBundle.AddPublicKeyRing (PublicKeyRingBundle, keyring);
SavePublicKeyRingBundle ();
}

/// <summary>
/// Gets the equivalent <see cref="Org.BouncyCastle.Bcpg.HashAlgorithmTag"/> for the
Expand Down
65 changes: 65 additions & 0 deletions MimeKit/Cryptography/OpenPgpKeyCertification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//
// OpenPgpKeyCertification.cs
//
// Author: Jeffrey Stedfast <jestedfa@microsoft.com>
//
// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com)
//
// 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.
//

namespace MimeKit.Cryptography
{
/// <summary>
/// An OpenPGP key certification.
/// </summary>
/// <remarks>
/// An OpenPGP key certification.
/// </remarks>
public enum OpenPgpKeyCertification {
/// <summary>
/// Generic certification of a User ID and Public-Key packet.
/// The issuer of this certification does not make any particular
/// assertion as to how well the certifier has checked that the owner
/// of the key is in fact the person described by the User ID.
/// </summary>
GenericCertification = 0x10,

/// <summary>
/// Persona certification of a User ID and Public-Key packet.
/// The issuer of this certification has not done any verification of
/// the claim that the owner of this key is the User ID specified.
/// </summary>
PersonaCertification = 0x11,

/// <summary>
/// Casual certification of a User ID and Public-Key packet.
/// The issuer of this certification has done some casual
/// verification of the claim of identity.
/// </summary>
CasualCertification = 0x12,

/// <summary>
/// Positive certification of a User ID and Public-Key packet.
/// The issuer of this certification has done substantial
/// verification of the claim of identity.
/// </summary>
PositiveCertification = 0x13
}
}
1 change: 1 addition & 0 deletions MimeKit/MimeKit.Android.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
<Compile Include="Cryptography\OpenPgpDetectionFilter.cs" />
<Compile Include="Cryptography\OpenPgpDigitalCertificate.cs" />
<Compile Include="Cryptography\OpenPgpDigitalSignature.cs" />
<Compile Include="Cryptography\OpenPgpKeyCertification.cs" />
<Compile Include="Cryptography\PrivateKeyNotFoundException.cs" />
<Compile Include="Cryptography\PublicKeyAlgorithm.cs" />
<Compile Include="Cryptography\PublicKeyNotFoundException.cs" />
Expand Down
1 change: 1 addition & 0 deletions MimeKit/MimeKit.Mac.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
<Compile Include="Cryptography\OpenPgpDetectionFilter.cs" />
<Compile Include="Cryptography\OpenPgpDigitalCertificate.cs" />
<Compile Include="Cryptography\OpenPgpDigitalSignature.cs" />
<Compile Include="Cryptography\OpenPgpKeyCertification.cs" />
<Compile Include="Cryptography\PrivateKeyNotFoundException.cs" />
<Compile Include="Cryptography\PublicKeyAlgorithm.cs" />
<Compile Include="Cryptography\PublicKeyNotFoundException.cs" />
Expand Down
1 change: 1 addition & 0 deletions MimeKit/MimeKit.Net35.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
<Compile Include="Cryptography\OpenPgpDetectionFilter.cs" />
<Compile Include="Cryptography\OpenPgpDigitalCertificate.cs" />
<Compile Include="Cryptography\OpenPgpDigitalSignature.cs" />
<Compile Include="Cryptography\OpenPgpKeyCertification.cs" />
<Compile Include="Cryptography\PrivateKeyNotFoundException.cs" />
<Compile Include="Cryptography\PublicKeyAlgorithm.cs" />
<Compile Include="Cryptography\PublicKeyNotFoundException.cs" />
Expand Down
1 change: 1 addition & 0 deletions MimeKit/MimeKit.Net40.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
<Compile Include="Cryptography\OpenPgpDetectionFilter.cs" />
<Compile Include="Cryptography\OpenPgpDigitalCertificate.cs" />
<Compile Include="Cryptography\OpenPgpDigitalSignature.cs" />
<Compile Include="Cryptography\OpenPgpKeyCertification.cs" />
<Compile Include="Cryptography\PrivateKeyNotFoundException.cs" />
<Compile Include="Cryptography\PublicKeyAlgorithm.cs" />
<Compile Include="Cryptography\PublicKeyNotFoundException.cs" />
Expand Down
1 change: 1 addition & 0 deletions MimeKit/MimeKit.Net45.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
<Compile Include="Cryptography\OpenPgpDetectionFilter.cs" />
<Compile Include="Cryptography\OpenPgpDigitalCertificate.cs" />
<Compile Include="Cryptography\OpenPgpDigitalSignature.cs" />
<Compile Include="Cryptography\OpenPgpKeyCertification.cs" />
<Compile Include="Cryptography\PrivateKeyNotFoundException.cs" />
<Compile Include="Cryptography\PublicKeyAlgorithm.cs" />
<Compile Include="Cryptography\PublicKeyNotFoundException.cs" />
Expand Down
1 change: 1 addition & 0 deletions MimeKit/MimeKit.NetStandard.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
<Compile Include="Cryptography\OpenPgpDetectionFilter.cs" />
<Compile Include="Cryptography\OpenPgpDigitalCertificate.cs" />
<Compile Include="Cryptography\OpenPgpDigitalSignature.cs" />
<Compile Include="Cryptography\OpenPgpKeyCertification.cs" />
<Compile Include="Cryptography\PrivateKeyNotFoundException.cs" />
<Compile Include="Cryptography\PublicKeyAlgorithm.cs" />
<Compile Include="Cryptography\PublicKeyNotFoundException.cs" />
Expand Down
1 change: 1 addition & 0 deletions MimeKit/MimeKit.Portable.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
<Compile Include="Cryptography\OpenPgpDetectionFilter.cs" />
<Compile Include="Cryptography\OpenPgpDigitalCertificate.cs" />
<Compile Include="Cryptography\OpenPgpDigitalSignature.cs" />
<Compile Include="Cryptography\OpenPgpKeyCertification.cs" />
<Compile Include="Cryptography\PrivateKeyNotFoundException.cs" />
<Compile Include="Cryptography\PublicKeyAlgorithm.cs" />
<Compile Include="Cryptography\PublicKeyNotFoundException.cs" />
Expand Down
1 change: 1 addition & 0 deletions MimeKit/MimeKit.TvOS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
<Compile Include="Cryptography\OpenPgpDetectionFilter.cs" />
<Compile Include="Cryptography\OpenPgpDigitalCertificate.cs" />
<Compile Include="Cryptography\OpenPgpDigitalSignature.cs" />
<Compile Include="Cryptography\OpenPgpKeyCertification.cs" />
<Compile Include="Cryptography\PrivateKeyNotFoundException.cs" />
<Compile Include="Cryptography\PublicKeyAlgorithm.cs" />
<Compile Include="Cryptography\PublicKeyNotFoundException.cs" />
Expand Down
1 change: 1 addition & 0 deletions MimeKit/MimeKit.WatchOS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
<Compile Include="Cryptography\OpenPgpDetectionFilter.cs" />
<Compile Include="Cryptography\OpenPgpDigitalCertificate.cs" />
<Compile Include="Cryptography\OpenPgpDigitalSignature.cs" />
<Compile Include="Cryptography\OpenPgpKeyCertification.cs" />
<Compile Include="Cryptography\PrivateKeyNotFoundException.cs" />
<Compile Include="Cryptography\PublicKeyAlgorithm.cs" />
<Compile Include="Cryptography\PublicKeyNotFoundException.cs" />
Expand Down
1 change: 1 addition & 0 deletions MimeKit/MimeKit.WindowsUniversal81.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
<Compile Include="Cryptography\OpenPgpDetectionFilter.cs" />
<Compile Include="Cryptography\OpenPgpDigitalCertificate.cs" />
<Compile Include="Cryptography\OpenPgpDigitalSignature.cs" />
<Compile Include="Cryptography\OpenPgpKeyCertification.cs" />
<Compile Include="Cryptography\PrivateKeyNotFoundException.cs" />
<Compile Include="Cryptography\PublicKeyAlgorithm.cs" />
<Compile Include="Cryptography\PublicKeyNotFoundException.cs" />
Expand Down
1 change: 1 addition & 0 deletions MimeKit/MimeKit.iOS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
<Compile Include="Cryptography\OpenPgpDetectionFilter.cs" />
<Compile Include="Cryptography\OpenPgpDigitalCertificate.cs" />
<Compile Include="Cryptography\OpenPgpDigitalSignature.cs" />
<Compile Include="Cryptography\OpenPgpKeyCertification.cs" />
<Compile Include="Cryptography\PrivateKeyNotFoundException.cs" />
<Compile Include="Cryptography\PublicKeyAlgorithm.cs" />
<Compile Include="Cryptography\PublicKeyNotFoundException.cs" />
Expand Down
43 changes: 43 additions & 0 deletions UnitTests/PgpMimeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

using NUnit.Framework;

using Org.BouncyCastle.Bcpg;
using Org.BouncyCastle.Bcpg.OpenPgp;

using MimeKit;
Expand Down Expand Up @@ -136,6 +137,48 @@ public void TestKeyGeneration ()
}
}

[Test]
public void TestKeySigning ()
{
using (var ctx = new DummyOpenPgpContext ()) {
var seckey = ctx.EnumerateSecretKeys (new MailboxAddress ("", "mimekit@example.com")).FirstOrDefault ();
var mailbox = new MailboxAddress ("Snarky McSnarkypants", "snarky@snarkypants.net");

ctx.GenerateKeyPair (mailbox, "password", DateTime.Now.AddYears (1));

// delete the secret keyring, we don't need it
var secring = ctx.EnumerateSecretKeyRings (mailbox).FirstOrDefault ();
ctx.Delete (secring);

var pubring = ctx.EnumeratePublicKeyRings (mailbox).FirstOrDefault ();
var pubkey = pubring.GetPublicKey ();
int sigCount = 0;

foreach (PgpSignature sig in pubkey.GetKeySignatures ())
sigCount++;

Assert.AreEqual (0, sigCount);

ctx.SignKey (seckey, pubkey, DigestAlgorithm.Sha256, OpenPgpKeyCertification.CasualCertification);

pubring = ctx.EnumeratePublicKeyRings (mailbox).FirstOrDefault ();
pubkey = pubring.GetPublicKey ();

sigCount = 0;

foreach (PgpSignature sig in pubkey.GetKeySignatures ()) {
Assert.AreEqual (seckey.KeyId, sig.KeyId);
Assert.AreEqual (HashAlgorithmTag.Sha256, sig.HashAlgorithm);
Assert.AreEqual ((int) OpenPgpKeyCertification.CasualCertification, sig.SignatureType);
sigCount++;
}

Assert.AreEqual (1, sigCount);

ctx.Delete (pubring);
}
}

[Test]
public void TestMimeMessageSign ()
{
Expand Down

0 comments on commit a039327

Please sign in to comment.