Line data Source code
1 : #include "../burp.h"
2 : #include "../alloc.h"
3 : #include "../asfd.h"
4 : #include "../async.h"
5 : #include "../cmd.h"
6 : #include "../conf.h"
7 : #include "../conffile.h"
8 : #include "../fsops.h"
9 : #include "../handy.h"
10 : #include "../iobuf.h"
11 : #include "../log.h"
12 : #include "../run_script.h"
13 : #include "auth.h"
14 : #include "ca.h"
15 :
16 : static int setup_stuff_done=0;
17 :
18 0 : static char *get_ca_dir(const char *ca_conf)
19 : {
20 0 : struct fzp *fzp=NULL;
21 0 : char buf[4096]="";
22 0 : char *ca_dir=NULL;
23 0 : int r=0;
24 :
25 0 : if(!(fzp=fzp_open(ca_conf, "r")))
26 : goto end;
27 0 : while(fzp_gets(fzp, buf, sizeof(buf)))
28 : {
29 0 : char *field=NULL;
30 0 : char *value=NULL;
31 0 : if(conf_get_pair(buf, &field, &value, &r)
32 0 : || !field || !value) continue;
33 :
34 0 : if(!strcasecmp(field, "CA_DIR"))
35 : {
36 0 : if(!(ca_dir=strdup_w(value, __func__)))
37 : goto end;
38 0 : break;
39 : }
40 : }
41 : end:
42 0 : fzp_close(&fzp);
43 0 : return ca_dir;
44 : }
45 :
46 0 : static char *get_generated_crl_path(const char *ca_dir, const char *ca_name)
47 : {
48 0 : int flen=0;
49 0 : char *fname=NULL;
50 0 : char *crl_path=NULL;
51 :
52 0 : flen+=strlen(ca_name);
53 0 : flen+=strlen("CA_");
54 0 : flen+=strlen(".crl")+1;
55 0 : if(!(fname=(char *)malloc_w(flen, __func__)))
56 : goto end;
57 0 : snprintf(fname, flen, "CA_%s.crl", ca_name);
58 0 : crl_path=prepend_s(ca_dir, fname);
59 : end:
60 0 : free_w(&fname);
61 0 : return crl_path;
62 : }
63 :
64 0 : static char *get_crl_path(struct conf **confs,
65 : const char *ca_dir, const char *ca_name)
66 : {
67 : char *crl_path;
68 : // If the conf told us the path, use it.
69 0 : if((crl_path=get_string(confs[OPT_CA_CRL])))
70 0 : return strdup_w(crl_path, __func__);
71 :
72 : // Otherwise, build it ourselves.
73 0 : return get_generated_crl_path(ca_dir, ca_name);
74 : }
75 :
76 : static void remove_file(const char *path)
77 : {
78 0 : logp("Removing %s\n", path);
79 0 : unlink(path);
80 : }
81 :
82 0 : static int symlink_file(const char *oldpath, const char *newpath)
83 : {
84 : struct stat statp;
85 0 : logp("Symlinking %s to %s\n", newpath, oldpath);
86 0 : if(lstat(oldpath, &statp))
87 : {
88 0 : logp("Could not symlink: %s does not exist\n", oldpath);
89 0 : return -1;
90 : }
91 0 : if(symlink(oldpath, newpath))
92 : {
93 0 : logp("Could not symlink: %s does not exist\n", oldpath);
94 0 : return -1;
95 : }
96 : return 0;
97 : }
98 :
99 0 : static int ca_init(struct conf **confs, const char *ca_dir)
100 : {
101 0 : int a=0;
102 : const char *args[15];
103 0 : char linktarget[1024]="";
104 0 : const char *ca_name=get_string(confs[OPT_CA_NAME]);
105 0 : const char *ca_conf=get_string(confs[OPT_CA_CONF]);
106 0 : const char *ca_burp_ca=get_string(confs[OPT_CA_BURP_CA]);
107 0 : const char *ca_server_name=get_string(confs[OPT_CA_SERVER_NAME]);
108 0 : const char *ssl_cert=get_string(confs[OPT_SSL_CERT]);
109 0 : const char *ssl_cert_ca=get_string(confs[OPT_SSL_CERT_CA]);
110 0 : const char *ssl_key=get_string(confs[OPT_SSL_KEY]);
111 :
112 0 : if(is_dir_lstat(ca_dir)>0) return 0;
113 :
114 0 : setup_stuff_done++;
115 :
116 0 : logp("Initialising %s\n", ca_dir);
117 0 : logp("Running '%s --init --ca %s --dir %s --config %s'\n",
118 : ca_burp_ca, ca_name, ca_dir, ca_conf);
119 0 : args[a++]=ca_burp_ca;
120 0 : args[a++]="--init";
121 0 : args[a++]="--ca";
122 0 : args[a++]=ca_name;
123 0 : args[a++]="--dir";
124 0 : args[a++]=ca_dir;
125 0 : args[a++]="--config";
126 0 : args[a++]=ca_conf;
127 0 : args[a++]=NULL;
128 0 : if(run_script(NULL /* no async yet */, args, NULL, confs, 1 /* wait */,
129 : 0, 0 /* do not use logp - stupid openssl prints lots of dots
130 : one at a time with no way to turn it off */))
131 : {
132 0 : logp("Error running %s\n", ca_burp_ca);
133 0 : return -1;
134 : }
135 :
136 0 : logp("Generating server key and cert signing request\n");
137 0 : logp("Running '%s --key --request --name %s --dir %s --config %s'\n",
138 : ca_burp_ca, ca_server_name, ca_dir, ca_conf);
139 0 : a=0;
140 0 : args[a++]=ca_burp_ca;
141 0 : args[a++]="--key";
142 0 : args[a++]="--request";
143 0 : args[a++]="--name";
144 0 : args[a++]=ca_server_name;
145 0 : args[a++]="--dir";
146 0 : args[a++]=ca_dir;
147 0 : args[a++]="--config";
148 0 : args[a++]=ca_conf;
149 0 : args[a++]=NULL;
150 0 : if(run_script(NULL /* no async yet */, args, NULL, confs, 1 /* wait */,
151 : 0, 0 /* do not use logp - stupid openssl prints lots of dots
152 : one at a time with no way to turn it off */))
153 : {
154 0 : logp("Error running %s\n", ca_burp_ca);
155 0 : return -1;
156 : }
157 :
158 0 : logp("Signing request\n");
159 0 : logp("Running '%s --sign --ca %s --name %s --batch --dir %s --config %s'\n",
160 : ca_burp_ca, ca_name, ca_server_name, ca_dir, ca_conf);
161 0 : a=0;
162 0 : args[a++]=ca_burp_ca;
163 0 : args[a++]="--sign";
164 0 : args[a++]="--ca";
165 0 : args[a++]=ca_name;
166 0 : args[a++]="--name";
167 0 : args[a++]=ca_server_name;
168 0 : args[a++]="--batch";
169 0 : args[a++]="--dir";
170 0 : args[a++]=ca_dir;
171 0 : args[a++]="--config";
172 0 : args[a++]=ca_conf;
173 0 : args[a++]=NULL;
174 0 : if(run_script(NULL /* no async yet */, args, NULL, confs, 1 /* wait */,
175 : 0, 0 /* do not use logp - stupid openssl prints lots of dots
176 : one at a time with no way to turn it off */))
177 : {
178 0 : logp("Error running %s\n", ca_burp_ca);
179 0 : return -1;
180 : }
181 :
182 : snprintf(linktarget, sizeof(linktarget), "%s/CA_%s.crt",
183 : ca_dir, ca_name);
184 0 : if(strcmp(linktarget, ssl_cert_ca))
185 : {
186 : remove_file(ssl_cert_ca);
187 0 : if(symlink_file(linktarget, ssl_cert_ca)) return -1;
188 : }
189 :
190 : snprintf(linktarget, sizeof(linktarget), "%s/%s.crt",
191 : ca_dir, ca_server_name);
192 0 : if(strcmp(linktarget, ssl_cert))
193 : {
194 : remove_file(ssl_cert);
195 0 : if(symlink_file(linktarget, ssl_cert)) return -1;
196 : }
197 :
198 : snprintf(linktarget, sizeof(linktarget), "%s/%s.key",
199 : ca_dir, ca_server_name);
200 0 : if(strcmp(linktarget, ssl_key))
201 : {
202 : remove_file(ssl_key);
203 0 : if(symlink_file(linktarget, ssl_key)) return -1;
204 : }
205 :
206 : return 0;
207 : }
208 :
209 0 : static int maybe_make_dhfile(struct conf **confs, const char *ca_dir)
210 : {
211 0 : int a=0;
212 : const char *args[12];
213 : struct stat statp;
214 0 : const char *ca_burp_ca=get_string(confs[OPT_CA_BURP_CA]);
215 0 : const char *ssl_dhfile=get_string(confs[OPT_SSL_DHFILE]);
216 0 : if(!lstat(ssl_dhfile, &statp))
217 : return 0;
218 :
219 0 : setup_stuff_done++;
220 :
221 0 : logp("Creating %s\n", ssl_dhfile);
222 0 : logp("Running '%s --dhfile %s --dir %s'\n",
223 : ca_burp_ca, ssl_dhfile, ca_dir);
224 0 : a=0;
225 0 : args[a++]=ca_burp_ca;
226 0 : args[a++]="--dhfile";
227 0 : args[a++]=ssl_dhfile;
228 0 : args[a++]="--dir";
229 0 : args[a++]=ca_dir;
230 0 : args[a++]=NULL;
231 0 : if(run_script(NULL /* no async yet */, args, NULL, confs, 1 /* wait */,
232 : 0, 0 /* do not use logp - stupid openssl prints lots of dots
233 : one at a time with no way to turn it off */))
234 : {
235 0 : logp("Error running %s\n", ca_burp_ca);
236 0 : return -1;
237 : }
238 :
239 : return 0;
240 : }
241 :
242 0 : static int maybe_make_crl(struct conf **confs, const char *ca_dir,
243 : const char *ca_conf)
244 : {
245 0 : int a=0;
246 0 : int ret=-1;
247 : const char *args[12];
248 : struct stat statp;
249 0 : char *crl_path=NULL;
250 0 : const char *ca_name=get_string(confs[OPT_CA_NAME]);
251 0 : const char *ca_burp_ca=get_string(confs[OPT_CA_BURP_CA]);
252 0 : if(!ca_conf || !*ca_conf
253 0 : || !ca_burp_ca || !*ca_burp_ca
254 0 : || !ca_name || !*ca_name)
255 : return 0;
256 0 : if(!(crl_path=get_crl_path(confs, ca_dir, ca_name)))
257 : goto end;
258 0 : if(!lstat(crl_path, &statp))
259 : {
260 : ret=0;
261 : goto end;
262 : }
263 : // Create it even if we are not going to use it because of
264 : // OPT_CA_CRL_CHECK = 0.
265 :
266 0 : setup_stuff_done++;
267 :
268 0 : logp("Creating %s\n", crl_path);
269 0 : logp("Running '%s --name %s --config %s --dir %s --crl'\n",
270 : ca_burp_ca, ca_name, ca_conf, ca_dir);
271 0 : a=0;
272 0 : args[a++]=ca_burp_ca;
273 0 : args[a++]="--name";
274 0 : args[a++]=ca_name;
275 0 : args[a++]="--config";
276 0 : args[a++]=ca_conf;
277 0 : args[a++]="--dir";
278 0 : args[a++]=ca_dir;
279 0 : args[a++]="--crl";
280 0 : args[a++]=NULL;
281 0 : if(run_script(NULL /* no async yet */, args, NULL, confs, 1 /* wait */,
282 : 0, 0 /* do not use logp - stupid openssl prints lots of dots
283 : one at a time with no way to turn it off */))
284 : {
285 0 : logp("Error running %s\n", ca_burp_ca);
286 0 : return -1;
287 : }
288 : ret=0;
289 : end:
290 0 : free_w(&crl_path);
291 0 : return ret;
292 : }
293 :
294 0 : int ca_server_setup(struct conf **confs)
295 : {
296 0 : int ret=-1;
297 0 : char *ca_dir=NULL;
298 0 : const char *ca_conf=get_string(confs[OPT_CA_CONF]);
299 :
300 0 : if(!ca_conf)
301 : {
302 : ret=0;
303 : goto end;
304 : }
305 :
306 0 : if(!(ca_dir=get_ca_dir(ca_conf)))
307 : goto end;
308 :
309 0 : if(maybe_make_dhfile(confs, ca_dir))
310 : goto end;
311 :
312 0 : if(ca_init(confs, ca_dir))
313 : {
314 0 : recursive_delete(ca_dir);
315 0 : goto end;
316 : }
317 :
318 0 : if(maybe_make_crl(confs, ca_dir, ca_conf))
319 : goto end;
320 :
321 0 : ret=0;
322 : end:
323 0 : free_w(&ca_dir);
324 0 : if(setup_stuff_done)
325 : {
326 0 : if(ret) logp("CA setup failed\n");
327 0 : else logp("CA setup succeeded\n");
328 : }
329 0 : return ret;
330 : }
331 :
332 0 : static int check_path_does_not_exist(struct asfd *asfd,
333 : const char *client, const char *path)
334 : {
335 : struct stat statp;
336 0 : if(!lstat(path, &statp))
337 : {
338 0 : char msg[512]="";
339 : snprintf(msg, sizeof(msg), "Will not accept a client certificate request for '%s' - %s already exists!", client, path);
340 0 : log_and_send(asfd, msg);
341 : return -1;
342 : }
343 : return 0;
344 : }
345 :
346 : static int csr_done=0;
347 :
348 : // Return 0 for everything OK, signed and returned, -1 for error.
349 0 : static int sign_client_cert(struct asfd *asfd,
350 : const char *client, struct conf **confs)
351 : {
352 0 : int a=0;
353 0 : int ret=-1;
354 0 : char msg[256]="";
355 0 : char csrpath[512]="";
356 0 : char crtpath[512]="";
357 0 : char *ca_dir=NULL;
358 : const char *args[15];
359 0 : csr_done=0;
360 0 : const char *ca_name=get_string(confs[OPT_CA_NAME]);
361 0 : const char *ca_conf=get_string(confs[OPT_CA_CONF]);
362 0 : const char *ca_burp_ca=get_string(confs[OPT_CA_BURP_CA]);
363 0 : const char *ca_server_name=get_string(confs[OPT_CA_SERVER_NAME]);
364 0 : const char *ssl_cert_ca=get_string(confs[OPT_SSL_CERT_CA]);
365 0 : struct cntr *cntr=get_cntr(confs);
366 :
367 0 : if(!(ca_dir=get_ca_dir(ca_conf)))
368 : goto error;
369 :
370 0 : snprintf(csrpath, sizeof(csrpath), "%s/%s.csr", ca_dir, client);
371 0 : snprintf(crtpath, sizeof(crtpath), "%s/%s.crt", ca_dir, client);
372 :
373 0 : if(!strcmp(client, ca_name))
374 : {
375 0 : char msg[512]="";
376 : snprintf(msg, sizeof(msg), "Will not accept a client certificate request with the same name as the CA (%s)!", ca_name);
377 0 : log_and_send(asfd, msg);
378 : goto error;
379 : }
380 :
381 0 : if(check_path_does_not_exist(asfd, client, crtpath)
382 0 : || check_path_does_not_exist(asfd, client, csrpath))
383 : goto error;
384 :
385 : // Tell the client that we will do it, and send the server name at the
386 : // same time.
387 : snprintf(msg, sizeof(msg), "csr ok:%s", ca_server_name);
388 0 : if(asfd->write_str(asfd, CMD_GEN, msg))
389 : goto error;
390 :
391 : /* After this point, we might have uploaded files, so on error, go
392 : to end and delete any new files. */
393 :
394 : // Get the CSR from the client.
395 0 : if(receive_a_file(asfd, csrpath, cntr))
396 : goto del_files;
397 :
398 : // Now, sign it.
399 0 : logp("Signing certificate signing request from %s\n", client);
400 0 : logp("Running '%s --name %s --ca %s --sign --batch --dir %s --config %s'\n", ca_burp_ca, client, ca_name, ca_dir, ca_conf);
401 0 : a=0;
402 0 : args[a++]=ca_burp_ca;
403 0 : args[a++]="--name";
404 0 : args[a++]=client;
405 0 : args[a++]="--ca";
406 0 : args[a++]=ca_name;
407 0 : args[a++]="--sign";
408 0 : args[a++]="--batch";
409 0 : args[a++]="--dir";
410 0 : args[a++]=ca_dir;
411 0 : args[a++]="--config";
412 0 : args[a++]=ca_conf;
413 0 : args[a++]=NULL;
414 0 : if(run_script(asfd, args, NULL, confs, 1 /* wait */,
415 : 0, 0 /* do not use logp - stupid openssl prints lots of dots
416 : one at a time with no way to turn it off */))
417 : {
418 0 : logp("Error running %s\n", ca_burp_ca);
419 0 : goto del_files;
420 : }
421 :
422 : // Now, we should have a signed certificate.
423 : // Need to send it back to the client.
424 0 : if(send_a_file(asfd, crtpath, cntr))
425 : goto del_files;
426 :
427 : // Also need to send the CA public certificate back to the client.
428 0 : if(send_a_file(asfd, ssl_cert_ca, cntr))
429 : goto del_files;
430 :
431 0 : ret=0;
432 0 : csr_done++;
433 : del_files:
434 0 : if(ret<0)
435 : {
436 0 : unlink(crtpath);
437 0 : unlink(csrpath);
438 : }
439 : error:
440 0 : free_w(&ca_dir);
441 0 : return ret;
442 : }
443 :
444 3 : static enum asl_ret csr_server_func(struct asfd *asfd,
445 : struct conf **confs, void *param)
446 : {
447 : struct iobuf *rbuf;
448 : const char *ca_conf;
449 : const char **cname;
450 :
451 3 : rbuf=asfd->rbuf;
452 3 : cname=(const char **)param;
453 3 : ca_conf=get_string(confs[OPT_CA_CONF]);
454 :
455 3 : if(!strcmp(rbuf->buf, "csr"))
456 : {
457 : // Client wants to sign a certificate.
458 1 : logp("Client %s wants a certificate signed\n", *cname);
459 1 : if(!ca_conf)
460 : {
461 1 : logp("But server is not configured to sign client certificate requests.\n");
462 1 : logp("See option 'ca_conf'.\n");
463 1 : asfd->write_str(asfd, CMD_ERROR,
464 : "server not configured to sign client certificates");
465 1 : return ASL_END_ERROR;
466 : }
467 0 : if(sign_client_cert(asfd, *cname, confs))
468 : return ASL_END_ERROR;
469 0 : return ASL_END_OK;
470 : }
471 2 : else if(!strcmp(rbuf->buf, "nocsr"))
472 : {
473 : // Client does not want to sign a certificate.
474 : // No problem, just carry on.
475 1 : logp("Client %s does not want a certificate signed\n", *cname);
476 1 : if(asfd->write_str(asfd, CMD_GEN, "nocsr ok"))
477 : return ASL_END_ERROR;
478 1 : return ASL_END_OK;
479 : }
480 : else
481 : {
482 1 : iobuf_log_unexpected(rbuf, __func__);
483 1 : return ASL_END_ERROR;
484 : }
485 : }
486 :
487 : /* Return 1 for everything OK, signed and returned, -1 for error, 0 for
488 : nothing done. */
489 7 : int ca_server_maybe_sign_client_cert(struct asfd *asfd,
490 : struct conf **confs, struct conf **cconfs)
491 : {
492 7 : long min_ver=0;
493 7 : long cli_ver=0;
494 7 : const char *cname=NULL;
495 :
496 7 : if((min_ver=version_to_long("1.3.2"))<0
497 7 : || (cli_ver=version_to_long(get_string(cconfs[OPT_PEER_VERSION])))<0)
498 : return -1;
499 : // Clients before 1.3.2 did not know how to send cert signing requests.
500 7 : if(cli_ver<min_ver) return 0;
501 :
502 4 : if(!asfd)
503 : {
504 1 : logp("asfd not set up in %s\n", __func__);
505 1 : return -1;
506 : }
507 :
508 3 : cname=get_string(cconfs[OPT_CNAME]);
509 :
510 3 : if(asfd->simple_loop(asfd, confs, &cname, __func__, csr_server_func))
511 : return -1;
512 :
513 1 : return csr_done;
514 : }
515 :
516 0 : int ca_x509_verify_crl(struct conf **confs,
517 : X509 *peer_cert, const char *ssl_peer_cn)
518 : {
519 : int n;
520 : int i;
521 0 : int ret=-1;
522 0 : BIO *in=NULL;
523 0 : BIGNUM *bnser=NULL;
524 0 : X509_CRL *crl=NULL;
525 : X509_REVOKED *revoked;
526 0 : ASN1_INTEGER *serial=NULL;
527 0 : char *crl_path=NULL;
528 0 : char *ca_dir=NULL;
529 0 : const char *ca_name=get_string(confs[OPT_CA_NAME]);
530 0 : const char *ca_conf=get_string(confs[OPT_CA_CONF]);
531 0 : int crl_check=get_int(confs[OPT_CA_CRL_CHECK]);
532 :
533 0 : if(!crl_check)
534 : {
535 : ret=0;
536 : goto end;
537 : }
538 :
539 0 : if(!(ca_dir=get_ca_dir(ca_conf)))
540 : goto end;
541 :
542 0 : if(!ca_name || !*ca_name || !ca_dir)
543 : {
544 : ret=0;
545 : goto end;
546 : }
547 :
548 0 : if(!(crl_path=get_crl_path(confs, ca_dir, ca_name)))
549 : goto end;
550 :
551 0 : if(!(in=BIO_new_file(crl_path, "r")))
552 : {
553 0 : logp("CRL: cannot read: %s\n", crl_path);
554 0 : goto end;
555 : }
556 :
557 0 : if(!(crl=PEM_read_bio_X509_CRL(in, NULL, NULL, NULL)))
558 : {
559 0 : logp_ssl_err("CRL: cannot read CRL from file %s\n", crl_path);
560 0 : goto end;
561 : }
562 :
563 0 : if(X509_NAME_cmp(X509_CRL_get_issuer(crl),
564 0 : X509_get_issuer_name(peer_cert)))
565 : {
566 0 : logp_ssl_err("CRL: CRL %s is from a different issuer than the issuer of certificate %s\n", crl_path, ssl_peer_cn);
567 0 : goto end;
568 : }
569 :
570 0 : n=sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
571 0 : for(i=0; i<n; i++)
572 : {
573 0 : revoked=(X509_REVOKED *)
574 0 : sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
575 0 : if(!ASN1_INTEGER_cmp(
576 : #if OPENSSL_VERSION_NUMBER < 0x1010000fL || defined(LIBRESSL_VERSION_NUMBER)
577 0 : revoked->serialNumber,
578 : #else
579 : X509_REVOKED_get0_serialNumber(revoked),
580 : #endif
581 0 : X509_get_serialNumber(peer_cert)))
582 : {
583 0 : serial=X509_get_serialNumber(peer_cert);
584 0 : bnser=ASN1_INTEGER_to_BN(serial, NULL);
585 0 : logp_ssl_err("CRL check failed: %s (%s) is revoked\n",
586 : ssl_peer_cn,
587 : serial ? BN_bn2hex(bnser):"not available");
588 0 : goto end;
589 : }
590 : }
591 :
592 : ret=0;
593 : end:
594 0 : if(in) BIO_free(in);
595 0 : if(crl) X509_CRL_free(crl);
596 0 : free_w(&crl_path);
597 0 : free_w(&ca_dir);
598 0 : return ret;
599 : }
|