267 lines
9.9 KiB
C#
267 lines
9.9 KiB
C#
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
|
#pragma warning disable
|
|
using System;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
|
|
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1
|
|
{
|
|
/// <summary>GeneralizedTime ASN.1 type</summary>
|
|
public class Asn1GeneralizedTime
|
|
: Asn1Object
|
|
{
|
|
internal class Meta : Asn1UniversalType
|
|
{
|
|
internal static readonly Asn1UniversalType Instance = new Meta();
|
|
|
|
private Meta() : base(typeof(Asn1GeneralizedTime), Asn1Tags.GeneralizedTime) { }
|
|
|
|
internal override Asn1Object FromImplicitPrimitive(DerOctetString octetString)
|
|
{
|
|
return CreatePrimitive(octetString.GetOctets());
|
|
}
|
|
}
|
|
|
|
public static Asn1GeneralizedTime GetInstance(object obj)
|
|
{
|
|
if (obj == null)
|
|
return null;
|
|
|
|
if (obj is Asn1GeneralizedTime asn1GeneralizedTime)
|
|
return asn1GeneralizedTime;
|
|
|
|
if (obj is IAsn1Convertible asn1Convertible)
|
|
{
|
|
Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
|
|
if (asn1Object is Asn1GeneralizedTime converted)
|
|
return converted;
|
|
}
|
|
else if (obj is byte[] bytes)
|
|
{
|
|
try
|
|
{
|
|
return (Asn1GeneralizedTime)Meta.Instance.FromByteArray(bytes);
|
|
}
|
|
catch (IOException e)
|
|
{
|
|
throw new ArgumentException("failed to construct generalized time from byte[]: " + e.Message);
|
|
}
|
|
}
|
|
|
|
throw new ArgumentException("illegal object in GetInstance: " + Org.BouncyCastle.Utilities.Platform.GetTypeName(obj), nameof(obj));
|
|
}
|
|
|
|
public static Asn1GeneralizedTime GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
|
|
{
|
|
return (Asn1GeneralizedTime)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
|
|
}
|
|
|
|
private readonly string m_timeString;
|
|
private readonly bool m_timeStringCanonical;
|
|
private readonly DateTime m_dateTime;
|
|
|
|
public Asn1GeneralizedTime(string timeString)
|
|
{
|
|
m_timeString = timeString ?? throw new ArgumentNullException(nameof(timeString));
|
|
m_timeStringCanonical = false; // TODO Dynamic check?
|
|
|
|
try
|
|
{
|
|
m_dateTime = FromString(timeString);
|
|
}
|
|
catch (FormatException e)
|
|
{
|
|
throw new ArgumentException("invalid date string: " + e.Message);
|
|
}
|
|
}
|
|
|
|
public Asn1GeneralizedTime(DateTime dateTime)
|
|
{
|
|
dateTime = dateTime.ToUniversalTime();
|
|
|
|
m_dateTime = dateTime;
|
|
m_timeString = ToStringCanonical(dateTime);
|
|
m_timeStringCanonical = true;
|
|
}
|
|
|
|
// TODO TimeZoneInfo or other locale-specific constructors?
|
|
|
|
internal Asn1GeneralizedTime(byte[] contents)
|
|
: this(Encoding.ASCII.GetString(contents))
|
|
{
|
|
}
|
|
|
|
public string TimeString => m_timeString;
|
|
|
|
public DateTime ToDateTime()
|
|
{
|
|
return m_dateTime;
|
|
}
|
|
|
|
internal byte[] GetContents(int encoding)
|
|
{
|
|
if (encoding == Asn1OutputStream.EncodingDer && !m_timeStringCanonical)
|
|
return Encoding.ASCII.GetBytes(ToStringCanonical(m_dateTime));
|
|
|
|
return Encoding.ASCII.GetBytes(m_timeString);
|
|
}
|
|
|
|
internal override IAsn1Encoding GetEncoding(int encoding)
|
|
{
|
|
return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.GeneralizedTime, GetContents(encoding));
|
|
}
|
|
|
|
internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
|
|
{
|
|
return new PrimitiveEncoding(tagClass, tagNo, GetContents(encoding));
|
|
}
|
|
|
|
protected override bool Asn1Equals(Asn1Object asn1Object)
|
|
{
|
|
if (!(asn1Object is Asn1GeneralizedTime that))
|
|
return false;
|
|
|
|
// TODO Performance
|
|
return Arrays.AreEqual(
|
|
this.GetContents(Asn1OutputStream.EncodingDer),
|
|
that.GetContents(Asn1OutputStream.EncodingDer));
|
|
}
|
|
|
|
protected override int Asn1GetHashCode()
|
|
{
|
|
// TODO Performance
|
|
return Arrays.GetHashCode(
|
|
this.GetContents(Asn1OutputStream.EncodingDer));
|
|
}
|
|
|
|
internal static Asn1GeneralizedTime CreatePrimitive(byte[] contents)
|
|
{
|
|
return new Asn1GeneralizedTime(contents);
|
|
}
|
|
|
|
private static DateTime FromString(string s)
|
|
{
|
|
if (s.Length < 10)
|
|
throw new FormatException();
|
|
|
|
s = s.Replace(',', '.');
|
|
|
|
if (Org.BouncyCastle.Utilities.Platform.EndsWith(s, "Z"))
|
|
{
|
|
switch (s.Length)
|
|
{
|
|
case 11: return ParseUtc(s, @"yyyyMMddHH\Z");
|
|
case 13: return ParseUtc(s, @"yyyyMMddHHmm\Z");
|
|
case 15: return ParseUtc(s, @"yyyyMMddHHmmss\Z");
|
|
case 17: return ParseUtc(s, @"yyyyMMddHHmmss.f\Z");
|
|
case 18: return ParseUtc(s, @"yyyyMMddHHmmss.ff\Z");
|
|
case 19: return ParseUtc(s, @"yyyyMMddHHmmss.fff\Z");
|
|
case 20: return ParseUtc(s, @"yyyyMMddHHmmss.ffff\Z");
|
|
case 21: return ParseUtc(s, @"yyyyMMddHHmmss.fffff\Z");
|
|
case 22: return ParseUtc(s, @"yyyyMMddHHmmss.ffffff\Z");
|
|
case 23: return ParseUtc(s, @"yyyyMMddHHmmss.fffffff\Z");
|
|
default:
|
|
throw new FormatException();
|
|
}
|
|
}
|
|
|
|
int signIndex = IndexOfSign(s, System.Math.Max(10, s.Length - 5));
|
|
|
|
if (signIndex < 0)
|
|
{
|
|
switch (s.Length)
|
|
{
|
|
case 10: return ParseLocal(s, @"yyyyMMddHH");
|
|
case 12: return ParseLocal(s, @"yyyyMMddHHmm");
|
|
case 14: return ParseLocal(s, @"yyyyMMddHHmmss");
|
|
case 16: return ParseLocal(s, @"yyyyMMddHHmmss.f");
|
|
case 17: return ParseLocal(s, @"yyyyMMddHHmmss.ff");
|
|
case 18: return ParseLocal(s, @"yyyyMMddHHmmss.fff");
|
|
case 19: return ParseLocal(s, @"yyyyMMddHHmmss.ffff");
|
|
case 20: return ParseLocal(s, @"yyyyMMddHHmmss.fffff");
|
|
case 21: return ParseLocal(s, @"yyyyMMddHHmmss.ffffff");
|
|
case 22: return ParseLocal(s, @"yyyyMMddHHmmss.fffffff");
|
|
default:
|
|
throw new FormatException();
|
|
}
|
|
}
|
|
|
|
if (signIndex == s.Length - 5)
|
|
{
|
|
switch (s.Length)
|
|
{
|
|
case 15: return ParseTimeZone(s, @"yyyyMMddHHzzz");
|
|
case 17: return ParseTimeZone(s, @"yyyyMMddHHmmzzz");
|
|
case 19: return ParseTimeZone(s, @"yyyyMMddHHmmsszzz");
|
|
case 21: return ParseTimeZone(s, @"yyyyMMddHHmmss.fzzz");
|
|
case 22: return ParseTimeZone(s, @"yyyyMMddHHmmss.ffzzz");
|
|
case 23: return ParseTimeZone(s, @"yyyyMMddHHmmss.fffzzz");
|
|
case 24: return ParseTimeZone(s, @"yyyyMMddHHmmss.ffffzzz");
|
|
case 25: return ParseTimeZone(s, @"yyyyMMddHHmmss.fffffzzz");
|
|
case 26: return ParseTimeZone(s, @"yyyyMMddHHmmss.ffffffzzz");
|
|
case 27: return ParseTimeZone(s, @"yyyyMMddHHmmss.fffffffzzz");
|
|
default:
|
|
throw new FormatException();
|
|
}
|
|
}
|
|
|
|
if (signIndex == s.Length - 3)
|
|
{
|
|
switch (s.Length)
|
|
{
|
|
case 13: return ParseTimeZone(s, @"yyyyMMddHHzz");
|
|
case 15: return ParseTimeZone(s, @"yyyyMMddHHmmzz");
|
|
case 17: return ParseTimeZone(s, @"yyyyMMddHHmmsszz");
|
|
case 19: return ParseTimeZone(s, @"yyyyMMddHHmmss.fzz");
|
|
case 20: return ParseTimeZone(s, @"yyyyMMddHHmmss.ffzz");
|
|
case 21: return ParseTimeZone(s, @"yyyyMMddHHmmss.fffzz");
|
|
case 22: return ParseTimeZone(s, @"yyyyMMddHHmmss.ffffzz");
|
|
case 23: return ParseTimeZone(s, @"yyyyMMddHHmmss.fffffzz");
|
|
case 24: return ParseTimeZone(s, @"yyyyMMddHHmmss.ffffffzz");
|
|
case 25: return ParseTimeZone(s, @"yyyyMMddHHmmss.fffffffzz");
|
|
default:
|
|
throw new FormatException();
|
|
}
|
|
}
|
|
|
|
throw new FormatException();
|
|
}
|
|
|
|
private static int IndexOfSign(string s, int startIndex)
|
|
{
|
|
int index = Org.BouncyCastle.Utilities.Platform.IndexOf(s, '+', startIndex);
|
|
if (index < 0)
|
|
{
|
|
index = Org.BouncyCastle.Utilities.Platform.IndexOf(s, '-', startIndex);
|
|
}
|
|
return index;
|
|
}
|
|
|
|
private static DateTime ParseLocal(string s, string format)
|
|
{
|
|
return DateTime.ParseExact(s, format, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeLocal);
|
|
}
|
|
|
|
private static DateTime ParseTimeZone(string s, string format)
|
|
{
|
|
return DateTime.ParseExact(s, format, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AdjustToUniversal);
|
|
}
|
|
|
|
private static DateTime ParseUtc(string s, string format)
|
|
{
|
|
return DateTime.ParseExact(s, format, DateTimeFormatInfo.InvariantInfo,
|
|
DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);
|
|
}
|
|
|
|
private static string ToStringCanonical(DateTime dateTime)
|
|
{
|
|
return dateTime.ToUniversalTime().ToString(@"yyyyMMddHHmmss.FFFFFFFK", DateTimeFormatInfo.InvariantInfo);
|
|
}
|
|
}
|
|
}
|
|
#pragma warning restore
|
|
#endif
|