Initial commit
[mono.git] / mcs / class / referencesource / System / security / system / security / cryptography / x509 / x500Name.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6
7 //
8 // X500Name.cs
9 //
10 // 07/10/2003
11 //
12
13 namespace System.Security.Cryptography.X509Certificates {
14     using System.Globalization;
15     using System.Runtime.InteropServices;
16     using System.Security.Cryptography;
17
18     [Flags]
19     public enum X500DistinguishedNameFlags {
20         None                = 0x0000,
21         Reversed            = 0x0001,
22
23         UseSemicolons       = 0x0010,
24         DoNotUsePlusSign    = 0x0020,
25         DoNotUseQuotes      = 0x0040,
26         UseCommas           = 0x0080,
27         UseNewLines         = 0x0100,
28
29         UseUTF8Encoding     = 0x1000,
30         UseT61Encoding      = 0x2000,
31         ForceUTF8Encoding   = 0x4000,
32     }
33
34     public sealed class X500DistinguishedName : AsnEncodedData {
35         private string m_distinguishedName = null;
36
37         //
38         // Constructors.
39         //
40
41         internal X500DistinguishedName (CAPI.CRYPTOAPI_BLOB encodedDistinguishedNameBlob) : base (new Oid(), encodedDistinguishedNameBlob) {}
42
43         public X500DistinguishedName (byte[] encodedDistinguishedName) : base(new Oid(), encodedDistinguishedName) {}
44
45         public X500DistinguishedName (AsnEncodedData encodedDistinguishedName) : base(encodedDistinguishedName) {}
46
47         public X500DistinguishedName (X500DistinguishedName distinguishedName) : base((AsnEncodedData) distinguishedName) {
48             m_distinguishedName = distinguishedName.Name;
49         }
50
51         public X500DistinguishedName (string distinguishedName) : this(distinguishedName, X500DistinguishedNameFlags.Reversed) {}
52
53         public X500DistinguishedName (string distinguishedName, X500DistinguishedNameFlags flag) : base(new Oid(), Encode(distinguishedName, flag)) {
54             m_distinguishedName = distinguishedName;
55         }
56
57         //
58         // Public properties.
59         //
60
61         public string Name {
62             get {
63                 if (m_distinguishedName == null)
64                     m_distinguishedName = Decode(X500DistinguishedNameFlags.Reversed);
65                 return m_distinguishedName;
66             }
67         }
68
69         //
70         // Public methods.
71         //
72
73         public string Decode (X500DistinguishedNameFlags flag) {
74             uint dwStrType = CAPI.CERT_X500_NAME_STR | MapNameToStrFlag(flag);
75             unsafe {
76                 byte[] encodedDistinguishedName = this.m_rawData;
77                 fixed (byte * pbEncoded = encodedDistinguishedName) {
78                     CAPI.CRYPTOAPI_BLOB nameBlob;
79                     IntPtr pNameBlob = new IntPtr(&nameBlob);
80                     nameBlob.cbData = (uint) encodedDistinguishedName.Length;
81                     nameBlob.pbData = new IntPtr(pbEncoded);
82
83                     uint cchDecoded = CAPI.CertNameToStrW(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
84                                                           pNameBlob,
85                                                           dwStrType,
86                                                           SafeLocalAllocHandle.InvalidHandle,
87                                                           0);
88                     if (cchDecoded == 0)
89                         throw new CryptographicException(CAPI.CERT_E_INVALID_NAME);
90
91                     using (SafeLocalAllocHandle pwszDecodeName = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(2 * cchDecoded))) {
92                         if (CAPI.CertNameToStrW(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
93                                                 pNameBlob,
94                                                 dwStrType,
95                                                 pwszDecodeName,
96                                                 cchDecoded) == 0)
97                             throw new CryptographicException(CAPI.CERT_E_INVALID_NAME);
98                         return Marshal.PtrToStringUni(pwszDecodeName.DangerousGetHandle());
99                     }
100                 }
101             }
102         }
103
104         public override string Format (bool multiLine) {
105             //
106             // We must override to use the "numeric" pointer version of
107             // CryptFormatObject, since X509 DN does not have an official OID.
108             //
109
110             // Return empty string if no data to format.
111             if (m_rawData == null || m_rawData.Length == 0)
112                 return String.Empty;
113
114             return CAPI.CryptFormatObject(CAPI.X509_ASN_ENCODING, 
115                                           multiLine ? CAPI.CRYPT_FORMAT_STR_MULTI_LINE : 0,
116                                           new IntPtr(CAPI.X509_NAME),
117                                           m_rawData);
118         }
119
120         //
121         // Private methods.
122         //
123
124         private unsafe static byte[] Encode (string distinguishedName, X500DistinguishedNameFlags flag) {
125             if (distinguishedName == null)
126                 throw new ArgumentNullException("distinguishedName");
127
128             uint cbEncoded = 0;
129             uint dwStrType = CAPI.CERT_X500_NAME_STR | MapNameToStrFlag(flag);
130
131             if (!CAPI.CertStrToNameW(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
132                                      distinguishedName,
133                                      dwStrType,
134                                      IntPtr.Zero,
135                                      IntPtr.Zero,
136                                      ref cbEncoded,
137                                      IntPtr.Zero))
138                 throw new CryptographicException(Marshal.GetLastWin32Error());
139
140             byte[] encodedName = new byte[cbEncoded];
141             fixed (byte * pbEncoded = encodedName) {
142                 if (!CAPI.CertStrToNameW(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
143                                         distinguishedName,
144                                         dwStrType,
145                                         IntPtr.Zero,
146                                         new IntPtr(pbEncoded),
147                                         ref cbEncoded,
148                                         IntPtr.Zero))
149                     throw new CryptographicException(Marshal.GetLastWin32Error());
150             }
151
152             return encodedName;
153         }
154
155         private static uint MapNameToStrFlag (X500DistinguishedNameFlags flag) {
156             // All values or'ed together. Change this if you add values to the enumeration.
157             uint allFlags = 0x71F1;
158             uint dwFlags = (uint) flag;
159             if ((dwFlags & ~allFlags) != 0)
160                 throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.Arg_EnumIllegalVal), "flag"));
161
162             uint dwStrType = 0;
163             if (dwFlags != 0) {
164                 if ((flag & X500DistinguishedNameFlags.Reversed) == X500DistinguishedNameFlags.Reversed)
165                     dwStrType |= CAPI.CERT_NAME_STR_REVERSE_FLAG;
166
167                 if ((flag & X500DistinguishedNameFlags.UseSemicolons) == X500DistinguishedNameFlags.UseSemicolons)
168                     dwStrType |= CAPI.CERT_NAME_STR_SEMICOLON_FLAG;
169                 else if ((flag & X500DistinguishedNameFlags.UseCommas) == X500DistinguishedNameFlags.UseCommas)
170                     dwStrType |= CAPI.CERT_NAME_STR_COMMA_FLAG;
171                 else if ((flag & X500DistinguishedNameFlags.UseNewLines) == X500DistinguishedNameFlags.UseNewLines)
172                     dwStrType |= CAPI.CERT_NAME_STR_CRLF_FLAG;
173
174                 if ((flag & X500DistinguishedNameFlags.DoNotUsePlusSign) == X500DistinguishedNameFlags.DoNotUsePlusSign)
175                     dwStrType |= CAPI.CERT_NAME_STR_NO_PLUS_FLAG;
176                 if ((flag & X500DistinguishedNameFlags.DoNotUseQuotes) == X500DistinguishedNameFlags.DoNotUseQuotes)
177                     dwStrType |= CAPI.CERT_NAME_STR_NO_QUOTING_FLAG;
178
179                 if ((flag & X500DistinguishedNameFlags.ForceUTF8Encoding) == X500DistinguishedNameFlags.ForceUTF8Encoding)
180                     dwStrType |= CAPI.CERT_NAME_STR_FORCE_UTF8_DIR_STR_FLAG;
181
182                 if ((flag & X500DistinguishedNameFlags.UseUTF8Encoding) == X500DistinguishedNameFlags.UseUTF8Encoding)
183                     dwStrType |= CAPI.CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG;
184                 else if ((flag & X500DistinguishedNameFlags.UseT61Encoding) == X500DistinguishedNameFlags.UseT61Encoding)
185                     dwStrType |= CAPI.CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
186             }
187             return dwStrType;
188         }
189     }
190 }