1 #include "decode.h"
2
3 #include <errno.h>
4 #include "common.h"
5 #include "config.h"
6 #include "log.h"
7 #include "incidence/incidence.h"
8
9 #define COND_LOG(log, pr) (log ? pr : -EINVAL)
10
11 /* Decoded BER data */
12 struct ber_data {
13 const unsigned char *src;
14 size_t src_size;
15 size_t consumed;
16 };
17
18 static int
validate(asn_TYPE_descriptor_t const * descriptor,void * result,bool log)19 validate(asn_TYPE_descriptor_t const *descriptor, void *result, bool log)
20 {
21 char error_msg[256];
22 size_t error_msg_size;
23 int error;
24
25 /* The lib's inbuilt validations. (Probably not much.) */
26 error_msg_size = sizeof(error_msg);
27 error = asn_check_constraints(descriptor, result, error_msg,
28 &error_msg_size);
29 if (error == -1)
30 return COND_LOG(log,
31 pr_val_err("Error validating ASN.1 object: %s", error_msg));
32
33 return 0;
34 }
35
36 static int
der_coder(const void * buf,size_t size,void * app_key)37 der_coder(const void *buf, size_t size, void *app_key)
38 {
39 struct ber_data *data = app_key;
40
41 if (data->consumed + size > data->src_size) {
42 pr_val_debug("DER encoding will consume more bytes than expected (expected %lu, will get %lu)",
43 data->consumed + size, data->src_size);
44 return -1;
45 }
46
47 if (memcmp(data->src + data->consumed, buf, size) != 0)
48 return -1;
49
50 data->consumed += size;
51 return 0;
52 }
53
54 /*
55 * TODO (performance) This isn't efficient, consider implement DER decoding
56 * or something better.
57 */
58 static int
validate_der(size_t ber_consumed,asn_TYPE_descriptor_t const * descriptor,const void * original,void * result)59 validate_der(size_t ber_consumed, asn_TYPE_descriptor_t const *descriptor,
60 const void *original, void *result)
61 {
62 struct ber_data data;
63 asn_enc_rval_t eval;
64
65 data.src = (unsigned char *) original;
66 data.src_size = ber_consumed;
67 data.consumed = 0;
68
69 eval = der_encode(descriptor, result, der_coder, &data);
70 if (eval.encoded == -1)
71 return incidence(INID_OBJ_NOT_DER,
72 "'%s' isn't DER encoded", eval.failed_type->name);
73
74 if (ber_consumed != eval.encoded) {
75 pr_val_debug("DER encoding consumed less bytes than expected (expected %lu, got %lu)",
76 ber_consumed, eval.encoded);
77 return incidence(INID_OBJ_NOT_DER, "'%s' isn't DER encoded",
78 descriptor->name);
79 }
80
81 return 0;
82 }
83
84 int
asn1_decode(const void * buffer,size_t buffer_size,asn_TYPE_descriptor_t const * descriptor,void ** result,bool log,bool dec_as_der)85 asn1_decode(const void *buffer, size_t buffer_size,
86 asn_TYPE_descriptor_t const *descriptor, void **result, bool log,
87 bool dec_as_der)
88 {
89 asn_codec_ctx_t s_codec_ctx;
90 asn_dec_rval_t rval;
91 int error;
92
93 *result = NULL;
94 s_codec_ctx.max_stack_size = config_get_asn1_decode_max_stack();
95
96 rval = ber_decode(&s_codec_ctx, descriptor, result, buffer,
97 buffer_size);
98 if (rval.code != RC_OK) {
99 /* Must free partial object according to API contracts. */
100 ASN_STRUCT_FREE(*descriptor, *result);
101 /* We expect the data to be complete; RC_WMORE is an error. */
102 return COND_LOG(log,
103 pr_val_err("Error '%u' decoding ASN.1 object around byte %zu",
104 rval.code, rval.consumed));
105 }
106
107 /* Validate DER encoding, only if wanted and incidence isn't ignored */
108 if (dec_as_der &&
109 incidence_get_action(INID_OBJ_NOT_DER) != INAC_IGNORE) {
110 error = validate_der(rval.consumed, descriptor, buffer,
111 *result);
112 if (error) {
113 ASN_STRUCT_FREE(*descriptor, *result);
114 return error;
115 }
116 }
117
118 error = validate(descriptor, *result, log);
119 if (error) {
120 ASN_STRUCT_FREE(*descriptor, *result);
121 return error;
122 }
123
124 return 0;
125 }
126
127 int
asn1_decode_any(ANY_t * any,asn_TYPE_descriptor_t const * descriptor,void ** result,bool log,bool dec_as_der)128 asn1_decode_any(ANY_t *any, asn_TYPE_descriptor_t const *descriptor,
129 void **result, bool log, bool dec_as_der)
130 {
131 return asn1_decode(any->buf, any->size, descriptor, result, log,
132 dec_as_der);
133 }
134
135 int
asn1_decode_octet_string(OCTET_STRING_t * string,asn_TYPE_descriptor_t const * descriptor,void ** result,bool log,bool dec_as_der)136 asn1_decode_octet_string(OCTET_STRING_t *string,
137 asn_TYPE_descriptor_t const *descriptor, void **result, bool log,
138 bool dec_as_der)
139 {
140 return asn1_decode(string->buf, string->size, descriptor, result, log,
141 dec_as_der);
142 }
143
144 /*
145 * TODO (next iteration) There's no need to load the entire file into memory.
146 * ber_decode() can take an incomplete buffer, in which case it returns
147 * RC_WMORE.
148 */
149 int
asn1_decode_fc(struct file_contents * fc,asn_TYPE_descriptor_t const * descriptor,void ** result,bool log,bool dec_as_der)150 asn1_decode_fc(struct file_contents *fc,
151 asn_TYPE_descriptor_t const *descriptor, void **result, bool log,
152 bool dec_as_der)
153 {
154 return asn1_decode(fc->buffer, fc->buffer_size, descriptor, result,
155 log, dec_as_der);
156 }
157