diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/libcrypto/asn1/a_time_tm.c | 210 | ||||
| -rw-r--r-- | src/lib/libcrypto/asn1/asn1_locl.h | 4 | ||||
| -rw-r--r-- | src/lib/libcrypto/asn1/tasn_dec.c | 9 |
3 files changed, 155 insertions, 68 deletions
diff --git a/src/lib/libcrypto/asn1/a_time_tm.c b/src/lib/libcrypto/asn1/a_time_tm.c index 23e2ce4b4c..9ddae82768 100644 --- a/src/lib/libcrypto/asn1/a_time_tm.c +++ b/src/lib/libcrypto/asn1/a_time_tm.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: a_time_tm.c,v 1.21 2022/06/27 13:54:57 beck Exp $ */ | 1 | /* $OpenBSD: a_time_tm.c,v 1.22 2022/06/29 08:56:44 beck Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2015 Bob Beck <beck@openbsd.org> | 3 | * Copyright (c) 2015 Bob Beck <beck@openbsd.org> |
| 4 | * | 4 | * |
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <openssl/asn1t.h> | 24 | #include <openssl/asn1t.h> |
| 25 | #include <openssl/err.h> | 25 | #include <openssl/err.h> |
| 26 | 26 | ||
| 27 | #include "bytestring.h" | ||
| 27 | #include "o_time.h" | 28 | #include "o_time.h" |
| 28 | 29 | ||
| 29 | #define RFC5280 0 | 30 | #define RFC5280 0 |
| @@ -173,6 +174,137 @@ tm_to_rfc5280_time(struct tm *tm, ASN1_TIME *atime) | |||
| 173 | return (tm_to_gentime(tm, atime)); | 174 | return (tm_to_gentime(tm, atime)); |
| 174 | } | 175 | } |
| 175 | 176 | ||
| 177 | |||
| 178 | static int | ||
| 179 | cbs_get_two_digit_value(CBS *cbs, int *out) | ||
| 180 | { | ||
| 181 | uint8_t first_digit, second_digit; | ||
| 182 | |||
| 183 | if (!CBS_get_u8(cbs, &first_digit)) | ||
| 184 | return 0; | ||
| 185 | if (!isdigit(first_digit)) | ||
| 186 | return 0; | ||
| 187 | if (!CBS_get_u8(cbs, &second_digit)) | ||
| 188 | return 0; | ||
| 189 | if (!isdigit(second_digit)) | ||
| 190 | return 0; | ||
| 191 | |||
| 192 | *out = (first_digit - '0') * 10 + (second_digit - '0'); | ||
| 193 | |||
| 194 | return 1; | ||
| 195 | } | ||
| 196 | |||
| 197 | static int | ||
| 198 | is_valid_day(int year, int month, int day) | ||
| 199 | { | ||
| 200 | if (day < 1) | ||
| 201 | return 0; | ||
| 202 | switch (month) { | ||
| 203 | case 1: | ||
| 204 | case 3: | ||
| 205 | case 5: | ||
| 206 | case 7: | ||
| 207 | case 8: | ||
| 208 | case 10: | ||
| 209 | case 12: | ||
| 210 | return day <= 31; | ||
| 211 | case 4: | ||
| 212 | case 6: | ||
| 213 | case 9: | ||
| 214 | case 11: | ||
| 215 | return day <= 30; | ||
| 216 | case 2: | ||
| 217 | if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) | ||
| 218 | return day <= 29; | ||
| 219 | else | ||
| 220 | return day <= 28; | ||
| 221 | default: | ||
| 222 | return 0; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | /* | ||
| 227 | * asn1_time_parse_cbs returns one if |cbs| is a valid DER-encoded, ASN.1 Time | ||
| 228 | * body within the limitations imposed by RFC 5280, or zero otherwise. The time | ||
| 229 | * is expected to parse as a Generalized Time if is_gentime is true, and as a | ||
| 230 | * UTC Time otherwise. If |out_tm| is non-NULL, |*out_tm| will be zeroed, and | ||
| 231 | * then set to the corresponding time in UTC. This function does not compute | ||
| 232 | * |out_tm->tm_wday| or |out_tm->tm_yday|. |cbs| is not consumed. | ||
| 233 | */ | ||
| 234 | int | ||
| 235 | asn1_time_parse_cbs(const CBS *cbs, int is_gentime, struct tm *out_tm) | ||
| 236 | { | ||
| 237 | int year, month, day, hour, min, sec, val; | ||
| 238 | CBS copy; | ||
| 239 | uint8_t tz; | ||
| 240 | |||
| 241 | CBS_dup(cbs, ©); | ||
| 242 | |||
| 243 | if (is_gentime) { | ||
| 244 | if (!cbs_get_two_digit_value(©, &val)) | ||
| 245 | return 0; | ||
| 246 | year = val * 100; | ||
| 247 | if (!cbs_get_two_digit_value(©, &val)) | ||
| 248 | return 0; | ||
| 249 | year += val; | ||
| 250 | } else { | ||
| 251 | year = 1900; | ||
| 252 | if (!cbs_get_two_digit_value(©, &val)) | ||
| 253 | return 0; | ||
| 254 | year += val; | ||
| 255 | if (year < 1950) | ||
| 256 | year += 100; | ||
| 257 | if (year >= 2050) | ||
| 258 | return 0; /* A Generalized time must be used. */ | ||
| 259 | } | ||
| 260 | |||
| 261 | if (!cbs_get_two_digit_value(©, &month)) | ||
| 262 | return 0; | ||
| 263 | if (month < 1 || month > 12) | ||
| 264 | return 0; /* Reject invalid months. */ | ||
| 265 | |||
| 266 | if (!cbs_get_two_digit_value(©, &day)) | ||
| 267 | return 0; | ||
| 268 | if (!is_valid_day(year, month, day)) | ||
| 269 | return 0; /* Reject invalid days. */ | ||
| 270 | |||
| 271 | if (!cbs_get_two_digit_value(©, &hour)) | ||
| 272 | return 0; | ||
| 273 | if (hour > 23) | ||
| 274 | return 0; /* Reject invalid hours. */ | ||
| 275 | |||
| 276 | if (!cbs_get_two_digit_value(©, &min)) | ||
| 277 | return 0; | ||
| 278 | if (min > 59) | ||
| 279 | return 0; /* Reject invalid minutes. */ | ||
| 280 | |||
| 281 | if (!cbs_get_two_digit_value(©, &sec)) | ||
| 282 | return 0; | ||
| 283 | if (sec > 59) | ||
| 284 | return 0; /* Reject invalid seconds. Leap seconds are invalid. */ | ||
| 285 | |||
| 286 | if (!CBS_get_u8(©, &tz)) | ||
| 287 | return 0; | ||
| 288 | if ( tz != 'Z') | ||
| 289 | return 0; /* Reject anything but Z on the end. */ | ||
| 290 | |||
| 291 | if (CBS_len(©) != 0) | ||
| 292 | return 0; /* Reject invalid lengths. */ | ||
| 293 | |||
| 294 | if (out_tm != NULL) { | ||
| 295 | memset(out_tm, 0, sizeof(*out_tm)); | ||
| 296 | /* Fill in the tm fields corresponding to what we validated. */ | ||
| 297 | out_tm->tm_year = year - 1900; | ||
| 298 | out_tm->tm_mon = month - 1; | ||
| 299 | out_tm->tm_mday = day; | ||
| 300 | out_tm->tm_hour = hour; | ||
| 301 | out_tm->tm_min = min; | ||
| 302 | out_tm->tm_sec = sec; | ||
| 303 | } | ||
| 304 | |||
| 305 | return 1; | ||
| 306 | } | ||
| 307 | |||
| 176 | /* | 308 | /* |
| 177 | * Parse an RFC 5280 format ASN.1 time string. | 309 | * Parse an RFC 5280 format ASN.1 time string. |
| 178 | * | 310 | * |
| @@ -188,83 +320,29 @@ tm_to_rfc5280_time(struct tm *tm, ASN1_TIME *atime) | |||
| 188 | * | 320 | * |
| 189 | * Fills in *tm with the corresponding time if tm is non NULL. | 321 | * Fills in *tm with the corresponding time if tm is non NULL. |
| 190 | */ | 322 | */ |
| 191 | #define ATOI2(ar) ((ar) += 2, ((ar)[-2] - '0') * 10 + ((ar)[-1] - '0')) | ||
| 192 | int | 323 | int |
| 193 | ASN1_time_parse(const char *bytes, size_t len, struct tm *tm, int mode) | 324 | ASN1_time_parse(const char *bytes, size_t len, struct tm *tm, int mode) |
| 194 | { | 325 | { |
| 195 | size_t i; | 326 | struct tm tml, *tmp = tm ? tm : &tml; |
| 196 | int type = 0; | 327 | int type = 0; |
| 197 | struct tm ltm; | 328 | CBS cbs; |
| 198 | struct tm *lt; | ||
| 199 | const char *p; | ||
| 200 | 329 | ||
| 201 | if (bytes == NULL) | 330 | if (bytes == NULL) |
| 202 | return (-1); | 331 | return (-1); |
| 203 | 332 | ||
| 204 | /* Constrain to valid lengths. */ | 333 | CBS_init(&cbs, bytes, len); |
| 205 | if (len != UTCTIME_LENGTH && len != GENTIME_LENGTH) | ||
| 206 | return (-1); | ||
| 207 | |||
| 208 | lt = tm; | ||
| 209 | if (lt == NULL) | ||
| 210 | lt = <m; | ||
| 211 | memset(lt, 0, sizeof(*lt)); | ||
| 212 | 334 | ||
| 213 | /* Timezone is required and must be GMT (Zulu). */ | 335 | if (CBS_len(&cbs) == UTCTIME_LENGTH) |
| 214 | if (bytes[len - 1] != 'Z') | 336 | type = V_ASN1_UTCTIME; |
| 215 | return (-1); | 337 | if (CBS_len(&cbs) == GENTIME_LENGTH) |
| 216 | |||
| 217 | /* Make sure everything else is digits. */ | ||
| 218 | for (i = 0; i < len - 1; i++) { | ||
| 219 | if (isdigit((unsigned char)bytes[i])) | ||
| 220 | continue; | ||
| 221 | return (-1); | ||
| 222 | } | ||
| 223 | |||
| 224 | /* | ||
| 225 | * Validate and convert the time | ||
| 226 | */ | ||
| 227 | p = bytes; | ||
| 228 | switch (len) { | ||
| 229 | case GENTIME_LENGTH: | ||
| 230 | if (mode == V_ASN1_UTCTIME) | ||
| 231 | return (-1); | ||
| 232 | lt->tm_year = (ATOI2(p) * 100) - 1900; /* cc */ | ||
| 233 | type = V_ASN1_GENERALIZEDTIME; | 338 | type = V_ASN1_GENERALIZEDTIME; |
| 234 | /* FALLTHROUGH */ | 339 | if (asn1_time_parse_cbs(&cbs, type == V_ASN1_GENERALIZEDTIME, tmp)) { |
| 235 | case UTCTIME_LENGTH: | 340 | if (mode != 0 && mode != type) |
| 236 | if (type == 0) { | 341 | return -1; |
| 237 | if (mode == V_ASN1_GENERALIZEDTIME) | 342 | return type; |
| 238 | return (-1); | ||
| 239 | type = V_ASN1_UTCTIME; | ||
| 240 | } | ||
| 241 | lt->tm_year += ATOI2(p); /* yy */ | ||
| 242 | if (type == V_ASN1_UTCTIME) { | ||
| 243 | if (lt->tm_year < 50) | ||
| 244 | lt->tm_year += 100; | ||
| 245 | } | ||
| 246 | lt->tm_mon = ATOI2(p) - 1; /* mm */ | ||
| 247 | if (lt->tm_mon < 0 || lt->tm_mon > 11) | ||
| 248 | return (-1); | ||
| 249 | lt->tm_mday = ATOI2(p); /* dd */ | ||
| 250 | if (lt->tm_mday < 1 || lt->tm_mday > 31) | ||
| 251 | return (-1); | ||
| 252 | lt->tm_hour = ATOI2(p); /* HH */ | ||
| 253 | if (lt->tm_hour < 0 || lt->tm_hour > 23) | ||
| 254 | return (-1); | ||
| 255 | lt->tm_min = ATOI2(p); /* MM */ | ||
| 256 | if (lt->tm_min < 0 || lt->tm_min > 59) | ||
| 257 | return (-1); | ||
| 258 | lt->tm_sec = ATOI2(p); /* SS */ | ||
| 259 | /* Leap second 60 is not accepted. Reconsider later? */ | ||
| 260 | if (lt->tm_sec < 0 || lt->tm_sec > 59) | ||
| 261 | return (-1); | ||
| 262 | break; | ||
| 263 | default: | ||
| 264 | return (-1); | ||
| 265 | } | 343 | } |
| 266 | 344 | ||
| 267 | return (type); | 345 | return -1; |
| 268 | } | 346 | } |
| 269 | 347 | ||
| 270 | /* | 348 | /* |
diff --git a/src/lib/libcrypto/asn1/asn1_locl.h b/src/lib/libcrypto/asn1/asn1_locl.h index a0a1842d99..ec853250f2 100644 --- a/src/lib/libcrypto/asn1/asn1_locl.h +++ b/src/lib/libcrypto/asn1/asn1_locl.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: asn1_locl.h,v 1.34 2022/06/27 12:36:05 tb Exp $ */ | 1 | /* $OpenBSD: asn1_locl.h,v 1.35 2022/06/29 08:56:44 beck Exp $ */ |
| 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
| 3 | * project 2006. | 3 | * project 2006. |
| 4 | */ | 4 | */ |
| @@ -219,4 +219,6 @@ int i2t_ASN1_OBJECT_internal(const ASN1_OBJECT *aobj, char *buf, int buf_len, | |||
| 219 | int no_name); | 219 | int no_name); |
| 220 | ASN1_OBJECT *t2i_ASN1_OBJECT_internal(const char *oid); | 220 | ASN1_OBJECT *t2i_ASN1_OBJECT_internal(const char *oid); |
| 221 | 221 | ||
| 222 | int asn1_time_parse_cbs(const CBS *cbs, int is_gentime, struct tm *out_tm); | ||
| 223 | |||
| 222 | __END_HIDDEN_DECLS | 224 | __END_HIDDEN_DECLS |
diff --git a/src/lib/libcrypto/asn1/tasn_dec.c b/src/lib/libcrypto/asn1/tasn_dec.c index 375425a9f2..235685484c 100644 --- a/src/lib/libcrypto/asn1/tasn_dec.c +++ b/src/lib/libcrypto/asn1/tasn_dec.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: tasn_dec.c,v 1.77 2022/06/25 17:43:56 jsing Exp $ */ | 1 | /* $OpenBSD: tasn_dec.c,v 1.78 2022/06/29 08:56:44 beck Exp $ */ |
| 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
| 3 | * project 2000. | 3 | * project 2000. |
| 4 | */ | 4 | */ |
| @@ -353,6 +353,13 @@ asn1_c2i_primitive(ASN1_VALUE **pval, CBS *content, int utype, const ASN1_ITEM * | |||
| 353 | ASN1error(ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH); | 353 | ASN1error(ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH); |
| 354 | goto err; | 354 | goto err; |
| 355 | } | 355 | } |
| 356 | if (utype == V_ASN1_UTCTIME || utype == V_ASN1_GENERALIZEDTIME) { | ||
| 357 | if (!asn1_time_parse_cbs(content, | ||
| 358 | utype == V_ASN1_GENERALIZEDTIME, NULL)) { | ||
| 359 | ASN1error(ASN1_R_INVALID_TIME_FORMAT); | ||
| 360 | goto err; | ||
| 361 | } | ||
| 362 | } | ||
| 356 | /* All based on ASN1_STRING and handled the same way. */ | 363 | /* All based on ASN1_STRING and handled the same way. */ |
| 357 | if (*pval == NULL) { | 364 | if (*pval == NULL) { |
| 358 | if ((stmp = ASN1_STRING_type_new(utype)) == NULL) { | 365 | if ((stmp = ASN1_STRING_type_new(utype)) == NULL) { |
