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