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