1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <malloc.h> 18 #include <stdint.h> 19 #include <string.h> 20 21 #include "asn1_decoder.h" 22 23 24 typedef struct asn1_context { 25 size_t length; 26 uint8_t* p; 27 int app_type; 28 } asn1_context_t; 29 30 31 static const int kMaskConstructed = 0xE0; 32 static const int kMaskTag = 0x7F; 33 static const int kMaskAppType = 0x1F; 34 35 static const int kTagOctetString = 0x04; 36 static const int kTagOid = 0x06; 37 static const int kTagSequence = 0x30; 38 static const int kTagSet = 0x31; 39 static const int kTagConstructed = 0xA0; 40 41 asn1_context_t* asn1_context_new(uint8_t* buffer, size_t length) { 42 asn1_context_t* ctx = (asn1_context_t*) calloc(1, sizeof(asn1_context_t)); 43 if (ctx == NULL) { 44 return NULL; 45 } 46 ctx->p = buffer; 47 ctx->length = length; 48 return ctx; 49 } 50 51 void asn1_context_free(asn1_context_t* ctx) { 52 free(ctx); 53 } 54 55 static inline int peek_byte(asn1_context_t* ctx) { 56 if (ctx->length <= 0) { 57 return -1; 58 } 59 return *ctx->p; 60 } 61 62 static inline int get_byte(asn1_context_t* ctx) { 63 if (ctx->length <= 0) { 64 return -1; 65 } 66 int byte = *ctx->p; 67 ctx->p++; 68 ctx->length--; 69 return byte; 70 } 71 72 static inline bool skip_bytes(asn1_context_t* ctx, size_t num_skip) { 73 if (ctx->length < num_skip) { 74 return false; 75 } 76 ctx->p += num_skip; 77 ctx->length -= num_skip; 78 return true; 79 } 80 81 static bool decode_length(asn1_context_t* ctx, size_t* out_len) { 82 int num_octets = get_byte(ctx); 83 if (num_octets == -1) { 84 return false; 85 } 86 if ((num_octets & 0x80) == 0x00) { 87 *out_len = num_octets; 88 return 1; 89 } 90 num_octets &= kMaskTag; 91 if ((size_t)num_octets >= sizeof(size_t)) { 92 return false; 93 } 94 size_t length = 0; 95 for (int i = 0; i < num_octets; ++i) { 96 int byte = get_byte(ctx); 97 if (byte == -1) { 98 return false; 99 } 100 length <<= 8; 101 length += byte; 102 } 103 *out_len = length; 104 return true; 105 } 106 107 /** 108 * Returns the constructed type and advances the pointer. E.g. A0 -> 0 109 */ 110 asn1_context_t* asn1_constructed_get(asn1_context_t* ctx) { 111 int type = get_byte(ctx); 112 if (type == -1 || (type & kMaskConstructed) != kTagConstructed) { 113 return NULL; 114 } 115 size_t length; 116 if (!decode_length(ctx, &length) || length > ctx->length) { 117 return NULL; 118 } 119 asn1_context_t* app_ctx = asn1_context_new(ctx->p, length); 120 app_ctx->app_type = type & kMaskAppType; 121 return app_ctx; 122 } 123 124 bool asn1_constructed_skip_all(asn1_context_t* ctx) { 125 int byte = peek_byte(ctx); 126 while (byte != -1 && (byte & kMaskConstructed) == kTagConstructed) { 127 skip_bytes(ctx, 1); 128 size_t length; 129 if (!decode_length(ctx, &length) || !skip_bytes(ctx, length)) { 130 return false; 131 } 132 byte = peek_byte(ctx); 133 } 134 return byte != -1; 135 } 136 137 int asn1_constructed_type(asn1_context_t* ctx) { 138 return ctx->app_type; 139 } 140 141 asn1_context_t* asn1_sequence_get(asn1_context_t* ctx) { 142 if ((get_byte(ctx) & kMaskTag) != kTagSequence) { 143 return NULL; 144 } 145 size_t length; 146 if (!decode_length(ctx, &length) || length > ctx->length) { 147 return NULL; 148 } 149 return asn1_context_new(ctx->p, length); 150 } 151 152 asn1_context_t* asn1_set_get(asn1_context_t* ctx) { 153 if ((get_byte(ctx) & kMaskTag) != kTagSet) { 154 return NULL; 155 } 156 size_t length; 157 if (!decode_length(ctx, &length) || length > ctx->length) { 158 return NULL; 159 } 160 return asn1_context_new(ctx->p, length); 161 } 162 163 bool asn1_sequence_next(asn1_context_t* ctx) { 164 size_t length; 165 if (get_byte(ctx) == -1 || !decode_length(ctx, &length) || !skip_bytes(ctx, length)) { 166 return false; 167 } 168 return true; 169 } 170 171 bool asn1_oid_get(asn1_context_t* ctx, uint8_t** oid, size_t* length) { 172 if (get_byte(ctx) != kTagOid) { 173 return false; 174 } 175 if (!decode_length(ctx, length) || *length == 0 || *length > ctx->length) { 176 return false; 177 } 178 *oid = ctx->p; 179 return true; 180 } 181 182 bool asn1_octet_string_get(asn1_context_t* ctx, uint8_t** octet_string, size_t* length) { 183 if (get_byte(ctx) != kTagOctetString) { 184 return false; 185 } 186 if (!decode_length(ctx, length) || *length == 0 || *length > ctx->length) { 187 return false; 188 } 189 *octet_string = ctx->p; 190 return true; 191 } 192