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