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 2316 : uint8_t atoi2(const char *& buf)
49 : {
50 2316 : uint8_t val = static_cast<uint8_t>((buf[0] - '0') * 10 + (buf[1] - '0'));
51 2316 : buf += 2;
52 2316 : 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 22112 : void itoa2(uint32_t val, char *& buf)
60 : {
61 22112 : buf[1] = static_cast<char>('0' + (val % 10));
62 22112 : val /= 10;
63 22112 : buf[0] = static_cast<char>('0' + (val % 10));
64 22112 : buf += 2;
65 22112 : }
66 :
67 : } // anonymous namespace
68 :
69 390 : CHIP_ERROR ASN1UniversalTime::ImportFrom_ASN1_TIME_string(const CharSpan & asn1_time)
70 : {
71 390 : const char * p = asn1_time.data();
72 390 : const size_t size = asn1_time.size();
73 :
74 390 : VerifyOrReturnError(p != nullptr, ASN1_ERROR_INVALID_STATE);
75 390 : VerifyOrReturnError(size == kASN1UTCTimeStringLength || size == kASN1GeneralizedTimeStringLength,
76 : ASN1_ERROR_UNSUPPORTED_ENCODING);
77 387 : VerifyOrReturnError(p[size - 1] == 'Z', ASN1_ERROR_UNSUPPORTED_ENCODING);
78 5021 : for (size_t i = 0; i < size - 1; i++)
79 : {
80 4636 : VerifyOrReturnError(isdigit(p[i]), ASN1_ERROR_INVALID_ENCODING);
81 : }
82 :
83 385 : if (size == kASN1GeneralizedTimeStringLength)
84 : {
85 6 : Year = static_cast<uint16_t>(atoi2(p) * 100 + atoi2(p));
86 : }
87 : else
88 : {
89 379 : Year = atoi2(p);
90 379 : Year = static_cast<uint16_t>(Year + ((Year >= 50) ? 1900 : 2000));
91 : }
92 :
93 385 : Month = atoi2(p);
94 385 : Day = atoi2(p);
95 385 : Hour = atoi2(p);
96 385 : Minute = atoi2(p);
97 385 : Second = atoi2(p);
98 :
99 385 : VerifyOrReturnError(Month > 0 && Month <= kMonthsPerYear, ASN1_ERROR_INVALID_ENCODING);
100 383 : VerifyOrReturnError(Day > 0 && Day <= kMaxDaysPerMonth, ASN1_ERROR_INVALID_ENCODING);
101 381 : VerifyOrReturnError(Hour < kHoursPerDay, ASN1_ERROR_INVALID_ENCODING);
102 380 : VerifyOrReturnError(Minute < kMinutesPerHour, ASN1_ERROR_INVALID_ENCODING);
103 379 : VerifyOrReturnError(Second < kSecondsPerMinute, ASN1_ERROR_INVALID_ENCODING);
104 :
105 378 : return CHIP_NO_ERROR;
106 : }
107 :
108 3683 : CHIP_ERROR ASN1UniversalTime::ExportTo_ASN1_TIME_string(MutableCharSpan & asn1_time) const
109 : {
110 3683 : char * p = asn1_time.data();
111 :
112 3683 : 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 3683 : 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 3669 : VerifyOrReturnError(asn1_time.size() >= kASN1UTCTimeStringLength, ASN1_ERROR_UNDERRUN);
126 : }
127 :
128 3683 : itoa2(Year, p);
129 3683 : itoa2(Month, p);
130 3683 : itoa2(Day, p);
131 3683 : itoa2(Hour, p);
132 3683 : itoa2(Minute, p);
133 3683 : itoa2(Second, p);
134 3683 : *p = 'Z';
135 :
136 3683 : asn1_time.reduce_size(static_cast<size_t>(p - asn1_time.data() + 1));
137 :
138 3683 : 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
|