From 7a79336a216eb2b3851f63647a3ba6c708259b99 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sat, 18 Feb 2023 15:15:10 +0700 Subject: ASN.1: "Alternative algorithm" types and extension OIDs --- crypto/src/asn1/x509/AlgorithmIdentifier.cs | 19 +++--- crypto/src/asn1/x509/AltSignatureAlgorithm.cs | 70 +++++++++++++++++++++ crypto/src/asn1/x509/AltSignatureValue.cs | 70 +++++++++++++++++++++ crypto/src/asn1/x509/SubjectAltPublicKeyInfo.cs | 84 +++++++++++++++++++++++++ crypto/src/asn1/x509/X509Extensions.cs | 15 +++++ crypto/test/src/asn1/test/X509AltTest.cs | 44 +++++++++++++ 6 files changed, 291 insertions(+), 11 deletions(-) create mode 100644 crypto/src/asn1/x509/AltSignatureAlgorithm.cs create mode 100644 crypto/src/asn1/x509/AltSignatureValue.cs create mode 100644 crypto/src/asn1/x509/SubjectAltPublicKeyInfo.cs create mode 100644 crypto/test/src/asn1/test/X509AltTest.cs diff --git a/crypto/src/asn1/x509/AlgorithmIdentifier.cs b/crypto/src/asn1/x509/AlgorithmIdentifier.cs index 169a95c0a..486772c16 100644 --- a/crypto/src/asn1/x509/AlgorithmIdentifier.cs +++ b/crypto/src/asn1/x509/AlgorithmIdentifier.cs @@ -8,23 +8,20 @@ namespace Org.BouncyCastle.Asn1.X509 private readonly DerObjectIdentifier algorithm; private readonly Asn1Encodable parameters; - public static AlgorithmIdentifier GetInstance( - Asn1TaggedObject obj, - bool explicitly) - { - return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); - } - - public static AlgorithmIdentifier GetInstance( - object obj) + public static AlgorithmIdentifier GetInstance(object obj) { if (obj == null) return null; - if (obj is AlgorithmIdentifier) - return (AlgorithmIdentifier)obj; + if (obj is AlgorithmIdentifier algorithmIdentifier) + return algorithmIdentifier; return new AlgorithmIdentifier(Asn1Sequence.GetInstance(obj)); } + public static AlgorithmIdentifier GetInstance(Asn1TaggedObject obj, bool explicitly) + { + return GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); + } + public AlgorithmIdentifier( DerObjectIdentifier algorithm) { diff --git a/crypto/src/asn1/x509/AltSignatureAlgorithm.cs b/crypto/src/asn1/x509/AltSignatureAlgorithm.cs new file mode 100644 index 000000000..0844de324 --- /dev/null +++ b/crypto/src/asn1/x509/AltSignatureAlgorithm.cs @@ -0,0 +1,70 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * X.509 Section 9.8.3. + *
+ * This extension may be used as a public-key certificate extension, a CRL extension or an AVL extension. It shall contain + * the algorithm identifier for the alternative digital signature algorithm used by the signer when creating an alternative + * digital signature and by the relying party when validating the alternative digital signature. + *
+     * altSignatureAlgorithm EXTENSION ::= {
+     *     SYNTAX AltSignatureAlgorithm
+     *     IDENTIFIED BY id-ce-altSignatureAlgorithm }
+     *
+     * AltSignatureAlgorithm ::= AlgorithmIdentifier{{SupportedAlgorithms}}
+     * 
+ * When the altSignatureAlgorithm extension is included in a particular value that is an instance of a data type that + * supports extensions, the altSignatureValue extension shall also be included. + *
+ * NOTE 1 – By having a separate altSignatureAlgorithm extension, instead of having it combined with the + * altSignatureValue extension, the alternative digital signature algorithm is protected by the alternative signature. + * This extension may be flagged either as critical or as non-critical. + *
+ * NOTE 2 – It is recommended that it be flagged as non-critical. Flagging it as critical would require all relying parties to understand + * the extension and the alternative public-key algorithms + */ + public class AltSignatureAlgorithm + : Asn1Encodable + { + private readonly AlgorithmIdentifier m_algorithm; + + public static AltSignatureAlgorithm GetInstance(object obj) + { + if (obj == null) + return null; + if (obj is AltSignatureAlgorithm altSignatureAlgorithm) + return altSignatureAlgorithm; + return new AltSignatureAlgorithm(AlgorithmIdentifier.GetInstance(obj)); + } + + public static AltSignatureAlgorithm GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) + { + return GetInstance(AlgorithmIdentifier.GetInstance(taggedObject, declaredExplicit)); + } + + public static AltSignatureAlgorithm FromExtensions(X509Extensions extensions) + { + return GetInstance( + X509Extensions.GetExtensionParsedValue(extensions, X509Extensions.AltSignatureAlgorithm)); + } + + public AltSignatureAlgorithm(AlgorithmIdentifier algorithm) + { + m_algorithm = algorithm; + } + + public AltSignatureAlgorithm(DerObjectIdentifier algorithm, Asn1Encodable parameters) + { + m_algorithm = new AlgorithmIdentifier(algorithm, parameters); + } + + public AlgorithmIdentifier Algorithm => m_algorithm; + + public override Asn1Object ToAsn1Object() + { + return m_algorithm.ToAsn1Object(); + } + } +} diff --git a/crypto/src/asn1/x509/AltSignatureValue.cs b/crypto/src/asn1/x509/AltSignatureValue.cs new file mode 100644 index 000000000..498c1d6d0 --- /dev/null +++ b/crypto/src/asn1/x509/AltSignatureValue.cs @@ -0,0 +1,70 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * X.509 Section 9.8.4. + *
+ * This extension may be used as a public-key certificate extension, a CRL extension or an AVL extension. + * This alternative signature shall be created by the issuer using its alternative private key, and it shall be verified using the + * alternative public key of the issuer. + *
+     * altSignatureValue EXTENSION ::= {
+     *     SYNTAX AltSignatureValue
+     *     IDENTIFIED BY id-ce-altSignatureValue }
+     *
+     * AltSignatureValue ::= BIT STRING
+     * 
+ * This extension can only be created by a signer holding a multiple cryptographic algorithms public-key certificate. When + * creating the alternative digital signature on an issued public-key certificate or CRL, the signer shall use its alternative + * private key. + *
+ * The procedures for creating and validating alternative digital signatures are specified in: + * + */ + public class AltSignatureValue + : Asn1Encodable + { + private readonly DerBitString m_signature; + + public static AltSignatureValue GetInstance(object obj) + { + if (obj == null) + return null; + if (obj is AltSignatureValue altSignatureValue) + return altSignatureValue; + return new AltSignatureValue(DerBitString.GetInstance(obj)); + } + + public static AltSignatureValue GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) + { + return GetInstance(DerBitString.GetInstance(taggedObject, declaredExplicit)); + } + + public static AltSignatureValue FromExtensions(X509Extensions extensions) + { + return GetInstance(X509Extensions.GetExtensionParsedValue(extensions, X509Extensions.AltSignatureValue)); + } + + private AltSignatureValue(DerBitString signature) + { + m_signature = signature; + } + + public AltSignatureValue(byte[] signature) + { + m_signature = new DerBitString(signature); + } + + public DerBitString Signature => m_signature; + + public override Asn1Object ToAsn1Object() + { + return m_signature; + } + } +} diff --git a/crypto/src/asn1/x509/SubjectAltPublicKeyInfo.cs b/crypto/src/asn1/x509/SubjectAltPublicKeyInfo.cs new file mode 100644 index 000000000..4fe165898 --- /dev/null +++ b/crypto/src/asn1/x509/SubjectAltPublicKeyInfo.cs @@ -0,0 +1,84 @@ +using System; + +namespace Org.BouncyCastle.Asn1.X509 +{ + /** + * X.509 Section 9.8.2. + *
+ * This public-key certificate extension, when present, shall contain the subject’s alternative public key information + *
+     * subjectAltPublicKeyInfo EXTENSION ::= {
+     *      SYNTAX SubjectAltPublicKeyInfo
+     *      IDENTIFIED BY id-ce-subjectAltPublicKeyInfo }
+     *
+     * SubjectAltPublicKeyInfo ::= SEQUENCE {
+     *     algorithm AlgorithmIdentifier{{SupportedAlgorithms}},
+     *     subjectAltPublicKey BIT STRING }
+     * 
+ * The SubjectAltPublicKeyInfo data type has the following components: + * + * This extension may be flagged as critical or as non-critical. + *
+ * NOTE – It is recommended that it be flagged as non-critical. Flagging it as critical would require relying parties to understand this + * extension and the alternative public-key algorithm. + */ + public class SubjectAltPublicKeyInfo + : Asn1Encodable + { + private readonly AlgorithmIdentifier m_algorithm; + private readonly DerBitString m_subjectAltPublicKey; + + public static SubjectAltPublicKeyInfo GetInstance(object obj) + { + if (obj == null) + return null; + if (obj is SubjectAltPublicKeyInfo subjectAltPublicKeyInfo) + return subjectAltPublicKeyInfo; + return new SubjectAltPublicKeyInfo(Asn1Sequence.GetInstance(obj)); + } + + public static SubjectAltPublicKeyInfo GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) + { + return GetInstance(Asn1Sequence.GetInstance(taggedObject, declaredExplicit)); + } + + public static SubjectAltPublicKeyInfo FromExtensions(X509Extensions extensions) + { + return GetInstance( + X509Extensions.GetExtensionParsedValue(extensions, X509Extensions.SubjectAltPublicKeyInfo)); + } + + private SubjectAltPublicKeyInfo(Asn1Sequence seq) + { + if (seq.Count != 2) + throw new ArgumentException("extension should contain only 2 elements"); + + m_algorithm = AlgorithmIdentifier.GetInstance(seq[0]); + m_subjectAltPublicKey = DerBitString.GetInstance(seq[1]); + } + + public SubjectAltPublicKeyInfo(AlgorithmIdentifier algorithm, DerBitString subjectAltPublicKey) + { + m_algorithm = algorithm; + m_subjectAltPublicKey = subjectAltPublicKey; + } + + public SubjectAltPublicKeyInfo(SubjectPublicKeyInfo subjectPublicKeyInfo) + { + m_algorithm = subjectPublicKeyInfo.AlgorithmID; + m_subjectAltPublicKey = subjectPublicKeyInfo.PublicKeyData; + } + + public AlgorithmIdentifier Algorithm => Algorithm; + + public DerBitString SubjectAltPublicKey => m_subjectAltPublicKey; + + public override Asn1Object ToAsn1Object() + { + return new DerSequence(m_algorithm, m_subjectAltPublicKey); + } + } +} diff --git a/crypto/src/asn1/x509/X509Extensions.cs b/crypto/src/asn1/x509/X509Extensions.cs index aa5205800..62291a829 100644 --- a/crypto/src/asn1/x509/X509Extensions.cs +++ b/crypto/src/asn1/x509/X509Extensions.cs @@ -169,6 +169,21 @@ namespace Org.BouncyCastle.Asn1.X509 */ public static readonly DerObjectIdentifier ExpiredCertsOnCrl = new DerObjectIdentifier("2.5.29.60"); + /** + * the subject’s alternative public key information + */ + public static readonly DerObjectIdentifier SubjectAltPublicKeyInfo = new DerObjectIdentifier("2.5.29.72"); + + /** + * the algorithm identifier for the alternative digital signature algorithm. + */ + public static readonly DerObjectIdentifier AltSignatureAlgorithm = new DerObjectIdentifier("2.5.29.73"); + + /** + * alternative signature shall be created by the issuer using its alternative private key. + */ + public static readonly DerObjectIdentifier AltSignatureValue = new DerObjectIdentifier("2.5.29.74"); + private readonly Dictionary m_extensions = new Dictionary(); private readonly List m_ordering; diff --git a/crypto/test/src/asn1/test/X509AltTest.cs b/crypto/test/src/asn1/test/X509AltTest.cs new file mode 100644 index 000000000..047d2e23b --- /dev/null +++ b/crypto/test/src/asn1/test/X509AltTest.cs @@ -0,0 +1,44 @@ +using NUnit.Framework; + +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Asn1.Tests +{ + [TestFixture] + public class X509AltTest + { + [Test] + public void TestX509AltTypes() + { + SubjectAltPublicKeyInfo subAlt = new SubjectAltPublicKeyInfo( + new AlgorithmIdentifier(PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance), + new DerBitString(Hex.DecodeStrict("0102030405060708090807060504030201"))); + AltSignatureValue sigValAlt = new AltSignatureValue(Hex.DecodeStrict("0102030405060708090807060504030201")); + + AltSignatureAlgorithm sigAlgAlt = new AltSignatureAlgorithm( + new AlgorithmIdentifier(PkcsObjectIdentifiers.MD5WithRsaEncryption, DerNull.Instance)); + AltSignatureAlgorithm sigAlgAlt2 = new AltSignatureAlgorithm( + PkcsObjectIdentifiers.MD5WithRsaEncryption, DerNull.Instance); + + Assert.AreEqual(sigAlgAlt, sigAlgAlt2); + + var extGen = new X509ExtensionsGenerator(); + extGen.AddExtension(X509Extensions.SubjectAltPublicKeyInfo, false, subAlt); + extGen.AddExtension(X509Extensions.AltSignatureAlgorithm, false, sigAlgAlt); + extGen.AddExtension(X509Extensions.AltSignatureValue, false, sigValAlt); + + var exts = extGen.Generate(); + Assert.AreEqual(subAlt, SubjectAltPublicKeyInfo.FromExtensions(exts)); + Assert.AreEqual(sigAlgAlt, AltSignatureAlgorithm.FromExtensions(exts)); + Assert.AreEqual(sigValAlt, AltSignatureValue.FromExtensions(exts)); + Assert.AreEqual(subAlt, SubjectAltPublicKeyInfo.GetInstance(subAlt.GetEncoded())); + Assert.AreEqual(sigAlgAlt, AltSignatureAlgorithm.GetInstance(sigAlgAlt.GetEncoded())); + Assert.AreEqual(sigValAlt, AltSignatureValue.GetInstance(sigValAlt.GetEncoded())); + Assert.AreEqual(subAlt, SubjectAltPublicKeyInfo.GetInstance(new DerTaggedObject(1, subAlt), true)); + Assert.AreEqual(sigAlgAlt, AltSignatureAlgorithm.GetInstance(new DerTaggedObject(1, sigAlgAlt), true)); + Assert.AreEqual(sigValAlt, AltSignatureValue.GetInstance(new DerTaggedObject(1, sigValAlt), true)); + } + } +} -- cgit 1.4.1