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 21920 : void itoa2(uint32_t val, char *& buf)
60 : {
61 21920 : buf[1] = static_cast<char>('0' + (val % 10));
62 21920 : val /= 10;
63 21920 : buf[0] = static_cast<char>('0' + (val % 10));
64 21920 : buf += 2;
65 21920 : }
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 3651 : CHIP_ERROR ASN1UniversalTime::ExportTo_ASN1_TIME_string(MutableCharSpan & asn1_time) const
109 : {
110 3651 : char * p = asn1_time.data();
111 :
112 3651 : 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 3651 : 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 3637 : VerifyOrReturnError(asn1_time.size() >= kASN1UTCTimeStringLength, ASN1_ERROR_UNDERRUN);
126 : }
127 :
128 3651 : itoa2(Year, p);
129 3651 : itoa2(Month, p);
130 3651 : itoa2(Day, p);
131 3651 : itoa2(Hour, p);
132 3651 : itoa2(Minute, p);
133 3651 : itoa2(Second, p);
134 3651 : *p = 'Z';
135 :
136 3651 : asn1_time.reduce_size(static_cast<size_t>(p - asn1_time.data() + 1));
137 :
138 3651 : 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
|