5 |
#include <regex.h> |
#include <regex.h> |
6 |
#include <string.h> |
#include <string.h> |
7 |
#include <stdlib.h> |
#include <stdlib.h> |
8 |
|
#include <ctype.h> |
9 |
#include <limits.h> |
#include <limits.h> |
10 |
#include <sys/stat.h> |
#include <sys/stat.h> |
11 |
#include <fcntl.h> |
#include <fcntl.h> |
15 |
#include "imapfilter.h" |
#include "imapfilter.h" |
16 |
#include "data.h" |
#include "data.h" |
17 |
|
|
18 |
|
#ifdef SSL_TLS |
19 |
|
#include <openssl/ssl.h> |
20 |
|
#include <openssl/x509.h> |
21 |
|
#include <openssl/pem.h> |
22 |
|
#endif |
23 |
|
|
24 |
|
|
25 |
extern char logfile[PATH_MAX]; |
extern char logfile[PATH_MAX]; |
26 |
extern unsigned int options; |
extern unsigned int options; |
553 |
} |
} |
554 |
if ((ds.st_mode & 00777) != mode) { |
if ((ds.st_mode & 00777) != mode) { |
555 |
error("warning: improper dir %s permissions\n", dname); |
error("warning: improper dir %s permissions\n", dname); |
556 |
error("warning: file's mode should be %o not %o\n", mode, |
error("warning: dir's mode should be %o not %o\n", mode, |
557 |
ds.st_mode & 00777); |
ds.st_mode & 00777); |
558 |
return ERROR_TRIVIAL; |
return ERROR_TRIVIAL; |
559 |
} |
} |
561 |
} |
} |
562 |
|
|
563 |
#endif /* CHECK_PERMISSIONS */ |
#endif /* CHECK_PERMISSIONS */ |
564 |
|
|
565 |
|
|
566 |
|
#ifdef SSL_TLS |
567 |
|
/* |
568 |
|
* Get SSL/TLS certificate check it, maybe ask user about it and act |
569 |
|
* accordingly. |
570 |
|
*/ |
571 |
|
int |
572 |
|
imf_ssl_cert(SSL * ssl) |
573 |
|
{ |
574 |
|
X509 *cert; |
575 |
|
unsigned char md[EVP_MAX_MD_SIZE]; |
576 |
|
unsigned int mdlen; |
577 |
|
|
578 |
|
mdlen = 0; |
579 |
|
|
580 |
|
if (!(cert = SSL_get_peer_certificate(ssl))) |
581 |
|
return ERROR_SSL; |
582 |
|
|
583 |
|
if (!(X509_digest(cert, EVP_md5(), md, &mdlen))) |
584 |
|
return ERROR_SSL; |
585 |
|
|
586 |
|
switch (imf_ssl_check_cert(cert, md, &mdlen)) { |
587 |
|
case SSL_CERT_NONEXISTENT: |
588 |
|
imf_ssl_print_cert(cert, md, &mdlen); |
589 |
|
if (imf_ssl_new_cert(cert) == SSL_CERT_ACTION_REJECT) |
590 |
|
goto abort; |
591 |
|
break; |
592 |
|
case SSL_CERT_MISMATCH: |
593 |
|
imf_ssl_print_cert(cert, md, &mdlen); |
594 |
|
if (imf_ssl_cert_mismatch() == SSL_CERT_ACTION_ABORT) |
595 |
|
goto abort; |
596 |
|
break; |
597 |
|
case SSL_CERT_OK: |
598 |
|
if (options & OPTION_DETAILS_VERBOSE) |
599 |
|
imf_ssl_print_cert(cert, md, &mdlen); |
600 |
|
} |
601 |
|
|
602 |
|
X509_free(cert); |
603 |
|
return 0; |
604 |
|
|
605 |
|
abort: |
606 |
|
X509_free(cert); |
607 |
|
return ERROR_SSL; |
608 |
|
} |
609 |
|
|
610 |
|
|
611 |
|
/* |
612 |
|
* Check if the SSL/TLS certificate exists in the certificates file. |
613 |
|
*/ |
614 |
|
int |
615 |
|
imf_ssl_check_cert(X509 * pcert, unsigned char *pmd, unsigned int *pmdlen) |
616 |
|
{ |
617 |
|
int r; |
618 |
|
FILE *fd; |
619 |
|
X509 *cert; |
620 |
|
unsigned char md[EVP_MAX_MD_SIZE]; |
621 |
|
unsigned int mdlen; |
622 |
|
char *cfn; |
623 |
|
|
624 |
|
r = SSL_CERT_NONEXISTENT; |
625 |
|
cert = NULL; |
626 |
|
cfn = ".imapfilter/certificates"; |
627 |
|
|
628 |
|
if (!exists_file(cfn)) |
629 |
|
return SSL_CERT_NONEXISTENT; |
630 |
|
|
631 |
|
fd = fopen(cfn, "r"); |
632 |
|
if (fd == NULL) |
633 |
|
return ERROR_FILE_OPEN; |
634 |
|
|
635 |
|
while ((cert = PEM_read_X509(fd, &cert, NULL, NULL)) != NULL) { |
636 |
|
if (X509_subject_name_cmp(cert, pcert) != 0 || |
637 |
|
X509_issuer_name_cmp(cert, pcert) != 0) |
638 |
|
continue; |
639 |
|
|
640 |
|
if (!X509_digest(cert, EVP_md5(), md, &mdlen) || |
641 |
|
*pmdlen != mdlen) |
642 |
|
continue; |
643 |
|
|
644 |
|
if (memcmp(pmd, md, mdlen) != 0) { |
645 |
|
r = SSL_CERT_MISMATCH; |
646 |
|
break; |
647 |
|
} |
648 |
|
r = SSL_CERT_OK; |
649 |
|
break; |
650 |
|
} |
651 |
|
|
652 |
|
fclose(fd); |
653 |
|
X509_free(cert); |
654 |
|
|
655 |
|
return r; |
656 |
|
} |
657 |
|
|
658 |
|
|
659 |
|
/* |
660 |
|
* Print information about the SSL/TLS certificate. |
661 |
|
*/ |
662 |
|
void |
663 |
|
imf_ssl_print_cert(X509 * cert, unsigned char *md, unsigned int *mdlen) |
664 |
|
{ |
665 |
|
unsigned int i; |
666 |
|
char *c; |
667 |
|
|
668 |
|
c = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); |
669 |
|
printf("Server certificate subject: %s\n", c); |
670 |
|
xfree(c); |
671 |
|
|
672 |
|
c = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0); |
673 |
|
printf("Server certificate issuer: %s\n", c); |
674 |
|
xfree(c); |
675 |
|
|
676 |
|
printf("Server key fingerprint: "); |
677 |
|
for (i = 0; i < *mdlen; i++) |
678 |
|
printf(i != *mdlen - 1 ? "%02X:" : "%02X\n", md[i]); |
679 |
|
} |
680 |
|
|
681 |
|
|
682 |
|
/* |
683 |
|
* Ask the user to reject/accept the SSL/TLS certificate. |
684 |
|
*/ |
685 |
|
int |
686 |
|
imf_ssl_new_cert(X509 * cert) |
687 |
|
{ |
688 |
|
FILE *fd; |
689 |
|
char c, *cfn, buf[LINE_MAX]; |
690 |
|
|
691 |
|
do { |
692 |
|
printf("(R)eject, accept (t)emporarily or " |
693 |
|
"accept (p)ermanently? "); |
694 |
|
fgets(buf, LINE_MAX, stdin); |
695 |
|
c = tolower(*buf); |
696 |
|
} while (c != 'r' && c != 't' && c != 'p'); |
697 |
|
|
698 |
|
if (c == 'r') |
699 |
|
return SSL_CERT_ACTION_REJECT; |
700 |
|
else if (c == 't') |
701 |
|
return SSL_CERT_ACTION_ACCEPT; |
702 |
|
|
703 |
|
cfn = ".imapfilter/certificates"; |
704 |
|
|
705 |
|
create_file(cfn, S_IRUSR | S_IWUSR); |
706 |
|
|
707 |
|
fd = fopen(cfn, "a"); |
708 |
|
if (fd == NULL) |
709 |
|
return SSL_CERT_ACTION_REJECT; |
710 |
|
|
711 |
|
PEM_write_X509(fd, cert); |
712 |
|
|
713 |
|
fclose(fd); |
714 |
|
|
715 |
|
return SSL_CERT_ACTION_ACCEPT; |
716 |
|
} |
717 |
|
|
718 |
|
|
719 |
|
/* |
720 |
|
* Ask user to proceed, while a fingerprint mismatch in the SSL/TLS |
721 |
|
* certificate was found. |
722 |
|
*/ |
723 |
|
int |
724 |
|
imf_ssl_cert_mismatch(void) |
725 |
|
{ |
726 |
|
char c, buf[LINE_MAX]; |
727 |
|
|
728 |
|
do { |
729 |
|
printf("WARNING: SSL/TLS certificate fingerprint mismatch.\n" |
730 |
|
"Proceed with the connection (y/n)? "); |
731 |
|
fgets(buf, LINE_MAX, stdin); |
732 |
|
c = tolower(*buf); |
733 |
|
} while (c != 'y' && c != 'n'); |
734 |
|
|
735 |
|
if (c == 'y') |
736 |
|
return SSL_CERT_ACTION_CONTINUE; |
737 |
|
else |
738 |
|
return SSL_CERT_ACTION_ABORT; |
739 |
|
} |
740 |
|
|
741 |
|
#endif /* SSL_TLS */ |