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