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