/[imapfilter]/imapfilter/cert.c
ViewVC logotype

Contents of /imapfilter/cert.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (show annotations)
Tue Feb 10 22:21:08 2004 UTC (20 years, 1 month ago) by lefcha
Branch: MAIN
Changes since 1.3: +2 -2 lines
File MIME type: text/plain
Replaced integer options and bitwise OPTION_* with an options struct.

1 #include <stdio.h>
2 #include <string.h>
3 #include <ctype.h>
4 #include <limits.h>
5 #include <sys/stat.h>
6
7 #include "config.h"
8 #include "imapfilter.h"
9 #include "pathnames.h"
10
11 #ifdef SSL_TLS
12 #include <openssl/x509.h>
13 #include <openssl/ssl.h>
14 #include <openssl/pem.h>
15 #include <openssl/evp.h>
16
17
18 extern char *home;
19 extern opts_t opts;
20 extern unsigned int flags;
21
22
23 int check_cert(X509 * pcert, unsigned char *pmd, unsigned int *pmdlen);
24 void print_cert(X509 * cert, unsigned char *md, unsigned int *mdlen);
25 int write_cert(X509 * cert);
26 int mismatch_cert(void);
27
28
29 /*
30 * Get SSL/TLS certificate check it, maybe ask user about it and act
31 * accordingly.
32 */
33 int
34 get_cert(conn_t * conn)
35 {
36 X509 *cert;
37 unsigned char md[EVP_MAX_MD_SIZE];
38 unsigned int mdlen;
39
40 mdlen = 0;
41
42 if (!(cert = SSL_get_peer_certificate(conn->ssl)))
43 return ERROR_SSL;
44
45 if (!(X509_digest(cert, EVP_md5(), md, &mdlen)))
46 return ERROR_SSL;
47
48 switch (check_cert(cert, md, &mdlen)) {
49 case SSL_CERT_NONEXISTENT:
50 print_cert(cert, md, &mdlen);
51 if (flags & FLAG_DAEMON_MODE ||
52 write_cert(cert) == SSL_CERT_ACTION_REJECT)
53 goto abort;
54 break;
55 case SSL_CERT_MISMATCH:
56 print_cert(cert, md, &mdlen);
57 if (flags & FLAG_DAEMON_MODE ||
58 mismatch_cert() == SSL_CERT_ACTION_ABORT)
59 goto abort;
60 break;
61 case SSL_CERT_OK:
62 if (opts.verbosity >= 1)
63 print_cert(cert, md, &mdlen);
64 }
65
66 X509_free(cert);
67 return 0;
68
69 abort:
70 X509_free(cert);
71 return ERROR_SSL;
72 }
73
74
75 /*
76 * Check if the SSL/TLS certificate exists in the certificates file.
77 */
78 int
79 check_cert(X509 * pcert, unsigned char *pmd, unsigned int *pmdlen)
80 {
81 int r;
82 FILE *fd;
83 char certf[PATH_MAX];
84 X509 *cert;
85 unsigned char md[EVP_MAX_MD_SIZE];
86 unsigned int mdlen;
87
88 r = SSL_CERT_NONEXISTENT;
89 cert = NULL;
90
91 snprintf(certf, PATH_MAX, "%s/%s", home, PATHNAME_CERT_FILE);
92 if (!exists_file(certf))
93 return SSL_CERT_NONEXISTENT;
94
95 fd = fopen(certf, "r");
96 if (fd == NULL)
97 return ERROR_FILE_OPEN;
98
99 while ((cert = PEM_read_X509(fd, &cert, NULL, NULL)) != NULL) {
100 if (X509_subject_name_cmp(cert, pcert) != 0 ||
101 X509_issuer_name_cmp(cert, pcert) != 0)
102 continue;
103
104 if (!X509_digest(cert, EVP_md5(), md, &mdlen) ||
105 *pmdlen != mdlen)
106 continue;
107
108 if (memcmp(pmd, md, mdlen) != 0) {
109 r = SSL_CERT_MISMATCH;
110 break;
111 }
112 r = SSL_CERT_OK;
113 break;
114 }
115
116 fclose(fd);
117 X509_free(cert);
118
119 return r;
120 }
121
122
123 /*
124 * Print information about the SSL/TLS certificate.
125 */
126 void
127 print_cert(X509 * cert, unsigned char *md, unsigned int *mdlen)
128 {
129 unsigned int i;
130 char *c;
131
132 c = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
133 printf("Server certificate subject: %s\n", c);
134 xfree(c);
135
136 c = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
137 printf("Server certificate issuer: %s\n", c);
138 xfree(c);
139
140 printf("Server key fingerprint: ");
141 for (i = 0; i < *mdlen; i++)
142 printf(i != *mdlen - 1 ? "%02X:" : "%02X\n", md[i]);
143 }
144
145
146 /*
147 * Write the SSL/TLS certificate after asking the user to accept/reject it.
148 */
149 int
150 write_cert(X509 * cert)
151 {
152 FILE *fd;
153 char c, buf[LINE_MAX];
154 char certf[PATH_MAX];
155
156 do {
157 printf("(R)eject, accept (t)emporarily or "
158 "accept (p)ermanently? ");
159 fgets(buf, LINE_MAX, stdin);
160 c = tolower(*buf);
161 } while (c != 'r' && c != 't' && c != 'p');
162
163 if (c == 'r')
164 return SSL_CERT_ACTION_REJECT;
165 else if (c == 't')
166 return SSL_CERT_ACTION_ACCEPT;
167
168 snprintf(certf, PATH_MAX, "%s/%s", home, PATHNAME_CERT_FILE);
169 create_file(certf, S_IRUSR | S_IWUSR);
170
171 fd = fopen(certf, "a");
172 if (fd == NULL)
173 return SSL_CERT_ACTION_REJECT;
174
175 PEM_write_X509(fd, cert);
176
177 fclose(fd);
178
179 return SSL_CERT_ACTION_ACCEPT;
180 }
181
182
183 /*
184 * Ask user to proceed, while a fingerprint mismatch in the SSL/TLS
185 * certificate was found.
186 */
187 int
188 mismatch_cert(void)
189 {
190 char c, buf[LINE_MAX];
191
192 do {
193 printf("WARNING: SSL/TLS certificate fingerprint mismatch.\n"
194 "Proceed with the connection (y/n)? ");
195 fgets(buf, LINE_MAX, stdin);
196 c = tolower(*buf);
197 } while (c != 'y' && c != 'n');
198
199 if (c == 'y')
200 return SSL_CERT_ACTION_CONTINUE;
201 else
202 return SSL_CERT_ACTION_ABORT;
203 }
204 #endif /* SSL_TLS */

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26