Flip the sign on timezone offset calculation A timezone offset of -0400 means that the local time is UTC-4. To go from local time back to UTC, we have to negate the operation. Update-Note: Invalid UTCTime structures with timezones will be parsed differently. Previously we may have misinterpreted it by a day or so. Change-Id: I4b90965eae96dc6bf215f351c0290cdd68e191f5 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/96607 Commit-Queue: Lily Chen <chlily@google.com> Auto-Submit: David Benjamin <davidben@google.com> Commit-Queue: David Benjamin <davidben@google.com> Reviewed-by: Lily Chen <chlily@google.com>
diff --git a/crypto/asn1/asn1_test.cc b/crypto/asn1/asn1_test.cc index e1b2993..087301d 100644 --- a/crypto/asn1/asn1_test.cc +++ b/crypto/asn1/asn1_test.cc
@@ -1301,13 +1301,13 @@ EXPECT_EQ("700101000000Z", ASN1StringToStringView(s.get())); // UTCTIME_set_string should not allow a timezone offset - EXPECT_FALSE(ASN1_UTCTIME_set_string(s.get(), "700101000000-0400")); + EXPECT_FALSE(ASN1_UTCTIME_set_string(s.get(), "700101000000+0400")); // Forcibly construct a utc time with a timezone offset. - ASSERT_TRUE(ASN1_STRING_set(s.get(), "700101000000-0400", - strlen("700101000000-0400"))); + ASSERT_TRUE(ASN1_STRING_set(s.get(), "700101000000+0400", + strlen("700101000000+0400"))); EXPECT_EQ(V_ASN1_UTCTIME, ASN1_STRING_type(s.get())); - EXPECT_EQ("700101000000-0400", ASN1StringToStringView(s.get())); + EXPECT_EQ("700101000000+0400", ASN1StringToStringView(s.get())); // check is expected to be valid with timezone offsets ASSERT_TRUE(ASN1_UTCTIME_check(s.get())); @@ -1326,7 +1326,7 @@ // This should be the correct value // EXPECT_EQ("19691231200000Z", ASN1StringToStringView(g.get())); // But this function currently generates invalid times. - EXPECT_EQ("19700101000000-0400", ASN1StringToStringView(g.get())); + EXPECT_EQ("19700101000000+0400", ASN1StringToStringView(g.get())); // Force this to be a generalized time the same as our utc time EXPECT_TRUE(ASN1_GENERALIZEDTIME_set_string(g.get(), "19691231200000Z"));
diff --git a/crypto/bytestring/bytestring_test.cc b/crypto/bytestring/bytestring_test.cc index 443b086..32b6f6c 100644 --- a/crypto/bytestring/bytestring_test.cc +++ b/crypto/bytestring/bytestring_test.cc
@@ -2077,6 +2077,60 @@ } } +TEST(CBSTest, ParseTime) { + tm expected = {}; + expected.tm_year = 70; // 1970 + expected.tm_mon = 0; // January + expected.tm_mday = 1; + expected.tm_hour = 4; + expected.tm_min = 0; + expected.tm_sec = 0; + + // 1970-01-01 00:00:00 -0400 should be 1970-01-01 04:00:00 UTC + CBS cbs; + tm tm; + cbs = StringAsBytes("700101000000-0400"); + ASSERT_TRUE(CBS_parse_utc_time(&cbs, &tm, /*allow_timezone_offset=*/1)); + EXPECT_EQ(tm.tm_year, expected.tm_year); + EXPECT_EQ(tm.tm_mon, expected.tm_mon); + EXPECT_EQ(tm.tm_mday, expected.tm_mday); + EXPECT_EQ(tm.tm_hour, expected.tm_hour); + EXPECT_EQ(tm.tm_min, expected.tm_min); + EXPECT_EQ(tm.tm_sec, expected.tm_sec); + + cbs = StringAsBytes("19700101000000-0400"); + ASSERT_TRUE( + CBS_parse_generalized_time(&cbs, &tm, /*allow_timezone_offset=*/1)); + EXPECT_EQ(tm.tm_year, expected.tm_year); + EXPECT_EQ(tm.tm_mon, expected.tm_mon); + EXPECT_EQ(tm.tm_mday, expected.tm_mday); + EXPECT_EQ(tm.tm_hour, expected.tm_hour); + EXPECT_EQ(tm.tm_min, expected.tm_min); + EXPECT_EQ(tm.tm_sec, expected.tm_sec); + + // 1970-01-01 08:00:00 +0400 should be 1970-01-01 04:00:00 UTC + expected.tm_hour = 4; + cbs = StringAsBytes("700101080000+0400"); + ASSERT_TRUE(CBS_parse_utc_time(&cbs, &tm, /*allow_timezone_offset=*/1)); + EXPECT_EQ(tm.tm_year, expected.tm_year); + EXPECT_EQ(tm.tm_mon, expected.tm_mon); + EXPECT_EQ(tm.tm_mday, expected.tm_mday); + EXPECT_EQ(tm.tm_hour, expected.tm_hour); + EXPECT_EQ(tm.tm_min, expected.tm_min); + EXPECT_EQ(tm.tm_sec, expected.tm_sec); + + expected.tm_hour = 4; + cbs = StringAsBytes("19700101080000+0400"); + ASSERT_TRUE( + CBS_parse_generalized_time(&cbs, &tm, /*allow_timezone_offset=*/1)); + EXPECT_EQ(tm.tm_year, expected.tm_year); + EXPECT_EQ(tm.tm_mon, expected.tm_mon); + EXPECT_EQ(tm.tm_mday, expected.tm_mday); + EXPECT_EQ(tm.tm_hour, expected.tm_hour); + EXPECT_EQ(tm.tm_min, expected.tm_min); + EXPECT_EQ(tm.tm_sec, expected.tm_sec); +} + TEST(CBSTest, GetU64Decimal) { const struct { uint64_t val;
diff --git a/crypto/bytestring/cbs.cc b/crypto/bytestring/cbs.cc index 2aef878..18a2c2e 100644 --- a/crypto/bytestring/cbs.cc +++ b/crypto/bytestring/cbs.cc
@@ -920,10 +920,10 @@ case 'Z': break; // We correctly have 'Z' on the end as per spec. case '+': - offset_sign = 1; + offset_sign = -1; break; // Should not be allowed per RFC 5280. case '-': - offset_sign = -1; + offset_sign = 1; break; // Should not be allowed per RFC 5280. default: return 0; // Reject anything else after the time.