**** Merged from MCS ****
[mono-project.git] / mcs / class / corlib / Mono.Security / ASN1Convert.cs
blob5840f9e549ad4ae3bbc4b64283c84529bfe7daf9
1 //
2 // ASN1Convert.cs: Abstract Syntax Notation 1 convertion routines
3 //
4 // Authors:
5 // Sebastien Pouliot <sebastien@ximian.com>
6 // Jesper Pedersen <jep@itplus.dk>
7 //
8 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
9 // (C) 2004 Novell (http://www.novell.com)
10 // (C) 2004 IT+ A/S (http://www.itplus.dk)
14 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 //
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 //
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System;
37 using System.Collections;
38 using System.Globalization;
39 using System.Security.Cryptography;
40 using System.Text;
42 namespace Mono.Security {
44 // References:
45 // a. ITU ASN.1 standards (free download)
46 // http://www.itu.int/ITU-T/studygroups/com17/languages/
48 #if INSIDE_CORLIB
49 internal
50 #else
51 public
52 #endif
53 sealed class ASN1Convert {
55 private ASN1Convert ()
59 // RFC3280, section 4.2.1.5
60 // CAs conforming to this profile MUST always encode certificate
61 // validity dates through the year 2049 as UTCTime; certificate validity
62 // dates in 2050 or later MUST be encoded as GeneralizedTime.
63 static public ASN1 FromDateTime (DateTime dt)
65 if (dt.Year < 2050) {
66 // UTCTIME
67 return new ASN1 (0x17, Encoding.ASCII.GetBytes (
68 dt.ToUniversalTime ().ToString ("yyMMddHHmmss",
69 CultureInfo.InvariantCulture) + "Z"));
71 else {
72 // GENERALIZEDTIME
73 return new ASN1 (0x18, Encoding.ASCII.GetBytes (
74 dt.ToUniversalTime ().ToString ("yyyyMMddHHmmss",
75 CultureInfo.InvariantCulture) + "Z"));
79 static public ASN1 FromInt32 (Int32 value)
81 byte[] integer = BitConverterLE.GetBytes (value);
82 Array.Reverse (integer);
83 int x = 0;
84 while ((x < integer.Length) && (integer [x] == 0x00))
85 x++;
86 ASN1 asn1 = new ASN1 (0x02);
87 switch (x) {
88 case 0:
89 asn1.Value = integer;
90 break;
91 case 4:
92 asn1.Value = new byte [0];
93 break;
94 default:
95 byte[] smallerInt = new byte [4 - x];
96 Buffer.BlockCopy (integer, x, smallerInt, 0, smallerInt.Length);
97 asn1.Value = smallerInt;
98 break;
100 return asn1;
103 static public ASN1 FromOid (string oid)
105 if (oid == null)
106 throw new ArgumentNullException ("oid");
108 return new ASN1 (CryptoConfig.EncodeOID (oid));
111 static public ASN1 FromUnsignedBigInteger (byte[] big)
113 if (big == null)
114 throw new ArgumentNullException ("big");
116 if (big [0] != 0x00) {
117 // this first byte is added so we're sure this is an unsigned integer
118 // however we can't feed it into RSAParameters or DSAParameters
119 int length = big.Length + 1;
120 byte[] uinteger = new byte [length];
121 Buffer.BlockCopy (big, 0, uinteger, 1, length - 1);
122 big = uinteger;
124 return new ASN1 (0x02, big);
127 static public int ToInt32 (ASN1 asn1)
129 if (asn1 == null)
130 throw new ArgumentNullException ("asn1");
131 if (asn1.Tag != 0x02)
132 throw new FormatException ("Only integer can be converted");
134 int x = 0;
135 for (int i=0; i < asn1.Value.Length; i++)
136 x = (x << 8) + asn1.Value [i];
137 return x;
140 // Convert a binary encoded OID to human readable string representation of
141 // an OID (IETF style). Based on DUMPASN1.C from Peter Gutmann.
142 static public string ToOid (ASN1 asn1)
144 if (asn1 == null)
145 throw new ArgumentNullException ("asn1");
147 byte[] aOID = asn1.Value;
148 StringBuilder sb = new StringBuilder ();
149 // Pick apart the OID
150 byte x = (byte) (aOID[0] / 40);
151 byte y = (byte) (aOID[0] % 40);
152 if (x > 2) {
153 // Handle special case for large y if x = 2
154 y += (byte) ((x - 2) * 40);
155 x = 2;
157 sb.Append (x.ToString (CultureInfo.InvariantCulture));
158 sb.Append (".");
159 sb.Append (y.ToString (CultureInfo.InvariantCulture));
160 ulong val = 0;
161 for (x = 1; x < aOID.Length; x++) {
162 val = ((val << 7) | ((byte) (aOID [x] & 0x7F)));
163 if ( !((aOID [x] & 0x80) == 0x80)) {
164 sb.Append (".");
165 sb.Append (val.ToString (CultureInfo.InvariantCulture));
166 val = 0;
169 return sb.ToString ();
172 static public DateTime ToDateTime (ASN1 time)
174 if (time == null)
175 throw new ArgumentNullException ("time");
177 string t = Encoding.ASCII.GetString (time.Value);
178 // to support both UTCTime and GeneralizedTime (and not so common format)
179 string mask = null;
180 switch (t.Length) {
181 case 11:
182 mask = "yyMMddHHmmZ"; // illegal I think ... must check
183 break;
184 case 13:
185 // RFC3280: 4.1.2.5.1 UTCTime
186 int year = Convert.ToInt16 (t.Substring (0, 2), CultureInfo.InvariantCulture);
187 // Where YY is greater than or equal to 50, the
188 // year SHALL be interpreted as 19YY; and
189 // Where YY is less than 50, the year SHALL be
190 // interpreted as 20YY.
191 if (year >= 50)
192 t = "19" + t;
193 else
194 t = "20" + t;
195 mask = "yyyyMMddHHmmssZ";
196 break;
197 case 15:
198 mask = "yyyyMMddHHmmssZ"; // GeneralizedTime
199 break;
201 return DateTime.ParseExact (t, mask, null);