Coverage Report

Created: 2023-06-07 07:13

/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
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