2 // X501Name.cs: X.501 Distinguished Names stuff
5 // Sebastien Pouliot <sebastien@ximian.com>
7 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
8 // (C) 2004 Novell (http://www.novell.com)
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:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
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.
35 using System
.Globalization
;
40 namespace Mono
.Security
.X509
{
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
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 }
;
78 static public string ToString (ASN1 seq
)
80 StringBuilder sb
= new StringBuilder ();
81 for (int i
= 0; i
< seq
.Count
; i
++) {
83 ASN1 pair
= entry
[0];
93 if (poid
.CompareValue (countryName
))
95 else if (poid
.CompareValue (organizationName
))
97 else if (poid
.CompareValue (organizationalUnitName
))
99 else if (poid
.CompareValue (commonName
))
101 else if (poid
.CompareValue (localityName
))
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
))
109 else if (poid
.CompareValue (userid
))
111 else if (poid
.CompareValue (email
))
112 sb
.Append ("E="); // NOTE: Not part of RFC2253
115 sb
.Append ("OID."); // NOTE: Not present as RFC2253
116 sb
.Append (ASN1Convert
.ToOid (poid
));
120 string sValue
= null;
121 // 16bits or 8bits string ? TODO not complete (+special chars!)
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 ();
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
+ "\"";
144 // separator (not on last iteration)
145 if (i
< seq
.Count
- 1)
148 return sb
.ToString ();
151 static private X520
.AttributeTypeAndValue
GetAttributeFromOid (string attributeType
)
153 switch (attributeType
.ToUpper (CultureInfo
.InvariantCulture
).Trim ()) {
155 return new X520
.CountryName ();
157 return new X520
.OrganizationName ();
159 return new X520
.OrganizationalUnitName ();
161 return new X520
.CommonName ();
163 return new X520
.LocalityName ();
164 case "S": // Microsoft
165 case "ST": // RFC2253
166 return new X520
.StateOrProvinceName ();
168 // return streetAddress;
170 // return domainComponent;
176 static public ASN1
FromString (string rdn
)
179 throw new ArgumentNullException ("rdn");
180 // get string from here to ',' or end of string
183 ASN1 asn1
= new ASN1 (0x30);
184 while (start
< rdn
.Length
) {
185 end
= rdn
.IndexOf (',', end
) + 1;
187 end
= rdn
.Length
+ 1;
188 string av
= rdn
.Substring (start
, end
- start
- 1);
189 // get '=' position in substring
190 int equal
= av
.IndexOf ('=');
192 string attributeType
= av
.Substring (0, equal
);
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 ()));
203 if (end
> rdn
.Length
)