18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* Decoder for ASN.1 BER/DER/CER encoded bytestream 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. 58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/export.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/errno.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/asn1_decoder.h> 138c2ecf20Sopenharmony_ci#include <linux/asn1_ber_bytecode.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic const unsigned char asn1_op_lengths[ASN1_OP__NR] = { 168c2ecf20Sopenharmony_ci /* OPC TAG JMP ACT */ 178c2ecf20Sopenharmony_ci [ASN1_OP_MATCH] = 1 + 1, 188c2ecf20Sopenharmony_ci [ASN1_OP_MATCH_OR_SKIP] = 1 + 1, 198c2ecf20Sopenharmony_ci [ASN1_OP_MATCH_ACT] = 1 + 1 + 1, 208c2ecf20Sopenharmony_ci [ASN1_OP_MATCH_ACT_OR_SKIP] = 1 + 1 + 1, 218c2ecf20Sopenharmony_ci [ASN1_OP_MATCH_JUMP] = 1 + 1 + 1, 228c2ecf20Sopenharmony_ci [ASN1_OP_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, 238c2ecf20Sopenharmony_ci [ASN1_OP_MATCH_ANY] = 1, 248c2ecf20Sopenharmony_ci [ASN1_OP_MATCH_ANY_OR_SKIP] = 1, 258c2ecf20Sopenharmony_ci [ASN1_OP_MATCH_ANY_ACT] = 1 + 1, 268c2ecf20Sopenharmony_ci [ASN1_OP_MATCH_ANY_ACT_OR_SKIP] = 1 + 1, 278c2ecf20Sopenharmony_ci [ASN1_OP_COND_MATCH_OR_SKIP] = 1 + 1, 288c2ecf20Sopenharmony_ci [ASN1_OP_COND_MATCH_ACT_OR_SKIP] = 1 + 1 + 1, 298c2ecf20Sopenharmony_ci [ASN1_OP_COND_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, 308c2ecf20Sopenharmony_ci [ASN1_OP_COND_MATCH_ANY] = 1, 318c2ecf20Sopenharmony_ci [ASN1_OP_COND_MATCH_ANY_OR_SKIP] = 1, 328c2ecf20Sopenharmony_ci [ASN1_OP_COND_MATCH_ANY_ACT] = 1 + 1, 338c2ecf20Sopenharmony_ci [ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP] = 1 + 1, 348c2ecf20Sopenharmony_ci [ASN1_OP_COND_FAIL] = 1, 358c2ecf20Sopenharmony_ci [ASN1_OP_COMPLETE] = 1, 368c2ecf20Sopenharmony_ci [ASN1_OP_ACT] = 1 + 1, 378c2ecf20Sopenharmony_ci [ASN1_OP_MAYBE_ACT] = 1 + 1, 388c2ecf20Sopenharmony_ci [ASN1_OP_RETURN] = 1, 398c2ecf20Sopenharmony_ci [ASN1_OP_END_SEQ] = 1, 408c2ecf20Sopenharmony_ci [ASN1_OP_END_SEQ_OF] = 1 + 1, 418c2ecf20Sopenharmony_ci [ASN1_OP_END_SET] = 1, 428c2ecf20Sopenharmony_ci [ASN1_OP_END_SET_OF] = 1 + 1, 438c2ecf20Sopenharmony_ci [ASN1_OP_END_SEQ_ACT] = 1 + 1, 448c2ecf20Sopenharmony_ci [ASN1_OP_END_SEQ_OF_ACT] = 1 + 1 + 1, 458c2ecf20Sopenharmony_ci [ASN1_OP_END_SET_ACT] = 1 + 1, 468c2ecf20Sopenharmony_ci [ASN1_OP_END_SET_OF_ACT] = 1 + 1 + 1, 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* 508c2ecf20Sopenharmony_ci * Find the length of an indefinite length object 518c2ecf20Sopenharmony_ci * @data: The data buffer 528c2ecf20Sopenharmony_ci * @datalen: The end of the innermost containing element in the buffer 538c2ecf20Sopenharmony_ci * @_dp: The data parse cursor (updated before returning) 548c2ecf20Sopenharmony_ci * @_len: Where to return the size of the element. 558c2ecf20Sopenharmony_ci * @_errmsg: Where to return a pointer to an error message on error 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_cistatic int asn1_find_indefinite_length(const unsigned char *data, size_t datalen, 588c2ecf20Sopenharmony_ci size_t *_dp, size_t *_len, 598c2ecf20Sopenharmony_ci const char **_errmsg) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci unsigned char tag, tmp; 628c2ecf20Sopenharmony_ci size_t dp = *_dp, len, n; 638c2ecf20Sopenharmony_ci int indef_level = 1; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cinext_tag: 668c2ecf20Sopenharmony_ci if (unlikely(datalen - dp < 2)) { 678c2ecf20Sopenharmony_ci if (datalen == dp) 688c2ecf20Sopenharmony_ci goto missing_eoc; 698c2ecf20Sopenharmony_ci goto data_overrun_error; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* Extract a tag from the data */ 738c2ecf20Sopenharmony_ci tag = data[dp++]; 748c2ecf20Sopenharmony_ci if (tag == ASN1_EOC) { 758c2ecf20Sopenharmony_ci /* It appears to be an EOC. */ 768c2ecf20Sopenharmony_ci if (data[dp++] != 0) 778c2ecf20Sopenharmony_ci goto invalid_eoc; 788c2ecf20Sopenharmony_ci if (--indef_level <= 0) { 798c2ecf20Sopenharmony_ci *_len = dp - *_dp; 808c2ecf20Sopenharmony_ci *_dp = dp; 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci goto next_tag; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (unlikely((tag & 0x1f) == ASN1_LONG_TAG)) { 878c2ecf20Sopenharmony_ci do { 888c2ecf20Sopenharmony_ci if (unlikely(datalen - dp < 2)) 898c2ecf20Sopenharmony_ci goto data_overrun_error; 908c2ecf20Sopenharmony_ci tmp = data[dp++]; 918c2ecf20Sopenharmony_ci } while (tmp & 0x80); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* Extract the length */ 958c2ecf20Sopenharmony_ci len = data[dp++]; 968c2ecf20Sopenharmony_ci if (len <= 0x7f) 978c2ecf20Sopenharmony_ci goto check_length; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (unlikely(len == ASN1_INDEFINITE_LENGTH)) { 1008c2ecf20Sopenharmony_ci /* Indefinite length */ 1018c2ecf20Sopenharmony_ci if (unlikely((tag & ASN1_CONS_BIT) == ASN1_PRIM << 5)) 1028c2ecf20Sopenharmony_ci goto indefinite_len_primitive; 1038c2ecf20Sopenharmony_ci indef_level++; 1048c2ecf20Sopenharmony_ci goto next_tag; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci n = len - 0x80; 1088c2ecf20Sopenharmony_ci if (unlikely(n > sizeof(len) - 1)) 1098c2ecf20Sopenharmony_ci goto length_too_long; 1108c2ecf20Sopenharmony_ci if (unlikely(n > datalen - dp)) 1118c2ecf20Sopenharmony_ci goto data_overrun_error; 1128c2ecf20Sopenharmony_ci len = 0; 1138c2ecf20Sopenharmony_ci for (; n > 0; n--) { 1148c2ecf20Sopenharmony_ci len <<= 8; 1158c2ecf20Sopenharmony_ci len |= data[dp++]; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_cicheck_length: 1188c2ecf20Sopenharmony_ci if (len > datalen - dp) 1198c2ecf20Sopenharmony_ci goto data_overrun_error; 1208c2ecf20Sopenharmony_ci dp += len; 1218c2ecf20Sopenharmony_ci goto next_tag; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cilength_too_long: 1248c2ecf20Sopenharmony_ci *_errmsg = "Unsupported length"; 1258c2ecf20Sopenharmony_ci goto error; 1268c2ecf20Sopenharmony_ciindefinite_len_primitive: 1278c2ecf20Sopenharmony_ci *_errmsg = "Indefinite len primitive not permitted"; 1288c2ecf20Sopenharmony_ci goto error; 1298c2ecf20Sopenharmony_ciinvalid_eoc: 1308c2ecf20Sopenharmony_ci *_errmsg = "Invalid length EOC"; 1318c2ecf20Sopenharmony_ci goto error; 1328c2ecf20Sopenharmony_cidata_overrun_error: 1338c2ecf20Sopenharmony_ci *_errmsg = "Data overrun error"; 1348c2ecf20Sopenharmony_ci goto error; 1358c2ecf20Sopenharmony_cimissing_eoc: 1368c2ecf20Sopenharmony_ci *_errmsg = "Missing EOC in indefinite len cons"; 1378c2ecf20Sopenharmony_cierror: 1388c2ecf20Sopenharmony_ci *_dp = dp; 1398c2ecf20Sopenharmony_ci return -1; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/** 1438c2ecf20Sopenharmony_ci * asn1_ber_decoder - Decoder BER/DER/CER ASN.1 according to pattern 1448c2ecf20Sopenharmony_ci * @decoder: The decoder definition (produced by asn1_compiler) 1458c2ecf20Sopenharmony_ci * @context: The caller's context (to be passed to the action functions) 1468c2ecf20Sopenharmony_ci * @data: The encoded data 1478c2ecf20Sopenharmony_ci * @datalen: The size of the encoded data 1488c2ecf20Sopenharmony_ci * 1498c2ecf20Sopenharmony_ci * Decode BER/DER/CER encoded ASN.1 data according to a bytecode pattern 1508c2ecf20Sopenharmony_ci * produced by asn1_compiler. Action functions are called on marked tags to 1518c2ecf20Sopenharmony_ci * allow the caller to retrieve significant data. 1528c2ecf20Sopenharmony_ci * 1538c2ecf20Sopenharmony_ci * LIMITATIONS: 1548c2ecf20Sopenharmony_ci * 1558c2ecf20Sopenharmony_ci * To keep down the amount of stack used by this function, the following limits 1568c2ecf20Sopenharmony_ci * have been imposed: 1578c2ecf20Sopenharmony_ci * 1588c2ecf20Sopenharmony_ci * (1) This won't handle datalen > 65535 without increasing the size of the 1598c2ecf20Sopenharmony_ci * cons stack elements and length_too_long checking. 1608c2ecf20Sopenharmony_ci * 1618c2ecf20Sopenharmony_ci * (2) The stack of constructed types is 10 deep. If the depth of non-leaf 1628c2ecf20Sopenharmony_ci * constructed types exceeds this, the decode will fail. 1638c2ecf20Sopenharmony_ci * 1648c2ecf20Sopenharmony_ci * (3) The SET type (not the SET OF type) isn't really supported as tracking 1658c2ecf20Sopenharmony_ci * what members of the set have been seen is a pain. 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_ciint asn1_ber_decoder(const struct asn1_decoder *decoder, 1688c2ecf20Sopenharmony_ci void *context, 1698c2ecf20Sopenharmony_ci const unsigned char *data, 1708c2ecf20Sopenharmony_ci size_t datalen) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci const unsigned char *machine = decoder->machine; 1738c2ecf20Sopenharmony_ci const asn1_action_t *actions = decoder->actions; 1748c2ecf20Sopenharmony_ci size_t machlen = decoder->machlen; 1758c2ecf20Sopenharmony_ci enum asn1_opcode op; 1768c2ecf20Sopenharmony_ci unsigned char tag = 0, csp = 0, jsp = 0, optag = 0, hdr = 0; 1778c2ecf20Sopenharmony_ci const char *errmsg; 1788c2ecf20Sopenharmony_ci size_t pc = 0, dp = 0, tdp = 0, len = 0; 1798c2ecf20Sopenharmony_ci int ret; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci unsigned char flags = 0; 1828c2ecf20Sopenharmony_ci#define FLAG_INDEFINITE_LENGTH 0x01 1838c2ecf20Sopenharmony_ci#define FLAG_MATCHED 0x02 1848c2ecf20Sopenharmony_ci#define FLAG_LAST_MATCHED 0x04 /* Last tag matched */ 1858c2ecf20Sopenharmony_ci#define FLAG_CONS 0x20 /* Corresponds to CONS bit in the opcode tag 1868c2ecf20Sopenharmony_ci * - ie. whether or not we are going to parse 1878c2ecf20Sopenharmony_ci * a compound type. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci#define NR_CONS_STACK 10 1918c2ecf20Sopenharmony_ci unsigned short cons_dp_stack[NR_CONS_STACK]; 1928c2ecf20Sopenharmony_ci unsigned short cons_datalen_stack[NR_CONS_STACK]; 1938c2ecf20Sopenharmony_ci unsigned char cons_hdrlen_stack[NR_CONS_STACK]; 1948c2ecf20Sopenharmony_ci#define NR_JUMP_STACK 10 1958c2ecf20Sopenharmony_ci unsigned char jump_stack[NR_JUMP_STACK]; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (datalen > 65535) 1988c2ecf20Sopenharmony_ci return -EMSGSIZE; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cinext_op: 2018c2ecf20Sopenharmony_ci pr_debug("next_op: pc=\e[32m%zu\e[m/%zu dp=\e[33m%zu\e[m/%zu C=%d J=%d\n", 2028c2ecf20Sopenharmony_ci pc, machlen, dp, datalen, csp, jsp); 2038c2ecf20Sopenharmony_ci if (unlikely(pc >= machlen)) 2048c2ecf20Sopenharmony_ci goto machine_overrun_error; 2058c2ecf20Sopenharmony_ci op = machine[pc]; 2068c2ecf20Sopenharmony_ci if (unlikely(pc + asn1_op_lengths[op] > machlen)) 2078c2ecf20Sopenharmony_ci goto machine_overrun_error; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* If this command is meant to match a tag, then do that before 2108c2ecf20Sopenharmony_ci * evaluating the command. 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_ci if (op <= ASN1_OP__MATCHES_TAG) { 2138c2ecf20Sopenharmony_ci unsigned char tmp; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* Skip conditional matches if possible */ 2168c2ecf20Sopenharmony_ci if ((op & ASN1_OP_MATCH__COND && flags & FLAG_MATCHED) || 2178c2ecf20Sopenharmony_ci (op & ASN1_OP_MATCH__SKIP && dp == datalen)) { 2188c2ecf20Sopenharmony_ci flags &= ~FLAG_LAST_MATCHED; 2198c2ecf20Sopenharmony_ci pc += asn1_op_lengths[op]; 2208c2ecf20Sopenharmony_ci goto next_op; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci flags = 0; 2248c2ecf20Sopenharmony_ci hdr = 2; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* Extract a tag from the data */ 2278c2ecf20Sopenharmony_ci if (unlikely(datalen - dp < 2)) 2288c2ecf20Sopenharmony_ci goto data_overrun_error; 2298c2ecf20Sopenharmony_ci tag = data[dp++]; 2308c2ecf20Sopenharmony_ci if (unlikely((tag & 0x1f) == ASN1_LONG_TAG)) 2318c2ecf20Sopenharmony_ci goto long_tag_not_supported; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (op & ASN1_OP_MATCH__ANY) { 2348c2ecf20Sopenharmony_ci pr_debug("- any %02x\n", tag); 2358c2ecf20Sopenharmony_ci } else { 2368c2ecf20Sopenharmony_ci /* Extract the tag from the machine 2378c2ecf20Sopenharmony_ci * - Either CONS or PRIM are permitted in the data if 2388c2ecf20Sopenharmony_ci * CONS is not set in the op stream, otherwise CONS 2398c2ecf20Sopenharmony_ci * is mandatory. 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_ci optag = machine[pc + 1]; 2428c2ecf20Sopenharmony_ci flags |= optag & FLAG_CONS; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* Determine whether the tag matched */ 2458c2ecf20Sopenharmony_ci tmp = optag ^ tag; 2468c2ecf20Sopenharmony_ci tmp &= ~(optag & ASN1_CONS_BIT); 2478c2ecf20Sopenharmony_ci pr_debug("- match? %02x %02x %02x\n", tag, optag, tmp); 2488c2ecf20Sopenharmony_ci if (tmp != 0) { 2498c2ecf20Sopenharmony_ci /* All odd-numbered tags are MATCH_OR_SKIP. */ 2508c2ecf20Sopenharmony_ci if (op & ASN1_OP_MATCH__SKIP) { 2518c2ecf20Sopenharmony_ci pc += asn1_op_lengths[op]; 2528c2ecf20Sopenharmony_ci dp--; 2538c2ecf20Sopenharmony_ci goto next_op; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci goto tag_mismatch; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci flags |= FLAG_MATCHED; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci len = data[dp++]; 2618c2ecf20Sopenharmony_ci if (len > 0x7f) { 2628c2ecf20Sopenharmony_ci if (unlikely(len == ASN1_INDEFINITE_LENGTH)) { 2638c2ecf20Sopenharmony_ci /* Indefinite length */ 2648c2ecf20Sopenharmony_ci if (unlikely(!(tag & ASN1_CONS_BIT))) 2658c2ecf20Sopenharmony_ci goto indefinite_len_primitive; 2668c2ecf20Sopenharmony_ci flags |= FLAG_INDEFINITE_LENGTH; 2678c2ecf20Sopenharmony_ci if (unlikely(2 > datalen - dp)) 2688c2ecf20Sopenharmony_ci goto data_overrun_error; 2698c2ecf20Sopenharmony_ci } else { 2708c2ecf20Sopenharmony_ci int n = len - 0x80; 2718c2ecf20Sopenharmony_ci if (unlikely(n > 2)) 2728c2ecf20Sopenharmony_ci goto length_too_long; 2738c2ecf20Sopenharmony_ci if (unlikely(n > datalen - dp)) 2748c2ecf20Sopenharmony_ci goto data_overrun_error; 2758c2ecf20Sopenharmony_ci hdr += n; 2768c2ecf20Sopenharmony_ci for (len = 0; n > 0; n--) { 2778c2ecf20Sopenharmony_ci len <<= 8; 2788c2ecf20Sopenharmony_ci len |= data[dp++]; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci if (unlikely(len > datalen - dp)) 2818c2ecf20Sopenharmony_ci goto data_overrun_error; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci } else { 2848c2ecf20Sopenharmony_ci if (unlikely(len > datalen - dp)) 2858c2ecf20Sopenharmony_ci goto data_overrun_error; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (flags & FLAG_CONS) { 2898c2ecf20Sopenharmony_ci /* For expected compound forms, we stack the positions 2908c2ecf20Sopenharmony_ci * of the start and end of the data. 2918c2ecf20Sopenharmony_ci */ 2928c2ecf20Sopenharmony_ci if (unlikely(csp >= NR_CONS_STACK)) 2938c2ecf20Sopenharmony_ci goto cons_stack_overflow; 2948c2ecf20Sopenharmony_ci cons_dp_stack[csp] = dp; 2958c2ecf20Sopenharmony_ci cons_hdrlen_stack[csp] = hdr; 2968c2ecf20Sopenharmony_ci if (!(flags & FLAG_INDEFINITE_LENGTH)) { 2978c2ecf20Sopenharmony_ci cons_datalen_stack[csp] = datalen; 2988c2ecf20Sopenharmony_ci datalen = dp + len; 2998c2ecf20Sopenharmony_ci } else { 3008c2ecf20Sopenharmony_ci cons_datalen_stack[csp] = 0; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci csp++; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci pr_debug("- TAG: %02x %zu%s\n", 3068c2ecf20Sopenharmony_ci tag, len, flags & FLAG_CONS ? " CONS" : ""); 3078c2ecf20Sopenharmony_ci tdp = dp; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* Decide how to handle the operation */ 3118c2ecf20Sopenharmony_ci switch (op) { 3128c2ecf20Sopenharmony_ci case ASN1_OP_MATCH: 3138c2ecf20Sopenharmony_ci case ASN1_OP_MATCH_OR_SKIP: 3148c2ecf20Sopenharmony_ci case ASN1_OP_MATCH_ACT: 3158c2ecf20Sopenharmony_ci case ASN1_OP_MATCH_ACT_OR_SKIP: 3168c2ecf20Sopenharmony_ci case ASN1_OP_MATCH_ANY: 3178c2ecf20Sopenharmony_ci case ASN1_OP_MATCH_ANY_OR_SKIP: 3188c2ecf20Sopenharmony_ci case ASN1_OP_MATCH_ANY_ACT: 3198c2ecf20Sopenharmony_ci case ASN1_OP_MATCH_ANY_ACT_OR_SKIP: 3208c2ecf20Sopenharmony_ci case ASN1_OP_COND_MATCH_OR_SKIP: 3218c2ecf20Sopenharmony_ci case ASN1_OP_COND_MATCH_ACT_OR_SKIP: 3228c2ecf20Sopenharmony_ci case ASN1_OP_COND_MATCH_ANY: 3238c2ecf20Sopenharmony_ci case ASN1_OP_COND_MATCH_ANY_OR_SKIP: 3248c2ecf20Sopenharmony_ci case ASN1_OP_COND_MATCH_ANY_ACT: 3258c2ecf20Sopenharmony_ci case ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP: 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (!(flags & FLAG_CONS)) { 3288c2ecf20Sopenharmony_ci if (flags & FLAG_INDEFINITE_LENGTH) { 3298c2ecf20Sopenharmony_ci size_t tmp = dp; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci ret = asn1_find_indefinite_length( 3328c2ecf20Sopenharmony_ci data, datalen, &tmp, &len, &errmsg); 3338c2ecf20Sopenharmony_ci if (ret < 0) 3348c2ecf20Sopenharmony_ci goto error; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci pr_debug("- LEAF: %zu\n", len); 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (op & ASN1_OP_MATCH__ACT) { 3408c2ecf20Sopenharmony_ci unsigned char act; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (op & ASN1_OP_MATCH__ANY) 3438c2ecf20Sopenharmony_ci act = machine[pc + 1]; 3448c2ecf20Sopenharmony_ci else 3458c2ecf20Sopenharmony_ci act = machine[pc + 2]; 3468c2ecf20Sopenharmony_ci ret = actions[act](context, hdr, tag, data + dp, len); 3478c2ecf20Sopenharmony_ci if (ret < 0) 3488c2ecf20Sopenharmony_ci return ret; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (!(flags & FLAG_CONS)) 3528c2ecf20Sopenharmony_ci dp += len; 3538c2ecf20Sopenharmony_ci pc += asn1_op_lengths[op]; 3548c2ecf20Sopenharmony_ci goto next_op; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci case ASN1_OP_MATCH_JUMP: 3578c2ecf20Sopenharmony_ci case ASN1_OP_MATCH_JUMP_OR_SKIP: 3588c2ecf20Sopenharmony_ci case ASN1_OP_COND_MATCH_JUMP_OR_SKIP: 3598c2ecf20Sopenharmony_ci pr_debug("- MATCH_JUMP\n"); 3608c2ecf20Sopenharmony_ci if (unlikely(jsp == NR_JUMP_STACK)) 3618c2ecf20Sopenharmony_ci goto jump_stack_overflow; 3628c2ecf20Sopenharmony_ci jump_stack[jsp++] = pc + asn1_op_lengths[op]; 3638c2ecf20Sopenharmony_ci pc = machine[pc + 2]; 3648c2ecf20Sopenharmony_ci goto next_op; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci case ASN1_OP_COND_FAIL: 3678c2ecf20Sopenharmony_ci if (unlikely(!(flags & FLAG_MATCHED))) 3688c2ecf20Sopenharmony_ci goto tag_mismatch; 3698c2ecf20Sopenharmony_ci pc += asn1_op_lengths[op]; 3708c2ecf20Sopenharmony_ci goto next_op; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci case ASN1_OP_COMPLETE: 3738c2ecf20Sopenharmony_ci if (unlikely(jsp != 0 || csp != 0)) { 3748c2ecf20Sopenharmony_ci pr_err("ASN.1 decoder error: Stacks not empty at completion (%u, %u)\n", 3758c2ecf20Sopenharmony_ci jsp, csp); 3768c2ecf20Sopenharmony_ci return -EBADMSG; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci case ASN1_OP_END_SET: 3818c2ecf20Sopenharmony_ci case ASN1_OP_END_SET_ACT: 3828c2ecf20Sopenharmony_ci if (unlikely(!(flags & FLAG_MATCHED))) 3838c2ecf20Sopenharmony_ci goto tag_mismatch; 3848c2ecf20Sopenharmony_ci /* fall through */ 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci case ASN1_OP_END_SEQ: 3878c2ecf20Sopenharmony_ci case ASN1_OP_END_SET_OF: 3888c2ecf20Sopenharmony_ci case ASN1_OP_END_SEQ_OF: 3898c2ecf20Sopenharmony_ci case ASN1_OP_END_SEQ_ACT: 3908c2ecf20Sopenharmony_ci case ASN1_OP_END_SET_OF_ACT: 3918c2ecf20Sopenharmony_ci case ASN1_OP_END_SEQ_OF_ACT: 3928c2ecf20Sopenharmony_ci if (unlikely(csp <= 0)) 3938c2ecf20Sopenharmony_ci goto cons_stack_underflow; 3948c2ecf20Sopenharmony_ci csp--; 3958c2ecf20Sopenharmony_ci tdp = cons_dp_stack[csp]; 3968c2ecf20Sopenharmony_ci hdr = cons_hdrlen_stack[csp]; 3978c2ecf20Sopenharmony_ci len = datalen; 3988c2ecf20Sopenharmony_ci datalen = cons_datalen_stack[csp]; 3998c2ecf20Sopenharmony_ci pr_debug("- end cons t=%zu dp=%zu l=%zu/%zu\n", 4008c2ecf20Sopenharmony_ci tdp, dp, len, datalen); 4018c2ecf20Sopenharmony_ci if (datalen == 0) { 4028c2ecf20Sopenharmony_ci /* Indefinite length - check for the EOC. */ 4038c2ecf20Sopenharmony_ci datalen = len; 4048c2ecf20Sopenharmony_ci if (unlikely(datalen - dp < 2)) 4058c2ecf20Sopenharmony_ci goto data_overrun_error; 4068c2ecf20Sopenharmony_ci if (data[dp++] != 0) { 4078c2ecf20Sopenharmony_ci if (op & ASN1_OP_END__OF) { 4088c2ecf20Sopenharmony_ci dp--; 4098c2ecf20Sopenharmony_ci csp++; 4108c2ecf20Sopenharmony_ci pc = machine[pc + 1]; 4118c2ecf20Sopenharmony_ci pr_debug("- continue\n"); 4128c2ecf20Sopenharmony_ci goto next_op; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci goto missing_eoc; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci if (data[dp++] != 0) 4178c2ecf20Sopenharmony_ci goto invalid_eoc; 4188c2ecf20Sopenharmony_ci len = dp - tdp - 2; 4198c2ecf20Sopenharmony_ci } else { 4208c2ecf20Sopenharmony_ci if (dp < len && (op & ASN1_OP_END__OF)) { 4218c2ecf20Sopenharmony_ci datalen = len; 4228c2ecf20Sopenharmony_ci csp++; 4238c2ecf20Sopenharmony_ci pc = machine[pc + 1]; 4248c2ecf20Sopenharmony_ci pr_debug("- continue\n"); 4258c2ecf20Sopenharmony_ci goto next_op; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci if (dp != len) 4288c2ecf20Sopenharmony_ci goto cons_length_error; 4298c2ecf20Sopenharmony_ci len -= tdp; 4308c2ecf20Sopenharmony_ci pr_debug("- cons len l=%zu d=%zu\n", len, dp - tdp); 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (op & ASN1_OP_END__ACT) { 4348c2ecf20Sopenharmony_ci unsigned char act; 4358c2ecf20Sopenharmony_ci if (op & ASN1_OP_END__OF) 4368c2ecf20Sopenharmony_ci act = machine[pc + 2]; 4378c2ecf20Sopenharmony_ci else 4388c2ecf20Sopenharmony_ci act = machine[pc + 1]; 4398c2ecf20Sopenharmony_ci ret = actions[act](context, hdr, 0, data + tdp, len); 4408c2ecf20Sopenharmony_ci if (ret < 0) 4418c2ecf20Sopenharmony_ci return ret; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci pc += asn1_op_lengths[op]; 4448c2ecf20Sopenharmony_ci goto next_op; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci case ASN1_OP_MAYBE_ACT: 4478c2ecf20Sopenharmony_ci if (!(flags & FLAG_LAST_MATCHED)) { 4488c2ecf20Sopenharmony_ci pc += asn1_op_lengths[op]; 4498c2ecf20Sopenharmony_ci goto next_op; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci /* fall through */ 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci case ASN1_OP_ACT: 4548c2ecf20Sopenharmony_ci ret = actions[machine[pc + 1]](context, hdr, tag, data + tdp, len); 4558c2ecf20Sopenharmony_ci if (ret < 0) 4568c2ecf20Sopenharmony_ci return ret; 4578c2ecf20Sopenharmony_ci pc += asn1_op_lengths[op]; 4588c2ecf20Sopenharmony_ci goto next_op; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci case ASN1_OP_RETURN: 4618c2ecf20Sopenharmony_ci if (unlikely(jsp <= 0)) 4628c2ecf20Sopenharmony_ci goto jump_stack_underflow; 4638c2ecf20Sopenharmony_ci pc = jump_stack[--jsp]; 4648c2ecf20Sopenharmony_ci flags |= FLAG_MATCHED | FLAG_LAST_MATCHED; 4658c2ecf20Sopenharmony_ci goto next_op; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci default: 4688c2ecf20Sopenharmony_ci break; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* Shouldn't reach here */ 4728c2ecf20Sopenharmony_ci pr_err("ASN.1 decoder error: Found reserved opcode (%u) pc=%zu\n", 4738c2ecf20Sopenharmony_ci op, pc); 4748c2ecf20Sopenharmony_ci return -EBADMSG; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cidata_overrun_error: 4778c2ecf20Sopenharmony_ci errmsg = "Data overrun error"; 4788c2ecf20Sopenharmony_ci goto error; 4798c2ecf20Sopenharmony_cimachine_overrun_error: 4808c2ecf20Sopenharmony_ci errmsg = "Machine overrun error"; 4818c2ecf20Sopenharmony_ci goto error; 4828c2ecf20Sopenharmony_cijump_stack_underflow: 4838c2ecf20Sopenharmony_ci errmsg = "Jump stack underflow"; 4848c2ecf20Sopenharmony_ci goto error; 4858c2ecf20Sopenharmony_cijump_stack_overflow: 4868c2ecf20Sopenharmony_ci errmsg = "Jump stack overflow"; 4878c2ecf20Sopenharmony_ci goto error; 4888c2ecf20Sopenharmony_cicons_stack_underflow: 4898c2ecf20Sopenharmony_ci errmsg = "Cons stack underflow"; 4908c2ecf20Sopenharmony_ci goto error; 4918c2ecf20Sopenharmony_cicons_stack_overflow: 4928c2ecf20Sopenharmony_ci errmsg = "Cons stack overflow"; 4938c2ecf20Sopenharmony_ci goto error; 4948c2ecf20Sopenharmony_cicons_length_error: 4958c2ecf20Sopenharmony_ci errmsg = "Cons length error"; 4968c2ecf20Sopenharmony_ci goto error; 4978c2ecf20Sopenharmony_cimissing_eoc: 4988c2ecf20Sopenharmony_ci errmsg = "Missing EOC in indefinite len cons"; 4998c2ecf20Sopenharmony_ci goto error; 5008c2ecf20Sopenharmony_ciinvalid_eoc: 5018c2ecf20Sopenharmony_ci errmsg = "Invalid length EOC"; 5028c2ecf20Sopenharmony_ci goto error; 5038c2ecf20Sopenharmony_cilength_too_long: 5048c2ecf20Sopenharmony_ci errmsg = "Unsupported length"; 5058c2ecf20Sopenharmony_ci goto error; 5068c2ecf20Sopenharmony_ciindefinite_len_primitive: 5078c2ecf20Sopenharmony_ci errmsg = "Indefinite len primitive not permitted"; 5088c2ecf20Sopenharmony_ci goto error; 5098c2ecf20Sopenharmony_citag_mismatch: 5108c2ecf20Sopenharmony_ci errmsg = "Unexpected tag"; 5118c2ecf20Sopenharmony_ci goto error; 5128c2ecf20Sopenharmony_cilong_tag_not_supported: 5138c2ecf20Sopenharmony_ci errmsg = "Long tag not supported"; 5148c2ecf20Sopenharmony_cierror: 5158c2ecf20Sopenharmony_ci pr_debug("\nASN1: %s [m=%zu d=%zu ot=%02x t=%02x l=%zu]\n", 5168c2ecf20Sopenharmony_ci errmsg, pc, dp, optag, tag, len); 5178c2ecf20Sopenharmony_ci return -EBADMSG; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(asn1_ber_decoder); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 522