Coverage Report

Created: 2025-06-11 06:40

/src/asn1_pdu_to_der.cc
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
2.29k
                                        size_t len_pos) {
31
2.29k
  der_.insert(der_.begin() + len_pos, raw_len.begin(), raw_len.end());
32
2.29k
}
33
34
3.62k
void ASN1PDUToDER::EncodeIndefiniteLength(size_t len_pos) {
35
3.62k
  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
3.62k
  der_.push_back(0x00);
39
3.62k
  der_.push_back(0x00);
40
3.62k
}
41
42
26.3k
void ASN1PDUToDER::EncodeDefiniteLength(size_t actual_len, size_t len_pos) {
43
26.3k
  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
26.3k
  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
9.64k
    size_t len_num_bytes = GetVariableIntLen(actual_len, 256);
54
9.64k
    der_.insert(der_.begin() + len_pos, (0x80 | len_num_bytes));
55
9.64k
  }
56
26.3k
}
57
58
void ASN1PDUToDER::EncodeLength(const Length& len,
59
                                size_t actual_len,
60
32.2k
                                size_t len_pos) {
61
32.2k
  if (len.has_length_override()) {
62
2.29k
    EncodeOverrideLength(len.length_override(), len_pos);
63
29.9k
  } else if (len.has_indefinite_form() && len.indefinite_form()) {
64
3.62k
    EncodeIndefiniteLength(len_pos);
65
26.3k
  } else {
66
26.3k
    EncodeDefiniteLength(actual_len, len_pos);
67
26.3k
  }
68
32.2k
}
69
70
32.2k
void ASN1PDUToDER::EncodeValue(const Value& val) {
71
67.1k
  for (const auto& val_ele : val.val_array()) {
72
67.1k
    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
67.1k
    if (val_ele.has_pdu()) {
78
25.6k
      EncodePDU(val_ele.pdu());
79
41.4k
    } else {
80
41.4k
      der_.insert(der_.end(), val_ele.val_bits().begin(),
81
41.4k
                  val_ele.val_bits().end());
82
41.4k
    }
83
67.1k
  }
84
32.2k
}
85
86
void ASN1PDUToDER::EncodeHighTagNumberForm(uint8_t id_class,
87
                                           uint8_t encoding,
88
2.09k
                                           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
2.09k
  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
2.09k
  InsertVariableIntBase128(tag_num, der_.size(), der_);
94
2.09k
}
95
96
32.2k
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
32.2k
  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
32.2k
  uint8_t encoding = static_cast<uint8_t>(id.encoding()) << 5;
102
103
32.2k
  uint32_t tag_num = id.tag_num().has_high_tag_num()
104
32.2k
                         ? id.tag_num().high_tag_num()
105
32.2k
                         : 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
32.2k
  if (tag_num >= 31) {
109
2.09k
    EncodeHighTagNumberForm(id_class, encoding, tag_num);
110
30.1k
  } else {
111
30.1k
    der_.push_back(static_cast<uint8_t>(id_class | encoding | tag_num));
112
30.1k
  }
113
32.2k
}
114
115
32.2k
void ASN1PDUToDER::EncodePDU(const PDU& pdu) {
116
  // Artifically limit the stack depth to avoid stack overflow.
117
32.2k
  if (depth_ > kRecursionLimit) {
118
0
    recursion_exceeded_ = true;
119
0
    return;
120
0
  }
121
32.2k
  ++depth_;
122
32.2k
  EncodeIdentifier(pdu.id());
123
32.2k
  size_t len_pos = der_.size();
124
32.2k
  EncodeValue(pdu.val());
125
32.2k
  EncodeLength(pdu.len(), der_.size() - len_pos, len_pos);
126
32.2k
  --depth_;
127
32.2k
}
128
129
6.57k
std::vector<uint8_t> ASN1PDUToDER::PDUToDER(const PDU& pdu) {
130
  // Reset the previous state.
131
6.57k
  der_.clear();
132
6.57k
  depth_ = 0;
133
6.57k
  recursion_exceeded_ = false;
134
135
6.57k
  EncodePDU(pdu);
136
6.57k
  if (recursion_exceeded_) {
137
0
    der_.clear();
138
0
  }
139
6.57k
  return der_;
140
6.57k
}
141
142
}  // namespace asn1_pdu