From d342a45d98c4795b3a3fe1aaef5236ad4a782b55 Mon Sep 17 00:00:00 2001 From: Yuuta Liang Date: Thu, 12 Oct 2023 12:10:33 +0800 Subject: Implement data structures from X.680, X.501, X.509, and PKCS#10, with X.690 encoding / decoding support The implementation took four days, and it is still a little bit rough. Updated version should arrive soon. Signed-off-by: Yuuta Liang --- src/main/model/asn1/GeneralizedTime.java | 90 ++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/main/model/asn1/GeneralizedTime.java (limited to 'src/main/model/asn1/GeneralizedTime.java') diff --git a/src/main/model/asn1/GeneralizedTime.java b/src/main/model/asn1/GeneralizedTime.java new file mode 100644 index 0000000..385642d --- /dev/null +++ b/src/main/model/asn1/GeneralizedTime.java @@ -0,0 +1,90 @@ +package model.asn1; + +import model.asn1.exceptions.ParseException; +import model.asn1.parsing.BytesReader; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoField; + +/** + * Represents the ASN.1 GeneralizedTime type. It encodes the time in "YYYYMMDDhhmm[ss]Z" string format, in UTC. + */ +public class GeneralizedTime extends ASN1Time { + /** + * The X.680 universal class tag assignment. + */ + public static final Tag TAG = new Tag(TagClass.UNIVERSAL, false, 0x18); + + /** + * Rather stupid impl ... + */ + private static final DateTimeFormatter formatterNoSecs = new DateTimeFormatterBuilder() + .appendValue(ChronoField.YEAR, 4) + .appendValue(ChronoField.MONTH_OF_YEAR, 2) + .appendValue(ChronoField.DAY_OF_MONTH, 2) + .appendValue(ChronoField.HOUR_OF_DAY, 2) + .appendValue(ChronoField.MINUTE_OF_HOUR, 2) + .appendLiteral('Z') + .toFormatter() + .withZone(ZoneId.of("UTC")); + + private static final DateTimeFormatter formatter = new DateTimeFormatterBuilder() + .appendValue(ChronoField.YEAR, 4) + .appendValue(ChronoField.MONTH_OF_YEAR, 2) + .appendValue(ChronoField.DAY_OF_MONTH, 2) + .appendValue(ChronoField.HOUR_OF_DAY, 2) + .appendValue(ChronoField.MINUTE_OF_HOUR, 2) + .optionalStart() + .appendValue(ChronoField.SECOND_OF_MINUTE, 2) + .optionalEnd() + .appendLiteral('Z') + .toFormatter() + .withZone(ZoneId.of("UTC")); + + /** + * EFFECT: Construct the UTCTime with the given tag, parentTag, and timestamp. For tag and parentTag, + * consult {@link ASN1Object}. + * REQUIRES: timestamp must be in UTC. + */ + public GeneralizedTime(Tag tag, Tag parentTag, ZonedDateTime timestamp) { + super(tag, parentTag, timestamp); + } + + /** + * EFFECT: Parse the given DER input. Time will be assumed to be in UTC. + * Throws {@link ParseException}: + * - The time is not in the string format specified in class specification + * - Other invalid input is found. See {@link ASN1Object} for more details on parsing + */ + public GeneralizedTime(BytesReader encoded, boolean hasParentTag) throws ParseException { + super(encoded, hasParentTag); + } + + /** + * EFFECT: Parse the string into time, in the format specified in class specification. + * Throws {@link ParseException} if the input is malformed. + */ + @Override + public ZonedDateTime toDate(String str) throws ParseException { + try { + return ZonedDateTime.parse(str, formatter); + } catch (DateTimeParseException e) { + throw new ParseException(e.getMessage()); + } + } + + /** + * EFFECT: Convert the time into format "YYYYMMDDhhmm[ss]Z". + */ + @Override + public String toString() { + if (getTimestamp().getSecond() == 0) { + return getTimestamp().format(formatterNoSecs); + } + return getTimestamp().format(formatter); + } +} -- cgit v1.2.3