From 43aa4227f41ad04da4651d8ea1eade17bc03b75b Mon Sep 17 00:00:00 2001 From: David Hook Date: Thu, 17 Jul 2014 16:19:24 +1000 Subject: BJA-467 added support for passing in a specific locale to help with date interpretation. --- .../org/bouncycastle/asn1/ASN1GeneralizedTime.java | 23 +++++++- .../java/org/bouncycastle/asn1/ASN1UTCTime.java | 19 +++++++ .../main/java/org/bouncycastle/asn1/cms/Time.java | 44 +++++++++++++-- .../main/java/org/bouncycastle/asn1/x509/Time.java | 44 +++++++++++++-- .../cert/X509v2AttributeCertificateBuilder.java | 35 +++++++++++- .../org/bouncycastle/cert/X509v2CRLBuilder.java | 66 +++++++++++++++++++++- .../cert/X509v3CertificateBuilder.java | 18 ++++++ 7 files changed, 236 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java b/core/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java index 4643f84a..d760a1fa 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Locale; import java.util.SimpleTimeZone; import java.util.TimeZone; @@ -101,7 +102,9 @@ public class ASN1GeneralizedTime } /** - * base constructor from a java.util.date object + * Base constructor from a java.util.date object + * + * @param time a date object representing the time of interest. */ public ASN1GeneralizedTime( Date time) @@ -113,6 +116,24 @@ public class ASN1GeneralizedTime this.time = Strings.toByteArray(dateF.format(time)); } + /** + * Base constructor from a java.util.date and Locale - you may need to use this if the default locale + * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. + * + * @param time a date object representing the time of interest. + * @param locale an appropriate Locale for producing an ASN.1 GeneralizedTime value. + */ + public ASN1GeneralizedTime( + Date time, + Locale locale) + { + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", locale); + + dateF.setTimeZone(new SimpleTimeZone(0, "Z")); + + this.time = Strings.toByteArray(dateF.format(time)); + } + ASN1GeneralizedTime( byte[] bytes) { diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java b/core/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java index 2297cfef..2c82df30 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Locale; import java.util.SimpleTimeZone; import org.bouncycastle.util.Arrays; @@ -129,6 +130,24 @@ public class ASN1UTCTime this.time = Strings.toByteArray(dateF.format(time)); } + /** + * Base constructor from a java.util.date and Locale - you may need to use this if the default locale + * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. + * + * @param time a date object representing the time of interest. + * @param locale an appropriate Locale for producing an ASN.1 UTCTime value. + */ + public ASN1UTCTime( + Date time, + Locale locale) + { + SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", locale); + + dateF.setTimeZone(new SimpleTimeZone(0,"Z")); + + this.time = Strings.toByteArray(dateF.format(time)); + } + ASN1UTCTime( byte[] time) { diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/Time.java b/core/src/main/java/org/bouncycastle/asn1/cms/Time.java index 81b8bc03..84f12a9c 100644 --- a/core/src/main/java/org/bouncycastle/asn1/cms/Time.java +++ b/core/src/main/java/org/bouncycastle/asn1/cms/Time.java @@ -3,6 +3,7 @@ package org.bouncycastle.asn1.cms; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Locale; import java.util.SimpleTimeZone; import org.bouncycastle.asn1.ASN1Choice; @@ -59,28 +60,61 @@ public class Time } /** - * Create a time object from a given date - if the year is in between 1950 + * Creates a time object from a given date - if the date is between 1950 * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime * is used. + * + * @param time a date object representing the time of interest. */ public Time( - Date date) + Date time) { SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss"); dateF.setTimeZone(tz); - String d = dateF.format(date) + "Z"; + String d = dateF.format(time) + "Z"; + int year = Integer.parseInt(d.substring(0, 4)); + + if (year < 1950 || year > 2049) + { + this.time = new DERGeneralizedTime(d); + } + else + { + this.time = new DERUTCTime(d.substring(2)); + } + } + + /** + * Creates a time object from a given date and locale - if the date is between 1950 + * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime + * is used. You may need to use this constructor if the default locale + * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. + * + * @param time a date object representing the time of interest. + * @param locale an appropriate Locale for producing an ASN.1 GeneralizedTime value. + */ + public Time( + Date time, + Locale locale) + { + SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", locale); + + dateF.setTimeZone(tz); + + String d = dateF.format(time) + "Z"; int year = Integer.parseInt(d.substring(0, 4)); if (year < 1950 || year > 2049) { - time = new DERGeneralizedTime(d); + this.time = new DERGeneralizedTime(d); } else { - time = new DERUTCTime(d.substring(2)); + this.time = new DERUTCTime(d.substring(2)); } } diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/Time.java b/core/src/main/java/org/bouncycastle/asn1/x509/Time.java index b68e8646..77d36b31 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/Time.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/Time.java @@ -3,6 +3,7 @@ package org.bouncycastle.asn1.x509; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Locale; import java.util.SimpleTimeZone; import org.bouncycastle.asn1.ASN1Choice; @@ -40,28 +41,61 @@ public class Time } /** - * creates a time object from a given date - if the date is between 1950 + * Creates a time object from a given date - if the date is between 1950 * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime * is used. + * + * @param time a date object representing the time of interest. */ public Time( - Date date) + Date time) { SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss"); dateF.setTimeZone(tz); - String d = dateF.format(date) + "Z"; + String d = dateF.format(time) + "Z"; int year = Integer.parseInt(d.substring(0, 4)); if (year < 1950 || year > 2049) { - time = new DERGeneralizedTime(d); + this.time = new DERGeneralizedTime(d); } else { - time = new DERUTCTime(d.substring(2)); + this.time = new DERUTCTime(d.substring(2)); + } + } + + /** + * Creates a time object from a given date and locale - if the date is between 1950 + * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime + * is used. You may need to use this constructor if the default locale + * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. + * + * @param time a date object representing the time of interest. + * @param locale an appropriate Locale for producing an ASN.1 GeneralizedTime value. + */ + public Time( + Date time, + Locale locale) + { + SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", locale); + + dateF.setTimeZone(tz); + + String d = dateF.format(time) + "Z"; + int year = Integer.parseInt(d.substring(0, 4)); + + if (year < 1950 || year > 2049) + { + this.time = new DERGeneralizedTime(d); + } + else + { + this.time = new DERUTCTime(d.substring(2)); } } diff --git a/pkix/src/main/java/org/bouncycastle/cert/X509v2AttributeCertificateBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/X509v2AttributeCertificateBuilder.java index ba30aa8c..4cd10a3f 100644 --- a/pkix/src/main/java/org/bouncycastle/cert/X509v2AttributeCertificateBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/cert/X509v2AttributeCertificateBuilder.java @@ -2,6 +2,7 @@ package org.bouncycastle.cert; import java.math.BigInteger; import java.util.Date; +import java.util.Locale; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1GeneralizedTime; @@ -22,7 +23,16 @@ public class X509v2AttributeCertificateBuilder private V2AttributeCertificateInfoGenerator acInfoGen; private ExtensionsGenerator extGenerator; - public X509v2AttributeCertificateBuilder(AttributeCertificateHolder holder, AttributeCertificateIssuer issuer, BigInteger serialNumber, Date notBefore, Date notAfter) + /** + * Base constructor. + * + * @param holder holder certificate details + * @param issuer issuer of this attribute certificate. + * @param serialNumber serial number of this attribute certificate. + * @param notBefore the date before which the certificate is not valid. + * @param notAfter the date after which the certificate is not valid. + */ + public X509v2AttributeCertificateBuilder(AttributeCertificateHolder holder, AttributeCertificateIssuer issuer, BigInteger serialNumber, Date notBefore, Date notAfter) { acInfoGen = new V2AttributeCertificateInfoGenerator(); extGenerator = new ExtensionsGenerator(); @@ -34,6 +44,29 @@ public class X509v2AttributeCertificateBuilder acInfoGen.setEndDate(new ASN1GeneralizedTime(notAfter)); } + /** + * Base constructor with locale for interpreting dates. You may need to use this constructor if the default locale + * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. + * + * @param holder holder certificate details + * @param issuer issuer of this attribute certificate. + * @param serialNumber serial number of this attribute certificate. + * @param notBefore the date before which the certificate is not valid. + * @param notAfter the date after which the certificate is not valid. + * @param dateLocale locale to be used for date interpretation. + */ + public X509v2AttributeCertificateBuilder(AttributeCertificateHolder holder, AttributeCertificateIssuer issuer, BigInteger serialNumber, Date notBefore, Date notAfter, Locale dateLocale) + { + acInfoGen = new V2AttributeCertificateInfoGenerator(); + extGenerator = new ExtensionsGenerator(); + + acInfoGen.setHolder(holder.holder); + acInfoGen.setIssuer(AttCertIssuer.getInstance(issuer.form)); + acInfoGen.setSerialNumber(new ASN1Integer(serialNumber)); + acInfoGen.setStartDate(new ASN1GeneralizedTime(notBefore, dateLocale)); + acInfoGen.setEndDate(new ASN1GeneralizedTime(notAfter, dateLocale)); + } + /** * Add an attribute to the certification request we are building. * diff --git a/pkix/src/main/java/org/bouncycastle/cert/X509v2CRLBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/X509v2CRLBuilder.java index fe6dad62..896f55be 100644 --- a/pkix/src/main/java/org/bouncycastle/cert/X509v2CRLBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/cert/X509v2CRLBuilder.java @@ -3,6 +3,7 @@ package org.bouncycastle.cert; import java.math.BigInteger; import java.util.Date; import java.util.Enumeration; +import java.util.Locale; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1GeneralizedTime; @@ -43,6 +44,43 @@ public class X509v2CRLBuilder tbsGen.setThisUpdate(new Time(thisUpdate)); } + /** + * Basic constructor with Locale. You may need to use this constructor if the default locale + * doesn't use a Gregorian calender so that the Time produced is compatible with other ASN.1 implementations. + * + * @param issuer the issuer this CRL is associated with. + * @param thisUpdate the date of this update. + * @param dateLocale locale to be used for date interpretation. + */ + public X509v2CRLBuilder( + X500Name issuer, + Date thisUpdate, + Locale dateLocale) + { + tbsGen = new V2TBSCertListGenerator(); + extGenerator = new ExtensionsGenerator(); + + tbsGen.setIssuer(issuer); + tbsGen.setThisUpdate(new Time(thisUpdate, dateLocale)); + } + + /** + * Basic constructor. + * + * @param issuer the issuer this CRL is associated with. + * @param thisUpdate the Time of this update. + */ + public X509v2CRLBuilder( + X500Name issuer, + Time thisUpdate) + { + tbsGen = new V2TBSCertListGenerator(); + extGenerator = new ExtensionsGenerator(); + + tbsGen.setIssuer(issuer); + tbsGen.setThisUpdate(thisUpdate); + } + /** * Set the date by which the next CRL will become available. * @@ -52,7 +90,33 @@ public class X509v2CRLBuilder public X509v2CRLBuilder setNextUpdate( Date date) { - tbsGen.setNextUpdate(new Time(date)); + return this.setNextUpdate(new Time(date)); + } + + /** + * Set the date by which the next CRL will become available. + * + * @param date date of next CRL update. + * @param dateLocale locale to be used for date interpretation. + * @return the current builder. + */ + public X509v2CRLBuilder setNextUpdate( + Date date, + Locale dateLocale) + { + return this.setNextUpdate(new Time(date, dateLocale)); + } + + /** + * Set the date by which the next CRL will become available. + * + * @param date date of next CRL update. + * @return the current builder. + */ + public X509v2CRLBuilder setNextUpdate( + Time date) + { + tbsGen.setNextUpdate(date); return this; } diff --git a/pkix/src/main/java/org/bouncycastle/cert/X509v3CertificateBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/X509v3CertificateBuilder.java index a93f2157..22905b97 100644 --- a/pkix/src/main/java/org/bouncycastle/cert/X509v3CertificateBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/cert/X509v3CertificateBuilder.java @@ -2,6 +2,7 @@ package org.bouncycastle.cert; import java.math.BigInteger; import java.util.Date; +import java.util.Locale; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Integer; @@ -39,6 +40,23 @@ public class X509v3CertificateBuilder this(issuer, serial, new Time(notBefore), new Time(notAfter), subject, publicKeyInfo); } + /** + * Create a builder for a version 3 certificate. You may need to use this constructor if the default locale + * doesn't use a Gregorian calender so that the Time produced is compatible with other ASN.1 implementations. + * + * @param issuer the certificate issuer + * @param serial the certificate serial number + * @param notBefore the date before which the certificate is not valid + * @param notAfter the date after which the certificate is not valid + * @param dateLocale locale to be used for date interpretation. + * @param subject the certificate subject + * @param publicKeyInfo the info structure for the public key to be associated with this certificate. + */ + public X509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, Locale dateLocale, X500Name subject, SubjectPublicKeyInfo publicKeyInfo) + { + this(issuer, serial, new Time(notBefore, dateLocale), new Time(notAfter, dateLocale), subject, publicKeyInfo); + } + /** * Create a builder for a version 3 certificate. * -- cgit v1.2.3