diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2022-08-11 12:41:05 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2022-08-11 12:41:05 +0700 |
commit | 2447cea7296abf3b77207eeeb39dc75ae2a73a4e (patch) | |
tree | 2e01b1b243d0b9a506934765632685931ebf40aa | |
parent | Add note for future Arm implementation (diff) | |
download | BouncyCastle.NET-ed25519-2447cea7296abf3b77207eeeb39dc75ae2a73a4e.tar.xz |
GeneralizedTime improvements
-rw-r--r-- | crypto/src/asn1/DerGeneralizedTime.cs | 94 | ||||
-rw-r--r-- | crypto/test/src/asn1/test/GeneralizedTimeTest.cs | 87 |
2 files changed, 158 insertions, 23 deletions
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] */ |