1 #include "state.h"
2
3 #include <errno.h>
4 #include "rrdp/db/db_rrdp.h"
5 #include "log.h"
6 #include "thread_var.h"
7
8 /**
9 * The current state of the validation cycle.
10 *
11 * It is one of the core objects in this project. Every time a trust anchor
12 * triggers a validation cycle, the validator creates one of these objects and
13 * uses it to traverse the tree and keep track of validated data.
14 */
15 struct validation {
16 struct tal *tal;
17
18 struct x509_data {
19 /** https://www.openssl.org/docs/man1.1.1/man3/X509_STORE_load_locations.html */
20 X509_STORE *store;
21 X509_VERIFY_PARAM *params;
22 } x509_data;
23
24 struct cert_stack *certstack;
25
26 struct uri_list *rsync_visited_uris;
27
28 /* Local RRDP workspace path */
29 char const *rrdp_workspace;
30
31 /* Shallow copy of RRDP URIs and its corresponding visited uris */
32 struct db_rrdp_uri *rrdp_uris;
33
34 /* Did the TAL's public key match the root certificate's public key? */
35 enum pubkey_state pubkey_state;
36
37 /**
38 * Two buffers calling code will store stringified IP addresses in,
39 * to prevent proliferation of similar buffers on the stack.
40 *
41 * They are meant to be large enough to contain both IPv4 and IPv6
42 * addresses.
43 */
44 char addr_buffer1[INET6_ADDRSTRLEN];
45 char addr_buffer2[INET6_ADDRSTRLEN];
46
47 struct validation_handler validation_handler;
48 };
49
50 /*
51 * It appears that this function is called by LibreSSL whenever it finds an
52 * error while validating.
53 * It is expected to return "okay" status: Nonzero if the error should be
54 * ignored, zero if the error is grounds to abort the validation.
55 *
56 * Note to myself: During my tests, this function was called in
57 * X509_verify_cert(ctx) -> check_chain_extensions(0, ctx),
58 * and then twice again in
59 * X509_verify_cert(ctx) -> internal_verify(1, ctx).
60 *
61 * Regarding the ok argument: I'm not 100% sure that I get it; I don't
62 * understand why this function would be called with ok = 1.
63 * http://openssl.cs.utah.edu/docs/crypto/X509_STORE_CTX_set_verify_cb.html
64 * The logic I implemented is the same as the second example: Always ignore the
65 * error that's troubling the library, otherwise try to be as unintrusive as
66 * possible.
67 */
68 static int
cb(int ok,X509_STORE_CTX * ctx)69 cb(int ok, X509_STORE_CTX *ctx)
70 {
71 int error;
72
73 /*
74 * We need to handle two new critical extensions (IP Resources and ASN
75 * Resources), so unknown critical extensions are fine as far as
76 * LibreSSL is concerned.
77 * Unfortunately, LibreSSL has no way of telling us *which* is the
78 * unknown critical extension, but since RPKI defines its own set of
79 * valid extensions, we'll have to figure it out later anyway.
80 */
81 error = X509_STORE_CTX_get_error(ctx);
82 return (error == X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION) ? 1 : ok;
83 }
84
85 /**
86 * Creates a struct validation, puts it in thread local, and (incidentally)
87 * returns it.
88 */
89 int
validation_prepare(struct validation ** out,struct tal * tal,struct validation_handler * validation_handler)90 validation_prepare(struct validation **out, struct tal *tal,
91 struct validation_handler *validation_handler)
92 {
93 struct validation *result;
94 X509_VERIFY_PARAM *params;
95 int error;
96
97 result = malloc(sizeof(struct validation));
98 if (!result)
99 return pr_enomem();
100
101 error = state_store(result);
102 if (error)
103 goto abort1;
104
105 result->tal = tal;
106
107 result->x509_data.store = X509_STORE_new();
108 if (!result->x509_data.store) {
109 error = val_crypto_err("X509_STORE_new() returned NULL");
110 goto abort1;
111 }
112
113 params = X509_VERIFY_PARAM_new();
114 if (params == NULL) {
115 error = pr_enomem();
116 goto abort2;
117 }
118
119 X509_VERIFY_PARAM_set_flags(params, X509_V_FLAG_CRL_CHECK);
120 X509_STORE_set1_param(result->x509_data.store, params);
121 X509_STORE_set_verify_cb(result->x509_data.store, cb);
122
123 error = certstack_create(&result->certstack);
124 if (error)
125 goto abort3;
126
127 error = rsync_create(&result->rsync_visited_uris);
128 if (error)
129 goto abort4;
130
131 result->rrdp_uris = db_rrdp_get_uris(tal_get_file_name(tal));
132 result->rrdp_workspace = db_rrdp_get_workspace(tal_get_file_name(tal));
133
134 result->pubkey_state = PKS_UNTESTED;
135 result->validation_handler = *validation_handler;
136 result->x509_data.params = params; /* Ownership transfered */
137
138 *out = result;
139 return 0;
140 abort4:
141 certstack_destroy(result->certstack);
142 abort3:
143 X509_VERIFY_PARAM_free(params);
144 abort2:
145 X509_STORE_free(result->x509_data.store);
146 abort1:
147 free(result);
148 return error;
149 }
150
151 void
validation_destroy(struct validation * state)152 validation_destroy(struct validation *state)
153 {
154 X509_VERIFY_PARAM_free(state->x509_data.params);
155 X509_STORE_free(state->x509_data.store);
156 certstack_destroy(state->certstack);
157 rsync_destroy(state->rsync_visited_uris);
158 free(state);
159 }
160
161 struct tal *
validation_tal(struct validation * state)162 validation_tal(struct validation *state)
163 {
164 return state->tal;
165 }
166
167 X509_STORE *
validation_store(struct validation * state)168 validation_store(struct validation *state)
169 {
170 return state->x509_data.store;
171 }
172
173 struct cert_stack *
validation_certstack(struct validation * state)174 validation_certstack(struct validation *state)
175 {
176 return state->certstack;
177 }
178
179 struct uri_list *
validation_rsync_visited_uris(struct validation * state)180 validation_rsync_visited_uris(struct validation *state)
181 {
182 return state->rsync_visited_uris;
183 }
184
185 void
validation_pubkey_valid(struct validation * state)186 validation_pubkey_valid(struct validation *state)
187 {
188 state->pubkey_state = PKS_VALID;
189 }
190
191 void
validation_pubkey_invalid(struct validation * state)192 validation_pubkey_invalid(struct validation *state)
193 {
194 state->pubkey_state = PKS_INVALID;
195 }
196
197 enum pubkey_state
validation_pubkey_state(struct validation * state)198 validation_pubkey_state(struct validation *state)
199 {
200 return state->pubkey_state;
201 }
202
203 char *
validation_get_ip_buffer1(struct validation * state)204 validation_get_ip_buffer1(struct validation *state)
205 {
206 return state->addr_buffer1;
207 }
208
209 char *
validation_get_ip_buffer2(struct validation * state)210 validation_get_ip_buffer2(struct validation *state)
211 {
212 return state->addr_buffer2;
213 }
214
215 struct validation_handler const *
validation_get_validation_handler(struct validation * state)216 validation_get_validation_handler(struct validation *state)
217 {
218 return &state->validation_handler;
219 }
220
221 struct db_rrdp_uri *
validation_get_rrdp_uris(struct validation * state)222 validation_get_rrdp_uris(struct validation *state)
223 {
224 return state->rrdp_uris;
225 }
226
227 char const *
validation_get_rrdp_workspace(struct validation * state)228 validation_get_rrdp_workspace(struct validation *state)
229 {
230 return state->rrdp_workspace;
231 }
232