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