diff --git a/crypto/src/asn1/icao/CscaMasterList.cs b/crypto/src/asn1/icao/CscaMasterList.cs
new file mode 100644
index 000000000..6890d8a2e
--- /dev/null
+++ b/crypto/src/asn1/icao/CscaMasterList.cs
@@ -0,0 +1,83 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+ /**
+ * The CscaMasterList object. This object can be wrapped in a
+ * CMSSignedData to be published in LDAP.
+ *
+ * <pre>
+ * CscaMasterList ::= SEQUENCE {
+ * version CscaMasterListVersion,
+ * certList SET OF Certificate }
+ *
+ * CscaMasterListVersion :: INTEGER {v0(0)}
+ * </pre>
+ */
+ public class CscaMasterList
+ : Asn1Encodable
+ {
+ private DerInteger version = new DerInteger(0);
+ private X509CertificateStructure[] certList;
+
+ public static CscaMasterList GetInstance(
+ object obj)
+ {
+ if (obj is CscaMasterList)
+ return (CscaMasterList)obj;
+
+ if (obj != null)
+ return new CscaMasterList(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ private CscaMasterList(
+ Asn1Sequence seq)
+ {
+ if (seq == null || seq.Count == 0)
+ throw new ArgumentException("null or empty sequence passed.");
+
+ if (seq.Count != 2)
+ throw new ArgumentException("Incorrect sequence size: " + seq.Count);
+
+ this.version = DerInteger.GetInstance(seq[0]);
+
+ Asn1Set certSet = Asn1Set.GetInstance(seq[1]);
+
+ this.certList = new X509CertificateStructure[certSet.Count];
+ for (int i = 0; i < certList.Length; i++)
+ {
+ certList[i] = X509CertificateStructure.GetInstance(certSet[i]);
+ }
+ }
+
+ public CscaMasterList(
+ X509CertificateStructure[] certStructs)
+ {
+ certList = CopyCertList(certStructs);
+ }
+
+ public virtual int Version
+ {
+ get { return version.Value.IntValue; }
+ }
+
+ public X509CertificateStructure[] GetCertStructs()
+ {
+ return CopyCertList(certList);
+ }
+
+ private static X509CertificateStructure[] CopyCertList(X509CertificateStructure[] orig)
+ {
+ return (X509CertificateStructure[])orig.Clone();
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(version, new DerSet(certList));
+ }
+ }
+}
diff --git a/crypto/src/asn1/icao/DataGroupHash.cs b/crypto/src/asn1/icao/DataGroupHash.cs
new file mode 100644
index 000000000..e0d7eee7b
--- /dev/null
+++ b/crypto/src/asn1/icao/DataGroupHash.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+ /**
+ * The DataGroupHash object.
+ * <pre>
+ * DataGroupHash ::= SEQUENCE {
+ * dataGroupNumber DataGroupNumber,
+ * dataGroupHashValue OCTET STRING }
+ *
+ * DataGroupNumber ::= INTEGER {
+ * dataGroup1 (1),
+ * dataGroup1 (2),
+ * dataGroup1 (3),
+ * dataGroup1 (4),
+ * dataGroup1 (5),
+ * dataGroup1 (6),
+ * dataGroup1 (7),
+ * dataGroup1 (8),
+ * dataGroup1 (9),
+ * dataGroup1 (10),
+ * dataGroup1 (11),
+ * dataGroup1 (12),
+ * dataGroup1 (13),
+ * dataGroup1 (14),
+ * dataGroup1 (15),
+ * dataGroup1 (16) }
+ *
+ * </pre>
+ */
+ public class DataGroupHash
+ : Asn1Encodable
+ {
+ private readonly DerInteger dataGroupNumber;
+ private readonly Asn1OctetString dataGroupHashValue;
+
+ public static DataGroupHash GetInstance(
+ object obj)
+ {
+ if (obj is DataGroupHash)
+ return (DataGroupHash)obj;
+
+ if (obj != null)
+ return new DataGroupHash(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ private DataGroupHash(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ this.dataGroupNumber = DerInteger.GetInstance(seq[0]);
+ this.dataGroupHashValue = Asn1OctetString.GetInstance(seq[1]);
+ }
+
+ public DataGroupHash(
+ int dataGroupNumber,
+ Asn1OctetString dataGroupHashValue)
+ {
+ this.dataGroupNumber = new DerInteger(dataGroupNumber);
+ this.dataGroupHashValue = dataGroupHashValue;
+ }
+
+ public int DataGroupNumber
+ {
+ get { return dataGroupNumber.Value.IntValue; }
+ }
+
+ public Asn1OctetString DataGroupHashValue
+ {
+ get { return dataGroupHashValue; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(dataGroupNumber, dataGroupHashValue);
+ }
+ }
+}
diff --git a/crypto/src/asn1/icao/ICAOObjectIdentifiers.cs b/crypto/src/asn1/icao/ICAOObjectIdentifiers.cs
new file mode 100644
index 000000000..389d4dacd
--- /dev/null
+++ b/crypto/src/asn1/icao/ICAOObjectIdentifiers.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+ public abstract class IcaoObjectIdentifiers
+ {
+ //
+ // base id
+ //
+ public static readonly DerObjectIdentifier IdIcao = new DerObjectIdentifier("2.23.136");
+
+ public static readonly DerObjectIdentifier IdIcaoMrtd = IdIcao.Branch("1");
+ public static readonly DerObjectIdentifier IdIcaoMrtdSecurity = IdIcaoMrtd.Branch("1");
+
+ // LDS security object, see ICAO Doc 9303-Volume 2-Section IV-A3.2
+ public static readonly DerObjectIdentifier IdIcaoLdsSecurityObject = IdIcaoMrtdSecurity.Branch("1");
+
+ // CSCA master list, see TR CSCA Countersigning and Master List issuance
+ public static readonly DerObjectIdentifier IdIcaoCscaMasterList = IdIcaoMrtdSecurity.Branch("2");
+ public static readonly DerObjectIdentifier IdIcaoCscaMasterListSigningKey = IdIcaoMrtdSecurity.Branch("3");
+
+ // document type list, see draft TR LDS and PKI Maintenance, par. 3.2.1
+ public static readonly DerObjectIdentifier IdIcaoDocumentTypeList = IdIcaoMrtdSecurity.Branch("4");
+
+ // Active Authentication protocol, see draft TR LDS and PKI Maintenance,
+ // par. 5.2.2
+ public static readonly DerObjectIdentifier IdIcaoAAProtocolObject = IdIcaoMrtdSecurity.Branch("5");
+
+ // CSCA name change and key reoll-over, see draft TR LDS and PKI
+ // Maintenance, par. 3.2.1
+ public static readonly DerObjectIdentifier IdIcaoExtensions = IdIcaoMrtdSecurity.Branch("6");
+ public static readonly DerObjectIdentifier IdIcaoExtensionsNamechangekeyrollover = IdIcaoExtensions.Branch("1");
+ }
+}
diff --git a/crypto/src/asn1/icao/LDSSecurityObject.cs b/crypto/src/asn1/icao/LDSSecurityObject.cs
new file mode 100644
index 000000000..c33ca6877
--- /dev/null
+++ b/crypto/src/asn1/icao/LDSSecurityObject.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+ /**
+ * The LDSSecurityObject object (V1.8).
+ * <pre>
+ * LDSSecurityObject ::= SEQUENCE {
+ * version LDSSecurityObjectVersion,
+ * hashAlgorithm DigestAlgorithmIdentifier,
+ * dataGroupHashValues SEQUENCE SIZE (2..ub-DataGroups) OF DataHashGroup,
+ * ldsVersionInfo LDSVersionInfo OPTIONAL
+ * -- if present, version MUST be v1 }
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier,
+ *
+ * LDSSecurityObjectVersion :: INTEGER {V0(0)}
+ * </pre>
+ */
+ public class LdsSecurityObject
+ : Asn1Encodable
+ {
+ public const int UBDataGroups = 16;
+
+ private DerInteger version = new DerInteger(0);
+ private AlgorithmIdentifier digestAlgorithmIdentifier;
+ private DataGroupHash[] datagroupHash;
+ private LdsVersionInfo versionInfo;
+
+ public static LdsSecurityObject GetInstance(
+ object obj)
+ {
+ if (obj is LdsSecurityObject)
+ return (LdsSecurityObject)obj;
+
+ if (obj != null)
+ return new LdsSecurityObject(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ private LdsSecurityObject(
+ Asn1Sequence seq)
+ {
+ if (seq == null || seq.Count == 0)
+ throw new ArgumentException("null or empty sequence passed.");
+
+ IEnumerator e = seq.GetEnumerator();
+
+ // version
+ e.MoveNext();
+ version = DerInteger.GetInstance(e.Current);
+ // digestAlgorithmIdentifier
+ e.MoveNext();
+ digestAlgorithmIdentifier = AlgorithmIdentifier.GetInstance(e.Current);
+
+ e.MoveNext();
+ Asn1Sequence datagroupHashSeq = Asn1Sequence.GetInstance(e.Current);
+
+ if (version.Value.Equals(BigInteger.One))
+ {
+ e.MoveNext();
+ versionInfo = LdsVersionInfo.GetInstance(e.Current);
+ }
+
+ CheckDatagroupHashSeqSize(datagroupHashSeq.Count);
+
+ datagroupHash = new DataGroupHash[datagroupHashSeq.Count];
+ for (int i= 0; i< datagroupHashSeq.Count; i++)
+ {
+ datagroupHash[i] = DataGroupHash.GetInstance(datagroupHashSeq[i]);
+ }
+ }
+
+ public LdsSecurityObject(
+ AlgorithmIdentifier digestAlgorithmIdentifier,
+ DataGroupHash[] datagroupHash)
+ {
+ this.version = new DerInteger(0);
+ this.digestAlgorithmIdentifier = digestAlgorithmIdentifier;
+ this.datagroupHash = datagroupHash;
+
+ CheckDatagroupHashSeqSize(datagroupHash.Length);
+ }
+
+
+ public LdsSecurityObject(
+ AlgorithmIdentifier digestAlgorithmIdentifier,
+ DataGroupHash[] datagroupHash,
+ LdsVersionInfo versionInfo)
+ {
+ this.version = new DerInteger(1);
+ this.digestAlgorithmIdentifier = digestAlgorithmIdentifier;
+ this.datagroupHash = datagroupHash;
+ this.versionInfo = versionInfo;
+
+ CheckDatagroupHashSeqSize(datagroupHash.Length);
+ }
+
+ private void CheckDatagroupHashSeqSize(int size)
+ {
+ if (size < 2 || size > UBDataGroups)
+ throw new ArgumentException("wrong size in DataGroupHashValues : not in (2.."+ UBDataGroups +")");
+ }
+
+ public BigInteger Version
+ {
+ get { return version.Value; }
+ }
+
+ public AlgorithmIdentifier DigestAlgorithmIdentifier
+ {
+ get { return digestAlgorithmIdentifier; }
+ }
+
+ public DataGroupHash[] GetDatagroupHash()
+ {
+ return datagroupHash;
+ }
+
+ public LdsVersionInfo VersionInfo
+ {
+ get { return versionInfo; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ DerSequence hashSeq = new DerSequence(datagroupHash);
+
+ Asn1EncodableVector v = new Asn1EncodableVector(version, digestAlgorithmIdentifier, hashSeq);
+
+ if (versionInfo != null)
+ {
+ v.Add(versionInfo);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/crypto/src/asn1/icao/LDSVersionInfo.cs b/crypto/src/asn1/icao/LDSVersionInfo.cs
new file mode 100644
index 000000000..2cdcad2db
--- /dev/null
+++ b/crypto/src/asn1/icao/LDSVersionInfo.cs
@@ -0,0 +1,61 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+ public class LdsVersionInfo
+ : Asn1Encodable
+ {
+ private DerPrintableString ldsVersion;
+ private DerPrintableString unicodeVersion;
+
+ public LdsVersionInfo(string ldsVersion, string unicodeVersion)
+ {
+ this.ldsVersion = new DerPrintableString(ldsVersion);
+ this.unicodeVersion = new DerPrintableString(unicodeVersion);
+ }
+
+ private LdsVersionInfo(Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("sequence wrong size for LDSVersionInfo", "seq");
+
+ this.ldsVersion = DerPrintableString.GetInstance(seq[0]);
+ this.unicodeVersion = DerPrintableString.GetInstance(seq[1]);
+ }
+
+ public static LdsVersionInfo GetInstance(object obj)
+ {
+ if (obj is LdsVersionInfo)
+ return (LdsVersionInfo)obj;
+
+ if (obj != null)
+ return new LdsVersionInfo(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ public virtual string GetLdsVersion()
+ {
+ return ldsVersion.GetString();
+ }
+
+ public virtual string GetUnicodeVersion()
+ {
+ return unicodeVersion.GetString();
+ }
+
+ /**
+ * <pre>
+ * LDSVersionInfo ::= SEQUENCE {
+ * ldsVersion PRINTABLE STRING
+ * unicodeVersion PRINTABLE STRING
+ * }
+ * </pre>
+ * @return
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(ldsVersion, unicodeVersion);
+ }
+ }
+}
|