summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Hook <dgh@bouncycastle.org>2021-05-23 19:27:59 +1000
committerDavid Hook <dgh@bouncycastle.org>2021-05-23 19:27:59 +1000
commit8ebe171819966753072c65743fd9b1c9e7f090a5 (patch)
treea5a9a3e907a7b5c096b0d59e17a1481140ba718e
parentgithub #250 lookup table error (diff)
downloadBouncyCastle.NET-ed25519-8ebe171819966753072c65743fd9b1c9e7f090a5.tar.xz
github #23 added method for handling signing subkey
-rw-r--r--crypto/src/bcpg/SignaturePacket.cs8
-rw-r--r--crypto/src/openpgp/PgpKeyRingGenerator.cs94
-rw-r--r--crypto/src/openpgp/PgpSignatureGenerator.cs6
-rw-r--r--crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs28
-rw-r--r--crypto/src/openpgp/PgpSignatureSubpacketVector.cs22
-rw-r--r--crypto/test/src/openpgp/test/PgpKeyRingTest.cs42
6 files changed, 165 insertions, 35 deletions
diff --git a/crypto/src/bcpg/SignaturePacket.cs b/crypto/src/bcpg/SignaturePacket.cs
index 5b91c15a3..70138d584 100644
--- a/crypto/src/bcpg/SignaturePacket.cs
+++ b/crypto/src/bcpg/SignaturePacket.cs
@@ -473,5 +473,11 @@ namespace Org.BouncyCastle.Bcpg
 				}
 			}
 		}
-	}
+        public static SignaturePacket FromByteArray(byte[] data)
+        {
+            BcpgInputStream input = BcpgInputStream.Wrap(new MemoryStream(data));
+
+            return new SignaturePacket(input);
+        }
+    }
 }
diff --git a/crypto/src/openpgp/PgpKeyRingGenerator.cs b/crypto/src/openpgp/PgpKeyRingGenerator.cs
index 4f6a4b12f..352575b0b 100644
--- a/crypto/src/openpgp/PgpKeyRingGenerator.cs
+++ b/crypto/src/openpgp/PgpKeyRingGenerator.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections;
-
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 
@@ -280,42 +279,70 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             this.AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector, hashAlgorithm);
         }
 
-		/// <summary>
-		/// Add a subkey with specific hashed and unhashed packets associated with it and
-		/// default certification.
-		/// </summary>
-		/// <param name="keyPair">Public/private key pair.</param>
-		/// <param name="hashedPackets">Hashed packet values to be included in certification.</param>
-		/// <param name="unhashedPackets">Unhashed packets values to be included in certification.</param>
-		/// <exception cref="PgpException"></exception>
-		public void AddSubKey(
+        /// <summary>
+        /// Add a signing subkey to the key ring to be generated with default certification and a primary key binding signature.
+        /// </summary>
+        /// <param name="keyPair">The key pair.</param>
+        /// <param name="hashAlgorithm">The hash algorithm.</param>
+        /// <param name="primaryKeyBindingHashAlgorithm">The primary-key binding hash algorithm.</param>
+        public void AddSubKey(PgpKeyPair keyPair, HashAlgorithmTag hashAlgorithm, HashAlgorithmTag primaryKeyBindingHashAlgorithm)
+        {
+            this.AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector, hashAlgorithm, primaryKeyBindingHashAlgorithm);
+        }
+
+        /// <summary>
+        /// Add a subkey with specific hashed and unhashed packets associated with it and
+        /// default certification using SHA-1.
+        /// </summary>
+        /// <param name="keyPair">Public/private key pair.</param>
+        /// <param name="hashedPackets">Hashed packet values to be included in certification.</param>
+        /// <param name="unhashedPackets">Unhashed packets values to be included in certification.</param>
+        /// <exception cref="PgpException"></exception>
+        public void AddSubKey(
 			PgpKeyPair					keyPair,
 			PgpSignatureSubpacketVector	hashedPackets,
 			PgpSignatureSubpacketVector	unhashedPackets)
 		{
-			try
+            AddSubKey(keyPair, hashedPackets, unhashedPackets, HashAlgorithmTag.Sha1);
+        }
+
+        /// <summary>
+        /// Add a subkey with specific hashed and unhashed packets associated with it and
+        /// default certification.
+        /// </summary>
+        /// <param name="keyPair">Public/private key pair.</param>
+        /// <param name="hashedPackets">Hashed packet values to be included in certification.</param>
+        /// <param name="unhashedPackets">Unhashed packets values to be included in certification.</param>
+        /// <param name="hashAlgorithm">The hash algorithm.</param>
+        /// <exception cref="Org.BouncyCastle.Bcpg.OpenPgp.PgpException">exception adding subkey: </exception>
+        /// <exception cref="PgpException"></exception>
+        public void AddSubKey(
+            PgpKeyPair keyPair,
+            PgpSignatureSubpacketVector hashedPackets,
+            PgpSignatureSubpacketVector unhashedPackets,
+            HashAlgorithmTag hashAlgorithm)
+        {
+            try
             {
-                PgpSignatureGenerator sGen = new PgpSignatureGenerator(
-					masterKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
+                PgpSignatureGenerator sGen = new PgpSignatureGenerator(masterKey.PublicKey.Algorithm, hashAlgorithm);
 
-				//
+                //
                 // Generate the certification
                 //
                 sGen.InitSign(PgpSignature.SubkeyBinding, masterKey.PrivateKey);
 
-				sGen.SetHashedSubpackets(hashedPackets);
+                sGen.SetHashedSubpackets(hashedPackets);
                 sGen.SetUnhashedSubpackets(unhashedPackets);
 
-				IList subSigs = Platform.CreateArrayList();
-
-				subSigs.Add(sGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
+                IList subSigs = Platform.CreateArrayList();
+                subSigs.Add(sGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
 
-				keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, subSigs), encAlgorithm,
+                keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, subSigs), encAlgorithm,
                     rawPassPhrase, false, useSha1, rand, false));
-			}
-            catch (PgpException e)
+            }
+            catch (PgpException)
             {
-                throw e;
+                throw;
             }
             catch (Exception e)
             {
@@ -324,20 +351,22 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         }
 
         /// <summary>
-        /// Add a subkey with specific hashed and unhashed packets associated with it and
-        /// default certification.
+        /// Add a signing subkey with specific hashed and unhashed packets associated with it and
+        /// default certifications, including the primary-key binding signature.
         /// </summary>
         /// <param name="keyPair">Public/private key pair.</param>
         /// <param name="hashedPackets">Hashed packet values to be included in certification.</param>
         /// <param name="unhashedPackets">Unhashed packets values to be included in certification.</param>
         /// <param name="hashAlgorithm">The hash algorithm.</param>
+        /// <param name="primaryKeyBindingHashAlgorithm">The primary-key binding hash algorithm.</param>
         /// <exception cref="Org.BouncyCastle.Bcpg.OpenPgp.PgpException">exception adding subkey: </exception>
         /// <exception cref="PgpException"></exception>
         public void AddSubKey(
             PgpKeyPair keyPair,
             PgpSignatureSubpacketVector hashedPackets,
             PgpSignatureSubpacketVector unhashedPackets,
-            HashAlgorithmTag hashAlgorithm)
+            HashAlgorithmTag hashAlgorithm,
+            HashAlgorithmTag primaryKeyBindingHashAlgorithm)
         {
             try
             {
@@ -348,7 +377,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                 //
                 sGen.InitSign(PgpSignature.SubkeyBinding, masterKey.PrivateKey);
 
-                sGen.SetHashedSubpackets(hashedPackets);
+                // add primary key binding sub packet
+                PgpSignatureGenerator pGen = new PgpSignatureGenerator(keyPair.PublicKey.Algorithm, primaryKeyBindingHashAlgorithm);
+
+                pGen.InitSign(PgpSignature.PrimaryKeyBinding, keyPair.PrivateKey);
+
+                PgpSignatureSubpacketGenerator spGen = new PgpSignatureSubpacketGenerator(hashedPackets);
+
+                spGen.SetEmbeddedSignature(false,
+                        pGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
+                
+                sGen.SetHashedSubpackets(spGen.Generate());
                 sGen.SetUnhashedSubpackets(unhashedPackets);
 
                 IList subSigs = Platform.CreateArrayList();
@@ -367,8 +406,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             }
         }
 
-
-		/// <summary>Return the secret key ring.</summary>
+        /// <summary>Return the secret key ring.</summary>
         public PgpSecretKeyRing GenerateSecretKeyRing()
         {
             return new PgpSecretKeyRing(keys);
diff --git a/crypto/src/openpgp/PgpSignatureGenerator.cs b/crypto/src/openpgp/PgpSignatureGenerator.cs
index c5309689f..74dff2570 100644
--- a/crypto/src/openpgp/PgpSignatureGenerator.cs
+++ b/crypto/src/openpgp/PgpSignatureGenerator.cs
@@ -75,6 +75,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			lastb = 0;
 		}
 
+		public void InitSign(
+			int sigType,
+			ISignatureWithDigestFactory signer)
+		{
+		}
+
 		public void Update(
             byte b)
         {
diff --git a/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs b/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs
index d2177d09c..3987012ae 100644
--- a/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs
+++ b/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs
@@ -11,7 +11,33 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
     {
         private IList list = Platform.CreateArrayList();
 
-		public void SetRevocable(
+
+        /// <summary>
+        ///Base constructor, creates an empty generator.
+        /// </summary>
+        public PgpSignatureSubpacketGenerator()
+        {
+        }
+
+        ///  <summary>
+        ///  Constructor for pre-initialising the generator from an existing one.
+        ///  </summary>
+        ///  <param name="sigSubV">
+        ///  sigSubV an initial set of subpackets.
+        ///  </param>
+        public PgpSignatureSubpacketGenerator(PgpSignatureSubpacketVector sigSubV)
+        {
+            if (sigSubV != null)
+            {
+                SignatureSubpacket[] subs = sigSubV.ToSubpacketArray();
+                for (int i = 0; i != sigSubV.Count; i++)
+                {
+                    list.Add(subs[i]);
+                }
+            }
+        }
+
+        public void SetRevocable(
             bool	isCritical,
             bool	isRevocable)
         {
diff --git a/crypto/src/openpgp/PgpSignatureSubpacketVector.cs b/crypto/src/openpgp/PgpSignatureSubpacketVector.cs
index 1d3d75941..3dc96ea90 100644
--- a/crypto/src/openpgp/PgpSignatureSubpacketVector.cs
+++ b/crypto/src/openpgp/PgpSignatureSubpacketVector.cs
@@ -1,6 +1,6 @@
 using System;
 using System.Collections;
-
+using System.IO;
 using Org.BouncyCastle.Bcpg.Sig;
 using Org.BouncyCastle.Utilities;
 
@@ -189,6 +189,26 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			return false;
 		}
 
+        public PgpSignatureList GetEmbeddedSignatures()
+        {
+            SignatureSubpacket [] sigs = GetSubpackets(SignatureSubpacketTag.EmbeddedSignature);
+            PgpSignature[] l = new PgpSignature[sigs.Length];
+   
+            for (int i = 0; i < sigs.Length; i++)
+            {
+                try
+                {
+                    l[i] = new PgpSignature(SignaturePacket.FromByteArray(sigs[i].GetData()));
+                }
+                catch (IOException e)
+                {
+                    throw new PgpException("Unable to parse signature packet: " + e.Message, e);
+                }
+            }
+
+            return new PgpSignatureList(l);
+        }
+
 		public SignatureSubpacketTag[] GetCriticalTags()
         {
             int count = 0;
diff --git a/crypto/test/src/openpgp/test/PgpKeyRingTest.cs b/crypto/test/src/openpgp/test/PgpKeyRingTest.cs
index 5f1d83459..aed750318 100644
--- a/crypto/test/src/openpgp/test/PgpKeyRingTest.cs
+++ b/crypto/test/src/openpgp/test/PgpKeyRingTest.cs
@@ -2261,7 +2261,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
         }
 
         [Test]
-        public void GenerateSha1Test()
+        public void GenerateSha256Test()
         {
             char[] passPhrase = "hello".ToCharArray();
 
@@ -2296,11 +2296,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
 
             PgpKeyPair dsaKeyPair = new PgpKeyPair(PublicKeyAlgorithmTag.Dsa, dsaKp, DateTime.UtcNow);
             PgpKeyPair elgKeyPair = new PgpKeyPair(PublicKeyAlgorithmTag.ElGamalEncrypt, elgKp, DateTime.UtcNow);
+            PgpKeyPair dsaSubKeyPair = new PgpKeyPair(PublicKeyAlgorithmTag.Dsa, dsaKpg.GenerateKeyPair(), DateTime.UtcNow);
 
             PgpKeyRingGenerator keyRingGen = new PgpKeyRingGenerator(PgpSignature.PositiveCertification, dsaKeyPair,
                 "test", SymmetricKeyAlgorithmTag.Aes256, passPhrase, true, null, null, Random);
 
-            keyRingGen.AddSubKey(elgKeyPair);
+            keyRingGen.AddSubKey(elgKeyPair, HashAlgorithmTag.Sha256);
+
+            keyRingGen.AddSubKey(dsaSubKeyPair, HashAlgorithmTag.Sha256, HashAlgorithmTag.Sha256);
 
             PgpSecretKeyRing keyRing = keyRingGen.GenerateSecretKeyRing();
 
@@ -2310,6 +2313,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
 
             PgpPublicKey vKey = null;
             PgpPublicKey sKey = null;
+            PgpPublicKey sdKey = null;
 
             foreach (PgpPublicKey pk in pubRing.GetPublicKeys())
             {
@@ -2319,7 +2323,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
                 }
                 else
                 {
-                    sKey = pk;
+                    if (pk.IsEncryptionKey)
+                    {
+                        sKey = pk;
+                    }
+                    else
+                    {
+                        sdKey = pk;
+                    }
                 }
             }
 
@@ -2336,6 +2347,29 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
                     }
                 }
             }
+
+            foreach (PgpSignature sig in sdKey.GetSignatures())
+            {
+                if (sig.KeyId == vKey.KeyId
+                    && sig.SignatureType == PgpSignature.SubkeyBinding)
+                {
+                    sig.InitVerify(vKey);
+
+                    if (!sig.VerifyCertification(vKey, sdKey))
+                    {
+                        Fail("failed to verify dsa sub-key signature.");
+                    }
+
+                    PgpSignature bindSig = sig.GetHashedSubPackets().GetEmbeddedSignatures()[0];
+
+                    bindSig.InitVerify(sdKey);
+
+                    if (!bindSig.VerifyCertification(vKey, sdKey))
+                    {
+                        Fail("failed to verify dsa sub-key primary binding signature.");
+                    }
+                }
+            }
         }
 
         [Test]
@@ -2574,7 +2608,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
             PerformTest11();
 
             GenerateTest();
-            GenerateSha1Test();
+            GenerateSha256Test();
             RewrapTest();
             PublicKeyRingWithX509Test();
             SecretKeyRingWithPersonalCertificateTest();