Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2020 Google Inc. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | // |
15 | | //////////////////////////////////////////////////////////////////////////////// |
16 | | |
17 | | #include "asn1_pdu_to_der.h" |
18 | | |
19 | | #include "common.h" |
20 | | |
21 | | #include <limits.h> |
22 | | |
23 | | namespace asn1_pdu { |
24 | | |
25 | | // The maximum level of recursion allowed. Values greater than this will just |
26 | | // fail. |
27 | | static constexpr size_t kRecursionLimit = 200; |
28 | | |
29 | | void ASN1PDUToDER::EncodeOverrideLength(const std::string& raw_len, |
30 | 7.25k | size_t len_pos) { |
31 | 7.25k | der_.insert(der_.begin() + len_pos, raw_len.begin(), raw_len.end()); |
32 | 7.25k | } |
33 | | |
34 | 2.92k | void ASN1PDUToDER::EncodeIndefiniteLength(size_t len_pos) { |
35 | 2.92k | der_.insert(der_.begin() + len_pos, 0x80); |
36 | | // The PDU's value is from |len_pos| to the end of |der_|, so just add an |
37 | | // EOC marker to the end. |
38 | 2.92k | der_.push_back(0x00); |
39 | 2.92k | der_.push_back(0x00); |
40 | 2.92k | } |
41 | | |
42 | 54.7k | void ASN1PDUToDER::EncodeDefiniteLength(size_t actual_len, size_t len_pos) { |
43 | 54.7k | InsertVariableIntBase256(actual_len, len_pos, der_); |
44 | | // X.690 (2015), 8.1.3.3: The long-form is used when the length is |
45 | | // larger than 127. |
46 | | // Note: |len_num_bytes| is not checked here, because it will equal |
47 | | // 1 for values [128..255], but those require the long-form length. |
48 | 54.7k | if (actual_len > 127) { |
49 | | // See X.690 (2015) 8.1.3.5. |
50 | | // Long-form length is encoded as a byte with the high-bit set to indicate |
51 | | // the long-form, while the remaining bits indicate how many bytes are used |
52 | | // to encode the length. |
53 | 17.5k | size_t len_num_bytes = GetVariableIntLen(actual_len, 256); |
54 | 17.5k | der_.insert(der_.begin() + len_pos, (0x80 | len_num_bytes)); |
55 | 17.5k | } |
56 | 54.7k | } |
57 | | |
58 | | void ASN1PDUToDER::EncodeLength(const Length& len, |
59 | | size_t actual_len, |
60 | 64.9k | size_t len_pos) { |
61 | 64.9k | if (len.has_length_override()) { |
62 | 7.25k | EncodeOverrideLength(len.length_override(), len_pos); |
63 | 57.6k | } else if (len.has_indefinite_form() && len.indefinite_form()) { |
64 | 2.92k | EncodeIndefiniteLength(len_pos); |
65 | 54.7k | } else { |
66 | 54.7k | EncodeDefiniteLength(actual_len, len_pos); |
67 | 54.7k | } |
68 | 64.9k | } |
69 | | |
70 | 64.9k | void ASN1PDUToDER::EncodeValue(const Value& val) { |
71 | 118k | for (const auto& val_ele : val.val_array()) { |
72 | 118k | if (recursion_exceeded_) { |
73 | | // If the message exceeds the recursion limit, abort processing the |
74 | | // protobuf in order to limit uninteresting work. |
75 | 0 | return; |
76 | 0 | } |
77 | 118k | if (val_ele.has_pdu()) { |
78 | 50.3k | EncodePDU(val_ele.pdu()); |
79 | 67.9k | } else { |
80 | 67.9k | der_.insert(der_.end(), val_ele.val_bits().begin(), |
81 | 67.9k | val_ele.val_bits().end()); |
82 | 67.9k | } |
83 | 118k | } |
84 | 64.9k | } |
85 | | |
86 | | void ASN1PDUToDER::EncodeHighTagNumberForm(uint8_t id_class, |
87 | | uint8_t encoding, |
88 | 4.74k | uint32_t tag_num) { |
89 | | // High-tag-number form requires the lower 5 bits of the identifier to be set |
90 | | // to 1 (X.690 (2015), 8.1.2.4.1). |
91 | 4.74k | der_.push_back(id_class | encoding | 0x1F); |
92 | | // The high-tag-number form base 128 encodes |tag_num| (X.690 (2015), 8.1.2). |
93 | 4.74k | InsertVariableIntBase128(tag_num, der_.size(), der_); |
94 | 4.74k | } |
95 | | |
96 | 64.9k | void ASN1PDUToDER::EncodeIdentifier(const Identifier& id) { |
97 | | // The class comprises the 7th and 8th bit of the identifier (X.690 |
98 | | // (2015), 8.1.2). |
99 | 64.9k | uint8_t id_class = static_cast<uint8_t>(id.id_class()) << 6; |
100 | | // The encoding comprises the 6th bit of the identifier (X.690 (2015), 8.1.2). |
101 | 64.9k | uint8_t encoding = static_cast<uint8_t>(id.encoding()) << 5; |
102 | | |
103 | 64.9k | uint32_t tag_num = id.tag_num().has_high_tag_num() |
104 | 64.9k | ? id.tag_num().high_tag_num() |
105 | 64.9k | : id.tag_num().low_tag_num(); |
106 | | // When the tag number is greater than or equal to 31, encode with a single |
107 | | // byte; otherwise, use the high-tag-number form (X.690 (2015), 8.1.2). |
108 | 64.9k | if (tag_num >= 31) { |
109 | 4.74k | EncodeHighTagNumberForm(id_class, encoding, tag_num); |
110 | 60.1k | } else { |
111 | 60.1k | der_.push_back(static_cast<uint8_t>(id_class | encoding | tag_num)); |
112 | 60.1k | } |
113 | 64.9k | } |
114 | | |
115 | 64.9k | void ASN1PDUToDER::EncodePDU(const PDU& pdu) { |
116 | | // Artifically limit the stack depth to avoid stack overflow. |
117 | 64.9k | if (depth_ > kRecursionLimit) { |
118 | 0 | recursion_exceeded_ = true; |
119 | 0 | return; |
120 | 0 | } |
121 | 64.9k | ++depth_; |
122 | 64.9k | EncodeIdentifier(pdu.id()); |
123 | 64.9k | size_t len_pos = der_.size(); |
124 | 64.9k | EncodeValue(pdu.val()); |
125 | 64.9k | EncodeLength(pdu.len(), der_.size() - len_pos, len_pos); |
126 | 64.9k | --depth_; |
127 | 64.9k | } |
128 | | |
129 | 14.5k | std::vector<uint8_t> ASN1PDUToDER::PDUToDER(const PDU& pdu) { |
130 | | // Reset the previous state. |
131 | 14.5k | der_.clear(); |
132 | 14.5k | depth_ = 0; |
133 | 14.5k | recursion_exceeded_ = false; |
134 | | |
135 | 14.5k | EncodePDU(pdu); |
136 | 14.5k | if (recursion_exceeded_) { |
137 | 0 | der_.clear(); |
138 | 0 | } |
139 | 14.5k | return der_; |
140 | 14.5k | } |
141 | | |
142 | | } // namespace asn1_pdu |