xref: /aosp_15_r20/bootable/recovery/otautil/asn1_decoder.cpp (revision e7c364b630b241adcb6c7726a21055250b91fdac)
1*e7c364b6SAndroid Build Coastguard Worker /*
2*e7c364b6SAndroid Build Coastguard Worker  * Copyright (C) 2013 The Android Open Source Project
3*e7c364b6SAndroid Build Coastguard Worker  *
4*e7c364b6SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*e7c364b6SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*e7c364b6SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*e7c364b6SAndroid Build Coastguard Worker  *
8*e7c364b6SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*e7c364b6SAndroid Build Coastguard Worker  *
10*e7c364b6SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*e7c364b6SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*e7c364b6SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*e7c364b6SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*e7c364b6SAndroid Build Coastguard Worker  * limitations under the License.
15*e7c364b6SAndroid Build Coastguard Worker  */
16*e7c364b6SAndroid Build Coastguard Worker 
17*e7c364b6SAndroid Build Coastguard Worker #include "private/asn1_decoder.h"
18*e7c364b6SAndroid Build Coastguard Worker 
peek_byte() const19*e7c364b6SAndroid Build Coastguard Worker int asn1_context::peek_byte() const {
20*e7c364b6SAndroid Build Coastguard Worker   if (length_ == 0) {
21*e7c364b6SAndroid Build Coastguard Worker     return -1;
22*e7c364b6SAndroid Build Coastguard Worker   }
23*e7c364b6SAndroid Build Coastguard Worker   return *p_;
24*e7c364b6SAndroid Build Coastguard Worker }
25*e7c364b6SAndroid Build Coastguard Worker 
get_byte()26*e7c364b6SAndroid Build Coastguard Worker int asn1_context::get_byte() {
27*e7c364b6SAndroid Build Coastguard Worker   if (length_ == 0) {
28*e7c364b6SAndroid Build Coastguard Worker     return -1;
29*e7c364b6SAndroid Build Coastguard Worker   }
30*e7c364b6SAndroid Build Coastguard Worker 
31*e7c364b6SAndroid Build Coastguard Worker   int byte = *p_;
32*e7c364b6SAndroid Build Coastguard Worker   p_++;
33*e7c364b6SAndroid Build Coastguard Worker   length_--;
34*e7c364b6SAndroid Build Coastguard Worker   return byte;
35*e7c364b6SAndroid Build Coastguard Worker }
36*e7c364b6SAndroid Build Coastguard Worker 
skip_bytes(size_t num_skip)37*e7c364b6SAndroid Build Coastguard Worker bool asn1_context::skip_bytes(size_t num_skip) {
38*e7c364b6SAndroid Build Coastguard Worker   if (length_ < num_skip) {
39*e7c364b6SAndroid Build Coastguard Worker     return false;
40*e7c364b6SAndroid Build Coastguard Worker   }
41*e7c364b6SAndroid Build Coastguard Worker   p_ += num_skip;
42*e7c364b6SAndroid Build Coastguard Worker   length_ -= num_skip;
43*e7c364b6SAndroid Build Coastguard Worker   return true;
44*e7c364b6SAndroid Build Coastguard Worker }
45*e7c364b6SAndroid Build Coastguard Worker 
decode_length(size_t * out_len)46*e7c364b6SAndroid Build Coastguard Worker bool asn1_context::decode_length(size_t* out_len) {
47*e7c364b6SAndroid Build Coastguard Worker   int num_octets = get_byte();
48*e7c364b6SAndroid Build Coastguard Worker   if (num_octets == -1) {
49*e7c364b6SAndroid Build Coastguard Worker     return false;
50*e7c364b6SAndroid Build Coastguard Worker   }
51*e7c364b6SAndroid Build Coastguard Worker   if ((num_octets & 0x80) == 0x00) {
52*e7c364b6SAndroid Build Coastguard Worker     *out_len = num_octets;
53*e7c364b6SAndroid Build Coastguard Worker     return true;
54*e7c364b6SAndroid Build Coastguard Worker   }
55*e7c364b6SAndroid Build Coastguard Worker   num_octets &= kMaskTag;
56*e7c364b6SAndroid Build Coastguard Worker   if (static_cast<size_t>(num_octets) >= sizeof(size_t)) {
57*e7c364b6SAndroid Build Coastguard Worker     return false;
58*e7c364b6SAndroid Build Coastguard Worker   }
59*e7c364b6SAndroid Build Coastguard Worker   size_t length = 0;
60*e7c364b6SAndroid Build Coastguard Worker   for (int i = 0; i < num_octets; ++i) {
61*e7c364b6SAndroid Build Coastguard Worker     int byte = get_byte();
62*e7c364b6SAndroid Build Coastguard Worker     if (byte == -1) {
63*e7c364b6SAndroid Build Coastguard Worker       return false;
64*e7c364b6SAndroid Build Coastguard Worker     }
65*e7c364b6SAndroid Build Coastguard Worker     length <<= 8;
66*e7c364b6SAndroid Build Coastguard Worker     length += byte;
67*e7c364b6SAndroid Build Coastguard Worker   }
68*e7c364b6SAndroid Build Coastguard Worker   *out_len = length;
69*e7c364b6SAndroid Build Coastguard Worker   return true;
70*e7c364b6SAndroid Build Coastguard Worker }
71*e7c364b6SAndroid Build Coastguard Worker 
72*e7c364b6SAndroid Build Coastguard Worker /**
73*e7c364b6SAndroid Build Coastguard Worker  * Returns the constructed type and advances the pointer. E.g. A0 -> 0
74*e7c364b6SAndroid Build Coastguard Worker  */
asn1_constructed_get()75*e7c364b6SAndroid Build Coastguard Worker asn1_context* asn1_context::asn1_constructed_get() {
76*e7c364b6SAndroid Build Coastguard Worker   int type = get_byte();
77*e7c364b6SAndroid Build Coastguard Worker   if (type == -1 || (type & kMaskConstructed) != kTagConstructed) {
78*e7c364b6SAndroid Build Coastguard Worker     return nullptr;
79*e7c364b6SAndroid Build Coastguard Worker   }
80*e7c364b6SAndroid Build Coastguard Worker   size_t length;
81*e7c364b6SAndroid Build Coastguard Worker   if (!decode_length(&length) || length > length_) {
82*e7c364b6SAndroid Build Coastguard Worker     return nullptr;
83*e7c364b6SAndroid Build Coastguard Worker   }
84*e7c364b6SAndroid Build Coastguard Worker   asn1_context* app_ctx = new asn1_context(p_, length);
85*e7c364b6SAndroid Build Coastguard Worker   app_ctx->app_type_ = type & kMaskAppType;
86*e7c364b6SAndroid Build Coastguard Worker   return app_ctx;
87*e7c364b6SAndroid Build Coastguard Worker }
88*e7c364b6SAndroid Build Coastguard Worker 
asn1_constructed_skip_all()89*e7c364b6SAndroid Build Coastguard Worker bool asn1_context::asn1_constructed_skip_all() {
90*e7c364b6SAndroid Build Coastguard Worker   int byte = peek_byte();
91*e7c364b6SAndroid Build Coastguard Worker   while (byte != -1 && (byte & kMaskConstructed) == kTagConstructed) {
92*e7c364b6SAndroid Build Coastguard Worker     skip_bytes(1);
93*e7c364b6SAndroid Build Coastguard Worker     size_t length;
94*e7c364b6SAndroid Build Coastguard Worker     if (!decode_length(&length) || !skip_bytes(length)) {
95*e7c364b6SAndroid Build Coastguard Worker       return false;
96*e7c364b6SAndroid Build Coastguard Worker     }
97*e7c364b6SAndroid Build Coastguard Worker     byte = peek_byte();
98*e7c364b6SAndroid Build Coastguard Worker   }
99*e7c364b6SAndroid Build Coastguard Worker   return byte != -1;
100*e7c364b6SAndroid Build Coastguard Worker }
101*e7c364b6SAndroid Build Coastguard Worker 
asn1_constructed_type() const102*e7c364b6SAndroid Build Coastguard Worker int asn1_context::asn1_constructed_type() const {
103*e7c364b6SAndroid Build Coastguard Worker   return app_type_;
104*e7c364b6SAndroid Build Coastguard Worker }
105*e7c364b6SAndroid Build Coastguard Worker 
asn1_sequence_get()106*e7c364b6SAndroid Build Coastguard Worker asn1_context* asn1_context::asn1_sequence_get() {
107*e7c364b6SAndroid Build Coastguard Worker   if ((get_byte() & kMaskTag) != kTagSequence) {
108*e7c364b6SAndroid Build Coastguard Worker     return nullptr;
109*e7c364b6SAndroid Build Coastguard Worker   }
110*e7c364b6SAndroid Build Coastguard Worker   size_t length;
111*e7c364b6SAndroid Build Coastguard Worker   if (!decode_length(&length) || length > length_) {
112*e7c364b6SAndroid Build Coastguard Worker     return nullptr;
113*e7c364b6SAndroid Build Coastguard Worker   }
114*e7c364b6SAndroid Build Coastguard Worker   return new asn1_context(p_, length);
115*e7c364b6SAndroid Build Coastguard Worker }
116*e7c364b6SAndroid Build Coastguard Worker 
asn1_set_get()117*e7c364b6SAndroid Build Coastguard Worker asn1_context* asn1_context::asn1_set_get() {
118*e7c364b6SAndroid Build Coastguard Worker   if ((get_byte() & kMaskTag) != kTagSet) {
119*e7c364b6SAndroid Build Coastguard Worker     return nullptr;
120*e7c364b6SAndroid Build Coastguard Worker   }
121*e7c364b6SAndroid Build Coastguard Worker   size_t length;
122*e7c364b6SAndroid Build Coastguard Worker   if (!decode_length(&length) || length > length_) {
123*e7c364b6SAndroid Build Coastguard Worker     return nullptr;
124*e7c364b6SAndroid Build Coastguard Worker   }
125*e7c364b6SAndroid Build Coastguard Worker   return new asn1_context(p_, length);
126*e7c364b6SAndroid Build Coastguard Worker }
127*e7c364b6SAndroid Build Coastguard Worker 
asn1_sequence_next()128*e7c364b6SAndroid Build Coastguard Worker bool asn1_context::asn1_sequence_next() {
129*e7c364b6SAndroid Build Coastguard Worker   size_t length;
130*e7c364b6SAndroid Build Coastguard Worker   if (get_byte() == -1 || !decode_length(&length) || !skip_bytes(length)) {
131*e7c364b6SAndroid Build Coastguard Worker     return false;
132*e7c364b6SAndroid Build Coastguard Worker   }
133*e7c364b6SAndroid Build Coastguard Worker   return true;
134*e7c364b6SAndroid Build Coastguard Worker }
135*e7c364b6SAndroid Build Coastguard Worker 
asn1_oid_get(const uint8_t ** oid,size_t * length)136*e7c364b6SAndroid Build Coastguard Worker bool asn1_context::asn1_oid_get(const uint8_t** oid, size_t* length) {
137*e7c364b6SAndroid Build Coastguard Worker   if (get_byte() != kTagOid) {
138*e7c364b6SAndroid Build Coastguard Worker     return false;
139*e7c364b6SAndroid Build Coastguard Worker   }
140*e7c364b6SAndroid Build Coastguard Worker   if (!decode_length(length) || *length == 0 || *length > length_) {
141*e7c364b6SAndroid Build Coastguard Worker     return false;
142*e7c364b6SAndroid Build Coastguard Worker   }
143*e7c364b6SAndroid Build Coastguard Worker   *oid = p_;
144*e7c364b6SAndroid Build Coastguard Worker   return true;
145*e7c364b6SAndroid Build Coastguard Worker }
146*e7c364b6SAndroid Build Coastguard Worker 
asn1_octet_string_get(const uint8_t ** octet_string,size_t * length)147*e7c364b6SAndroid Build Coastguard Worker bool asn1_context::asn1_octet_string_get(const uint8_t** octet_string, size_t* length) {
148*e7c364b6SAndroid Build Coastguard Worker   if (get_byte() != kTagOctetString) {
149*e7c364b6SAndroid Build Coastguard Worker     return false;
150*e7c364b6SAndroid Build Coastguard Worker   }
151*e7c364b6SAndroid Build Coastguard Worker   if (!decode_length(length) || *length == 0 || *length > length_) {
152*e7c364b6SAndroid Build Coastguard Worker     return false;
153*e7c364b6SAndroid Build Coastguard Worker   }
154*e7c364b6SAndroid Build Coastguard Worker   *octet_string = p_;
155*e7c364b6SAndroid Build Coastguard Worker   return true;
156*e7c364b6SAndroid Build Coastguard Worker }
157