"Fossies" - the Fresh Open Source Software Archive

Member "imapfilter-2.8.2/src/cert.c" (26 Dec 2023, 5034 Bytes) of package /linux/privat/imapfilter-2.8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "cert.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.7.6_vs_2.8.0.

    1 #include <stdio.h>
    2 #include <string.h>
    3 #include <ctype.h>
    4 #include <limits.h>
    5 #include <sys/stat.h>
    6 #include <unistd.h>
    7 
    8 #include <openssl/x509.h>
    9 #include <openssl/ssl.h>
   10 #include <openssl/pem.h>
   11 #include <openssl/evp.h>
   12 
   13 #include "imapfilter.h"
   14 #include "session.h"
   15 
   16 
   17 extern environment env;
   18 
   19 
   20 int check_cert(X509 *pcert, unsigned char *pmd, unsigned int *pmdlen);
   21 void print_cert(X509 *cert, unsigned char *md, unsigned int *mdlen);
   22 char *get_serial(X509 *cert);
   23 int store_cert(X509 *cert);
   24 
   25 int handle_cert_error(X509 *cert);
   26 
   27 
   28 /*
   29  * Cleanup on read/write socket failures.
   30  */
   31 int
   32 handle_cert_error(X509 *cert)
   33 {
   34 
   35     X509_free(cert);
   36 
   37     return -1;
   38 }
   39 
   40 
   41 /*
   42  * Get SSL/TLS certificate check it, maybe ask user about it and act
   43  * accordingly.
   44  */
   45 int
   46 get_cert(session *ssn)
   47 {
   48     X509 *cert;
   49     unsigned char md[EVP_MAX_MD_SIZE];
   50     unsigned int mdlen;
   51     long verify;
   52 
   53     mdlen = 0;
   54 
   55 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
   56     if (!(cert = SSL_get1_peer_certificate(ssn->sslconn)))
   57 #else
   58     if (!(cert = SSL_get_peer_certificate(ssn->sslconn)))
   59 #endif
   60         return -1;
   61 
   62     verify = SSL_get_verify_result(ssn->sslconn);
   63     if (!((verify == X509_V_OK) ||
   64         (verify == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ||
   65         (verify == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY))) {
   66         error("certificate verification failed; %s\n",
   67               X509_verify_cert_error_string(verify));
   68         return handle_cert_error(cert);
   69     }
   70 
   71     if (verify != X509_V_OK) {
   72         if (!(X509_digest(cert, EVP_md5(), md, &mdlen)))
   73             return -1;
   74 
   75         switch (check_cert(cert, md, &mdlen)) {
   76         case 0:
   77             if (isatty(STDIN_FILENO) == 0)
   78                 fatal(ERROR_CERTIFICATE, "%s\n",
   79                     "can't accept certificate in "
   80                     "non-interactive mode");
   81             print_cert(cert, md, &mdlen);
   82             if (store_cert(cert) == -1)
   83                 return handle_cert_error(cert);
   84             break;
   85         case -1:
   86             error("certificate mismatch occurred\n");
   87             return handle_cert_error(cert);
   88         }
   89     }
   90 
   91     X509_free(cert);
   92 
   93     return 0;
   94 }
   95 
   96 
   97 /*
   98  * Check if the SSL/TLS certificate exists in the certificates file.
   99  */
  100 int
  101 check_cert(X509 *pcert, unsigned char *pmd, unsigned int *pmdlen)
  102 {
  103     int r;
  104     FILE *fd;
  105     char *certf;
  106     X509 *cert;
  107     unsigned char md[EVP_MAX_MD_SIZE];
  108     unsigned int mdlen;
  109 
  110     r = 0;
  111     cert = NULL;
  112 
  113     certf = get_filepath("certificates");
  114     if (!exists_file(certf)) {
  115         xfree(certf);
  116         return 0;
  117     }
  118     fd = fopen(certf, "r");
  119     xfree(certf);
  120     if (fd == NULL)
  121         return -1;
  122 
  123     while ((cert = PEM_read_X509(fd, &cert, NULL, NULL)) != NULL) {
  124         if (X509_subject_name_cmp(cert, pcert) != 0 ||
  125             X509_issuer_and_serial_cmp(cert, pcert) != 0)
  126             continue;
  127 
  128         if (!X509_digest(cert, EVP_md5(), md, &mdlen) ||
  129             *pmdlen != mdlen)
  130             continue;
  131 
  132         if (memcmp(pmd, md, mdlen) != 0) {
  133             r = -1;
  134             break;
  135         }
  136         r = 1;
  137         break;
  138     }
  139 
  140     fclose(fd);
  141     X509_free(cert);
  142 
  143     return r;
  144 }
  145 
  146 
  147 /*
  148  * Print information about the SSL/TLS certificate.
  149  */
  150 void
  151 print_cert(X509 *cert, unsigned char *md, unsigned int *mdlen)
  152 {
  153     unsigned int i;
  154     char *s;
  155 
  156     s = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
  157     printf("Server certificate subject: %s\n", s);
  158     xfree(s);
  159 
  160     s = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
  161     printf("Server certificate issuer: %s\n", s);
  162     xfree(s);
  163 
  164     s = get_serial(cert);
  165     printf("Server certificate serial: %s\n", s);
  166     xfree(s);
  167 
  168     printf("Server key fingerprint: ");
  169     for (i = 0; i < *mdlen; i++)
  170         printf(i != *mdlen - 1 ? "%02X:" : "%02X\n", md[i]);
  171 }
  172 
  173 
  174 /*
  175  * Extract certificate serial number as a string.
  176  */
  177 char *
  178 get_serial(X509 *cert)
  179 {
  180     ASN1_INTEGER* serial;
  181     char *buf;
  182     long num;
  183     int  i;
  184     size_t len;
  185 
  186     serial = X509_get_serialNumber(cert);
  187     buf = xmalloc(LINE_MAX);
  188     *buf = '\0';
  189     if (serial->length <= (int)sizeof(long)) {
  190         num = ASN1_INTEGER_get(serial);
  191         if (serial->type == V_ASN1_NEG_INTEGER) {
  192             snprintf(buf, LINE_MAX, "-%lX", -num);
  193         } else {
  194             snprintf(buf, LINE_MAX, "%lX", num);
  195         }
  196     } else {
  197         if (serial->type == V_ASN1_NEG_INTEGER) {
  198             snprintf(buf, LINE_MAX, "-");
  199         }
  200         for (i = 0; i < serial->length; i++) {
  201             len = strlen(buf);
  202             snprintf(buf + len, LINE_MAX - len, "%02X",
  203                 serial->data[i]);
  204         }
  205     }
  206     return buf;
  207 }
  208 
  209 
  210 /*
  211  * Store the SSL/TLS certificate after asking the user to accept/reject it.
  212  */
  213 int
  214 store_cert(X509 *cert)
  215 {
  216     FILE *fd;
  217     char c, buf[LINE_MAX];
  218     char *certf;
  219     char *s;
  220 
  221     do {
  222         printf("(R)eject, accept (t)emporarily or "
  223             "accept (p)ermanently? ");
  224         if (fgets(buf, LINE_MAX, stdin) == NULL)
  225             return -1;
  226         c = tolower((int)(*buf));
  227     } while (c != 'r' && c != 't' && c != 'p');
  228 
  229     if (c == 'r')
  230         return -1;
  231     else if (c == 't')
  232         return 0;
  233 
  234     certf = get_filepath("certificates");
  235     create_file(certf, S_IRUSR | S_IWUSR);
  236     fd = fopen(certf, "a");
  237     xfree(certf);
  238     if (fd == NULL)
  239         return -1;
  240 
  241     s = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
  242     fprintf(fd, "Subject: %s\n", s);
  243     xfree(s);
  244     s = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
  245     fprintf(fd, "Issuer: %s\n", s);
  246     xfree(s);
  247     s = get_serial(cert);
  248     fprintf(fd, "Serial: %s\n", s);
  249     xfree(s);
  250 
  251     PEM_write_X509(fd, cert);
  252 
  253     fprintf(fd, "\n");
  254     fclose(fd);
  255 
  256     return 0;
  257 }