**** Merged from MCS ****
[mono-project.git] / mcs / class / corlib / Mono.Security.X509 / X501Name.cs
blob58acf80873a2d7be932d70933e3e5ef997539f22
1 //
2 // X501Name.cs: X.501 Distinguished Names stuff
3 //
4 // Author:
5 // Sebastien Pouliot <sebastien@ximian.com>
6 //
7 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
8 // (C) 2004 Novell (http://www.novell.com)
9 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System;
35 using System.Globalization;
36 using System.Text;
38 using Mono.Security;
40 namespace Mono.Security.X509 {
42 // References:
43 // 1. Information technology - Open Systems Interconnection - The Directory: Models
44 // http://www.itu.int/rec/recommendation.asp?type=items&lang=e&parent=T-REC-X.501-200102-I
45 // 2. RFC2253: Lightweight Directory Access Protocol (v3): UTF-8 String Representation of Distinguished Names
46 // http://www.ietf.org/rfc/rfc2253.txt
49 * Name ::= CHOICE { RDNSequence }
51 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
53 * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
55 #if INSIDE_CORLIB
56 internal
57 #else
58 public
59 #endif
60 sealed class X501 {
62 static byte[] countryName = { 0x55, 0x04, 0x06 };
63 static byte[] organizationName = { 0x55, 0x04, 0x0A };
64 static byte[] organizationalUnitName = { 0x55, 0x04, 0x0B };
65 static byte[] commonName = { 0x55, 0x04, 0x03 };
66 static byte[] localityName = { 0x55, 0x04, 0x07 };
67 static byte[] stateOrProvinceName = { 0x55, 0x04, 0x08 };
68 static byte[] streetAddress = { 0x55, 0x04, 0x09 };
69 static byte[] serialNumber = { 0x55, 0x04, 0x05 };
70 static byte[] domainComponent = { 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x19 };
71 static byte[] userid = { 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x01 };
72 static byte[] email = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 };
74 private X501 ()
78 static public string ToString (ASN1 seq)
80 StringBuilder sb = new StringBuilder ();
81 for (int i = 0; i < seq.Count; i++) {
82 ASN1 entry = seq [i];
83 ASN1 pair = entry [0];
85 ASN1 s = pair [1];
86 if (s == null)
87 continue;
89 ASN1 poid = pair [0];
90 if (poid == null)
91 continue;
93 if (poid.CompareValue (countryName))
94 sb.Append ("C=");
95 else if (poid.CompareValue (organizationName))
96 sb.Append ("O=");
97 else if (poid.CompareValue (organizationalUnitName))
98 sb.Append ("OU=");
99 else if (poid.CompareValue (commonName))
100 sb.Append ("CN=");
101 else if (poid.CompareValue (localityName))
102 sb.Append ("L=");
103 else if (poid.CompareValue (stateOrProvinceName))
104 sb.Append ("S="); // NOTE: RFC2253 uses ST=
105 else if (poid.CompareValue (streetAddress))
106 sb.Append ("STREET=");
107 else if (poid.CompareValue (domainComponent))
108 sb.Append ("DC=");
109 else if (poid.CompareValue (userid))
110 sb.Append ("UID=");
111 else if (poid.CompareValue (email))
112 sb.Append ("E="); // NOTE: Not part of RFC2253
113 else {
114 // unknown OID
115 sb.Append ("OID."); // NOTE: Not present as RFC2253
116 sb.Append (ASN1Convert.ToOid (poid));
117 sb.Append ("=");
120 string sValue = null;
121 // 16bits or 8bits string ? TODO not complete (+special chars!)
122 if (s.Tag == 0x1E) {
123 // BMPSTRING
124 StringBuilder sb2 = new StringBuilder ();
125 for (int j = 1; j < s.Value.Length; j+=2)
126 sb2.Append ((char) s.Value[j]);
127 sValue = sb2.ToString ();
129 else {
130 sValue = System.Text.Encoding.UTF8.GetString (s.Value);
131 // in some cases we must quote (") the value
132 // Note: this doesn't seems to conform to RFC2253
133 char[] specials = { ',', '+', '"', '\\', '<', '>', ';' };
134 if (sValue.IndexOfAny(specials, 0, sValue.Length) > 0)
135 sValue = "\"" + sValue + "\"";
136 else if (sValue.StartsWith (" "))
137 sValue = "\"" + sValue + "\"";
138 else if (sValue.EndsWith (" "))
139 sValue = "\"" + sValue + "\"";
142 sb.Append (sValue);
144 // separator (not on last iteration)
145 if (i < seq.Count - 1)
146 sb.Append (", ");
148 return sb.ToString ();
151 static private X520.AttributeTypeAndValue GetAttributeFromOid (string attributeType)
153 switch (attributeType.ToUpper (CultureInfo.InvariantCulture).Trim ()) {
154 case "C":
155 return new X520.CountryName ();
156 case "O":
157 return new X520.OrganizationName ();
158 case "OU":
159 return new X520.OrganizationalUnitName ();
160 case "CN":
161 return new X520.CommonName ();
162 case "L":
163 return new X520.LocalityName ();
164 case "S": // Microsoft
165 case "ST": // RFC2253
166 return new X520.StateOrProvinceName ();
167 case "DC":
168 // return streetAddress;
169 case "UID":
170 // return domainComponent;
171 default:
172 return null;
176 static public ASN1 FromString (string rdn)
178 if (rdn == null)
179 throw new ArgumentNullException ("rdn");
180 // get string from here to ',' or end of string
181 int start = 0;
182 int end = 0;
183 ASN1 asn1 = new ASN1 (0x30);
184 while (start < rdn.Length) {
185 end = rdn.IndexOf (',', end) + 1;
186 if (end == 0)
187 end = rdn.Length + 1;
188 string av = rdn.Substring (start, end - start - 1);
189 // get '=' position in substring
190 int equal = av.IndexOf ('=');
191 // get AttributeType
192 string attributeType = av.Substring (0, equal);
193 // get value
194 string attributeValue = av.Substring (equal + 1);
196 X520.AttributeTypeAndValue atv = GetAttributeFromOid (attributeType);
197 atv.Value = attributeValue;
198 asn1.Add (new ASN1 (0x31, atv.GetBytes ()));
200 // next part
201 start = end;
202 if (start != - 1) {
203 if (end > rdn.Length)
204 break;
207 return asn1;