Coverage Report

Created: 2025-06-24 07:00

/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
8.34k
                                        size_t len_pos) {
31
8.34k
  der_.insert(der_.begin() + len_pos, raw_len.begin(), raw_len.end());
32
8.34k
}
33
34
4.08k
void ASN1PDUToDER::EncodeIndefiniteLength(size_t len_pos) {
35
4.08k
  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
4.08k
  der_.push_back(0x00);
39
4.08k
  der_.push_back(0x00);
40
4.08k
}
41
42
49.9k
void ASN1PDUToDER::EncodeDefiniteLength(size_t actual_len, size_t len_pos) {
43
49.9k
  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
49.9k
  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
15.3k
    size_t len_num_bytes = GetVariableIntLen(actual_len, 256);
54
15.3k
    der_.insert(der_.begin() + len_pos, (0x80 | len_num_bytes));
55
15.3k
  }
56
49.9k
}
57
58
void ASN1PDUToDER::EncodeLength(const Length& len,
59
                                size_t actual_len,
60
62.3k
                                size_t len_pos) {
61
62.3k
  if (len.has_length_override()) {
62
8.34k
    EncodeOverrideLength(len.length_override(), len_pos);
63
53.9k
  } else if (len.has_indefinite_form() && len.indefinite_form()) {
64
4.08k
    EncodeIndefiniteLength(len_pos);
65
49.9k
  } else {
66
49.9k
    EncodeDefiniteLength(actual_len, len_pos);
67
49.9k
  }
68
62.3k
}
69
70
62.3k
void ASN1PDUToDER::EncodeValue(const Value& val) {
71
117k
  for (const auto& val_ele : val.val_array()) {
72
117k
    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
117k
    if (val_ele.has_pdu()) {
78
47.7k
      EncodePDU(val_ele.pdu());
79
69.4k
    } else {
80
69.4k
      der_.insert(der_.end(), val_ele.val_bits().begin(),
81
69.4k
                  val_ele.val_bits().end());
82
69.4k
    }
83
117k
  }
84
62.3k
}
85
86
void ASN1PDUToDER::EncodeHighTagNumberForm(uint8_t id_class,
87
                                           uint8_t encoding,
88
5.78k
                                           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
5.78k
  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
5.78k
  InsertVariableIntBase128(tag_num, der_.size(), der_);
94
5.78k
}
95
96
62.3k
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
62.3k
  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
62.3k
  uint8_t encoding = static_cast<uint8_t>(id.encoding()) << 5;
102
103
62.3k
  uint32_t tag_num = id.tag_num().has_high_tag_num()
104
62.3k
                         ? id.tag_num().high_tag_num()
105
62.3k
                         : 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
62.3k
  if (tag_num >= 31) {
109
5.78k
    EncodeHighTagNumberForm(id_class, encoding, tag_num);
110
56.5k
  } else {
111
56.5k
    der_.push_back(static_cast<uint8_t>(id_class | encoding | tag_num));
112
56.5k
  }
113
62.3k
}
114
115
62.3k
void ASN1PDUToDER::EncodePDU(const PDU& pdu) {
116
  // Artifically limit the stack depth to avoid stack overflow.
117
62.3k
  if (depth_ > kRecursionLimit) {
118
0
    recursion_exceeded_ = true;
119
0
    return;
120
0
  }
121
62.3k
  ++depth_;
122
62.3k
  EncodeIdentifier(pdu.id());
123
62.3k
  size_t len_pos = der_.size();
124
62.3k
  EncodeValue(pdu.val());
125
62.3k
  EncodeLength(pdu.len(), der_.size() - len_pos, len_pos);
126
62.3k
  --depth_;
127
62.3k
}
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