2004-04-12 David Sheldon <dave-mono@earth.li>
[mono.git] / mcs / class / corlib / Mono.Security.X509 / X501Name.cs
1 //
2 // X501Name.cs: X.501 Distinguished Names stuff 
3 //
4 // Author:
5 //      Sebastien Pouliot (spouliot@motus.com)
6 //
7 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
8 //
9
10 using System;
11 using System.Text;
12
13 using Mono.Security;
14
15 namespace Mono.Security.X509 {
16
17         // References:
18         // 1.   Information technology - Open Systems Interconnection - The Directory: Models
19         //      http://www.itu.int/rec/recommendation.asp?type=items&lang=e&parent=T-REC-X.501-200102-I
20         // 2.   RFC2253: Lightweight Directory Access Protocol (v3): UTF-8 String Representation of Distinguished Names
21         //      http://www.ietf.org/rfc/rfc2253.txt
22
23         /*
24          * Name ::= CHOICE { RDNSequence }
25          * 
26          * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
27          * 
28          * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
29          */
30 #if INSIDE_CORLIB
31         internal
32 #else
33         public
34 #endif
35         class X501 {
36
37                 static byte[] countryName = { 0x55, 0x04, 0x06 };
38                 static byte[] organizationName = { 0x55, 0x04, 0x0A };
39                 static byte[] organizationalUnitName = { 0x55, 0x04, 0x0B };
40                 static byte[] commonName = { 0x55, 0x04, 0x03 };
41                 static byte[] localityName = { 0x55, 0x04, 0x07 };
42                 static byte[] stateOrProvinceName = { 0x55, 0x04, 0x08 };
43                 static byte[] streetAddress = { 0x55, 0x04, 0x09 };
44                 static byte[] serialNumber = { 0x55, 0x04, 0x05 };
45                 static byte[] domainComponent = { 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x19 };
46                 static byte[] userid = { 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x01 };
47                 static byte[] email = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 };
48
49                 static public string ToString (ASN1 seq) 
50                 {
51                         StringBuilder sb = new StringBuilder ();
52                         for (int i = 0; i < seq.Count; i++) {
53                                 ASN1 entry = seq [i];
54                                 ASN1 pair = entry [0];
55
56                                 ASN1 s = pair [1];
57                                 if (s == null)
58                                         continue;
59
60                                 ASN1 poid = pair [0];
61                                 if (poid == null)
62                                         continue;
63
64                                 if (poid.CompareValue (countryName))
65                                         sb.Append ("C=");
66                                 else if (poid.CompareValue (organizationName))
67                                         sb.Append ("O=");
68                                 else if (poid.CompareValue (organizationalUnitName))
69                                         sb.Append ("OU=");
70                                 else if (poid.CompareValue (commonName))
71                                         sb.Append ("CN=");
72                                 else if (poid.CompareValue (localityName))
73                                         sb.Append ("L=");
74                                 else if (poid.CompareValue (stateOrProvinceName))
75                                         sb.Append ("S=");       // NOTE: RFC2253 uses ST=
76                                 else if (poid.CompareValue (streetAddress))
77                                         sb.Append ("STREET=");
78                                 else if (poid.CompareValue (domainComponent))
79                                         sb.Append ("DC=");
80                                 else if (poid.CompareValue (userid))
81                                         sb.Append ("UID=");
82                                 else if (poid.CompareValue (email))
83                                         sb.Append ("E=");       // NOTE: Not part of RFC2253
84                                 else {
85                                         // unknown OID
86                                         sb.Append ("OID.");     // NOTE: Not present as RFC2253
87                                         sb.Append (ASN1Convert.ToOID (poid));
88                                         sb.Append ("=");
89                                 }
90
91                                 string sValue = null;
92                                 // 16bits or 8bits string ? TODO not complete (+special chars!)
93                                 if (s.Tag == 0x1E) {
94                                         // BMPSTRING
95                                         StringBuilder sb2 = new StringBuilder ();
96                                         for (int j = 1; j < s.Value.Length; j+=2)
97                                                 sb2.Append ((char) s.Value[j]);
98                                         sValue = sb2.ToString ();
99                                 }
100                                 else {
101                                         sValue = System.Text.Encoding.UTF8.GetString (s.Value);
102                                         // in some cases we must quote (") the value
103                                         // Note: this doesn't seems to conform to RFC2253
104                                         char[] specials = { ',', '+', '"', '\\', '<', '>', ';' };
105                                         if (sValue.IndexOfAny(specials, 0, sValue.Length) > 0)
106                                                 sValue = "\"" + sValue + "\"";
107                                         else if (sValue.StartsWith (" "))
108                                                 sValue = "\"" + sValue + "\"";
109                                         else if (sValue.EndsWith (" "))
110                                                 sValue = "\"" + sValue + "\"";
111                                 }
112
113                                 sb.Append (sValue);
114
115                                 // separator (not on last iteration)
116                                 if (i < seq.Count - 1)
117                                         sb.Append (", ");
118                         }
119                         return sb.ToString ();
120                 }
121
122                 static private X520.AttributeTypeAndValue GetAttributeFromOID (string attributeType) 
123                 {
124                         switch (attributeType.ToUpper ().Trim ()) {
125                                 case "C":
126                                         return new X520.CountryName ();
127                                 case "O":
128                                         return new X520.OrganizationName ();
129                                 case "OU":
130                                         return new X520.OrganizationalUnitName ();
131                                 case "CN":
132                                         return new X520.CommonName ();
133                                 case "L":
134                                         return new X520.LocalityName ();
135                                 case "S":       // Microsoft
136                                 case "ST":      // RFC2253
137                                         return new X520.StateOrProvinceName ();
138                                 case "DC":
139 //                                      return streetAddress;
140                                 case "UID":
141 //                                      return domainComponent;
142                                         return null;
143
144                                 default:
145                                         return null;
146                         }
147                 }
148
149                 static public ASN1 FromString (string rdn) 
150                 {
151                         if (rdn == null)
152                                 throw new ArgumentNullException ("rdn");
153                         // get string from here to ',' or end of string
154                         int start = 0;
155                         int end = 0;
156                         ASN1 asn1 = new ASN1 (0x30);
157                         while (start < rdn.Length) {
158                                 end = rdn.IndexOf (',', end) + 1;
159                                 if (end == 0)
160                                         end = rdn.Length + 1;
161                                 string av = rdn.Substring (start, end - start - 1);
162                                 // get '=' position in substring
163                                 int equal = av.IndexOf ('=');
164                                 // get AttributeType
165                                 string attributeType = av.Substring (0, equal);
166                                 // get value
167                                 string attributeValue = av.Substring (equal + 1);
168
169                                 X520.AttributeTypeAndValue atv = GetAttributeFromOID (attributeType);
170                                 atv.Value = attributeValue;
171                                 asn1.Add (new ASN1 (0x31, atv.GetBytes ()));
172
173                                 // next part
174                                 start = end;
175                                 if (start != - 1) {
176                                         if (end > rdn.Length)
177                                                 break;
178                                 }
179                         }
180                         return asn1;
181                 }
182         }
183 }