summary refs log tree commit diff
path: root/crypto
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-02-24 22:08:14 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-02-24 22:08:14 +0700
commit6529112d56fb76cd823b314b2fa2c7f11ef37f36 (patch)
tree670cd96f619e29a0c9afcac6d731529d94363278 /crypto
parentCipherStream refactoring (diff)
downloadBouncyCastle.NET-ed25519-6529112d56fb76cd823b314b2fa2c7f11ef37f36.tar.xz
Bcpg: update signature subpackets
Diffstat (limited to 'crypto')
-rw-r--r--crypto/src/bcpg/SignaturePacket.cs156
-rw-r--r--crypto/src/bcpg/SignatureSubpacket.cs2
-rw-r--r--crypto/src/bcpg/SignatureSubpacketTags.cs16
-rw-r--r--crypto/src/bcpg/SignatureSubpacketsReader.cs15
-rw-r--r--crypto/src/bcpg/sig/IntendedRecipientFingerprint.cs28
-rw-r--r--crypto/src/bcpg/sig/IssuerFingerprint.cs28
-rw-r--r--crypto/src/bcpg/sig/PolicyUrl.cs24
-rw-r--r--crypto/src/bcpg/sig/RegularExpression.cs40
-rw-r--r--crypto/src/bcpg/sig/RevocationKey.cs23
-rw-r--r--crypto/src/bcpg/sig/SignatureTarget.cs30
-rw-r--r--crypto/src/util/Strings.cs5
11 files changed, 255 insertions, 112 deletions
diff --git a/crypto/src/bcpg/SignaturePacket.cs b/crypto/src/bcpg/SignaturePacket.cs
index a0e8588b3..09e6b059d 100644
--- a/crypto/src/bcpg/SignaturePacket.cs
+++ b/crypto/src/bcpg/SignaturePacket.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.IO;
 
 using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Date;
 using Org.BouncyCastle.Utilities.IO;
 
@@ -24,8 +25,7 @@ namespace Org.BouncyCastle.Bcpg
         private SignatureSubpacket[]	unhashedData;
 		private byte[]					signatureEncoding;
 
-		internal SignaturePacket(
-            BcpgInputStream bcpgIn)
+		internal SignaturePacket(BcpgInputStream bcpgIn)
         {
             version = bcpgIn.ReadByte();
 
@@ -125,42 +125,36 @@ namespace Org.BouncyCastle.Bcpg
 
 			switch (keyAlgorithm)
             {
-                case PublicKeyAlgorithmTag.RsaGeneral:
-                case PublicKeyAlgorithmTag.RsaSign:
-                    MPInteger v = new MPInteger(bcpgIn);
-					signature = new MPInteger[1]{ v };
-                    break;
-				case PublicKeyAlgorithmTag.Dsa:
-                    MPInteger r = new MPInteger(bcpgIn);
-                    MPInteger s = new MPInteger(bcpgIn);
-					signature = new MPInteger[2]{ r, s };
-                    break;
-                case PublicKeyAlgorithmTag.ElGamalEncrypt: // yep, this really does happen sometimes.
-                case PublicKeyAlgorithmTag.ElGamalGeneral:
-                    MPInteger p = new MPInteger(bcpgIn);
-                    MPInteger g = new MPInteger(bcpgIn);
-                    MPInteger y = new MPInteger(bcpgIn);
-					signature = new MPInteger[3]{ p, g, y };
-                    break;
-                case PublicKeyAlgorithmTag.ECDsa:
-                case PublicKeyAlgorithmTag.EdDsa:
-                    MPInteger ecR = new MPInteger(bcpgIn);
-                    MPInteger ecS = new MPInteger(bcpgIn);
-                    signature = new MPInteger[2]{ ecR, ecS };
-                    break;
-                default:
-					if (keyAlgorithm < PublicKeyAlgorithmTag.Experimental_1 || keyAlgorithm > PublicKeyAlgorithmTag.Experimental_11)
-                        throw new IOException("unknown signature key algorithm: " + keyAlgorithm);
-
-                    signature = null;
-					MemoryStream bOut = new MemoryStream();
-					int ch;
-					while ((ch = bcpgIn.ReadByte()) >= 0)
-					{
-						bOut.WriteByte((byte) ch);
-					}
-					signatureEncoding = bOut.ToArray();
-					break;
+            case PublicKeyAlgorithmTag.RsaGeneral:
+            case PublicKeyAlgorithmTag.RsaSign:
+                MPInteger v = new MPInteger(bcpgIn);
+				signature = new MPInteger[1]{ v };
+                break;
+			case PublicKeyAlgorithmTag.Dsa:
+                MPInteger r = new MPInteger(bcpgIn);
+                MPInteger s = new MPInteger(bcpgIn);
+				signature = new MPInteger[2]{ r, s };
+                break;
+            case PublicKeyAlgorithmTag.ElGamalEncrypt: // yep, this really does happen sometimes.
+            case PublicKeyAlgorithmTag.ElGamalGeneral:
+                MPInteger p = new MPInteger(bcpgIn);
+                MPInteger g = new MPInteger(bcpgIn);
+                MPInteger y = new MPInteger(bcpgIn);
+				signature = new MPInteger[3]{ p, g, y };
+                break;
+            case PublicKeyAlgorithmTag.ECDsa:
+            case PublicKeyAlgorithmTag.EdDsa:
+                MPInteger ecR = new MPInteger(bcpgIn);
+                MPInteger ecS = new MPInteger(bcpgIn);
+                signature = new MPInteger[2]{ ecR, ecS };
+                break;
+            default:
+				if (keyAlgorithm < PublicKeyAlgorithmTag.Experimental_1 || keyAlgorithm > PublicKeyAlgorithmTag.Experimental_11)
+                    throw new IOException("unknown signature key algorithm: " + keyAlgorithm);
+
+                signature = null;
+                signatureEncoding = Streams.ReadAll(bcpgIn);
+				break;
             }
         }
 
@@ -238,23 +232,23 @@ namespace Org.BouncyCastle.Bcpg
 			}
 		}
 
-		public int Version
-        {
-			get { return version; }
-        }
+		public int Version => version;
 
-		public int SignatureType
-        {
-			get { return signatureType; }
-		}
+		public int SignatureType => signatureType;
 
-		/**
+        /**
         * return the keyId
         * @return the keyId that created the signature.
         */
-        public long KeyId
+        public long KeyId => keyId;
+
+        /**
+         * Return the signatures fingerprint.
+         * @return fingerprint (digest prefix) of the signature
+         */
+        public byte[] GetFingerprint()
         {
-            get { return keyId; }
+            return Arrays.Clone(fingerprint);
         }
 
 		/**
@@ -314,24 +308,15 @@ namespace Org.BouncyCastle.Bcpg
             return sOut.ToArray();
         }
 
-		public PublicKeyAlgorithmTag KeyAlgorithm
-        {
-			get { return keyAlgorithm; }
-        }
+		public PublicKeyAlgorithmTag KeyAlgorithm => keyAlgorithm;
 
-		public HashAlgorithmTag HashAlgorithm
-		{
-			get { return hashAlgorithm; }
-        }
+        public HashAlgorithmTag HashAlgorithm => hashAlgorithm;
 
-		/**
+        /**
 		* return the signature as a set of integers - note this is normalised to be the
         * ASN.1 encoding of what appears in the signature packet.
         */
-        public MPInteger[] GetSignature()
-        {
-            return signature;
-        }
+        public MPInteger[] GetSignature() => signature;
 
 		/**
 		 * Return the byte encoding of the signature section.
@@ -340,43 +325,34 @@ namespace Org.BouncyCastle.Bcpg
 		public byte[] GetSignatureBytes()
 		{
 			if (signatureEncoding != null)
-			{
-				return (byte[]) signatureEncoding.Clone();
-			}
+				return (byte[])signatureEncoding.Clone();
 
 			MemoryStream bOut = new MemoryStream();
-			BcpgOutputStream bcOut = new BcpgOutputStream(bOut);
 
-			foreach (MPInteger sigObj in signature)
-			{
-				try
-				{
-					bcOut.WriteObject(sigObj);
-				}
-				catch (IOException e)
-				{
-					throw new Exception("internal error: " + e);
-				}
-			}
+            using (var pOut = new BcpgOutputStream(bOut))
+            {
+                foreach (MPInteger sigObj in signature)
+                {
+                    try
+                    {
+                        pOut.WriteObject(sigObj);
+                    }
+                    catch (IOException e)
+                    {
+                        throw new Exception("internal error: " + e);
+                    }
+                }
+            }
 
-			return bOut.ToArray();
+            return bOut.ToArray();
 		}
 
-		public SignatureSubpacket[] GetHashedSubPackets()
-        {
-            return hashedData;
-        }
+		public SignatureSubpacket[] GetHashedSubPackets() => hashedData;
 
-		public SignatureSubpacket[] GetUnhashedSubPackets()
-        {
-            return unhashedData;
-        }
+		public SignatureSubpacket[] GetUnhashedSubPackets() => unhashedData;
 
 		/// <summary>Return the creation time in milliseconds since 1 Jan., 1970 UTC.</summary>
-        public long CreationTime
-        {
-            get { return creationTime; }
-        }
+        public long CreationTime => creationTime;
 
 		public override void Encode(BcpgOutputStream bcpgOut)
         {
diff --git a/crypto/src/bcpg/SignatureSubpacket.cs b/crypto/src/bcpg/SignatureSubpacket.cs
index 5accadc14..c2186f373 100644
--- a/crypto/src/bcpg/SignatureSubpacket.cs
+++ b/crypto/src/bcpg/SignatureSubpacket.cs
@@ -42,7 +42,7 @@ namespace Org.BouncyCastle.Bcpg
         /// <summary>Return the generic data making up the packet.</summary>
         public byte[] GetData()
         {
-            return (byte[]) data.Clone();
+            return (byte[])data.Clone();
         }
 
 		public void Encode(
diff --git a/crypto/src/bcpg/SignatureSubpacketTags.cs b/crypto/src/bcpg/SignatureSubpacketTags.cs
index 1a8e254c0..0574c274b 100644
--- a/crypto/src/bcpg/SignatureSubpacketTags.cs
+++ b/crypto/src/bcpg/SignatureSubpacketTags.cs
@@ -25,9 +25,15 @@ namespace Org.BouncyCastle.Bcpg
         PolicyUrl = 26,							// policy URL
         KeyFlags = 27,							// key flags
         SignerUserId = 28,						// signer's user id
-        RevocationReason = 29,					// reason for revocation
-		Features = 30,							// features
-		SignatureTarget = 31,					// signature target
-		EmbeddedSignature = 32					// embedded signature
-	}
+        RevocationReason = 29,                  // reason for revocation
+        Features = 30,                          // features
+        SignatureTarget = 31,                   // signature target
+        EmbeddedSignature = 32,					// embedded signature
+        IssuerFingerprint = 33,                 // issuer key fingerprint
+        //PreferredAeadAlgorithms = 34,         // RESERVED since crypto-refresh-05
+        IntendedRecipientFingerprint = 35,      // intended recipient fingerprint
+        AttestedCertifications = 37,            // attested certifications (RESERVED)
+        KeyBlock = 38,                          // Key Block (RESERVED)
+        PreferredAeadAlgorithms = 39,           // preferred AEAD algorithms
+    }
 }
diff --git a/crypto/src/bcpg/SignatureSubpacketsReader.cs b/crypto/src/bcpg/SignatureSubpacketsReader.cs
index 86ad11207..35831fa9c 100644
--- a/crypto/src/bcpg/SignatureSubpacketsReader.cs
+++ b/crypto/src/bcpg/SignatureSubpacketsReader.cs
@@ -92,6 +92,8 @@ namespace Org.BouncyCastle.Bcpg
 			{
 			case SignatureSubpacketTag.CreationTime:
 				return new SignatureCreationTime(isCritical, isLongLength, data);
+            case SignatureSubpacketTag.EmbeddedSignature:
+                return new EmbeddedSignature(isCritical, isLongLength, data);
 			case SignatureSubpacketTag.KeyExpireTime:
                 return new KeyExpirationTime(isCritical, isLongLength, data);
 			case SignatureSubpacketTag.ExpireTime:
@@ -100,6 +102,8 @@ namespace Org.BouncyCastle.Bcpg
                 return new Revocable(isCritical, isLongLength, data);
 			case SignatureSubpacketTag.Exportable:
                 return new Exportable(isCritical, isLongLength, data);
+			case SignatureSubpacketTag.Features:
+                return new Features(isCritical, isLongLength, data);
 			case SignatureSubpacketTag.IssuerKeyId:
                 return new IssuerKeyId(isCritical, isLongLength, data);
 			case SignatureSubpacketTag.TrustSig:
@@ -107,19 +111,30 @@ namespace Org.BouncyCastle.Bcpg
 			case SignatureSubpacketTag.PreferredCompressionAlgorithms:
 			case SignatureSubpacketTag.PreferredHashAlgorithms:
 			case SignatureSubpacketTag.PreferredSymmetricAlgorithms:
+			case SignatureSubpacketTag.PreferredAeadAlgorithms:
                 return new PreferredAlgorithms(type, isCritical, isLongLength, data);
 			case SignatureSubpacketTag.KeyFlags:
                 return new KeyFlags(isCritical, isLongLength, data);
+            case SignatureSubpacketTag.PolicyUrl:
+                return new PolicyUrl(isCritical, isLongLength, data);
 			case SignatureSubpacketTag.PrimaryUserId:
                 return new PrimaryUserId(isCritical, isLongLength, data);
 			case SignatureSubpacketTag.SignerUserId:
                 return new SignerUserId(isCritical, isLongLength, data);
 			case SignatureSubpacketTag.NotationData:
                 return new NotationData(isCritical, isLongLength, data);
+			case SignatureSubpacketTag.RegExp:
+                return new RegularExpression(isCritical, isLongLength, data);
             case SignatureSubpacketTag.RevocationReason:
                 return new RevocationReason(isCritical, isLongLength, data);
             case SignatureSubpacketTag.RevocationKey:
                 return new RevocationKey(isCritical, isLongLength, data);
+            case SignatureSubpacketTag.SignatureTarget:
+                return new SignatureTarget(isCritical, isLongLength, data);
+            case SignatureSubpacketTag.IssuerFingerprint:
+                return new IssuerFingerprint(isCritical, isLongLength, data);
+            case SignatureSubpacketTag.IntendedRecipientFingerprint:
+                return new IntendedRecipientFingerprint(isCritical, isLongLength, data);
             }
             return new SignatureSubpacket(type, isCritical, isLongLength, data);
 		}
diff --git a/crypto/src/bcpg/sig/IntendedRecipientFingerprint.cs b/crypto/src/bcpg/sig/IntendedRecipientFingerprint.cs
new file mode 100644
index 000000000..7077c2d40
--- /dev/null
+++ b/crypto/src/bcpg/sig/IntendedRecipientFingerprint.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+     * packet giving the intended recipient fingerprint.
+     */
+    public class IntendedRecipientFingerprint
+        : SignatureSubpacket
+    {
+        public IntendedRecipientFingerprint(bool critical, bool isLongLength, byte[] data)
+            : base(SignatureSubpacketTag.IntendedRecipientFingerprint, critical, isLongLength, data)
+        {
+        }
+
+        public IntendedRecipientFingerprint(bool critical, int keyVersion, byte[] fingerprint)
+            : base(SignatureSubpacketTag.IntendedRecipientFingerprint, critical, false,
+                Arrays.Prepend(fingerprint, (byte)keyVersion))
+        {
+        }
+
+        public int KeyVersion => data[0];
+
+        public byte[] GetFingerprint() => Arrays.CopyOfRange(data, 1, data.Length);
+    }
+}
diff --git a/crypto/src/bcpg/sig/IssuerFingerprint.cs b/crypto/src/bcpg/sig/IssuerFingerprint.cs
new file mode 100644
index 000000000..469a8e0d8
--- /dev/null
+++ b/crypto/src/bcpg/sig/IssuerFingerprint.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+     * packet giving the issuer key fingerprint.
+     */
+    public class IssuerFingerprint
+        : SignatureSubpacket
+    {
+        public IssuerFingerprint(bool critical, bool isLongLength, byte[] data)
+            : base(SignatureSubpacketTag.IssuerFingerprint, critical, isLongLength, data)
+        {
+        }
+
+        public IssuerFingerprint(bool critical, int keyVersion, byte[] fingerprint)
+            : base(SignatureSubpacketTag.IssuerFingerprint, critical, false,
+                Arrays.Prepend(fingerprint, (byte)keyVersion))
+        {
+        }
+
+        public int KeyVersion => data[0];
+
+        public byte[] GetFingerprint() => Arrays.CopyOfRange(data, 1, data.Length);
+    }
+}
diff --git a/crypto/src/bcpg/sig/PolicyUrl.cs b/crypto/src/bcpg/sig/PolicyUrl.cs
new file mode 100644
index 000000000..16f4d1a64
--- /dev/null
+++ b/crypto/src/bcpg/sig/PolicyUrl.cs
@@ -0,0 +1,24 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    public class PolicyUrl
+        : SignatureSubpacket
+    {
+        public PolicyUrl(bool critical, string url)
+            : this(critical, false, Strings.ToUtf8ByteArray(url))
+        {
+        }
+
+        public PolicyUrl(bool critical, bool isLongLength, byte[] data)
+            : base(SignatureSubpacketTag.PolicyUrl, critical, isLongLength, data)
+        {
+        }
+
+        public string Url => Strings.FromUtf8ByteArray(data);
+
+        public byte[] GetRawUrl() => Arrays.Clone(data);
+    }
+}
diff --git a/crypto/src/bcpg/sig/RegularExpression.cs b/crypto/src/bcpg/sig/RegularExpression.cs
new file mode 100644
index 000000000..c4b48ea2a
--- /dev/null
+++ b/crypto/src/bcpg/sig/RegularExpression.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Text.RegularExpressions;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+     * Regexp Packet - RFC 4880 5.2.3.14. Note: the RFC says the byte encoding is to be null terminated.
+     */
+    public class RegularExpression
+        : SignatureSubpacket
+    {
+        public RegularExpression(bool critical, bool isLongLength, byte[] data)
+            : base(SignatureSubpacketTag.RegExp, critical, isLongLength, data)
+        {
+            if (data[data.Length - 1] != 0)
+                throw new ArgumentException("data in regex missing null termination");
+        }
+
+        public RegularExpression(bool critical, string regex)
+            : base(SignatureSubpacketTag.RegExp, critical, false, ToNullTerminatedUtf8ByteArray(regex))
+        {
+        }
+
+        public string Regex
+        {
+            // last byte is null terminator
+            get { return Strings.FromUtf8ByteArray(data, 0, data.Length - 1); }
+        }
+
+        public byte[] GetRawRegex() => Arrays.Clone(data);
+
+        private static byte[] ToNullTerminatedUtf8ByteArray(string str)
+        {
+            byte[] utf8 = Strings.ToUtf8ByteArray(str);
+            return Arrays.Append(utf8, 0x00);
+        }
+    }
+}
diff --git a/crypto/src/bcpg/sig/RevocationKey.cs b/crypto/src/bcpg/sig/RevocationKey.cs
index 11467d2af..e4ad4195b 100644
--- a/crypto/src/bcpg/sig/RevocationKey.cs
+++ b/crypto/src/bcpg/sig/RevocationKey.cs
@@ -12,28 +12,20 @@ namespace Org.BouncyCastle.Bcpg
 		// 1 octet of class, 
 		// 1 octet of public-key algorithm ID, 
 		// 20 octets of fingerprint
-		public RevocationKey(
-			bool	isCritical,
-            bool    isLongLength,
-            byte[]  data)
+		public RevocationKey(bool isCritical, bool isLongLength, byte[] data)
 			: base(SignatureSubpacketTag.RevocationKey, isCritical, isLongLength, data)
 		{
 		}
 
-        public RevocationKey(
-			bool					isCritical,
-			RevocationKeyTag		signatureClass,
-			PublicKeyAlgorithmTag	keyAlgorithm,
-			byte[]					fingerprint)
+        public RevocationKey(bool isCritical, RevocationKeyTag signatureClass, PublicKeyAlgorithmTag keyAlgorithm,
+			byte[] fingerprint)
 			: base(SignatureSubpacketTag.RevocationKey, isCritical, false,
 				CreateData(signatureClass, keyAlgorithm, fingerprint))
 		{
 		}
 
-		private static byte[] CreateData(
-			RevocationKeyTag		signatureClass,
-			PublicKeyAlgorithmTag	keyAlgorithm,
-			byte[]					fingerprint)
+		private static byte[] CreateData(RevocationKeyTag signatureClass, PublicKeyAlgorithmTag keyAlgorithm,
+			byte[] fingerprint)
 		{
 			byte[] data = new byte[2 + fingerprint.Length];
 			data[0] = (byte)signatureClass;
@@ -44,17 +36,16 @@ namespace Org.BouncyCastle.Bcpg
 
 		public virtual RevocationKeyTag SignatureClass
 		{
-			get { return (RevocationKeyTag)this.GetData()[0]; }
+			get { return (RevocationKeyTag)data[0]; }
 		}
 
 		public virtual PublicKeyAlgorithmTag Algorithm
 		{
-			get { return (PublicKeyAlgorithmTag)this.GetData()[1]; }
+			get { return (PublicKeyAlgorithmTag)data[1]; }
 		}
 
         public virtual byte[] GetFingerprint()
 		{
-			byte[] data = this.GetData();
 			byte[] fingerprint = new byte[data.Length - 2];
 			Array.Copy(data, 2, fingerprint, 0, fingerprint.Length);
 			return fingerprint;
diff --git a/crypto/src/bcpg/sig/SignatureTarget.cs b/crypto/src/bcpg/sig/SignatureTarget.cs
new file mode 100644
index 000000000..c6a8dc574
--- /dev/null
+++ b/crypto/src/bcpg/sig/SignatureTarget.cs
@@ -0,0 +1,30 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+     * RFC 4880, Section 5.2.3.25 - Signature Target subpacket.
+     */
+    public class SignatureTarget
+        : SignatureSubpacket
+    {
+        public SignatureTarget(bool critical, bool isLongLength, byte[] data)
+            : base(SignatureSubpacketTag.SignatureTarget, critical, isLongLength, data)
+        {
+        }
+
+        public SignatureTarget(bool critical, int publicKeyAlgorithm, int hashAlgorithm, byte[] hashData)
+            : base(SignatureSubpacketTag.SignatureTarget, critical, false,
+                  Arrays.Concatenate(new byte[]{ (byte)publicKeyAlgorithm, (byte)hashAlgorithm }, hashData))
+        {
+        }
+
+        public int PublicKeyAlgorithm => data[0];
+
+        public int HashAlgorithm => data[1];
+
+        public byte[] GetHashData() => Arrays.CopyOfRange(data, 2, data.Length);
+    }
+}
diff --git a/crypto/src/util/Strings.cs b/crypto/src/util/Strings.cs
index 29a95a07e..b1a63a3a1 100644
--- a/crypto/src/util/Strings.cs
+++ b/crypto/src/util/Strings.cs
@@ -78,6 +78,11 @@ namespace Org.BouncyCastle.Utilities
             return Encoding.UTF8.GetString(bytes);
         }
 
+        public static string FromUtf8ByteArray(byte[] bytes, int index, int count)
+        {
+            return Encoding.UTF8.GetString(bytes, index, count);
+        }
+
         public static byte[] ToUtf8ByteArray(char[] cs)
         {
             return Encoding.UTF8.GetBytes(cs);