Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upstream merge 2024 08 23 #1799

Merged
merged 14 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 87 additions & 2 deletions crypto/asn1/asn1_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1194,8 +1194,8 @@ TEST(ASN1Test, AdjTime) {
struct tm tm1, tm2;
int days, secs;

OPENSSL_posix_to_tm(0, &tm1);
OPENSSL_posix_to_tm(0, &tm2);
EXPECT_TRUE(OPENSSL_posix_to_tm(0, &tm1));
EXPECT_TRUE(OPENSSL_posix_to_tm(0, &tm2));
// Test values that are too large and should be rejected.
EXPECT_FALSE(OPENSSL_gmtime_adj(&tm1, INT_MIN, INT_MIN));
EXPECT_FALSE(OPENSSL_gmtime_adj(&tm1, INT_MAX, INT_MAX));
Expand Down Expand Up @@ -2480,6 +2480,91 @@ TEST(ASN1Test, ASN1Dup) {
0);
}

static std::tuple<int, int, int, int, int, int> TimeToTuple(const tm &t) {
return std::make_tuple(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min,
t.tm_sec);
}

TEST(ASN1Test, TimeOverflow) {
// Input time is out of range and may overflow internal calculations to shift
// |tm_year| and |tm_mon| to a more normal value.
tm overflow_year;
OPENSSL_memset(&overflow_year, 0, sizeof(overflow_year));
overflow_year.tm_year = INT_MAX - 1899;
overflow_year.tm_mday = 1;
tm overflow_month;
OPENSSL_memset(&overflow_month, 0, sizeof(overflow_month));
overflow_month.tm_mon = INT_MAX;
overflow_month.tm_mday = 1;
int64_t posix_u64;
EXPECT_FALSE(OPENSSL_tm_to_posix(&overflow_year, &posix_u64));
EXPECT_FALSE(OPENSSL_tm_to_posix(&overflow_month, &posix_u64));
time_t posix;
EXPECT_FALSE(OPENSSL_timegm(&overflow_year, &posix));
EXPECT_FALSE(OPENSSL_timegm(&overflow_month, &posix));
EXPECT_FALSE(
OPENSSL_gmtime_adj(&overflow_year, /*offset_day=*/0, /*offset_sec=*/0));
EXPECT_FALSE(
OPENSSL_gmtime_adj(&overflow_month, /*offset_day=*/0, /*offset_sec=*/0));
int days, secs;
EXPECT_FALSE(
OPENSSL_gmtime_diff(&days, &secs, &overflow_year, &overflow_year));
EXPECT_FALSE(
OPENSSL_gmtime_diff(&days, &secs, &overflow_month, &overflow_month));

// Input time is in range, but even adding one second puts it out of range.
tm max_time;
OPENSSL_memset(&max_time, 0, sizeof(max_time));
max_time.tm_year = 9999 - 1900;
max_time.tm_mon = 12 - 1;
max_time.tm_mday = 31;
max_time.tm_hour = 23;
max_time.tm_min = 59;
max_time.tm_sec = 59;
tm copy = max_time;
EXPECT_TRUE(OPENSSL_gmtime_adj(&copy, /*offset_day=*/0, /*offset_sec=*/0));
EXPECT_EQ(TimeToTuple(copy), TimeToTuple(max_time));
EXPECT_FALSE(OPENSSL_gmtime_adj(&copy, /*offset_day=*/0, /*offset_sec=*/1));

// Likewise for the earliest representable time.
tm min_time;
OPENSSL_memset(&min_time, 0, sizeof(min_time));
min_time.tm_year = 0 - 1900;
min_time.tm_mon = 1 - 1;
min_time.tm_mday = 1;
min_time.tm_hour = 0;
min_time.tm_min = 0;
min_time.tm_sec = 0;
copy = min_time;
EXPECT_TRUE(OPENSSL_gmtime_adj(&copy, /*offset_day=*/0, /*offset_sec=*/0));
EXPECT_EQ(TimeToTuple(copy), TimeToTuple(min_time));
EXPECT_FALSE(OPENSSL_gmtime_adj(&copy, /*offset_day=*/0, /*offset_sec=*/-1));

// Test we can offset between the minimum and maximum times.
const int64_t kValidTimeRange = 315569519999;
copy = min_time;
EXPECT_TRUE(OPENSSL_gmtime_adj(&copy, /*offset_day=*/0, kValidTimeRange));
EXPECT_EQ(TimeToTuple(copy), TimeToTuple(max_time));
EXPECT_TRUE(OPENSSL_gmtime_adj(&copy, /*offset_day=*/0, -kValidTimeRange));
EXPECT_EQ(TimeToTuple(copy), TimeToTuple(min_time));

// The second offset may even exceed kValidTimeRange if it is canceled out by
// offset_day.
EXPECT_TRUE(OPENSSL_gmtime_adj(&copy, /*offset_day=*/-1,
kValidTimeRange + 24 * 3600));
EXPECT_EQ(TimeToTuple(copy), TimeToTuple(max_time));
EXPECT_TRUE(OPENSSL_gmtime_adj(&copy, /*offset_day=*/1,
-kValidTimeRange - 24 * 3600));
EXPECT_EQ(TimeToTuple(copy), TimeToTuple(min_time));

// Make sure the internal calculations for |OPENSSL_gmtime_adj| stay in
// bounds.
copy = max_time;
EXPECT_FALSE(OPENSSL_gmtime_adj(&copy, INT_MAX, LONG_MAX));
copy = min_time;
EXPECT_FALSE(OPENSSL_gmtime_adj(&copy, INT_MIN, LONG_MIN));
}

// The ASN.1 macros do not work on Windows shared library builds, where usage of
// |OPENSSL_EXPORT| is a bit stricter.
#if !defined(OPENSSL_WINDOWS) || !defined(BORINGSSL_SHARED_LIBRARY)
Expand Down
21 changes: 4 additions & 17 deletions crypto/asn1/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@

#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/posix_time.h>

#include "../internal.h"

#if defined(__cplusplus)
extern "C" {
Expand All @@ -71,33 +74,17 @@ extern "C" {

// Wrapper functions for time functions.

// OPENSSL_posix_to_tm converts a int64_t POSIX time value in |time| which must
// be in the range of year 0000 to 9999 to a broken out time value in |tm|. It
// returns one on success and zero on error.
OPENSSL_EXPORT int OPENSSL_posix_to_tm(int64_t time, struct tm *out_tm);

// OPENSSL_tm_to_posix converts a time value between the years 0 and 9999 in
// |tm| to a POSIX time value in |out|. One is returned on success, zero is
// returned on failure. It is a failure if the tm contains out of range values.
OPENSSL_EXPORT int OPENSSL_tm_to_posix(const struct tm *tm, int64_t *out);

// OPENSSL_gmtime converts a time_t value in |time| which must be in the range
// of year 0000 to 9999 to a broken out time value in |tm|. On success |tm| is
// returned. On failure NULL is returned.
OPENSSL_EXPORT struct tm *OPENSSL_gmtime(const time_t *time, struct tm *result);

// OPENSSL_timegm converts a time value between the years 0 and 9999 in |tm| to
// a time_t value in |out|. One is returned on success, zero is returned on
// failure. It is a failure if the converted time can not be represented in a
// time_t, or if the tm contains out of range values.
OPENSSL_EXPORT int OPENSSL_timegm(const struct tm *tm, time_t *out);

// OPENSSL_gmtime_adj returns one on success, and updates |tm| by adding
// |offset_day| days and |offset_sec| seconds. It returns zero on failure. |tm|
// must be in the range of year 0000 to 9999 both before and after the update or
// a failure will be returned.
OPENSSL_EXPORT int OPENSSL_gmtime_adj(struct tm *tm, int offset_day,
long offset_sec);
int64_t offset_sec);

// OPENSSL_gmtime_diff calculates the difference between |from| and |to|. It
// returns one, and outputs the difference as a number of days and seconds in
Expand Down
91 changes: 51 additions & 40 deletions crypto/asn1/posix_time.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,15 @@
#include <string.h>
#include <time.h>

#include "../internal.h"
#include "internal.h"

#define SECS_PER_HOUR (60 * 60)
#define SECS_PER_DAY (24 * SECS_PER_HOUR)
#define SECS_PER_DAY (INT64_C(24) * SECS_PER_HOUR)


// Is a year/month/day combination valid, in the range from year 0000
// to 9999?
static int is_valid_date(int year, int month, int day) {
static int is_valid_date(int64_t year, int64_t month, int64_t day) {
if (day < 1 || month < 1 || year < 0 || year > 9999) {
return 0;
}
Expand Down Expand Up @@ -61,25 +60,30 @@ static int is_valid_date(int year, int month, int day) {

// Is a time valid? Leap seconds of 60 are not considered valid, as
// the POSIX time in seconds does not include them.
static int is_valid_time(int hours, int minutes, int seconds) {
static int is_valid_time(int64_t hours, int64_t minutes, int64_t seconds) {
if (hours < 0 || minutes < 0 || seconds < 0 || hours > 23 || minutes > 59 ||
seconds > 59) {
return 0;
}
return 1;
}

// Is a int64 time representing a time within our expected range?
static int is_valid_epoch_time(int64_t time) {
// 0000-01-01 00:00:00 UTC to 9999-12-31 23:59:59 UTC
return (int64_t)-62167219200 <= time && time <= (int64_t)253402300799;
// 0000-01-01 00:00:00 UTC
#define MIN_POSIX_TIME INT64_C(-62167219200)
// 9999-12-31 23:59:59 UTC
#define MAX_POSIX_TIME INT64_C(253402300799)

// Is an int64 time within our expected range?
static int is_valid_posix_time(int64_t time) {
return MIN_POSIX_TIME <= time && time <= MAX_POSIX_TIME;
}

// Inspired by algorithms presented in
// https://howardhinnant.github.io/date_algorithms.html
// (Public Domain)
static int posix_time_from_utc(int year, int month, int day, int hours,
int minutes, int seconds, int64_t *out_time) {
static int posix_time_from_utc(int64_t year, int64_t month, int64_t day,
int64_t hours, int64_t minutes, int64_t seconds,
int64_t *out_time) {
if (!is_valid_date(year, month, day) ||
!is_valid_time(hours, minutes, seconds)) {
return 0;
Expand Down Expand Up @@ -107,7 +111,7 @@ static int posix_time_from_utc(int year, int month, int day, int hours,
static int utc_from_posix_time(int64_t time, int *out_year, int *out_month,
int *out_day, int *out_hours, int *out_minutes,
int *out_seconds) {
if (!is_valid_epoch_time(time)) {
if (!is_valid_posix_time(time)) {
return 0;
}
int64_t days = time / SECS_PER_DAY;
Expand Down Expand Up @@ -142,23 +146,26 @@ static int utc_from_posix_time(int64_t time, int *out_year, int *out_month,
}

int OPENSSL_tm_to_posix(const struct tm *tm, int64_t *out) {
return posix_time_from_utc(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec, out);
return posix_time_from_utc(tm->tm_year + INT64_C(1900),
tm->tm_mon + INT64_C(1), tm->tm_mday, tm->tm_hour,
tm->tm_min, tm->tm_sec, out);
}

int OPENSSL_posix_to_tm(int64_t time, struct tm *out_tm) {
if (out_tm == NULL) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
OPENSSL_memset(out_tm, 0, sizeof(struct tm));
if (!utc_from_posix_time(time, &out_tm->tm_year, &out_tm->tm_mon,
&out_tm->tm_mday, &out_tm->tm_hour, &out_tm->tm_min,
&out_tm->tm_sec)) {
struct tm tmp_tm;
OPENSSL_memset(&tmp_tm, 0, sizeof(tmp_tm));
if (!utc_from_posix_time(time, &tmp_tm.tm_year, &tmp_tm.tm_mon,
&tmp_tm.tm_mday, &tmp_tm.tm_hour, &tmp_tm.tm_min,
&tmp_tm.tm_sec)) {
return 0;
}
out_tm->tm_year -= 1900;
out_tm->tm_mon -= 1;
tmp_tm.tm_year -= 1900;
tmp_tm.tm_mon -= 1;
*out_tm = tmp_tm;

return 1;
}
Expand Down Expand Up @@ -190,43 +197,47 @@ struct tm *OPENSSL_gmtime(const time_t *time, struct tm *out_tm) {
return out_tm;
}

int OPENSSL_gmtime_adj(struct tm *tm, int off_day, long offset_sec) {
int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, int64_t offset_sec) {
int64_t posix_time;
if (!posix_time_from_utc(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec, &posix_time)) {
if (!OPENSSL_tm_to_posix(tm, &posix_time)) {
return 0;
}
OPENSSL_STATIC_ASSERT(INT_MAX <= INT64_MAX / SECS_PER_DAY,
day_offset_in_seconds_cannot_overflow)
OPENSSL_STATIC_ASSERT(MAX_POSIX_TIME <= INT64_MAX - INT_MAX * SECS_PER_DAY,
addition_cannot_overflow)
OPENSSL_STATIC_ASSERT(MIN_POSIX_TIME >= INT64_MIN - INT_MIN * SECS_PER_DAY,
addition_cannot_underflow)
posix_time += offset_day * SECS_PER_DAY;
if (posix_time > 0 && offset_sec > INT64_MAX - posix_time) {
return 0;
}
if (!utc_from_posix_time(
posix_time + (int64_t)off_day * SECS_PER_DAY + offset_sec,
&tm->tm_year, &tm->tm_mon, &tm->tm_mday, &tm->tm_hour, &tm->tm_min,
&tm->tm_sec)) {
if (posix_time < 0 && offset_sec < INT64_MIN - posix_time) {
return 0;
}
posix_time += offset_sec;

if (!OPENSSL_posix_to_tm(posix_time, tm)) {
return 0;
}
tm->tm_year -= 1900;
tm->tm_mon -= 1;

return 1;
}

int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from,
const struct tm *to) {
int64_t time_to;
if (!posix_time_from_utc(to->tm_year + 1900, to->tm_mon + 1, to->tm_mday,
to->tm_hour, to->tm_min, to->tm_sec, &time_to)) {
return 0;
}
int64_t time_from;
if (!posix_time_from_utc(from->tm_year + 1900, from->tm_mon + 1,
from->tm_mday, from->tm_hour, from->tm_min,
from->tm_sec, &time_from)) {
int64_t time_to, time_from;
if (!OPENSSL_tm_to_posix(to, &time_to) ||
!OPENSSL_tm_to_posix(from, &time_from)) {
return 0;
}
// Times are in range, so these calculations can not overflow.
OPENSSL_STATIC_ASSERT(SECS_PER_DAY <= INT_MAX, seconds_per_day_does_not_fit_in_int)
OPENSSL_STATIC_ASSERT((MAX_POSIX_TIME - MIN_POSIX_TIME) / SECS_PER_DAY <= INT_MAX,
range_of_valid_POSIX_times_in_days_does_not_fit_in_int)
int64_t timediff = time_to - time_from;
int64_t daydiff = timediff / SECS_PER_DAY;
timediff %= SECS_PER_DAY;
if (daydiff > INT_MAX || daydiff < INT_MIN) {
return 0;
}
*out_secs = (int)timediff;
*out_days = (int)daydiff;
return 1;
Expand Down
4 changes: 2 additions & 2 deletions crypto/bio/bio.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,11 +504,11 @@ int BIO_set_close(BIO *bio, int close_flag) {
return (int)BIO_ctrl(bio, BIO_CTRL_SET_CLOSE, close_flag, NULL);
}

OPENSSL_EXPORT size_t BIO_number_read(const BIO *bio) {
OPENSSL_EXPORT uint64_t BIO_number_read(const BIO *bio) {
return bio->num_read;
}

OPENSSL_EXPORT size_t BIO_number_written(const BIO *bio) {
OPENSSL_EXPORT uint64_t BIO_number_written(const BIO *bio) {
return bio->num_write;
}

Expand Down
Loading
Loading