Coverage Report

Created: 2023-06-07 07:11

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