1//
2// der_vm.h
3// CoreEntitlements
4//
5
6#ifndef CORE_ENTITLEMENTS_DER_VM_H
7#define CORE_ENTITLEMENTS_DER_VM_H
8
9#include <CoreEntitlements/CoreEntitlements.h>
10#include <stdint.h>
11#include <stdbool.h>
12
13__ptrcheck_abi_assume_single();
14
15// The kernel doesn't have access to this one
16#if __has_include (<corecrypto/ccder.h>)
17#include <corecrypto/ccder.h>
18#else
19typedef unsigned long ccder_tag;
20#endif
21
22
23/*!
24 * @typedef der_vm_context_t
25 * Represents the current execution state of the DERQL interpreter.
26 * The context can be initialized with der_vm_context_create and subsequently used in invocations of der_vm_execute.
27 * This object is passed by value and the functions that operate on the der_vm_context_t do not modify it but instead return a copy.
28 * As a consequence, the state of the interpreter can be captured at any execution point by holding on to the context.
29 */
30typedef struct der_vm_context {
31 CERuntime_t runtime;
32#if CE_ACCELERATION_SUPPORTED
33 struct CEAccelerationContext lookup;
34#endif
35 ccder_tag dictionary_tag;
36 bool sorted;
37 bool valid;
38 union {
39 // the one you should use
40 ccder_read_blob ccstate;
41
42 // for compatibility
43 struct {
44 const uint8_t *__ended_by(der_end) der_start;
45 const uint8_t *der_end;
46 } state;
47 };
48} der_vm_context_t;
49
50/*!
51 * @function der_vm_context_create
52 * Returns an initialized, valid, der_vm_context_t against which query operations may be performed
53 * @param rt
54 * Active runtime
55 * @param dictionary_tag
56 * Which DER tag should be used when matching dictionaries
57 * @param sorted_keys
58 * Whether the VM can assume that the keys are sorted
59 * @param der
60 * Pointer to the start of a DER object
61 * @param der_end
62 * Pointer to one byte past the end of the DER object
63 * @discussion
64 * The caller must ensure that the memory pointed to by der remains valid as long as the der_vm_context_t is used.
65 * The caller must ensure that the DER object has been validated.
66 */
67der_vm_context_t der_vm_context_create(const CERuntime_t rt, ccder_tag dictionary_tag, bool sorted_keys, const uint8_t *__ended_by(der_end) der, const uint8_t *der_end);
68
69/*!
70 * @function der_vm_execute
71 * Returns a new context that is derived by applying the op to the passed in context
72 *
73 * @param context
74 * Context to execute against
75 *
76 * @param op
77 * An operation to be performed against the context
78 * This op should be created by one of the CEMatch* or CESelect* functions
79 *
80 * @discussion
81 * If the VM encounters:
82 * 1. Invalid operation
83 * 2. An operation that fails to execute
84 * 3. Invalid state
85 * The VM will attempt to return an invalid context.
86 * If the VM encounters an operation that it does not understand, the runtime's abort function will be executed.
87 */
88der_vm_context_t der_vm_execute(const der_vm_context_t context, CEQueryOperation_t op);
89
90/*!
91 * @function der_vm_execute_nocopy
92 * Returns a new context that is derived by applying the op to the passed in context
93 *
94 * @param context
95 * Context to execute against
96 *
97 * @param op
98 * An operation to be performed against the context
99 * This op should be created by one of the CEMatch* or CESelect* functions
100 * The operation may be modified after execution and should not be re-used
101 *
102 * @discussion
103 * If the VM encounters:
104 * 1. Invalid operation
105 * 2. An operation that fails to execute
106 * 3. Invalid state
107 * The VM will attempt to return an invalid context.
108 * If the VM encounters an operation that it does not understand, the runtime's abort function will be executed.
109 */
110der_vm_context_t der_vm_execute_nocopy(const der_vm_context_t context, const CEQueryOperation_t* op);
111
112/*!
113 * @function der_vm_execute_seq_nocopy
114 * Returns a new context that is derived by applying the operation sequence to the passed in context
115 *
116 * @param context
117 * Context to execute against
118 *
119 * @param query
120 * Operations to be performed against the context, see der_vm_execute_nocopy for more
121 *
122 * @param queryLength
123 * Number of operations in the query
124 *
125 */
126der_vm_context_t der_vm_execute_seq_nocopy(const der_vm_context_t context, const CEQueryOperation_t *__counted_by(queryLength) query, size_t queryLength);
127
128/*!
129 * @typedef der_vm_iteration_context
130 * Iteration context that gets passed in on every call
131 *
132 * @field original
133 * The original DER VM context (the container over which we are iterating)
134 *
135 * @field active
136 * The actively selected DER VM context (i.e. the value)
137 *
138 * @field parent_type
139 * The type of object being iterated over (dictionary or array)
140 *
141 * @field active_type
142 * The type of the selected object
143 *
144 * @field user_data
145 * The object you passed in the call to der_vm_iterate
146 */
147typedef struct {
148 der_vm_context_t original;
149 der_vm_context_t active;
150 CEType_t parent_type;
151 CEType_t active_type;
152 void* user_data;
153} der_vm_iteration_context;
154
155/*!
156 * @typedef der_vm_iteration_callback
157 *
158 * @brief Function definition for the callback that der_vm_iterate uses
159 *
160 * @param ctx The information about the iterable is stored here
161 */
162typedef bool (*der_vm_iteration_callback)(der_vm_iteration_context ctx);
163
164
165
166/*!
167 * @function der_vm_iterate
168 * @brief Iterates over a DER container, caliing the callback for every element
169 *
170 * @param context The context that points to a container
171 * @param user_data This will be passed in verbatim in the der_vm_iteration_context
172 * @param callback This function is called for every element
173 *
174 * @returns kCENoError if the function exited normally
175 */
176CEError_t der_vm_iterate(const der_vm_context_t context, void* user_data, der_vm_iteration_callback callback);
177
178#ifdef __BLOCKS__
179/*!
180 * @typedef der_vm_iteration_block
181 *
182 * @brief Function definition for the callback that der_vm_iterate_b uses
183 *
184 * @param ctx The information about the iterable is stored here, you may modify it
185 */
186typedef bool (^der_vm_iteration_block)(der_vm_iteration_context* ctx);
187
188/*!
189 * @function der_vm_iterate_b
190 * @brief Iterates over a DER container, calling the block for every element
191 * @note dev_vm_iterate is implemented using the block interface. Using this function directly is more efficient.
192 * @param context The context that points to a container
193 * @param callback This block is called for every element
194 *
195 * @returns kCENoError if the function exited normally
196 */
197CEError_t der_vm_iterate_b(const der_vm_context_t* context, der_vm_iteration_block callback);
198#endif
199
200/*!
201 * @function der_vm_context_is_valid
202 * Returns a boolean indication if a particular context is valid
203 *
204 * @param context
205 * The context in question
206 *
207 * @discussion
208 * It is generally safe to execute any operation against an invalid context
209 * However the resulting context will also be invalid
210 */
211bool der_vm_context_is_valid(const der_vm_context_t context);
212
213/*!
214 * @function der_vm_CEType_from_context
215 * Returns a CEType_t corresponding to the item currently pointed to by the context's DER state
216 *
217 * @param context
218 * The context in question
219 * @param tag
220 * Nullable pointer to where to store the decoded DER tag
221 */
222CEType_t der_vm_CEType_from_context(const der_vm_context_t context, ccder_tag* tag);
223
224/*!
225 * @function der_vm_CEType_from_ccder_tag
226 * Returns a CEType_t corresponding to the tag value, without touching the context's DER state
227 *
228 * @param context
229 * The context in question
230 * @param tag
231 * Nullable pointer to where to store the decoded DER tag
232 */
233CEType_t der_vm_CEType_from_ccder_tag(const der_vm_context_t context, ccder_tag tag);
234
235/*!
236 * @function der_vm_integer_from_context
237 * Returns the number selected by the current context
238 */
239int64_t der_vm_integer_from_context(const der_vm_context_t context);
240
241/*!
242 * @function der_vm_string_from_context
243 * Returns the string selected by the current context
244 */
245CEBuffer der_vm_string_from_context(const der_vm_context_t context);
246
247/*!
248 * @function der_vm_bool_from_context
249 * Returns the bool selected by the current context
250 */
251bool der_vm_bool_from_context(const der_vm_context_t context);
252
253/*!
254 * @function der_vm_data_from_context
255 * Returns the data selected by the current context
256 */
257CEBuffer der_vm_data_from_context(const der_vm_context_t context);
258
259/*!
260 * @function der_vm_buffer_from_context
261 * Returns the content described by the tag in the context
262 */
263CEBuffer der_vm_buffer_from_context(const der_vm_context_t context);
264
265/*!
266 * @function CEBuffer_cmp
267 * Does a memcmp like match between two CEBuffers
268 */
269int CEBuffer_cmp(const CEBuffer left, const CEBuffer right);
270
271#endif
272