5 // Martin Baulig <martin.baulig@xamarin.com>
7 // Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 using System.Security.Cryptography.X509Certificates;
33 static class MonoBtlsUtils
35 static byte[] emailOid = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 };
37 public static bool Compare (byte[] a, byte[] b)
39 if (a.Length != b.Length)
41 for (int i = 0; i < a.Length; i++) {
48 static bool AppendEntry (StringBuilder sb, MonoBtlsX509Name name, int index, string separator, bool quotes)
50 var type = name.GetEntryType (index);
54 var oidValue = name.GetEntryOidData (index);
55 if (Compare (oidValue, emailOid))
56 type = MonoBtlsX509NameEntryType.Email;
59 var text = name.GetEntryValue (index, out tag);
62 var oid = name.GetEntryOid (index);
67 sb.Append (separator);
70 case MonoBtlsX509NameEntryType.CountryName:
73 case MonoBtlsX509NameEntryType.OrganizationName:
76 case MonoBtlsX509NameEntryType.OrganizationalUnitName:
79 case MonoBtlsX509NameEntryType.CommonName:
82 case MonoBtlsX509NameEntryType.LocalityName:
85 case MonoBtlsX509NameEntryType.StateOrProvinceName:
86 sb.Append ("S="); // NOTE: RFC2253 uses ST=
88 case MonoBtlsX509NameEntryType.StreetAddress:
89 sb.Append ("STREET=");
91 case MonoBtlsX509NameEntryType.DomainComponent:
94 case MonoBtlsX509NameEntryType.UserId:
97 case MonoBtlsX509NameEntryType.Email:
98 sb.Append ("E="); // NOTE: Not part of RFC2253
100 case MonoBtlsX509NameEntryType.DnQualifier:
101 sb.Append ("dnQualifier=");
103 case MonoBtlsX509NameEntryType.Title:
106 case MonoBtlsX509NameEntryType.Surname:
109 case MonoBtlsX509NameEntryType.GivenName:
112 case MonoBtlsX509NameEntryType.Initial:
117 sb.Append ("OID."); // NOTE: Not present as RFC2253
123 // 16bits or 8bits string ? TODO not complete (+special chars!)
124 char[] specials = { ',', '+', '"', '\\', '<', '>', ';' };
125 if (quotes && tag != 0x1E) {
126 if ((text.IndexOfAny (specials, 0, text.Length) > 0) ||
127 text.StartsWith (" ") || (text.EndsWith (" ")))
128 text = "\"" + text + "\"";
135 const X500DistinguishedNameFlags AllFlags = X500DistinguishedNameFlags.Reversed |
136 X500DistinguishedNameFlags.UseSemicolons | X500DistinguishedNameFlags.DoNotUsePlusSign |
137 X500DistinguishedNameFlags.DoNotUseQuotes | X500DistinguishedNameFlags.UseCommas |
138 X500DistinguishedNameFlags.UseNewLines | X500DistinguishedNameFlags.UseUTF8Encoding |
139 X500DistinguishedNameFlags.UseT61Encoding | X500DistinguishedNameFlags.ForceUTF8Encoding;
141 static string GetSeparator (X500DistinguishedNameFlags flag)
143 if ((flag & X500DistinguishedNameFlags.UseSemicolons) != 0)
145 if ((flag & X500DistinguishedNameFlags.UseCommas) != 0)
147 if ((flag & X500DistinguishedNameFlags.UseNewLines) != 0)
148 return Environment.NewLine;
149 return ", "; //default
152 public static string FormatName (MonoBtlsX509Name name, X500DistinguishedNameFlags flag)
154 if ((flag != 0) && ((flag & AllFlags) == 0))
155 throw new ArgumentException ("flag");
157 if (name.GetEntryCount () == 0)
160 // Mono.Security reversed isn't the same as fx 2.0 (which is the reverse of 1.x)
161 bool reversed = ((flag & X500DistinguishedNameFlags.Reversed) != 0);
162 bool quotes = ((flag & X500DistinguishedNameFlags.DoNotUseQuotes) == 0);
163 string separator = GetSeparator (flag);
165 return FormatName (name, reversed, separator, quotes);
168 public static string FormatName (MonoBtlsX509Name name, bool reversed, string separator, bool quotes)
170 var count = name.GetEntryCount ();
171 StringBuilder sb = new StringBuilder ();
174 for (int i = count - 1; i >= 0; i--) {
175 AppendEntry (sb, name, i, separator, quotes);
178 for (int i = 0; i < count; i++) {
179 AppendEntry (sb, name, i, separator, quotes);
183 return sb.ToString ();