Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastien Pouliot <sebastien@ximian.com>2003-03-16 03:41:50 +0300
committerSebastien Pouliot <sebastien@ximian.com>2003-03-16 03:41:50 +0300
commit8e6623df7b256c204111a8566c68f3bd9cb70ac3 (patch)
tree7510feef44ab6556b4fe66b97be6008fffe01b0a /mcs/class/Mono.Security/Mono.Security.X509
parenta4a6e2334b06db7834e78871b6f961beb57923dd (diff)
2003-03-15 Sebastien Pouliot <spouliot@videotron.ca>
* X501Name.cs: New. X.501 Distinguished Names stuff * X509Builder.cs: New. Abstract class for building X.509 related structures (like certificates and CRLs). * X509Certificate.cs: New. A more complete class to handle X.509 certificates. * X509CertificateBuilder.cs: New. Class to build X.509 certificates. * X509Extension.cs: New. A base class for all X.509 extensions. * X509Extensions.cs: New. X509Extension collection. * X520Attributes.cs: New. X.520 attributes (mainly for X501 names) svn path=/trunk/mcs/; revision=12574
Diffstat (limited to 'mcs/class/Mono.Security/Mono.Security.X509')
-rw-r--r--mcs/class/Mono.Security/Mono.Security.X509/ChangeLog11
-rw-r--r--mcs/class/Mono.Security/Mono.Security.X509/X501Name.cs176
-rw-r--r--mcs/class/Mono.Security/Mono.Security.X509/X509Builder.cs122
-rw-r--r--mcs/class/Mono.Security/Mono.Security.X509/X509Certificate.cs429
-rw-r--r--mcs/class/Mono.Security/Mono.Security.X509/X509CertificateBuilder.cs221
-rw-r--r--mcs/class/Mono.Security/Mono.Security.X509/X509Extension.cs136
-rw-r--r--mcs/class/Mono.Security/Mono.Security.X509/X509Extensions.cs105
-rw-r--r--mcs/class/Mono.Security/Mono.Security.X509/X520Attributes.cs213
8 files changed, 1413 insertions, 0 deletions
diff --git a/mcs/class/Mono.Security/Mono.Security.X509/ChangeLog b/mcs/class/Mono.Security/Mono.Security.X509/ChangeLog
new file mode 100644
index 00000000000..c8f9e2bae70
--- /dev/null
+++ b/mcs/class/Mono.Security/Mono.Security.X509/ChangeLog
@@ -0,0 +1,11 @@
+2003-03-15 Sebastien Pouliot <spouliot@videotron.ca>
+
+ * X501Name.cs: New. X.501 Distinguished Names stuff
+ * X509Builder.cs: New. Abstract class for building X.509 related
+ structures (like certificates and CRLs).
+ * X509Certificate.cs: New. A more complete class to handle X.509
+ certificates.
+ * X509CertificateBuilder.cs: New. Class to build X.509 certificates.
+ * X509Extension.cs: New. A base class for all X.509 extensions.
+ * X509Extensions.cs: New. X509Extension collection.
+ * X520Attributes.cs: New. X.520 attributes (mainly for X501 names) \ No newline at end of file
diff --git a/mcs/class/Mono.Security/Mono.Security.X509/X501Name.cs b/mcs/class/Mono.Security/Mono.Security.X509/X501Name.cs
new file mode 100644
index 00000000000..7fbbf213fac
--- /dev/null
+++ b/mcs/class/Mono.Security/Mono.Security.X509/X501Name.cs
@@ -0,0 +1,176 @@
+//
+// X501Name.cs: X.501 Distinguished Names stuff
+//
+// Author:
+// Sebastien Pouliot (spouliot@motus.com)
+//
+// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
+//
+
+using System;
+using System.Text;
+
+using Mono.Security;
+
+namespace Mono.Security.X509 {
+
+ // References:
+ // 1. Information technology - Open Systems Interconnection - The Directory: Models
+ // http://www.itu.int/rec/recommendation.asp?type=items&lang=e&parent=T-REC-X.501-200102-I
+ // 2. RFC2253: Lightweight Directory Access Protocol (v3): UTF-8 String Representation of Distinguished Names
+ // http://www.ietf.org/rfc/rfc2253.txt
+
+ /*
+ * Name ::= CHOICE { RDNSequence }
+ *
+ * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ *
+ * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
+ */
+ public class X501 {
+
+ static byte[] countryName = { 0x55, 0x04, 0x06 };
+ static byte[] organizationName = { 0x55, 0x04, 0x0A };
+ static byte[] organizationalUnitName = { 0x55, 0x04, 0x0B };
+ static byte[] commonName = { 0x55, 0x04, 0x03 };
+ static byte[] localityName = { 0x55, 0x04, 0x07 };
+ static byte[] stateOrProvinceName = { 0x55, 0x04, 0x08 };
+ static byte[] streetAddress = { 0x55, 0x04, 0x09 };
+ static byte[] serialNumber = { 0x55, 0x04, 0x05 };
+ static byte[] domainComponent = { 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x19 };
+ static byte[] userid = { 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x01 };
+ static byte[] email = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 };
+
+ static public string ToString (ASN1 seq)
+ {
+ StringBuilder sb = new StringBuilder ();
+ for (int i = 0; i < seq.Count; i++) {
+ ASN1 entry = seq [i];
+ ASN1 pair = entry [0];
+
+ ASN1 s = pair [1];
+ if (s == null)
+ continue;
+
+ ASN1 poid = pair [0];
+ if (poid == null)
+ continue;
+
+ if (poid.CompareValue (countryName))
+ sb.Append ("C=");
+ else if (poid.CompareValue (organizationName))
+ sb.Append ("O=");
+ else if (poid.CompareValue (organizationalUnitName))
+ sb.Append ("OU=");
+ else if (poid.CompareValue (commonName))
+ sb.Append ("CN=");
+ else if (poid.CompareValue (localityName))
+ sb.Append ("L=");
+ else if (poid.CompareValue (stateOrProvinceName))
+ sb.Append ("S="); // NOTE: RFC2253 uses ST=
+ else if (poid.CompareValue (streetAddress))
+ sb.Append ("STREET=");
+ else if (poid.CompareValue (domainComponent))
+ sb.Append ("DC=");
+ else if (poid.CompareValue (userid))
+ sb.Append ("UID=");
+ else if (poid.CompareValue (email))
+ sb.Append ("E="); // NOTE: Not part of RFC2253
+ else {
+ // unknown OID
+ sb.Append ("OID."); // NOTE: Not present as RFC2253
+ sb.Append (ASN1Convert.ToOID (poid));
+ sb.Append ("=");
+ }
+
+ string sValue = null;
+ // 16bits or 8bits string ? TODO not complete (+special chars!)
+ if (s.Tag == 0x1E) {
+ // BMPSTRING
+ StringBuilder sb2 = new StringBuilder ();
+ for (int j = 1; j < s.Value.Length; j+=2)
+ sb2.Append ((char) s.Value[j]);
+ sValue = sb2.ToString ();
+ }
+ else {
+ sValue = System.Text.Encoding.UTF8.GetString (s.Value);
+ // in some cases we must quote (") the value
+ // Note: this doesn't seems to conform to RFC2253
+ char[] specials = { ',', '+', '"', '\\', '<', '>', ';' };
+ if (sValue.IndexOfAny(specials, 0, sValue.Length) > 0)
+ sValue = "\"" + sValue + "\"";
+ else if (sValue.StartsWith (" "))
+ sValue = "\"" + sValue + "\"";
+ else if (sValue.EndsWith (" "))
+ sValue = "\"" + sValue + "\"";
+ }
+
+ sb.Append (sValue);
+
+ // separator (not on last iteration)
+ if (i < seq.Count - 1)
+ sb.Append (", ");
+ }
+ return sb.ToString ();
+ }
+
+ static private X520.AttributeTypeAndValue GetAttributeFromOID (string attributeType)
+ {
+ switch (attributeType.ToUpper ().Trim ()) {
+ case "C":
+ return new X520.CountryName ();
+ case "O":
+ return new X520.OrganizationName ();
+ case "OU":
+ return new X520.OrganizationalUnitName ();
+ case "CN":
+ return new X520.CommonName ();
+ case "L":
+ return new X520.LocalityName ();
+ case "S": // Microsoft
+ case "ST": // RFC2253
+ return new X520.StateOrProvinceName ();
+ case "DC":
+// return streetAddress;
+ case "UID":
+// return domainComponent;
+ default:
+ return null;
+ }
+ }
+
+ static public ASN1 FromString (string rdn)
+ {
+ if (rdn == null)
+ throw new ArgumentNullException ("rdn");
+ // get string from here to ',' or end of string
+ int start = 0;
+ int end = 0;
+ ASN1 asn1 = new ASN1 (0x30);
+ while (start < rdn.Length) {
+ end = rdn.IndexOf (',', end) + 1;
+ if (end == 0)
+ end = rdn.Length + 1;
+ string av = rdn.Substring (start, end - start - 1);
+ // get '=' position in substring
+ int equal = av.IndexOf ('=');
+ // get AttributeType
+ string attributeType = av.Substring (0, equal);
+ // get value
+ string attributeValue = av.Substring (equal + 1);
+
+ X520.AttributeTypeAndValue atv = GetAttributeFromOID (attributeType);
+ atv.Value = attributeValue;
+ asn1.Add (new ASN1 (0x31, atv.GetBytes ()));
+
+ // next part
+ start = end;
+ if (start != - 1) {
+ if (end > rdn.Length)
+ break;
+ }
+ }
+ return asn1;
+ }
+ }
+}
diff --git a/mcs/class/Mono.Security/Mono.Security.X509/X509Builder.cs b/mcs/class/Mono.Security/Mono.Security.X509/X509Builder.cs
new file mode 100644
index 00000000000..591fe67fa64
--- /dev/null
+++ b/mcs/class/Mono.Security/Mono.Security.X509/X509Builder.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Security.Cryptography;
+
+using Mono.Security;
+
+namespace Mono.Security.X509 {
+
+ public abstract class X509Builder {
+
+ private const string defaultHash = "SHA1";
+ private string hashName;
+
+ public X509Builder ()
+ {
+ hashName = defaultHash;
+ }
+
+ protected abstract ASN1 ToBeSigned (string hashName);
+
+ // move to PKCS1
+ protected string GetOID (string hashName)
+ {
+ switch (hashName.ToLower ()) {
+ case "md2":
+ // md2withRSAEncryption (1 2 840 113549 1 1 2)
+ return "1.2.840.113549.1.1.2";
+ case "md4":
+ // md4withRSAEncryption (1 2 840 113549 1 1 3)
+ return "1.2.840.113549.1.1.3";
+ case "md5":
+ // md5withRSAEncryption (1 2 840 113549 1 1 4)
+ return "1.2.840.113549.1.1.4";
+ case "sha1":
+ // sha1withRSAEncryption (1 2 840 113549 1 1 5)
+ return "1.2.840.113549.1.1.5";
+ case "sha256":
+ // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
+ return "1.2.840.113549.1.1.11";
+ case "sha384":
+ // sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
+ return "1.2.840.113549.1.1.12";
+ case "sha512":
+ // sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
+ return "1.2.840.113549.1.1.13";
+ default:
+ throw new NotSupportedException ("Unknown hash algorithm " + hashName);
+ }
+ }
+
+ public string Hash {
+ get { return hashName; }
+ set {
+ if (hashName == null)
+ hashName = defaultHash;
+ else
+ hashName = value;
+ }
+ }
+
+ public virtual byte[] Sign (AsymmetricAlgorithm aa)
+ {
+ if (aa is RSA)
+ return Sign (aa as RSA);
+ else if (aa is DSA)
+ return Sign (aa as DSA);
+ else
+ throw new NotSupportedException ("Unknown Asymmetric Algorithm " + aa.ToString());
+ }
+
+ private byte[] Build (ASN1 tbs, string hashoid, byte[] signature)
+ {
+ ASN1 builder = new ASN1 (0x30);
+ builder.Add (tbs);
+ builder.Add (PKCS7.AlgorithmIdentifier (hashoid));
+ // first byte of BITSTRING is the number of unused bits in the first byte
+ byte[] bitstring = new byte [signature.Length + 1];
+ Array.Copy (signature, 0, bitstring, 1, signature.Length);
+ builder.Add (new ASN1 (0x03, bitstring));
+ return builder.GetBytes ();
+ }
+
+ public virtual byte[] Sign (RSA key)
+ {
+ string oid = GetOID (hashName);
+ ASN1 tbs = ToBeSigned (oid);
+ HashAlgorithm ha = HashAlgorithm.Create (hashName);
+ byte[] hash = ha.ComputeHash (tbs.GetBytes ());
+
+ RSAPKCS1SignatureFormatter pkcs1 = new RSAPKCS1SignatureFormatter (key);
+ pkcs1.SetHashAlgorithm (hashName);
+ byte[] signature = pkcs1.CreateSignature (hash);
+
+ return Build (tbs, oid, signature);
+ }
+
+ public virtual byte[] Sign (DSA key)
+ {
+ string oid = "1.2.840.10040.4.3";
+ ASN1 tbs = ToBeSigned (oid);
+ HashAlgorithm ha = HashAlgorithm.Create (hashName);
+ if (!(ha is SHA1))
+ throw new NotSupportedException ("Only SHA-1 is supported for DSA");
+ byte[] hash = ha.ComputeHash (tbs.GetBytes ());
+
+ DSASignatureFormatter dsa = new DSASignatureFormatter (key);
+ dsa.SetHashAlgorithm (hashName);
+ byte[] rs = dsa.CreateSignature (hash);
+
+ // split R and S
+ byte[] r = new byte [20];
+ Array.Copy (rs, 0, r, 0, 20);
+ byte[] s = new byte [20];
+ Array.Copy (rs, 20, s, 0, 20);
+ ASN1 signature = new ASN1 (0x30);
+ signature.Add (new ASN1 (0x02, r));
+ signature.Add (new ASN1 (0x02, s));
+
+ // dsaWithSha1 (1 2 840 10040 4 3)
+ return Build (tbs, oid, signature.GetBytes ());
+ }
+ }
+}
diff --git a/mcs/class/Mono.Security/Mono.Security.X509/X509Certificate.cs b/mcs/class/Mono.Security/Mono.Security.X509/X509Certificate.cs
new file mode 100644
index 00000000000..582e9cd3409
--- /dev/null
+++ b/mcs/class/Mono.Security/Mono.Security.X509/X509Certificate.cs
@@ -0,0 +1,429 @@
+//
+// X509Certificates.cs: Handles X.509 certificates.
+//
+// Author:
+// Sebastien Pouliot (spouliot@motus.com)
+//
+// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
+//
+
+using System;
+using System.Security.Cryptography;
+using SSCX = System.Security.Cryptography.X509Certificates;
+using System.Text;
+
+namespace Mono.Security.X509 {
+
+ // References:
+ // a. Internet X.509 Public Key Infrastructure Certificate and CRL Profile
+ // http://www.ietf.org/rfc/rfc3280.txt
+ // b. ITU ASN.1 standards (free download)
+ // http://www.itu.int/ITU-T/studygroups/com17/languages/
+
+ public class X509Certificate {
+
+ private ASN1 decoder;
+
+ private byte[] m_encodedcert;
+ private DateTime m_from;
+ private DateTime m_until;
+ private string m_issuername;
+ private string m_keyalgo;
+ private byte[] m_keyalgoparams;
+ private string m_subject;
+ private byte[] m_publickey;
+ private byte[] signature;
+ private string m_signaturealgo;
+ private byte[] m_signaturealgoparams;
+
+ // from http://www.ietf.org/rfc/rfc2459.txt
+ //
+ //Certificate ::= SEQUENCE {
+ // tbsCertificate TBSCertificate,
+ // signatureAlgorithm AlgorithmIdentifier,
+ // signature BIT STRING }
+ //
+ //TBSCertificate ::= SEQUENCE {
+ // version [0] Version DEFAULT v1,
+ // serialNumber CertificateSerialNumber,
+ // signature AlgorithmIdentifier,
+ // issuer Name,
+ // validity Validity,
+ // subject Name,
+ // subjectPublicKeyInfo SubjectPublicKeyInfo,
+ // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
+ // -- If present, version shall be v2 or v3
+ // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
+ // -- If present, version shall be v2 or v3
+ // extensions [3] Extensions OPTIONAL
+ // -- If present, version shall be v3 -- }
+ private int version;
+ private byte[] serialnumber;
+
+ private byte[] issuerUniqueID;
+ private byte[] subjectUniqueID;
+ private X509Extensions extensions;
+
+ // that's were the real job is!
+ private void Parse (byte[] data)
+ {
+ string e = "Input data cannot be coded as a valid certificate.";
+ try {
+ decoder = new ASN1 (data);
+ // Certificate
+ if (decoder.Tag != 0x30)
+ throw new CryptographicException (e);
+ // Certificate / TBSCertificate
+ if (decoder [0].Tag != 0x30)
+ throw new CryptographicException (e);
+
+ ASN1 tbsCertificate = decoder [0];
+
+ int tbs = 0;
+ // Certificate / TBSCertificate / Version
+ ASN1 v = decoder [0][tbs];
+ version = 1; // DEFAULT v1
+ if (v.Tag == 0xA0) {
+ // version (optional) is present only in v2+ certs
+ version += v.Value [0]; // zero based
+ tbs++;
+ }
+
+ // Certificate / TBSCertificate / CertificateSerialNumber
+ ASN1 sn = decoder [0][tbs++];
+ if (sn.Tag != 0x02)
+ throw new CryptographicException (e);
+ serialnumber = sn.Value;
+ Array.Reverse (serialnumber, 0, serialnumber.Length);
+
+ // Certificate / TBSCertificate / AlgorithmIdentifier
+ ASN1 signatureAlgo = tbsCertificate.Element (tbs++, 0x30);
+
+ ASN1 issuer = tbsCertificate.Element (tbs++, 0x30);
+ m_issuername = X501.ToString (issuer);
+
+ ASN1 validity = tbsCertificate.Element (tbs++, 0x30);
+ ASN1 notBefore = validity [0];
+ m_from = ASN1Convert.ToDateTime (notBefore);
+ ASN1 notAfter = validity [1];
+ m_until = ASN1Convert.ToDateTime (notAfter);
+
+ ASN1 subject = tbsCertificate.Element (tbs++, 0x30);
+ m_subject = X501.ToString (subject);
+
+ ASN1 subjectPublicKeyInfo = tbsCertificate.Element (tbs++, 0x30);
+
+ ASN1 algorithm = subjectPublicKeyInfo.Element (0, 0x30);
+ ASN1 algo = algorithm.Element (0, 0x06);
+ m_keyalgo = ASN1Convert.ToOID (algo);
+ // parameters ANY DEFINED BY algorithm OPTIONAL
+ // so we dont ask for a specific (Element) type and return DER
+ ASN1 parameters = algorithm [1];
+ m_keyalgoparams = parameters.GetBytes ();
+
+ ASN1 subjectPublicKey = subjectPublicKeyInfo.Element (1, 0x03);
+ // we must drop th first byte (which is the number of unused bits
+ // in the BITSTRING)
+ int n = subjectPublicKey.Length - 1;
+ m_publickey = new byte [n];
+ Array.Copy (subjectPublicKey.Value, 1, m_publickey, 0, n);
+
+ // signature processing
+ byte[] bitstring = decoder [2].Value;
+ // first byte contains unused bits in first byte
+ signature = new byte [bitstring.Length - 1];
+ Array.Copy (bitstring, 1, signature, 0, signature.Length);
+
+ algorithm = decoder [1];
+ algo = algorithm.Element (0, 0x06);
+ m_signaturealgo = ASN1Convert.ToOID (algo);
+ parameters = algorithm [1];
+ if (parameters != null)
+ m_signaturealgoparams = parameters.GetBytes ();
+ else
+ m_signaturealgoparams = null;
+
+ // Certificate / TBSCertificate / issuerUniqueID
+ ASN1 issuerUID = tbsCertificate.Element (tbs, 0xA1);
+ if (issuerUID != null) {
+ tbs++;
+ issuerUniqueID = issuerUID.Value;
+ }
+
+ // Certificate / TBSCertificate / subjectUniqueID
+ ASN1 subjectUID = tbsCertificate.Element (tbs, 0xA2);
+ if (subjectUID != null) {
+ tbs++;
+ subjectUniqueID = subjectUID.Value;
+ }
+
+ // Certificate / TBSCertificate / Extensions
+ ASN1 extns = tbsCertificate.Element (tbs, 0xA3);
+ if ((extns != null) && (extns.Count == 1))
+ extensions = new X509Extensions (extns [0]);
+ else
+ extensions = new X509Extensions (null);
+
+ // keep a copy of the original data
+ m_encodedcert = (byte[]) data.Clone ();
+ }
+ catch {
+ throw new CryptographicException (e);
+ }
+ }
+
+ // constructors
+
+ public X509Certificate (byte[] data)
+ {
+ if (data != null)
+ Parse (data);
+ }
+
+ private byte[] GetUnsignedBigInteger (byte[] integer)
+ {
+ if (integer [0] == 0x00) {
+ // this first byte is added so we're sure it's an unsigned integer
+ // however we can't feed it into RSAParameters or DSAParameters
+ int length = integer.Length - 1;
+ byte[] uinteger = new byte [length];
+ Array.Copy (integer, 1, uinteger, 0, length);
+ return uinteger;
+ }
+ else
+ return integer;
+ }
+
+ // public methods
+
+ public DSA DSA {
+ get {
+ DSAParameters dsaParams = new DSAParameters ();
+ // for DSA m_publickey contains 1 ASN.1 integer - Y
+ ASN1 pubkey = new ASN1 (m_publickey);
+ if ((pubkey == null) || (pubkey.Tag != 0x02))
+ return null;
+ dsaParams.Y = GetUnsignedBigInteger (pubkey.Value);
+
+ ASN1 param = new ASN1 (m_keyalgoparams);
+ if ((param == null) || (param.Tag != 0x30) || (param.Count < 3))
+ return null;
+ if ((param [0].Tag != 0x02) || (param [1].Tag != 0x02) || (param [2].Tag != 0x02))
+ return null;
+ dsaParams.P = GetUnsignedBigInteger (param [0].Value);
+ dsaParams.Q = GetUnsignedBigInteger (param [1].Value);
+ dsaParams.G = GetUnsignedBigInteger (param [2].Value);
+
+ // BUG: MS BCL 1.0 can't import a key which
+ // isn't the same size as the one present in
+ // the container.
+ DSACryptoServiceProvider dsa = new DSACryptoServiceProvider (dsaParams.Y.Length << 3);
+ dsa.ImportParameters (dsaParams);
+ return (DSA) dsa;
+ }
+ }
+
+ public X509Extensions Extensions {
+ get { return extensions; }
+ }
+
+ public byte[] Hash {
+ get {
+ HashAlgorithm hash = null;
+ switch (m_signaturealgo) {
+ case "1.2.840.113549.1.1.2": // MD2 with RSA encryption
+ // maybe someone installed MD2 ?
+ hash = HashAlgorithm.Create ("MD2");
+ break;
+ case "1.2.840.113549.1.1.4": // MD5 with RSA encryption
+ hash = MD5.Create ();
+ break;
+ case "1.2.840.113549.1.1.5": // SHA-1 with RSA Encryption
+ case "1.2.840.10040.4.3": // SHA1-1 with DSA
+ hash = SHA1.Create ();
+ break;
+ default:
+ return null;
+ }
+ try {
+ byte[] toBeSigned = decoder [0].GetBytes ();
+ return hash.ComputeHash (toBeSigned, 0, toBeSigned.Length);
+ }
+ catch {
+ return null;
+ }
+ }
+ }
+
+ public virtual string IssuerName {
+ get { return m_issuername; }
+ }
+
+ public virtual string KeyAlgorithm {
+ get { return m_keyalgo; }
+ }
+
+ public virtual byte[] KeyAlgorithmParameters {
+ get { return m_keyalgoparams; }
+ }
+
+ public virtual byte[] PublicKey {
+ get { return m_publickey; }
+ }
+
+ public virtual RSA RSA {
+ get {
+ RSAParameters rsaParams = new RSAParameters ();
+ // for RSA m_publickey contains 2 ASN.1 integers
+ // the modulus and the public exponent
+ ASN1 pubkey = new ASN1 (m_publickey);
+ ASN1 modulus = pubkey [0];
+ if ((modulus == null) || (modulus.Tag != 0x02))
+ return null;
+ ASN1 exponent = pubkey [1];
+ if (exponent.Tag != 0x02)
+ return null;
+
+ rsaParams.Modulus = GetUnsignedBigInteger (modulus.Value);
+ rsaParams.Exponent = exponent.Value;
+
+ // BUG: MS BCL 1.0 can't import a key which
+ // isn't the same size as the one present in
+ // the container.
+ int keySize = (rsaParams.Modulus.Length << 3);
+ RSACryptoServiceProvider rsa = new RSACryptoServiceProvider (keySize);
+ rsa.ImportParameters (rsaParams);
+ return (RSA)rsa;
+ }
+ }
+
+ public virtual byte[] RawData {
+ get { return (byte[]) m_encodedcert.Clone (); }
+ }
+
+ public virtual byte[] SerialNumber {
+ get { return serialnumber; }
+ }
+
+ public virtual byte[] Signature {
+ get {
+ switch (m_signaturealgo) {
+ case "1.2.840.113549.1.1.2": // MD2 with RSA encryption
+ case "1.2.840.113549.1.1.4": // MD5 with RSA encryption
+ case "1.2.840.113549.1.1.5": // SHA-1 with RSA Encryption
+ return signature;
+ case "1.2.840.10040.4.3": // SHA-1 with DSA
+ ASN1 sign = new ASN1 (signature);
+ if ((sign == null) || (sign.Count != 2))
+ return null;
+ // parts may be less than 20 bytes (i.e. first bytes were 0x00)
+ byte[] part1 = sign [0].Value;
+ byte[] part2 = sign [1].Value;
+ byte[] sig = new byte [40];
+ Array.Copy (part1, 0, sig, (20 - part1.Length), part1.Length);
+ Array.Copy (part2, 0, sig, (40 - part2.Length), part2.Length);
+ return sig;
+ default:
+ throw new CryptographicException ("Unsupported hash algorithm: " + m_signaturealgo);
+ }
+ }
+ }
+
+ public virtual string SignatureAlgorithm {
+ get { return m_signaturealgo; }
+ }
+
+ public virtual byte[] SignatureAlgorithmParameters {
+ get { return m_signaturealgoparams; }
+ }
+
+ public virtual string SubjectName {
+ get { return m_subject; }
+ }
+
+ public virtual DateTime ValidFrom {
+ get { return m_from; }
+ }
+
+ public virtual DateTime ValidUntil {
+ get { return m_until; }
+ }
+
+ public int Version {
+ get { return version; }
+ }
+
+ public bool IsCurrent {
+ get { return WasCurrent (DateTime.UtcNow); }
+ }
+
+ public bool WasCurrent (DateTime date)
+ {
+ return ((date > ValidFrom) && (date <= ValidUntil));
+ }
+
+ private byte[] GetHash (string hashName)
+ {
+ byte[] toBeSigned = decoder [0].GetBytes ();
+ HashAlgorithm ha = HashAlgorithm.Create (hashName);
+ return ha.ComputeHash (toBeSigned);
+ }
+
+ public bool VerifySignature (DSA dsa)
+ {
+ // signatureOID is check by both this.Hash and this.Signature
+ DSASignatureDeformatter v = new DSASignatureDeformatter (dsa);
+ // only SHA-1 is supported
+ v.SetHashAlgorithm ("SHA1");
+ return v.VerifySignature (this.Hash, this.Signature);
+ }
+
+ internal bool VerifySignature (RSA rsa)
+ {
+ RSAPKCS1SignatureDeformatter v = new RSAPKCS1SignatureDeformatter (rsa);
+ switch (m_signaturealgo) {
+ // MD2 with RSA encryption
+ case "1.2.840.113549.1.1.2":
+ // maybe someone installed MD2 ?
+ v.SetHashAlgorithm ("MD2");
+ break;
+ // MD5 with RSA encryption
+ case "1.2.840.113549.1.1.4":
+ v.SetHashAlgorithm ("MD5");
+ break;
+ // SHA-1 with RSA Encryption
+ case "1.2.840.113549.1.1.5":
+ v.SetHashAlgorithm ("SHA1");
+ break;
+ default:
+ throw new CryptographicException ("Unsupported hash algorithm: " + m_signaturealgo);
+ }
+ return v.VerifySignature (this.Hash, this.Signature);
+ }
+
+ public bool VerifySignature (AsymmetricAlgorithm aa)
+ {
+ if (aa is RSA)
+ return VerifySignature (aa as RSA);
+ else if (aa is DSA)
+ return VerifySignature (aa as DSA);
+ else
+ throw new NotSupportedException ("Unknown Asymmetric Algorithm " + aa.ToString ());
+ }
+
+ public bool CheckSignature (byte[] hash, string hashAlgorithm, byte[] signature)
+ {
+ RSACryptoServiceProvider r = (RSACryptoServiceProvider) RSA;
+ return r.VerifyHash (hash, hashAlgorithm, signature);
+ }
+
+ public bool IsSelfSigned {
+ get {
+ if (m_issuername == m_subject)
+ return VerifySignature (RSA);
+ else
+ return false;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mcs/class/Mono.Security/Mono.Security.X509/X509CertificateBuilder.cs b/mcs/class/Mono.Security/Mono.Security.X509/X509CertificateBuilder.cs
new file mode 100644
index 00000000000..e66b4e094ca
--- /dev/null
+++ b/mcs/class/Mono.Security/Mono.Security.X509/X509CertificateBuilder.cs
@@ -0,0 +1,221 @@
+//
+// X509CertificateBuilder.cs: Handles building of X.509 certificates.
+//
+// Author:
+// Sebastien Pouliot (spouliot@motus.com)
+//
+// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+
+using System;
+using System.Security.Cryptography;
+
+namespace Mono.Security.X509 {
+ // From RFC3280
+ /*
+ * Certificate ::= SEQUENCE {
+ * tbsCertificate TBSCertificate,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING
+ * }
+ * TBSCertificate ::= SEQUENCE {
+ * version [0] Version DEFAULT v1,
+ * serialNumber CertificateSerialNumber,
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * validity Validity,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
+ * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
+ * -- If present, version MUST be v2 or v3
+ * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
+ * -- If present, version MUST be v2 or v3
+ * extensions [3] Extensions OPTIONAL
+ * -- If present, version MUST be v3 --
+ * }
+ * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ * CertificateSerialNumber ::= INTEGER
+ * Validity ::= SEQUENCE {
+ * notBefore Time,
+ * notAfter Time
+ * }
+ * Time ::= CHOICE {
+ * utcTime UTCTime,
+ * generalTime GeneralizedTime
+ * }
+ */
+ public class X509CertificateBuilder : X509Builder {
+
+ private byte version;
+ private byte[] sn;
+ private string issuer;
+ private DateTime notBefore;
+ private DateTime notAfter;
+ private string subject;
+ private AsymmetricAlgorithm aa;
+ private byte[] issuerUniqueID;
+ private byte[] subjectUniqueID;
+ private X509Extensions extensions;
+
+ public X509CertificateBuilder () : this (3) {}
+
+ public X509CertificateBuilder (byte version)
+ {
+ if (version > 3)
+ throw new ArgumentException ("Invalid certificate version");
+ this.version = version;
+ extensions = new X509Extensions ();
+ }
+
+ public byte Version {
+ get { return version; }
+ set { version = value; }
+ }
+
+ public byte[] SerialNumber {
+ get { return sn; }
+ set { sn = value; }
+ }
+
+ public string IssuerName {
+ get { return issuer; }
+ set { issuer = value; }
+ }
+
+ public DateTime NotBefore {
+ get { return notBefore; }
+ set { notBefore = value; }
+ }
+
+ public DateTime NotAfter {
+ get { return notAfter; }
+ set { notAfter = value; }
+ }
+
+ public string SubjectName {
+ get { return subject; }
+ set { subject = value; }
+ }
+
+ public AsymmetricAlgorithm SubjectPublicKey {
+ get { return aa; }
+ set { aa = value; }
+ }
+
+ public byte[] IssuerUniqueID {
+ get { return issuerUniqueID; }
+ set { issuerUniqueID = value; }
+ }
+
+ public byte[] SubjectUniqueID {
+ get { return subjectUniqueID; }
+ set { subjectUniqueID = value; }
+ }
+
+ public X509Extensions Extensions {
+ get { return extensions; }
+ }
+
+
+ /* SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING }
+ */
+ private ASN1 SubjectPublicKeyInfo ()
+ {
+ ASN1 keyInfo = new ASN1 (0x30);
+ if (aa is RSA) {
+ keyInfo.Add (PKCS7.AlgorithmIdentifier ("1.2.840.113549.1.1.1"));
+ RSAParameters p = (aa as RSA).ExportParameters (false);
+ /* RSAPublicKey ::= SEQUENCE {
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER } -- e
+ */
+ ASN1 key = new ASN1 (0x30);
+ key.Add (ASN1Convert.FromUnsignedBigInteger (p.Modulus));
+ key.Add (ASN1Convert.FromUnsignedBigInteger (p.Exponent));
+ keyInfo.Add (new ASN1 (UniqueIdentifier (key.GetBytes ())));
+ }
+ else if (aa is DSA) {
+ DSAParameters p = (aa as DSA).ExportParameters (false);
+ /* Dss-Parms ::= SEQUENCE {
+ * p INTEGER,
+ * q INTEGER,
+ * g INTEGER }
+ */
+ ASN1 param = new ASN1 (0x30);
+ param.Add (ASN1Convert.FromUnsignedBigInteger (p.P));
+ param.Add (ASN1Convert.FromUnsignedBigInteger (p.Q));
+ param.Add (ASN1Convert.FromUnsignedBigInteger (p.G));
+ keyInfo.Add (PKCS7.AlgorithmIdentifier ("1.2.840.10040.4.1", param));
+ ASN1 key = keyInfo.Add (new ASN1 (0x03));
+ // DSAPublicKey ::= INTEGER -- public key, y
+ key.Add (ASN1Convert.FromUnsignedBigInteger (p.Y));
+ }
+ else
+ throw new NotSupportedException ("Unknown Asymmetric Algorithm " + aa.ToString ());
+ return keyInfo;
+ }
+
+ private byte[] UniqueIdentifier (byte[] id)
+ {
+ // UniqueIdentifier ::= BIT STRING
+ ASN1 uid = new ASN1 (0x03);
+ // first byte in a BITSTRING is the number of unused bits in the first byte
+ byte[] v = new byte [id.Length + 1];
+ Array.Copy (id, 0, v, 1, id.Length);
+ uid.Value = v;
+ return uid.GetBytes ();
+ }
+
+ protected override ASN1 ToBeSigned (string oid)
+ {
+ // TBSCertificate
+ ASN1 tbsCert = new ASN1 (0x30);
+
+ if (version > 1) {
+ // TBSCertificate / [0] Version DEFAULT v1,
+ byte[] ver = { (byte)(version - 1) };
+ ASN1 v = tbsCert.Add (new ASN1 (0xA0));
+ v.Add (new ASN1 (0x02, ver));
+ }
+
+ // TBSCertificate / CertificateSerialNumber,
+ tbsCert.Add (new ASN1 (0x02, sn));
+
+ // TBSCertificate / AlgorithmIdentifier,
+ tbsCert.Add (PKCS7.AlgorithmIdentifier (oid));
+
+ // TBSCertificate / Name
+ tbsCert.Add (X501.FromString (issuer));
+
+ // TBSCertificate / Validity
+ ASN1 validity = tbsCert.Add (new ASN1 (0x30));
+ // TBSCertificate / Validity / Time
+ validity.Add (ASN1Convert.FromDateTime (notBefore));
+ // TBSCertificate / Validity / Time
+ validity.Add (ASN1Convert.FromDateTime (notAfter));
+
+ // TBSCertificate / Name
+ tbsCert.Add (X501.FromString (subject));
+
+ // TBSCertificate / SubjectPublicKeyInfo
+ ASN1 keyInfo = tbsCert.Add (SubjectPublicKeyInfo ());
+
+ if (version > 1) {
+ // TBSCertificate / [1] IMPLICIT UniqueIdentifier OPTIONAL
+ if (issuerUniqueID != null)
+ tbsCert.Add (new ASN1 (0xA1, UniqueIdentifier (issuerUniqueID)));
+
+ // TBSCertificate / [2] IMPLICIT UniqueIdentifier OPTIONAL
+ if (subjectUniqueID != null)
+ tbsCert.Add (new ASN1 (0xA1, UniqueIdentifier (subjectUniqueID)));
+
+ // TBSCertificate / [3] Extensions OPTIONAL
+ if ((version > 2) && (extensions.Count > 0))
+ tbsCert.Add (new ASN1 (0xA3, extensions.GetBytes ()));
+ }
+
+ return tbsCert;
+ }
+ }
+}
diff --git a/mcs/class/Mono.Security/Mono.Security.X509/X509Extension.cs b/mcs/class/Mono.Security/Mono.Security.X509/X509Extension.cs
new file mode 100644
index 00000000000..353ad31beb8
--- /dev/null
+++ b/mcs/class/Mono.Security/Mono.Security.X509/X509Extension.cs
@@ -0,0 +1,136 @@
+//
+// X509Extension.cs: Base class for all X.509 extensions.
+//
+// Author:
+// Sebastien Pouliot (spouliot@motus.com)
+//
+// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+//
+
+using System;
+using System.Text;
+
+using Mono.Security;
+
+namespace Mono.Security.X509 {
+ /*
+ * Extension ::= SEQUENCE {
+ * extnID OBJECT IDENTIFIER,
+ * critical BOOLEAN DEFAULT FALSE,
+ * extnValue OCTET STRING
+ * }
+ */
+ public class X509Extension {
+
+ protected string extnOid;
+ protected bool extnCritical;
+ protected ASN1 extnValue;
+
+ internal X509Extension ()
+ {
+ extnCritical = false;
+ }
+
+ public X509Extension (ASN1 asn1)
+ {
+ if ((asn1.Tag != 0x30) || (asn1.Count < 2))
+ throw new ArgumentException ("Invalid X.509 extension");
+ if (asn1[0].Tag != 0x06)
+ throw new ArgumentException ("Invalid X.509 extension");
+ extnOid = ASN1Convert.ToOID (asn1 [0]);
+ extnCritical = ((asn1[1].Tag == 0x01) && (asn1[1].Value[0] == 0xFF));
+ extnValue = asn1 [asn1.Count - 1]; // last element
+ Decode ();
+ }
+
+ public X509Extension (X509Extension extension) : this ()
+ {
+ if (extension == null)
+ throw new ArgumentNullException ("extension");
+ if ((extension.Value.Tag != 0x04) || (extension.Value.Count != 0))
+ throw new ArgumentException ("Invalid extension");
+ extnOid = extension.OID;
+ extnCritical = extension.Critical;
+ extnValue = extension.Value;
+ Decode ();
+ }
+
+ protected virtual void Decode () {}
+
+ protected virtual void Encode () {}
+
+ public ASN1 ASN1 {
+ get {
+ ASN1 extension = new ASN1 (0x30);
+ extension.Add (ASN1Convert.FromOID (extnOid));
+ if (extnCritical)
+ extension.Add (new ASN1 (0x01, new byte [1] { 0x01 }));
+ ASN1 os = extension.Add (new ASN1 (0x04));
+ Encode ();
+ os.Add (extnValue);
+ return extension;
+ }
+ }
+
+ public string OID {
+ get { return extnOid; }
+ }
+
+ public bool Critical {
+ get { return extnCritical; }
+ }
+
+ // this gets overrided with more meaningful names
+ public virtual string Name {
+ get { return extnOid; }
+ }
+
+ public ASN1 Value {
+ get { return extnValue; }
+ }
+
+ public byte[] GetBytes ()
+ {
+ return ASN1.GetBytes ();
+ }
+
+ private void WriteLine (StringBuilder sb, int n, int pos)
+ {
+ byte[] value = extnValue.Value;
+ int p = pos;
+ StringBuilder preview = new StringBuilder ();
+ for (int j=0; j < 8; j++) {
+ if (j < n) {
+ sb.Append (value [p++].ToString ("X2"));
+ sb.Append (" ");
+ }
+ else
+ sb.Append (" ");
+ }
+ sb.Append (" ");
+ p = pos;
+ for (int j=0; j < n; j++) {
+ byte b = value [p++];
+ if (b < 0x20)
+ sb.Append (".");
+ else
+ sb.Append (Convert.ToChar (b));
+ }
+ sb.Append (Environment.NewLine);
+ }
+
+ public override string ToString ()
+ {
+ StringBuilder sb = new StringBuilder ();
+ int div = (extnValue.Length >> 3);
+ int rem = (extnValue.Length - (div << 3));
+ int x = 0;
+ for (int i=0; i < div; i++) {
+ WriteLine (sb, 8, x);
+ x += 8;
+ }
+ WriteLine (sb, rem, x);
+ return sb.ToString ();
+ }
+ }
+}
diff --git a/mcs/class/Mono.Security/Mono.Security.X509/X509Extensions.cs b/mcs/class/Mono.Security/Mono.Security.X509/X509Extensions.cs
new file mode 100644
index 00000000000..488ceed8725
--- /dev/null
+++ b/mcs/class/Mono.Security/Mono.Security.X509/X509Extensions.cs
@@ -0,0 +1,105 @@
+//
+// X509Extensions.cs: Handles X.509 extensions.
+//
+// Author:
+// Sebastien Pouliot (spouliot@motus.com)
+//
+// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+//
+
+using System;
+using System.Collections;
+
+using Mono.Security;
+
+namespace Mono.Security.X509 {
+ /*
+ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+ *
+ * Note: 1..MAX -> There shouldn't be 0 Extensions in the ASN1 structure
+ */
+ public class X509Extensions : ICollection, IEnumerable {
+
+ private ArrayList extensions;
+ private bool readOnly;
+
+ public X509Extensions ()
+ {
+ extensions = new ArrayList ();
+ }
+
+ public X509Extensions (ASN1 asn1) : this ()
+ {
+ readOnly = true;
+ if (asn1 == null)
+ return;
+ if (asn1.Tag != 0x30)
+ throw new Exception ("Invalid extensions format");
+ for (int i=0; i < asn1.Count; i++) {
+ X509Extension extension = new X509Extension (asn1 [i]);
+ extensions.Add (extension);
+ }
+ }
+
+ // ICollection
+ public int Count {
+ get { return extensions.Count; }
+ }
+
+ // ICollection
+ public bool IsSynchronized {
+ get { return extensions.IsSynchronized; }
+ }
+
+ // ICollection
+ public object SyncRoot {
+ get { return extensions.SyncRoot; }
+ }
+
+ // ICollection
+ public void CopyTo (Array array, int index)
+ {
+ extensions.CopyTo (array, index);
+ }
+
+ // IEnumerable
+ public IEnumerator GetEnumerator ()
+ {
+ return extensions.GetEnumerator ();
+ }
+
+ public X509Extension this [int index] {
+ get { return (X509Extension) extensions [index]; }
+ }
+
+ public X509Extension this [string index] {
+ get {
+ for (int i=0; i < extensions.Count; i++) {
+ X509Extension extension = (X509Extension) extensions [i];
+ if (extension.OID == index)
+ return extension;
+ }
+ return null;
+ }
+ }
+
+ public void Add (X509Extension extension)
+ {
+ if (readOnly)
+ throw new NotSupportedException ("Extensions are read only");
+ extensions.Add (extension);
+ }
+
+ public byte[] GetBytes ()
+ {
+ if (extensions.Count < 1)
+ return null;
+ ASN1 sequence = new ASN1 (0x30);
+ for (int i=0; i < extensions.Count; i++) {
+ X509Extension x = (X509Extension) extensions [i];
+ sequence.Add (x.ASN1);
+ }
+ return sequence.GetBytes ();
+ }
+ }
+}
diff --git a/mcs/class/Mono.Security/Mono.Security.X509/X520Attributes.cs b/mcs/class/Mono.Security/Mono.Security.X509/X520Attributes.cs
new file mode 100644
index 00000000000..98cd3ebf1ce
--- /dev/null
+++ b/mcs/class/Mono.Security/Mono.Security.X509/X520Attributes.cs
@@ -0,0 +1,213 @@
+//
+// X520.cs: X.520 related stuff (attributes, RDN)
+//
+// Author:
+// Sebastien Pouliot (spouliot@motus.com)
+//
+// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
+//
+
+using System;
+using System.Text;
+
+using Mono.Security;
+
+namespace Mono.Security.X509 {
+
+ // References:
+ // 1. Information technology - Open Systems Interconnection - The Directory: Selected attribute types
+ // http://www.itu.int/rec/recommendation.asp?type=folders&lang=e&parent=T-REC-X.520
+ // 2. Internet X.509 Public Key Infrastructure Certificate and CRL Profile
+ // http://www.ietf.org/rfc/rfc3280.txt
+
+ /*
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue
+ * }
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ *
+ * AttributeValue ::= ANY DEFINED BY AttributeType
+ */
+ public class X520 {
+
+ public abstract class AttributeTypeAndValue {
+ protected string oid;
+ protected string attrValue;
+ private int upperBound;
+ private byte inputEncoding;
+ protected byte defaultEncoding;
+
+ public AttributeTypeAndValue (string oid, int upperBound)
+ {
+ inputEncoding = 0xFF;
+ defaultEncoding = 0xFF;
+ this.oid = oid;
+ this.upperBound = upperBound;
+ }
+
+ public string Value {
+ get { return attrValue; }
+ set { attrValue = value; }
+ }
+
+ public ASN1 ASN1 {
+ get { return GetASN1 (); }
+ }
+
+ public ASN1 GetASN1 (byte encoding)
+ {
+ ASN1 asn1 = new ASN1 (0x30);
+ asn1.Add (ASN1Convert.FromOID (oid));
+ switch (encoding) {
+ case 0x13:
+ // PRINTABLESTRING
+ asn1.Add (new ASN1 (0x13, Encoding.ASCII.GetBytes (attrValue)));
+ break;
+ case 0x1E:
+ // BMPSTRING
+ asn1.Add (new ASN1 (0x1E, Encoding.BigEndianUnicode.GetBytes (attrValue)));
+ break;
+ }
+ return asn1;
+ }
+
+ public ASN1 GetASN1 ()
+ {
+ byte encoding = inputEncoding;
+ if (encoding == 0xFF)
+ encoding = defaultEncoding;
+ if (encoding == 0xFF)
+ encoding = SelectBestEncoding ();
+ return GetASN1 (encoding);
+ }
+
+ public byte[] GetBytes (byte encoding)
+ {
+ return GetASN1 (encoding) .GetBytes ();
+ }
+
+ public byte[] GetBytes ()
+ {
+ return GetASN1 () .GetBytes ();
+ }
+
+ private byte SelectBestEncoding ()
+ {
+ char[] notPrintableString = { '@', '_' };
+ if (attrValue.IndexOfAny (notPrintableString) != -1)
+ return 0x1E; // BMPSTRING
+ else
+ return 0x13; // PRINTABLESTRING
+ }
+ }
+
+ public class Name : AttributeTypeAndValue {
+
+ public Name () : base ("2.5.4.41", 32768) {}
+ }
+
+ public class CommonName : AttributeTypeAndValue {
+
+ public CommonName () : base ("2.5.4.3", 64) {}
+ }
+
+ public class LocalityName : AttributeTypeAndValue {
+
+ public LocalityName () : base ("2.5.4.7", 128) {}
+ }
+
+ public class StateOrProvinceName : AttributeTypeAndValue {
+
+ public StateOrProvinceName () : base ("2.5.4.8", 128) {}
+ }
+
+ public class OrganizationName : AttributeTypeAndValue {
+
+ public OrganizationName () : base ("2.5.4.10", 64) {}
+ }
+
+ public class OrganizationalUnitName : AttributeTypeAndValue {
+
+ public OrganizationalUnitName () : base ("2.5.4.11", 64) {}
+ }
+
+ /* -- Naming attributes of type X520Title
+ * id-at-title AttributeType ::= { id-at 12 }
+ *
+ * X520Title ::= CHOICE {
+ * teletexString TeletexString (SIZE (1..ub-title)),
+ * printableString PrintableString (SIZE (1..ub-title)),
+ * universalString UniversalString (SIZE (1..ub-title)),
+ * utf8String UTF8String (SIZE (1..ub-title)),
+ * bmpString BMPString (SIZE (1..ub-title))
+ * }
+ */
+ public class Title : AttributeTypeAndValue {
+
+ public Title () : base ("2.5.4.12", 64) {}
+ }
+
+ public class CountryName : AttributeTypeAndValue {
+
+ public CountryName () : base ("2.5.4.6", 2)
+ {
+ defaultEncoding = 0x13; // PRINTABLESTRING
+ }
+ }
+ }
+
+ /* From RFC3280
+ * -- specifications of Upper Bounds MUST be regarded as mandatory
+ * -- from Annex B of ITU-T X.411 Reference Definition of MTS Parameter
+ *
+ * -- Upper Bounds
+ *
+ * ub-name INTEGER ::= 32768
+ * ub-common-name INTEGER ::= 64
+ * ub-locality-name INTEGER ::= 128
+ * ub-state-name INTEGER ::= 128
+ * ub-organization-name INTEGER ::= 64
+ * ub-organizational-unit-name INTEGER ::= 64
+ * ub-title INTEGER ::= 64
+ * ub-serial-number INTEGER ::= 64
+ * ub-match INTEGER ::= 128
+ * ub-emailaddress-length INTEGER ::= 128
+ * ub-common-name-length INTEGER ::= 64
+ * ub-country-name-alpha-length INTEGER ::= 2
+ * ub-country-name-numeric-length INTEGER ::= 3
+ * ub-domain-defined-attributes INTEGER ::= 4
+ * ub-domain-defined-attribute-type-length INTEGER ::= 8
+ * ub-domain-defined-attribute-value-length INTEGER ::= 128
+ * ub-domain-name-length INTEGER ::= 16
+ * ub-extension-attributes INTEGER ::= 256
+ * ub-e163-4-number-length INTEGER ::= 15
+ * ub-e163-4-sub-address-length INTEGER ::= 40
+ * ub-generation-qualifier-length INTEGER ::= 3
+ * ub-given-name-length INTEGER ::= 16
+ * ub-initials-length INTEGER ::= 5
+ * ub-integer-options INTEGER ::= 256
+ * ub-numeric-user-id-length INTEGER ::= 32
+ * ub-organization-name-length INTEGER ::= 64
+ * ub-organizational-unit-name-length INTEGER ::= 32
+ * ub-organizational-units INTEGER ::= 4
+ * ub-pds-name-length INTEGER ::= 16
+ * ub-pds-parameter-length INTEGER ::= 30
+ * ub-pds-physical-address-lines INTEGER ::= 6
+ * ub-postal-code-length INTEGER ::= 16
+ * ub-pseudonym INTEGER ::= 128
+ * ub-surname-length INTEGER ::= 40
+ * ub-terminal-id-length INTEGER ::= 24
+ * ub-unformatted-address-length INTEGER ::= 180
+ * ub-x121-address-length INTEGER ::= 16
+ *
+ * -- Note - upper bounds on string types, such as TeletexString, are
+ * -- measured in characters. Excepting PrintableString or IA5String, a
+ * -- significantly greater number of octets will be required to hold
+ * -- such a value. As a minimum, 16 octets, or twice the specified
+ * -- upper bound, whichever is the larger, should be allowed for
+ * -- TeletexString. For UTF8String or UniversalString at least four
+ * -- times the upper bound should be allowed.
+ */
+}