Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1 | // Copyright 2015 The Chromium Authors |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "parse_values.h" |
| 6 | |
Bob Beck | 3aecf1d | 2023-09-08 11:56:02 -0600 | [diff] [blame] | 7 | #include <stdlib.h> |
| 8 | |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 9 | #include <tuple> |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 10 | |
Bob Beck | 0500756 | 2023-08-17 20:22:17 +0000 | [diff] [blame] | 11 | #include <openssl/base.h> |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 12 | #include <openssl/bytestring.h> |
Bob Beck | 3aecf1d | 2023-09-08 11:56:02 -0600 | [diff] [blame] | 13 | #include <openssl/mem.h> |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 14 | |
| 15 | namespace bssl::der { |
| 16 | |
| 17 | namespace { |
| 18 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 19 | bool ParseBoolInternal(const Input &in, bool *out, bool relaxed) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 20 | // According to ITU-T X.690 section 8.2, a bool is encoded as a single octet |
| 21 | // where the octet of all zeroes is FALSE and a non-zero value for the octet |
| 22 | // is TRUE. |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 23 | if (in.Length() != 1) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 24 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 25 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 26 | ByteReader data(in); |
| 27 | uint8_t byte; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 28 | if (!data.ReadByte(&byte)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 29 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 30 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 31 | if (byte == 0) { |
| 32 | *out = false; |
| 33 | return true; |
| 34 | } |
| 35 | // ITU-T X.690 section 11.1 specifies that for DER, the TRUE value must be |
| 36 | // encoded as an octet of all ones. |
| 37 | if (byte == 0xff || relaxed) { |
| 38 | *out = true; |
| 39 | return true; |
| 40 | } |
| 41 | return false; |
| 42 | } |
| 43 | |
| 44 | // Reads a positive decimal number with |digits| digits and stores it in |
| 45 | // |*out|. This function does not check that the type of |*out| is large |
| 46 | // enough to hold 10^digits - 1; the caller must choose an appropriate type |
| 47 | // based on the number of digits they wish to parse. |
| 48 | template <typename UINT> |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 49 | bool DecimalStringToUint(ByteReader &in, size_t digits, UINT *out) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 50 | UINT value = 0; |
| 51 | for (size_t i = 0; i < digits; ++i) { |
| 52 | uint8_t digit; |
| 53 | if (!in.ReadByte(&digit)) { |
| 54 | return false; |
| 55 | } |
| 56 | if (digit < '0' || digit > '9') { |
| 57 | return false; |
| 58 | } |
| 59 | value = (value * 10) + (digit - '0'); |
| 60 | } |
| 61 | *out = value; |
| 62 | return true; |
| 63 | } |
| 64 | |
| 65 | // Checks that the values in a GeneralizedTime struct are valid. This involves |
| 66 | // checking that the year is 4 digits, the month is between 1 and 12, the day |
| 67 | // is a day that exists in that month (following current leap year rules), |
| 68 | // hours are between 0 and 23, minutes between 0 and 59, and seconds between |
| 69 | // 0 and 60 (to allow for leap seconds; no validation is done that a leap |
| 70 | // second is on a day that could be a leap second). |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 71 | bool ValidateGeneralizedTime(const GeneralizedTime &time) { |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 72 | if (time.month < 1 || time.month > 12) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 73 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 74 | } |
| 75 | if (time.day < 1) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 76 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 77 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 78 | if (time.hours > 23) { |
| 79 | return false; |
| 80 | } |
| 81 | if (time.minutes > 59) { |
| 82 | return false; |
| 83 | } |
| 84 | // Leap seconds are allowed. |
| 85 | if (time.seconds > 60) { |
| 86 | return false; |
| 87 | } |
| 88 | |
| 89 | // validate upper bound for day of month |
| 90 | switch (time.month) { |
| 91 | case 4: |
| 92 | case 6: |
| 93 | case 9: |
| 94 | case 11: |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 95 | if (time.day > 30) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 96 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 97 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 98 | break; |
| 99 | case 1: |
| 100 | case 3: |
| 101 | case 5: |
| 102 | case 7: |
| 103 | case 8: |
| 104 | case 10: |
| 105 | case 12: |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 106 | if (time.day > 31) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 107 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 108 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 109 | break; |
| 110 | case 2: |
| 111 | if (time.year % 4 == 0 && |
| 112 | (time.year % 100 != 0 || time.year % 400 == 0)) { |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 113 | if (time.day > 29) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 114 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 115 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 116 | } else { |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 117 | if (time.day > 28) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 118 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 119 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 120 | } |
| 121 | break; |
| 122 | default: |
Bob Beck | 3aecf1d | 2023-09-08 11:56:02 -0600 | [diff] [blame] | 123 | abort(); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 124 | } |
| 125 | return true; |
| 126 | } |
| 127 | |
| 128 | // Returns the number of bytes of numeric precision in a DER encoded INTEGER |
| 129 | // value. |in| must be a valid DER encoding of an INTEGER for this to work. |
| 130 | // |
| 131 | // Normally the precision of the number is exactly in.Length(). However when |
| 132 | // encoding positive numbers using DER it is possible to have a leading zero |
| 133 | // (to prevent number from being interpreted as negative). |
| 134 | // |
| 135 | // For instance a 160-bit positive number might take 21 bytes to encode. This |
| 136 | // function will return 20 in such a case. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 137 | size_t GetUnsignedIntegerLength(const Input &in) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 138 | der::ByteReader reader(in); |
| 139 | uint8_t first_byte; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 140 | if (!reader.ReadByte(&first_byte)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 141 | return 0; // Not valid DER as |in| was empty. |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 142 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 143 | |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 144 | if (first_byte == 0 && in.Length() > 1) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 145 | return in.Length() - 1; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 146 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 147 | return in.Length(); |
| 148 | } |
| 149 | |
| 150 | } // namespace |
| 151 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 152 | bool ParseBool(const Input &in, bool *out) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 153 | return ParseBoolInternal(in, out, false /* relaxed */); |
| 154 | } |
| 155 | |
| 156 | // BER interprets any non-zero value as true, while DER requires a bool to |
| 157 | // have either all bits zero (false) or all bits one (true). To support |
| 158 | // malformed certs, we recognized the BER encoding instead of failing to |
| 159 | // parse. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 160 | bool ParseBoolRelaxed(const Input &in, bool *out) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 161 | return ParseBoolInternal(in, out, true /* relaxed */); |
| 162 | } |
| 163 | |
| 164 | // ITU-T X.690 section 8.3.2 specifies that an integer value must be encoded |
| 165 | // in the smallest number of octets. If the encoding consists of more than |
| 166 | // one octet, then the bits of the first octet and the most significant bit |
| 167 | // of the second octet must not be all zeroes or all ones. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 168 | bool IsValidInteger(const Input &in, bool *negative) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 169 | CBS cbs; |
| 170 | CBS_init(&cbs, in.UnsafeData(), in.Length()); |
| 171 | int negative_int; |
| 172 | if (!CBS_is_valid_asn1_integer(&cbs, &negative_int)) { |
| 173 | return false; |
| 174 | } |
| 175 | |
| 176 | *negative = !!negative_int; |
| 177 | return true; |
| 178 | } |
| 179 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 180 | bool ParseUint64(const Input &in, uint64_t *out) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 181 | // Reject non-minimally encoded numbers and negative numbers. |
| 182 | bool negative; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 183 | if (!IsValidInteger(in, &negative) || negative) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 184 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 185 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 186 | |
| 187 | // Reject (non-negative) integers whose value would overflow the output type. |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 188 | if (GetUnsignedIntegerLength(in) > sizeof(*out)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 189 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 190 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 191 | |
| 192 | ByteReader reader(in); |
| 193 | uint8_t data; |
| 194 | uint64_t value = 0; |
| 195 | |
| 196 | while (reader.ReadByte(&data)) { |
| 197 | value <<= 8; |
| 198 | value |= data; |
| 199 | } |
| 200 | *out = value; |
| 201 | return true; |
| 202 | } |
| 203 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 204 | bool ParseUint8(const Input &in, uint8_t *out) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 205 | // TODO(eroman): Implement this more directly. |
| 206 | uint64_t value; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 207 | if (!ParseUint64(in, &value)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 208 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 209 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 210 | |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 211 | if (value > 0xFF) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 212 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 213 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 214 | |
| 215 | *out = static_cast<uint8_t>(value); |
| 216 | return true; |
| 217 | } |
| 218 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 219 | BitString::BitString(const Input &bytes, uint8_t unused_bits) |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 220 | : bytes_(bytes), unused_bits_(unused_bits) { |
Bob Beck | 0500756 | 2023-08-17 20:22:17 +0000 | [diff] [blame] | 221 | BSSL_CHECK(unused_bits < 8); |
| 222 | BSSL_CHECK(unused_bits == 0 || bytes.Length() != 0); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 223 | // The unused bits must be zero. |
Bob Beck | 0500756 | 2023-08-17 20:22:17 +0000 | [diff] [blame] | 224 | BSSL_CHECK(bytes.Length() == 0 || |
| 225 | (bytes[bytes.Length() - 1] & ((1u << unused_bits) - 1)) == 0); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 226 | } |
| 227 | |
| 228 | bool BitString::AssertsBit(size_t bit_index) const { |
| 229 | // Index of the byte that contains the bit. |
| 230 | size_t byte_index = bit_index / 8; |
| 231 | |
| 232 | // If the bit is outside of the bitstring, by definition it is not |
| 233 | // asserted. |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 234 | if (byte_index >= bytes_.Length()) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 235 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 236 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 237 | |
| 238 | // Within a byte, bits are ordered from most significant to least significant. |
| 239 | // Convert |bit_index| to an index within the |byte_index| byte, measured from |
| 240 | // its least significant bit. |
| 241 | uint8_t bit_index_in_byte = 7 - (bit_index - byte_index * 8); |
| 242 | |
| 243 | // BIT STRING parsing already guarantees that unused bits in a byte are zero |
| 244 | // (otherwise it wouldn't be valid DER). Therefore it isn't necessary to check |
| 245 | // |unused_bits_| |
Bob Beck | 0500756 | 2023-08-17 20:22:17 +0000 | [diff] [blame] | 246 | uint8_t byte = bytes_[byte_index]; |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 247 | return 0 != (byte & (1 << bit_index_in_byte)); |
| 248 | } |
| 249 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 250 | std::optional<BitString> ParseBitString(const Input &in) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 251 | ByteReader reader(in); |
| 252 | |
| 253 | // From ITU-T X.690, section 8.6.2.2 (applies to BER, CER, DER): |
| 254 | // |
| 255 | // The initial octet shall encode, as an unsigned binary integer with |
| 256 | // bit 1 as the least significant bit, the number of unused bits in the final |
| 257 | // subsequent octet. The number shall be in the range zero to seven. |
| 258 | uint8_t unused_bits; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 259 | if (!reader.ReadByte(&unused_bits)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 260 | return std::nullopt; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 261 | } |
| 262 | if (unused_bits > 7) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 263 | return std::nullopt; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 264 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 265 | |
| 266 | Input bytes; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 267 | if (!reader.ReadBytes(reader.BytesLeft(), &bytes)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 268 | return std::nullopt; // Not reachable. |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 269 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 270 | |
| 271 | // Ensure that unused bits in the last byte are set to 0. |
| 272 | if (unused_bits > 0) { |
| 273 | // From ITU-T X.690, section 8.6.2.3 (applies to BER, CER, DER): |
| 274 | // |
| 275 | // If the bitstring is empty, there shall be no subsequent octets, |
| 276 | // and the initial octet shall be zero. |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 277 | if (bytes.Length() == 0) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 278 | return std::nullopt; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 279 | } |
Bob Beck | 0500756 | 2023-08-17 20:22:17 +0000 | [diff] [blame] | 280 | uint8_t last_byte = bytes[bytes.Length() - 1]; |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 281 | |
| 282 | // From ITU-T X.690, section 11.2.1 (applies to CER and DER, but not BER): |
| 283 | // |
| 284 | // Each unused bit in the final octet of the encoding of a bit string value |
| 285 | // shall be set to zero. |
| 286 | uint8_t mask = 0xFF >> (8 - unused_bits); |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 287 | if ((mask & last_byte) != 0) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 288 | return std::nullopt; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 289 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 290 | } |
| 291 | |
| 292 | return BitString(bytes, unused_bits); |
| 293 | } |
| 294 | |
| 295 | bool GeneralizedTime::InUTCTimeRange() const { |
| 296 | return 1950 <= year && year < 2050; |
| 297 | } |
| 298 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 299 | bool operator<(const GeneralizedTime &lhs, const GeneralizedTime &rhs) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 300 | return std::tie(lhs.year, lhs.month, lhs.day, lhs.hours, lhs.minutes, |
| 301 | lhs.seconds) < std::tie(rhs.year, rhs.month, rhs.day, |
| 302 | rhs.hours, rhs.minutes, rhs.seconds); |
| 303 | } |
| 304 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 305 | bool operator>(const GeneralizedTime &lhs, const GeneralizedTime &rhs) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 306 | return rhs < lhs; |
| 307 | } |
| 308 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 309 | bool operator<=(const GeneralizedTime &lhs, const GeneralizedTime &rhs) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 310 | return !(lhs > rhs); |
| 311 | } |
| 312 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 313 | bool operator>=(const GeneralizedTime &lhs, const GeneralizedTime &rhs) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 314 | return !(lhs < rhs); |
| 315 | } |
| 316 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 317 | bool ParseUTCTime(const Input &in, GeneralizedTime *value) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 318 | ByteReader reader(in); |
| 319 | GeneralizedTime time; |
| 320 | if (!DecimalStringToUint(reader, 2, &time.year) || |
| 321 | !DecimalStringToUint(reader, 2, &time.month) || |
| 322 | !DecimalStringToUint(reader, 2, &time.day) || |
| 323 | !DecimalStringToUint(reader, 2, &time.hours) || |
| 324 | !DecimalStringToUint(reader, 2, &time.minutes) || |
| 325 | !DecimalStringToUint(reader, 2, &time.seconds)) { |
| 326 | return false; |
| 327 | } |
| 328 | uint8_t zulu; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 329 | if (!reader.ReadByte(&zulu) || zulu != 'Z' || reader.HasMore()) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 330 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 331 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 332 | if (time.year < 50) { |
| 333 | time.year += 2000; |
| 334 | } else { |
| 335 | time.year += 1900; |
| 336 | } |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 337 | if (!ValidateGeneralizedTime(time)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 338 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 339 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 340 | *value = time; |
| 341 | return true; |
| 342 | } |
| 343 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 344 | bool ParseGeneralizedTime(const Input &in, GeneralizedTime *value) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 345 | ByteReader reader(in); |
| 346 | GeneralizedTime time; |
| 347 | if (!DecimalStringToUint(reader, 4, &time.year) || |
| 348 | !DecimalStringToUint(reader, 2, &time.month) || |
| 349 | !DecimalStringToUint(reader, 2, &time.day) || |
| 350 | !DecimalStringToUint(reader, 2, &time.hours) || |
| 351 | !DecimalStringToUint(reader, 2, &time.minutes) || |
| 352 | !DecimalStringToUint(reader, 2, &time.seconds)) { |
| 353 | return false; |
| 354 | } |
| 355 | uint8_t zulu; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 356 | if (!reader.ReadByte(&zulu) || zulu != 'Z' || reader.HasMore()) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 357 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 358 | } |
| 359 | if (!ValidateGeneralizedTime(time)) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 360 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 361 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 362 | *value = time; |
| 363 | return true; |
| 364 | } |
| 365 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 366 | bool ParseIA5String(Input in, std::string *out) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 367 | for (char c : in.AsStringView()) { |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 368 | if (static_cast<uint8_t>(c) > 127) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 369 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 370 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 371 | } |
| 372 | *out = in.AsString(); |
| 373 | return true; |
| 374 | } |
| 375 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 376 | bool ParseVisibleString(Input in, std::string *out) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 377 | // ITU-T X.680: |
| 378 | // VisibleString : "Defining registration number 6" + SPACE |
| 379 | // 6 includes all the characters from '!' .. '~' (33 .. 126), space is 32. |
| 380 | // Also ITU-T X.691 says it much more clearly: |
| 381 | // "for VisibleString [the range] is 32 to 126 ... For VisibleString .. all |
| 382 | // the values in the range are present." |
| 383 | for (char c : in.AsStringView()) { |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 384 | if (static_cast<uint8_t>(c) < 32 || static_cast<uint8_t>(c) > 126) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 385 | return false; |
Bob Beck | 6beabf3 | 2023-11-21 09:43:52 -0700 | [diff] [blame] | 386 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 387 | } |
| 388 | *out = in.AsString(); |
| 389 | return true; |
| 390 | } |
| 391 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 392 | bool ParsePrintableString(Input in, std::string *out) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 393 | for (char c : in.AsStringView()) { |
Bob Beck | 3aecf1d | 2023-09-08 11:56:02 -0600 | [diff] [blame] | 394 | if (!(OPENSSL_isalpha(c) || c == ' ' || (c >= '\'' && c <= ':') || |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 395 | c == '=' || c == '?')) { |
| 396 | return false; |
| 397 | } |
| 398 | } |
| 399 | *out = in.AsString(); |
| 400 | return true; |
| 401 | } |
| 402 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 403 | bool ParseTeletexStringAsLatin1(Input in, std::string *out) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 404 | out->clear(); |
| 405 | // Convert from Latin-1 to UTF-8. |
| 406 | size_t utf8_length = in.Length(); |
| 407 | for (size_t i = 0; i < in.Length(); i++) { |
Bob Beck | 0500756 | 2023-08-17 20:22:17 +0000 | [diff] [blame] | 408 | if (in[i] > 0x7f) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 409 | utf8_length++; |
Bob Beck | 0500756 | 2023-08-17 20:22:17 +0000 | [diff] [blame] | 410 | } |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 411 | } |
| 412 | out->reserve(utf8_length); |
| 413 | for (size_t i = 0; i < in.Length(); i++) { |
Bob Beck | 0500756 | 2023-08-17 20:22:17 +0000 | [diff] [blame] | 414 | uint8_t u = in[i]; |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 415 | if (u <= 0x7f) { |
| 416 | out->push_back(u); |
| 417 | } else { |
| 418 | out->push_back(0xc0 | (u >> 6)); |
| 419 | out->push_back(0x80 | (u & 0x3f)); |
| 420 | } |
| 421 | } |
Bob Beck | 0500756 | 2023-08-17 20:22:17 +0000 | [diff] [blame] | 422 | BSSL_CHECK(utf8_length == out->size()); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 423 | return true; |
| 424 | } |
| 425 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 426 | bool ParseUniversalString(Input in, std::string *out) { |
Bob Beck | 3aecf1d | 2023-09-08 11:56:02 -0600 | [diff] [blame] | 427 | if (in.Length() % 4 != 0) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 428 | return false; |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 429 | } |
Bob Beck | 3aecf1d | 2023-09-08 11:56:02 -0600 | [diff] [blame] | 430 | |
| 431 | CBS cbs; |
| 432 | CBS_init(&cbs, in.UnsafeData(), in.Length()); |
| 433 | bssl::ScopedCBB cbb; |
| 434 | if (!CBB_init(cbb.get(), in.Length())) { |
| 435 | return false; |
| 436 | } |
| 437 | |
| 438 | while (CBS_len(&cbs) != 0) { |
| 439 | uint32_t c; |
| 440 | if (!CBS_get_utf32_be(&cbs, &c) || // |
| 441 | !CBB_add_utf8(cbb.get(), c)) { |
| 442 | return false; |
| 443 | } |
| 444 | } |
| 445 | |
| 446 | out->assign(CBB_data(cbb.get()), CBB_data(cbb.get()) + CBB_len(cbb.get())); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 447 | return true; |
| 448 | } |
| 449 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 450 | bool ParseBmpString(Input in, std::string *out) { |
Bob Beck | 3aecf1d | 2023-09-08 11:56:02 -0600 | [diff] [blame] | 451 | if (in.Length() % 2 != 0) { |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 452 | return false; |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 453 | } |
Bob Beck | 3aecf1d | 2023-09-08 11:56:02 -0600 | [diff] [blame] | 454 | |
| 455 | CBS cbs; |
| 456 | CBS_init(&cbs, in.UnsafeData(), in.Length()); |
| 457 | bssl::ScopedCBB cbb; |
| 458 | if (!CBB_init(cbb.get(), in.Length())) { |
| 459 | return false; |
| 460 | } |
| 461 | |
| 462 | while (CBS_len(&cbs) != 0) { |
| 463 | uint32_t c; |
| 464 | if (!CBS_get_ucs2_be(&cbs, &c) || // |
| 465 | !CBB_add_utf8(cbb.get(), c)) { |
| 466 | return false; |
| 467 | } |
| 468 | } |
| 469 | |
| 470 | out->assign(CBB_data(cbb.get()), CBB_data(cbb.get()) + CBB_len(cbb.get())); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 471 | return true; |
| 472 | } |
| 473 | |
| 474 | } // namespace bssl::der |