DerGeneralizedTime.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Globalization;
  5. using System.Text;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  7. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1
  8. {
  9. /**
  10. * Generalized time object.
  11. */
  12. public class DerGeneralizedTime
  13. : Asn1Object
  14. {
  15. private readonly string time;
  16. /**
  17. * return a generalized time from the passed in object
  18. *
  19. * @exception ArgumentException if the object cannot be converted.
  20. */
  21. public static DerGeneralizedTime GetInstance(
  22. object obj)
  23. {
  24. if (obj == null || obj is DerGeneralizedTime)
  25. {
  26. return (DerGeneralizedTime)obj;
  27. }
  28. throw new ArgumentException("illegal object in GetInstance: " + BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.GetTypeName(obj), "obj");
  29. }
  30. /**
  31. * return a Generalized Time object from a tagged object.
  32. *
  33. * @param obj the tagged object holding the object we want
  34. * @param explicitly true if the object is meant to be explicitly
  35. * tagged false otherwise.
  36. * @exception ArgumentException if the tagged object cannot
  37. * be converted.
  38. */
  39. public static DerGeneralizedTime GetInstance(
  40. Asn1TaggedObject obj,
  41. bool isExplicit)
  42. {
  43. Asn1Object o = obj.GetObject();
  44. if (isExplicit || o is DerGeneralizedTime)
  45. {
  46. return GetInstance(o);
  47. }
  48. return new DerGeneralizedTime(((Asn1OctetString)o).GetOctets());
  49. }
  50. /**
  51. * The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z
  52. * for local time, or Z+-HHMM on the end, for difference between local
  53. * time and UTC time. The fractional second amount f must consist of at
  54. * least one number with trailing zeroes removed.
  55. *
  56. * @param time the time string.
  57. * @exception ArgumentException if string is an illegal format.
  58. */
  59. public DerGeneralizedTime(
  60. string time)
  61. {
  62. this.time = time;
  63. try
  64. {
  65. ToDateTime();
  66. }
  67. catch (FormatException e)
  68. {
  69. throw new ArgumentException("invalid date string: " + e.Message);
  70. }
  71. }
  72. /**
  73. * base constructor from a local time object
  74. */
  75. public DerGeneralizedTime(
  76. DateTime time)
  77. {
  78. #if PORTABLE || NETFX_CORE
  79. this.time = time.ToUniversalTime().ToString(@"yyyyMMddHHmmss\Z");
  80. #else
  81. this.time = time.ToString(@"yyyyMMddHHmmss\Z");
  82. #endif
  83. }
  84. internal DerGeneralizedTime(
  85. byte[] bytes)
  86. {
  87. //
  88. // explicitly convert to characters
  89. //
  90. this.time = Strings.FromAsciiByteArray(bytes);
  91. }
  92. /**
  93. * Return the time.
  94. * @return The time string as it appeared in the encoded object.
  95. */
  96. public string TimeString
  97. {
  98. get { return time; }
  99. }
  100. /**
  101. * return the time - always in the form of
  102. * YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
  103. * <p>
  104. * Normally in a certificate we would expect "Z" rather than "GMT",
  105. * however adding the "GMT" means we can just use:
  106. * <pre>
  107. * dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
  108. * </pre>
  109. * To read in the time and Get a date which is compatible with our local
  110. * time zone.</p>
  111. */
  112. public string GetTime()
  113. {
  114. //
  115. // standardise the format.
  116. //
  117. if (time[time.Length - 1] == 'Z')
  118. {
  119. return time.Substring(0, time.Length - 1) + "GMT+00:00";
  120. }
  121. else
  122. {
  123. int signPos = time.Length - 5;
  124. char sign = time[signPos];
  125. if (sign == '-' || sign == '+')
  126. {
  127. return time.Substring(0, signPos)
  128. + "GMT"
  129. + time.Substring(signPos, 3)
  130. + ":"
  131. + time.Substring(signPos + 3);
  132. }
  133. else
  134. {
  135. signPos = time.Length - 3;
  136. sign = time[signPos];
  137. if (sign == '-' || sign == '+')
  138. {
  139. return time.Substring(0, signPos)
  140. + "GMT"
  141. + time.Substring(signPos)
  142. + ":00";
  143. }
  144. }
  145. }
  146. return time + CalculateGmtOffset();
  147. }
  148. private string CalculateGmtOffset()
  149. {
  150. char sign = '+';
  151. DateTime time = ToDateTime();
  152. #if SILVERLIGHT || PORTABLE || NETFX_CORE
  153. long offset = time.Ticks - time.ToUniversalTime().Ticks;
  154. if (offset < 0)
  155. {
  156. sign = '-';
  157. offset = -offset;
  158. }
  159. int hours = (int)(offset / TimeSpan.TicksPerHour);
  160. int minutes = (int)(offset / TimeSpan.TicksPerMinute) % 60;
  161. #else
  162. // Note: GetUtcOffset incorporates Daylight Savings offset
  163. TimeSpan offset = TimeZone.CurrentTimeZone.GetUtcOffset(time);
  164. if (offset.CompareTo(TimeSpan.Zero) < 0)
  165. {
  166. sign = '-';
  167. offset = offset.Duration();
  168. }
  169. int hours = offset.Hours;
  170. int minutes = offset.Minutes;
  171. #endif
  172. return "GMT" + sign + Convert(hours) + ":" + Convert(minutes);
  173. }
  174. private static string Convert(
  175. int time)
  176. {
  177. if (time < 10)
  178. {
  179. return "0" + time;
  180. }
  181. return time.ToString();
  182. }
  183. public DateTime ToDateTime()
  184. {
  185. string formatStr;
  186. string d = time;
  187. bool makeUniversal = false;
  188. if (BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.EndsWith(d, "Z"))
  189. {
  190. if (HasFractionalSeconds)
  191. {
  192. int fCount = d.Length - d.IndexOf('.') - 2;
  193. formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"\Z";
  194. }
  195. else
  196. {
  197. formatStr = @"yyyyMMddHHmmss\Z";
  198. }
  199. }
  200. else if (time.IndexOf('-') > 0 || time.IndexOf('+') > 0)
  201. {
  202. d = GetTime();
  203. makeUniversal = true;
  204. if (HasFractionalSeconds)
  205. {
  206. int fCount = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.IndexOf(d, "GMT") - 1 - d.IndexOf('.');
  207. formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"'GMT'zzz";
  208. }
  209. else
  210. {
  211. formatStr = @"yyyyMMddHHmmss'GMT'zzz";
  212. }
  213. }
  214. else
  215. {
  216. if (HasFractionalSeconds)
  217. {
  218. int fCount = d.Length - 1 - d.IndexOf('.');
  219. formatStr = @"yyyyMMddHHmmss." + FString(fCount);
  220. }
  221. else
  222. {
  223. formatStr = @"yyyyMMddHHmmss";
  224. }
  225. // TODO?
  226. // dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID()));
  227. }
  228. return ParseDateString(d, formatStr, makeUniversal);
  229. }
  230. private string FString(
  231. int count)
  232. {
  233. StringBuilder sb = new StringBuilder();
  234. for (int i = 0; i < count; ++i)
  235. {
  236. sb.Append('f');
  237. }
  238. return sb.ToString();
  239. }
  240. private DateTime ParseDateString(string s, string format, bool makeUniversal)
  241. {
  242. /*
  243. * NOTE: DateTime.Kind and DateTimeStyles.AssumeUniversal not available in .NET 1.1
  244. */
  245. DateTimeStyles style = DateTimeStyles.None;
  246. if (BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.EndsWith(format, "Z"))
  247. {
  248. try
  249. {
  250. style = (DateTimeStyles)Enums.GetEnumValue(typeof(DateTimeStyles), "AssumeUniversal");
  251. }
  252. catch (Exception)
  253. {
  254. }
  255. style |= DateTimeStyles.AdjustToUniversal;
  256. }
  257. DateTime dt = DateTime.ParseExact(s, format, DateTimeFormatInfo.InvariantInfo, style);
  258. return makeUniversal ? dt.ToUniversalTime() : dt;
  259. }
  260. private bool HasFractionalSeconds
  261. {
  262. get { return time.IndexOf('.') == 14; }
  263. }
  264. private byte[] GetOctets()
  265. {
  266. return Strings.ToAsciiByteArray(time);
  267. }
  268. internal override int EncodedLength(bool withID)
  269. {
  270. return Asn1OutputStream.GetLengthOfEncodingDL(withID, time.Length);
  271. }
  272. internal override void Encode(Asn1OutputStream asn1Out, bool withID)
  273. {
  274. asn1Out.WriteEncodingDL(withID, Asn1Tags.GeneralizedTime, GetOctets());
  275. }
  276. protected override bool Asn1Equals(
  277. Asn1Object asn1Object)
  278. {
  279. DerGeneralizedTime other = asn1Object as DerGeneralizedTime;
  280. if (other == null)
  281. return false;
  282. return this.time.Equals(other.time);
  283. }
  284. protected override int Asn1GetHashCode()
  285. {
  286. return time.GetHashCode();
  287. }
  288. }
  289. }
  290. #pragma warning restore
  291. #endif