290 lines
6.9 KiB
C#
290 lines
6.9 KiB
C#
using System;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
|
|
namespace 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;
|
|
}
|
|
|
|
if (obj is Asn1OctetString)
|
|
{
|
|
return new DerGeneralizedTime(((Asn1OctetString)obj).GetOctets());
|
|
}
|
|
|
|
throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name, "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 explicitly)
|
|
{
|
|
return GetInstance(obj.GetObject());
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
this.time = time.ToString(@"yyyyMMddHHmmss\Z");
|
|
}
|
|
|
|
internal DerGeneralizedTime(
|
|
byte[] bytes)
|
|
{
|
|
//
|
|
// explicitly convert to characters
|
|
//
|
|
this.time = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
|
|
}
|
|
|
|
/**
|
|
* 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 = '+';
|
|
|
|
// Note: GetUtcOffset incorporates Daylight Savings offset
|
|
int minutes = TimeZone.CurrentTimeZone.GetUtcOffset(ToDateTime()).Minutes;
|
|
if (minutes < 0)
|
|
{
|
|
sign = '-';
|
|
minutes = -minutes;
|
|
}
|
|
int hours = minutes / 60;
|
|
minutes %= 60;
|
|
|
|
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 (d.EndsWith("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 = d.IndexOf("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 dateStr,
|
|
string formatStr,
|
|
bool makeUniversal)
|
|
{
|
|
DateTime dt = DateTime.ParseExact(
|
|
dateStr,
|
|
formatStr,
|
|
DateTimeFormatInfo.InvariantInfo);
|
|
|
|
return makeUniversal ? dt.ToUniversalTime() : dt;
|
|
}
|
|
|
|
private bool HasFractionalSeconds
|
|
{
|
|
get { return time.IndexOf('.') == 14; }
|
|
}
|
|
|
|
private byte[] GetOctets()
|
|
{
|
|
return Encoding.ASCII.GetBytes(time);
|
|
}
|
|
|
|
internal override void Encode(
|
|
DerOutputStream derOut)
|
|
{
|
|
derOut.WriteEncoded(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();
|
|
}
|
|
}
|
|
}
|