Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2022 Project CHIP Authors 4 : * All rights reserved. 5 : * 6 : * Licensed under the Apache License, Version 2.0 (the "License"); 7 : * you may not use this file except in compliance with the License. 8 : * You may obtain a copy of the License at 9 : * 10 : * http://www.apache.org/licenses/LICENSE-2.0 11 : * 12 : * Unless required by applicable law or agreed to in writing, software 13 : * distributed under the License is distributed on an "AS IS" BASIS, 14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 : * See the License for the specific language governing permissions and 16 : * limitations under the License. 17 : */ 18 : 19 : /** 20 : * @file 21 : * This file implements Abstract Syntax Notation One (ASN.1) Time functions. 22 : * 23 : */ 24 : 25 : #include <getopt.h> 26 : #include <inttypes.h> 27 : #include <limits.h> 28 : #include <memory> 29 : #include <stdint.h> 30 : #include <string.h> 31 : #include <unistd.h> 32 : 33 : #include <ctype.h> 34 : #include <stdio.h> 35 : 36 : #include <lib/asn1/ASN1.h> 37 : #include <lib/support/TimeUtils.h> 38 : 39 : namespace chip { 40 : namespace ASN1 { 41 : 42 : namespace { 43 : 44 : /** 45 : * @brief Parses the two first characters C-string interpreting its content as a two base-10 digits number. 46 : * The C-string pointer is advansed by two characters. 47 : */ 48 2280 : uint8_t atoi2(const char *& buf) 49 : { 50 2280 : uint8_t val = static_cast<uint8_t>((buf[0] - '0') * 10 + (buf[1] - '0')); 51 2280 : buf += 2; 52 2280 : return val; 53 : } 54 : 55 : /** 56 : * @brief Converts two low significan base-10 digits of an integer value (val % 100) to a two character C-string. 57 : * The C-string pointer is advansed by two characters. 58 : */ 59 19832 : void itoa2(uint32_t val, char *& buf) 60 : { 61 19832 : buf[1] = static_cast<char>('0' + (val % 10)); 62 19832 : val /= 10; 63 19832 : buf[0] = static_cast<char>('0' + (val % 10)); 64 19832 : buf += 2; 65 19832 : } 66 : 67 : } // anonymous namespace 68 : 69 384 : CHIP_ERROR ASN1UniversalTime::ImportFrom_ASN1_TIME_string(const CharSpan & asn1_time) 70 : { 71 384 : const char * p = asn1_time.data(); 72 384 : const size_t size = asn1_time.size(); 73 : 74 384 : VerifyOrReturnError(p != nullptr, ASN1_ERROR_INVALID_STATE); 75 384 : VerifyOrReturnError(size == kASN1UTCTimeStringLength || size == kASN1GeneralizedTimeStringLength, 76 : ASN1_ERROR_UNSUPPORTED_ENCODING); 77 381 : VerifyOrReturnError(p[size - 1] == 'Z', ASN1_ERROR_UNSUPPORTED_ENCODING); 78 4943 : for (size_t i = 0; i < size - 1; i++) 79 : { 80 4564 : VerifyOrReturnError(isdigit(p[i]), ASN1_ERROR_INVALID_ENCODING); 81 : } 82 : 83 379 : if (size == kASN1GeneralizedTimeStringLength) 84 : { 85 6 : Year = static_cast<uint16_t>(atoi2(p) * 100 + atoi2(p)); 86 : } 87 : else 88 : { 89 373 : Year = atoi2(p); 90 373 : Year = static_cast<uint16_t>(Year + ((Year >= 50) ? 1900 : 2000)); 91 : } 92 : 93 379 : Month = atoi2(p); 94 379 : Day = atoi2(p); 95 379 : Hour = atoi2(p); 96 379 : Minute = atoi2(p); 97 379 : Second = atoi2(p); 98 : 99 379 : VerifyOrReturnError(Month > 0 && Month <= kMonthsPerYear, ASN1_ERROR_INVALID_ENCODING); 100 377 : VerifyOrReturnError(Day > 0 && Day <= kMaxDaysPerMonth, ASN1_ERROR_INVALID_ENCODING); 101 375 : VerifyOrReturnError(Hour < kHoursPerDay, ASN1_ERROR_INVALID_ENCODING); 102 374 : VerifyOrReturnError(Minute < kMinutesPerHour, ASN1_ERROR_INVALID_ENCODING); 103 373 : VerifyOrReturnError(Second < kSecondsPerMinute, ASN1_ERROR_INVALID_ENCODING); 104 : 105 372 : return CHIP_NO_ERROR; 106 : } 107 : 108 3303 : CHIP_ERROR ASN1UniversalTime::ExportTo_ASN1_TIME_string(MutableCharSpan & asn1_time) const 109 : { 110 3303 : char * p = asn1_time.data(); 111 : 112 3303 : VerifyOrReturnError(p != nullptr, ASN1_ERROR_INVALID_STATE); 113 : 114 : // X.509/RFC5280 mandates that times before 2050 UTC must be encoded as ASN.1 UTCTime values, while 115 : // times equal or greater than 2050 must be encoded as GeneralizedTime values. The only difference 116 : // (in the context of X.509 DER) is that GeneralizedTimes are encoded with a 4 digit year, while 117 : // UTCTimes are encoded with a two-digit year. 118 3303 : if (Year < 1950 || Year >= 2050) 119 : { 120 14 : VerifyOrReturnError(asn1_time.size() >= kASN1GeneralizedTimeStringLength, ASN1_ERROR_UNDERRUN); 121 14 : itoa2(Year / 100, p); 122 : } 123 : else 124 : { 125 3289 : VerifyOrReturnError(asn1_time.size() >= kASN1UTCTimeStringLength, ASN1_ERROR_UNDERRUN); 126 : } 127 : 128 3303 : itoa2(Year, p); 129 3303 : itoa2(Month, p); 130 3303 : itoa2(Day, p); 131 3303 : itoa2(Hour, p); 132 3303 : itoa2(Minute, p); 133 3303 : itoa2(Second, p); 134 3303 : *p = 'Z'; 135 : 136 3303 : asn1_time.reduce_size(static_cast<size_t>(p - asn1_time.data() + 1)); 137 : 138 3303 : return CHIP_NO_ERROR; 139 : } 140 : 141 110 : bool ASN1UniversalTime::ExportTo_UnixTime(uint32_t & unixEpoch) 142 : { 143 110 : return CalendarTimeToSecondsSinceUnixEpoch(Year, Month, Day, Hour, Minute, Second, unixEpoch); 144 : } 145 : 146 : } // namespace ASN1 147 : } // namespace chip