diff --git a/crypto/src/asn1/DerGeneralizedTime.cs b/crypto/src/asn1/DerGeneralizedTime.cs
index 16774cb02..22dc04912 100644
--- a/crypto/src/asn1/DerGeneralizedTime.cs
+++ b/crypto/src/asn1/DerGeneralizedTime.cs
@@ -139,32 +139,28 @@ namespace Org.BouncyCastle.Asn1
// standardise the format.
//
if (time[time.Length - 1] == 'Z')
- {
return time.Substring(0, time.Length - 1) + "GMT+00:00";
+
+ 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
{
- int signPos = time.Length - 5;
- char sign = time[signPos];
+ signPos = time.Length - 3;
+ 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";
- }
+ + time.Substring(signPos)
+ + ":00";
}
}
@@ -212,10 +208,18 @@ namespace Org.BouncyCastle.Asn1
int fCount = d.Length - d.IndexOf('.') - 2;
formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"\Z";
}
- else
+ else if (HasSeconds)
{
formatStr = @"yyyyMMddHHmmss\Z";
}
+ else if (HasMinutes)
+ {
+ formatStr = @"yyyyMMddHHmm\Z";
+ }
+ else
+ {
+ formatStr = @"yyyyMMddHH\Z";
+ }
}
else if (time.IndexOf('-') > 0 || time.IndexOf('+') > 0)
{
@@ -239,10 +243,18 @@ namespace Org.BouncyCastle.Asn1
int fCount = d.Length - 1 - d.IndexOf('.');
formatStr = @"yyyyMMddHHmmss." + FString(fCount);
}
- else
+ else if (HasSeconds)
{
formatStr = @"yyyyMMddHHmmss";
}
+ else if (HasMinutes)
+ {
+ formatStr = @"yyyyMMddHHmm";
+ }
+ else
+ {
+ formatStr = @"yyyyMMddHH";
+ }
// TODO?
// dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID()));
@@ -291,19 +303,55 @@ namespace Org.BouncyCastle.Asn1
get { return time.IndexOf('.') == 14; }
}
- private byte[] GetOctets()
+ private bool HasSeconds => IsDigit(12) && IsDigit(13);
+
+ private bool HasMinutes => IsDigit(10) && IsDigit(11);
+
+ private bool IsDigit(int pos)
+ {
+ return time.Length > pos && char.IsDigit(time[pos]);
+ }
+
+ private byte[] GetOctets(int encoding)
{
+ if (Asn1OutputStream.EncodingDer == encoding && time[time.Length - 1] == 'Z')
+ {
+ if (!HasMinutes)
+ return Strings.ToAsciiByteArray(time.Insert(time.Length - 1, "0000"));
+ if (!HasSeconds)
+ return Strings.ToAsciiByteArray(time.Insert(time.Length - 1, "00"));
+
+ if (HasFractionalSeconds)
+ {
+ int ind = time.Length - 2;
+ while (ind > 0 && time[ind] == '0')
+ {
+ --ind;
+ }
+
+ if (time[ind] != '.')
+ {
+ ++ind;
+ }
+
+ if (ind != time.Length - 1)
+ {
+ return Strings.ToAsciiByteArray(time.Remove(ind, time.Length - 1 - ind));
+ }
+ }
+ }
+
return Strings.ToAsciiByteArray(time);
}
internal override IAsn1Encoding GetEncoding(int encoding)
{
- return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.GeneralizedTime, GetOctets());
+ return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.GeneralizedTime, GetOctets(encoding));
}
internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
{
- return new PrimitiveEncoding(tagClass, tagNo, GetOctets());
+ return new PrimitiveEncoding(tagClass, tagNo, GetOctets(encoding));
}
protected override bool Asn1Equals(Asn1Object asn1Object)
diff --git a/crypto/test/src/asn1/test/GeneralizedTimeTest.cs b/crypto/test/src/asn1/test/GeneralizedTimeTest.cs
index 4df2666b3..d9d84462a 100644
--- a/crypto/test/src/asn1/test/GeneralizedTimeTest.cs
+++ b/crypto/test/src/asn1/test/GeneralizedTimeTest.cs
@@ -2,6 +2,8 @@ using System;
using NUnit.Framework;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
using Org.BouncyCastle.Utilities.Test;
namespace Org.BouncyCastle.Asn1.Tests
@@ -113,6 +115,43 @@ namespace Org.BouncyCastle.Asn1.Tests
"20020122022220.000Z"
};
+ private static readonly string[] derMzOutput =
+ {
+ "20020122122220Z",
+ "20020122122220Z",
+ "20020122222220Z",
+ "20020122122220Z",
+ "20020122122220.1Z",
+ "20020122122220.1Z",
+ "20020122222220.1Z",
+ "20020122122220.1Z",
+ "20020122122220.01Z",
+ "20020122122220.01Z",
+ "20020122222220.01Z",
+ "20020122122220.01Z",
+ "20020122122220.001Z",
+ "20020122122220.001Z",
+ "20020122222220.001Z",
+ "20020122122220.001Z",
+ "20020122122220Z",
+ "20020122122220Z",
+ "20020122222220Z",
+ "20020122122220Z",
+ "20020122022220Z"
+ };
+
+ private static readonly string[] truncOutput =
+ {
+ "200201221222Z",
+ "2002012212Z"
+ };
+
+ private static readonly string[] derTruncOutput =
+ {
+ "20020122122200Z",
+ "20020122120000Z"
+ };
+
public override string Name
{
get { return "GeneralizedTime"; }
@@ -164,6 +203,54 @@ namespace Org.BouncyCastle.Asn1.Tests
}
}
+ // TODO
+ //for (int i = 0; i != mzOutput.Length; i++)
+ //{
+ // DerGeneralizedTime t = new DerGeneralizedTime(mzOutput[i]);
+
+ // if (!AreEqual(t.GetEncoded(), new DerGeneralizedTime(derMzOutput[i]).GetEncoded()))
+ // {
+ // Fail("der encoding wrong");
+ // }
+ //}
+
+ // TODO
+ //for (int i = 0; i != truncOutput.Length; i++)
+ //{
+ // DerGeneralizedTime t = new DerGeneralizedTime(truncOutput[i]);
+
+ // if (!AreEqual(t.GetEncoded(), new DerGeneralizedTime(derTruncOutput[i]).GetEncoded()))
+ // {
+ // Fail("trunc der encoding wrong");
+ // }
+ //}
+
+ {
+ // check BER encoding is still "as given"
+ DerGeneralizedTime t = new DerGeneralizedTime("202208091215Z");
+
+ //IsTrue(Arrays.AreEqual(Hex.Decode("180d3230323230383039313231355a"), t.GetEncoded(Asn1Encodable.DL)));
+ IsTrue(Arrays.AreEqual(Hex.Decode("180d3230323230383039313231355a"), t.GetEncoded(Asn1Encodable.Ber)));
+ IsTrue(Arrays.AreEqual(Hex.Decode("180f32303232303830393132313530305a"), t.GetEncoded(Asn1Encodable.Der)));
+ }
+
+ // TODO
+ //{
+ // // check an actual GMT string comes back untampered
+ // DerGeneralizedTime time = new DerGeneralizedTime("20190704031318GMT+00:00");
+
+ // IsTrue("20190704031318GMT+00:00".Equals(time.GetTime()));
+
+ // try
+ // {
+ // DerGeneralizedTime.GetInstance(new byte[0]);
+ // }
+ // catch (ArgumentException e)
+ // {
+ // IsTrue(e.Message.Equals("GeneralizedTime string too short"));
+ // }
+ //}
+
/*
* [BMA-87]
*/
|