You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
329 lines
9.8 KiB
329 lines
9.8 KiB
1 year ago
|
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||
|
#pragma warning disable
|
||
|
using System;
|
||
|
using System.Globalization;
|
||
|
using System.Text;
|
||
|
|
||
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||
|
|
||
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1
|
||
|
{
|
||
|
/**
|
||
|
* Generalized time object.
|
||
|
*/
|
||
|
public class DerGeneralizedTime
|
||
|
: Asn1Object
|
||
|
{
|
||
|
private readonly string time;
|
||
|
|
||
|
/**
|
||
|
* return a generalized time from the passed in object
|
||
|
*
|
||
|
* @exception ArgumentException if the object cannot be converted.
|
||
|
*/
|
||
|
public static DerGeneralizedTime GetInstance(
|
||
|
object obj)
|
||
|
{
|
||
|
if (obj == null || obj is DerGeneralizedTime)
|
||
|
{
|
||
|
return (DerGeneralizedTime)obj;
|
||
|
}
|
||
|
|
||
|
throw new ArgumentException("illegal object in GetInstance: " + BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.GetTypeName(obj), "obj");
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* return a Generalized Time object from a tagged object.
|
||
|
*
|
||
|
* @param obj the tagged object holding the object we want
|
||
|
* @param explicitly true if the object is meant to be explicitly
|
||
|
* tagged false otherwise.
|
||
|
* @exception ArgumentException if the tagged object cannot
|
||
|
* be converted.
|
||
|
*/
|
||
|
public static DerGeneralizedTime GetInstance(
|
||
|
Asn1TaggedObject obj,
|
||
|
bool isExplicit)
|
||
|
{
|
||
|
Asn1Object o = obj.GetObject();
|
||
|
|
||
|
if (isExplicit || o is DerGeneralizedTime)
|
||
|
{
|
||
|
return GetInstance(o);
|
||
|
}
|
||
|
|
||
|
return new DerGeneralizedTime(((Asn1OctetString)o).GetOctets());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z
|
||
|
* for local time, or Z+-HHMM on the end, for difference between local
|
||
|
* time and UTC time. The fractional second amount f must consist of at
|
||
|
* least one number with trailing zeroes removed.
|
||
|
*
|
||
|
* @param time the time string.
|
||
|
* @exception ArgumentException if string is an illegal format.
|
||
|
*/
|
||
|
public DerGeneralizedTime(
|
||
|
string time)
|
||
|
{
|
||
|
this.time = time;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
ToDateTime();
|
||
|
}
|
||
|
catch (FormatException e)
|
||
|
{
|
||
|
throw new ArgumentException("invalid date string: " + e.Message);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* base constructor from a local time object
|
||
|
*/
|
||
|
public DerGeneralizedTime(
|
||
|
DateTime time)
|
||
|
{
|
||
|
#if PORTABLE || NETFX_CORE
|
||
|
this.time = time.ToUniversalTime().ToString(@"yyyyMMddHHmmss\Z");
|
||
|
#else
|
||
|
this.time = time.ToString(@"yyyyMMddHHmmss\Z");
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
internal DerGeneralizedTime(
|
||
|
byte[] bytes)
|
||
|
{
|
||
|
//
|
||
|
// explicitly convert to characters
|
||
|
//
|
||
|
this.time = Strings.FromAsciiByteArray(bytes);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the time.
|
||
|
* @return The time string as it appeared in the encoded object.
|
||
|
*/
|
||
|
public string TimeString
|
||
|
{
|
||
|
get { return time; }
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* return the time - always in the form of
|
||
|
* YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
|
||
|
* <p>
|
||
|
* Normally in a certificate we would expect "Z" rather than "GMT",
|
||
|
* however adding the "GMT" means we can just use:
|
||
|
* <pre>
|
||
|
* dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
|
||
|
* </pre>
|
||
|
* To read in the time and Get a date which is compatible with our local
|
||
|
* time zone.</p>
|
||
|
*/
|
||
|
public string GetTime()
|
||
|
{
|
||
|
//
|
||
|
// standardise the format.
|
||
|
//
|
||
|
if (time[time.Length - 1] == 'Z')
|
||
|
{
|
||
|
return time.Substring(0, time.Length - 1) + "GMT+00:00";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int signPos = time.Length - 5;
|
||
|
char sign = time[signPos];
|
||
|
if (sign == '-' || sign == '+')
|
||
|
{
|
||
|
return time.Substring(0, signPos)
|
||
|
+ "GMT"
|
||
|
+ time.Substring(signPos, 3)
|
||
|
+ ":"
|
||
|
+ time.Substring(signPos + 3);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
signPos = time.Length - 3;
|
||
|
sign = time[signPos];
|
||
|
if (sign == '-' || sign == '+')
|
||
|
{
|
||
|
return time.Substring(0, signPos)
|
||
|
+ "GMT"
|
||
|
+ time.Substring(signPos)
|
||
|
+ ":00";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return time + CalculateGmtOffset();
|
||
|
}
|
||
|
|
||
|
private string CalculateGmtOffset()
|
||
|
{
|
||
|
char sign = '+';
|
||
|
DateTime time = ToDateTime();
|
||
|
|
||
|
#if SILVERLIGHT || PORTABLE || NETFX_CORE
|
||
|
long offset = time.Ticks - time.ToUniversalTime().Ticks;
|
||
|
if (offset < 0)
|
||
|
{
|
||
|
sign = '-';
|
||
|
offset = -offset;
|
||
|
}
|
||
|
int hours = (int)(offset / TimeSpan.TicksPerHour);
|
||
|
int minutes = (int)(offset / TimeSpan.TicksPerMinute) % 60;
|
||
|
#else
|
||
|
// Note: GetUtcOffset incorporates Daylight Savings offset
|
||
|
TimeSpan offset = TimeZone.CurrentTimeZone.GetUtcOffset(time);
|
||
|
if (offset.CompareTo(TimeSpan.Zero) < 0)
|
||
|
{
|
||
|
sign = '-';
|
||
|
offset = offset.Duration();
|
||
|
}
|
||
|
int hours = offset.Hours;
|
||
|
int minutes = offset.Minutes;
|
||
|
#endif
|
||
|
|
||
|
return "GMT" + sign + Convert(hours) + ":" + Convert(minutes);
|
||
|
}
|
||
|
|
||
|
private static string Convert(
|
||
|
int time)
|
||
|
{
|
||
|
if (time < 10)
|
||
|
{
|
||
|
return "0" + time;
|
||
|
}
|
||
|
|
||
|
return time.ToString();
|
||
|
}
|
||
|
|
||
|
public DateTime ToDateTime()
|
||
|
{
|
||
|
string formatStr;
|
||
|
string d = time;
|
||
|
bool makeUniversal = false;
|
||
|
|
||
|
if (BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.EndsWith(d, "Z"))
|
||
|
{
|
||
|
if (HasFractionalSeconds)
|
||
|
{
|
||
|
int fCount = d.Length - d.IndexOf('.') - 2;
|
||
|
formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"\Z";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
formatStr = @"yyyyMMddHHmmss\Z";
|
||
|
}
|
||
|
}
|
||
|
else if (time.IndexOf('-') > 0 || time.IndexOf('+') > 0)
|
||
|
{
|
||
|
d = GetTime();
|
||
|
makeUniversal = true;
|
||
|
|
||
|
if (HasFractionalSeconds)
|
||
|
{
|
||
|
int fCount = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.IndexOf(d, "GMT") - 1 - d.IndexOf('.');
|
||
|
formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"'GMT'zzz";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
formatStr = @"yyyyMMddHHmmss'GMT'zzz";
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (HasFractionalSeconds)
|
||
|
{
|
||
|
int fCount = d.Length - 1 - d.IndexOf('.');
|
||
|
formatStr = @"yyyyMMddHHmmss." + FString(fCount);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
formatStr = @"yyyyMMddHHmmss";
|
||
|
}
|
||
|
|
||
|
// TODO?
|
||
|
// dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID()));
|
||
|
}
|
||
|
|
||
|
return ParseDateString(d, formatStr, makeUniversal);
|
||
|
}
|
||
|
|
||
|
private string FString(
|
||
|
int count)
|
||
|
{
|
||
|
StringBuilder sb = new StringBuilder();
|
||
|
for (int i = 0; i < count; ++i)
|
||
|
{
|
||
|
sb.Append('f');
|
||
|
}
|
||
|
return sb.ToString();
|
||
|
}
|
||
|
|
||
|
private DateTime ParseDateString(string s, string format, bool makeUniversal)
|
||
|
{
|
||
|
/*
|
||
|
* NOTE: DateTime.Kind and DateTimeStyles.AssumeUniversal not available in .NET 1.1
|
||
|
*/
|
||
|
DateTimeStyles style = DateTimeStyles.None;
|
||
|
if (BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.EndsWith(format, "Z"))
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
style = (DateTimeStyles)Enums.GetEnumValue(typeof(DateTimeStyles), "AssumeUniversal");
|
||
|
}
|
||
|
catch (Exception)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
style |= DateTimeStyles.AdjustToUniversal;
|
||
|
}
|
||
|
|
||
|
DateTime dt = DateTime.ParseExact(s, format, DateTimeFormatInfo.InvariantInfo, style);
|
||
|
|
||
|
return makeUniversal ? dt.ToUniversalTime() : dt;
|
||
|
}
|
||
|
|
||
|
private bool HasFractionalSeconds
|
||
|
{
|
||
|
get { return time.IndexOf('.') == 14; }
|
||
|
}
|
||
|
|
||
|
private byte[] GetOctets()
|
||
|
{
|
||
|
return Strings.ToAsciiByteArray(time);
|
||
|
}
|
||
|
|
||
|
internal override int EncodedLength(bool withID)
|
||
|
{
|
||
|
return Asn1OutputStream.GetLengthOfEncodingDL(withID, time.Length);
|
||
|
}
|
||
|
|
||
|
internal override void Encode(Asn1OutputStream asn1Out, bool withID)
|
||
|
{
|
||
|
asn1Out.WriteEncodingDL(withID, Asn1Tags.GeneralizedTime, GetOctets());
|
||
|
}
|
||
|
|
||
|
protected override bool Asn1Equals(
|
||
|
Asn1Object asn1Object)
|
||
|
{
|
||
|
DerGeneralizedTime other = asn1Object as DerGeneralizedTime;
|
||
|
|
||
|
if (other == null)
|
||
|
return false;
|
||
|
|
||
|
return this.time.Equals(other.time);
|
||
|
}
|
||
|
|
||
|
protected override int Asn1GetHashCode()
|
||
|
{
|
||
|
return time.GetHashCode();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#pragma warning restore
|
||
|
#endif
|