diff --git a/crypto/src/asn1/Asn1EncodableVector.cs b/crypto/src/asn1/Asn1EncodableVector.cs
index 49532fe57..8a97e8b4f 100644
--- a/crypto/src/asn1/Asn1EncodableVector.cs
+++ b/crypto/src/asn1/Asn1EncodableVector.cs
@@ -61,6 +61,14 @@ namespace Org.BouncyCastle.Asn1
}
}
+ public void AddOptionalTagged(bool isExplicit, int tagNo, Asn1Encodable obj)
+ {
+ if (null != obj)
+ {
+ v.Add(new DerTaggedObject(isExplicit, tagNo, obj));
+ }
+ }
+
public Asn1Encodable this[
int index]
{
diff --git a/crypto/src/asn1/bc/BCObjectIdentifiers.cs b/crypto/src/asn1/bc/BCObjectIdentifiers.cs
index 1e2448853..0ffd65dfc 100644
--- a/crypto/src/asn1/bc/BCObjectIdentifiers.cs
+++ b/crypto/src/asn1/bc/BCObjectIdentifiers.cs
@@ -101,5 +101,14 @@ namespace Org.BouncyCastle.Asn1.BC
* NewHope
*/
public static readonly DerObjectIdentifier newHope = bc_exch.Branch("1");
+
+ /**
+ * X.509 extension(4) values
+ * <p>
+ * 1.3.6.1.4.1.22554.4
+ */
+ public static readonly DerObjectIdentifier bc_ext = bc.Branch("4");
+
+ public static readonly DerObjectIdentifier linkedCertificate = bc_ext.Branch("1");
}
-}
\ No newline at end of file
+}
diff --git a/crypto/src/asn1/bc/LinkedCertificate.cs b/crypto/src/asn1/bc/LinkedCertificate.cs
new file mode 100644
index 000000000..c8d05d8f5
--- /dev/null
+++ b/crypto/src/asn1/bc/LinkedCertificate.cs
@@ -0,0 +1,100 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.BC
+{
+ /**
+ * Extension to tie an alternate certificate to the containing certificate.
+ * <pre>
+ * LinkedCertificate := SEQUENCE {
+ * digest DigestInfo, -- digest of PQC certificate
+ * certLocation GeneralName, -- location of PQC certificate
+ * certIssuer [0] Name OPTIONAL, -- issuer of PQC cert (if different from current certificate)
+ * cACerts [1] GeneralNames OPTIONAL, -- CA certificates for PQC cert (one of more locations)
+ * }
+ * </pre>
+ */
+ public class LinkedCertificate
+ : Asn1Encodable
+ {
+ private readonly DigestInfo mDigest;
+ private readonly GeneralName mCertLocation;
+
+ private X509Name mCertIssuer;
+ private GeneralNames mCACerts;
+
+ public LinkedCertificate(DigestInfo digest, GeneralName certLocation)
+ : this(digest, certLocation, null, null)
+ {
+ }
+
+ public LinkedCertificate(DigestInfo digest, GeneralName certLocation, X509Name certIssuer, GeneralNames caCerts)
+ {
+ this.mDigest = digest;
+ this.mCertLocation = certLocation;
+ this.mCertIssuer = certIssuer;
+ this.mCACerts = caCerts;
+ }
+
+ private LinkedCertificate(Asn1Sequence seq)
+ {
+ this.mDigest = DigestInfo.GetInstance(seq[0]);
+ this.mCertLocation = GeneralName.GetInstance(seq[1]);
+
+ for (int i = 2; i < seq.Count; ++i)
+ {
+ Asn1TaggedObject tagged = Asn1TaggedObject.GetInstance(seq[i]);
+
+ switch (tagged.TagNo)
+ {
+ case 0:
+ this.mCertIssuer = X509Name.GetInstance(tagged, false);
+ break;
+ case 1:
+ this.mCACerts = GeneralNames.GetInstance(tagged, false);
+ break;
+ default:
+ throw new ArgumentException("unknown tag in tagged field");
+ }
+ }
+ }
+
+ public static LinkedCertificate GetInstance(object obj)
+ {
+ if (obj is LinkedCertificate)
+ return (LinkedCertificate)obj;
+ if (obj != null)
+ return new LinkedCertificate(Asn1Sequence.GetInstance(obj));
+ return null;
+ }
+
+ public virtual DigestInfo Digest
+ {
+ get { return mDigest; }
+ }
+
+ public virtual GeneralName CertLocation
+ {
+ get { return mCertLocation; }
+ }
+
+ public virtual X509Name CertIssuer
+ {
+ get { return mCertIssuer; }
+ }
+
+ public virtual GeneralNames CACerts
+ {
+ get { return mCACerts; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(mDigest, mCertLocation);
+ v.AddOptionalTagged(false, 0, mCertIssuer);
+ v.AddOptionalTagged(false, 1, mCACerts);
+ return new DerSequence(v);
+ }
+ }
+}
|