Line data Source code
1 : #include "burp.h"
2 : #include "alloc.h"
3 : #include "conf.h"
4 : #include "log.h"
5 : #include "server/ca.h"
6 : #include "ssl.h"
7 :
8 : static const char *pass=NULL;
9 :
10 0 : int ssl_do_accept(SSL *ssl)
11 : {
12 : while(1)
13 0 : {
14 0 : int r=0;
15 : int ssl_err;
16 0 : ERR_clear_error();
17 0 : switch((r=SSL_accept(ssl)))
18 : {
19 : case 1:
20 : return 0;
21 : case 0:
22 : default:
23 0 : ssl_err=SSL_get_error(ssl, r);
24 0 : switch(ssl_err)
25 : {
26 : case SSL_ERROR_WANT_READ:
27 0 : continue;
28 : default:
29 0 : logp_ssl_err("SSL_accept error: %d\n", ssl_err);
30 0 : return -1;
31 : }
32 : break;
33 : }
34 : }
35 : }
36 :
37 : #if OPENSSL_VERSION_NUMBER < 0x30000000L
38 0 : int ssl_load_dh_params(SSL_CTX *ctx, struct conf **confs)
39 : {
40 0 : DH *ret=0;
41 0 : BIO *bio=NULL;
42 0 : const char *ssl_dhfile=get_string(confs[OPT_SSL_DHFILE]);
43 :
44 0 : if(!(bio=BIO_new_file(ssl_dhfile, "r")))
45 : {
46 0 : logp_ssl_err("Couldn't open ssl_dhfile: %s\n", ssl_dhfile);
47 0 : return -1;
48 : }
49 :
50 0 : ret=PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
51 0 : BIO_free(bio);
52 0 : if(SSL_CTX_set_tmp_dh(ctx, ret)<0)
53 : {
54 0 : logp_ssl_err("Couldn't set DH parameters");
55 0 : return -1;
56 : }
57 : return 0;
58 : }
59 : #else
60 : #include <openssl/decoder.h>
61 : int ssl_load_dh_params(SSL_CTX *ctx, struct conf **confs)
62 : {
63 : BIO *bio=NULL;
64 : EVP_PKEY *pkey=NULL;
65 : OSSL_DECODER_CTX *dctx=NULL;
66 : const char *ssl_dhfile=get_string(confs[OPT_SSL_DHFILE]);
67 :
68 : if(!(bio=BIO_new_file(ssl_dhfile, "r")))
69 : {
70 : logp_ssl_err("Couldn't open ssl_dhfile: %s\n", ssl_dhfile);
71 : return -1;
72 : }
73 : if(!(dctx=OSSL_DECODER_CTX_new_for_pkey(
74 : &pkey, "PEM", NULL, "DH",
75 : OSSL_KEYMGMT_SELECT_KEYPAIR,
76 : NULL, NULL)))
77 : {
78 : logp_ssl_err("No suitable decoders found for: %s\n", ssl_dhfile);
79 : BIO_free(bio);
80 : OSSL_DECODER_CTX_free(dctx);
81 : return -1;
82 : }
83 :
84 : if(OSSL_DECODER_from_bio(dctx, bio))
85 : {
86 : logp_ssl_err("Decoding failure for: %s\n", ssl_dhfile);
87 : BIO_free(bio);
88 : OSSL_DECODER_CTX_free(dctx);
89 : return -1;
90 :
91 : }
92 :
93 : if(SSL_CTX_set_tmp_dh(ctx, pkey)<0)
94 : {
95 : logp_ssl_err("Couldn't set DH parameters");
96 : OSSL_DECODER_CTX_free(dctx);
97 : return -1;
98 : }
99 :
100 : OSSL_DECODER_CTX_free(dctx);
101 : return 0;
102 : }
103 : #endif
104 :
105 0 : static int password_cb(char *buf, int num,
106 : __attribute__ ((unused)) int rwflag,
107 : __attribute__ ((unused)) void *userdata)
108 : {
109 0 : if(num<(int)strlen(pass)+1) return 0;
110 0 : strcpy(buf, pass);
111 0 : return strlen(pass);
112 : }
113 :
114 1 : void ssl_load_globals(void)
115 : {
116 : // Global system initialization.
117 1 : SSL_library_init();
118 1 : SSL_load_error_strings();
119 1 : }
120 :
121 0 : static int check_path(const char *path, const char *what)
122 : {
123 : struct stat statp;
124 0 : if(!path) return -1;
125 0 : if(stat(path, &statp))
126 : {
127 0 : logp("Could not find %s %s: %s\n",
128 0 : what, path, strerror(errno));
129 0 : return -1;
130 : }
131 : return 0;
132 : }
133 :
134 0 : static int ssl_load_keys_and_certs(SSL_CTX *ctx, struct conf **confs)
135 : {
136 0 : char *ssl_key=NULL;
137 0 : const char *ssl_cert=get_string(confs[OPT_SSL_CERT]);
138 0 : const char *ssl_cert_ca=get_string(confs[OPT_SSL_CERT_CA]);
139 :
140 : // Load our keys and certificates if the path exists.
141 0 : if(!check_path(ssl_cert, "ssl_cert")
142 0 : && !SSL_CTX_use_certificate_chain_file(ctx, ssl_cert))
143 : {
144 0 : logp_ssl_err("Can't read ssl_cert: %s\n", ssl_cert);
145 0 : return -1;
146 : }
147 :
148 0 : pass=get_string(confs[OPT_SSL_KEY_PASSWORD]);
149 0 : SSL_CTX_set_default_passwd_cb(ctx, password_cb);
150 :
151 0 : ssl_key=get_string(confs[OPT_SSL_KEY]);
152 0 : if(!ssl_key) ssl_key=get_string(confs[OPT_SSL_CERT]);
153 :
154 : // Load the key file, if the path exists.
155 0 : if(!check_path(ssl_key, "ssl_key")
156 0 : && !SSL_CTX_use_PrivateKey_file(ctx, ssl_key, SSL_FILETYPE_PEM))
157 : {
158 0 : logp_ssl_err("Can't read ssl_key file: %s\n", ssl_key);
159 0 : return -1;
160 : }
161 :
162 : // Load the CAs we trust, if the path exists.
163 0 : if(!check_path(ssl_cert_ca, "ssl_cert_ca")
164 0 : && !SSL_CTX_load_verify_locations(ctx, ssl_cert_ca, 0))
165 : {
166 0 : logp_ssl_err("Can't read ssl_cert_ca file: %s\n", ssl_cert_ca);
167 0 : return -1;
168 : }
169 :
170 : return 0;
171 : }
172 :
173 0 : SSL_CTX *ssl_initialise_ctx(struct conf **confs)
174 : {
175 0 : SSL_CTX *ctx=NULL;
176 0 : SSL_METHOD *meth=NULL;
177 0 : const char *ssl_ciphers=get_string(confs[OPT_SSL_CIPHERS]);
178 :
179 : // Create our context.
180 0 : meth=(SSL_METHOD *)SSLv23_method();
181 0 : ctx=(SSL_CTX *)SSL_CTX_new(meth);
182 :
183 0 : if(ssl_load_keys_and_certs(ctx, confs)) return NULL;
184 :
185 0 : if(ssl_ciphers)
186 0 : SSL_CTX_set_cipher_list(ctx, ssl_ciphers);
187 :
188 : // Unclear what is negotiated, so keep quiet until I figure that out.
189 0 : if(!get_int(confs[OPT_SSL_COMPRESSION]))
190 : {
191 : #ifdef SSL_OP_NO_COMPRESSION
192 0 : SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
193 : #else
194 : logp("This version of openssl has no SSL_OP_NO_COMPRESSION option, so turning off config option '%s' will not work. You should probably upgrade openssl.\n", confs[OPT_SSL_COMPRESSION]->field);
195 : #endif
196 : }
197 : // Default is zlib5, which needs no option set.
198 :
199 0 : SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3);
200 :
201 0 : return ctx;
202 : }
203 :
204 1 : void ssl_destroy_ctx(SSL_CTX *ctx)
205 : {
206 1 : SSL_CTX_free(ctx);
207 1 : }
208 :
209 : #ifndef HAVE_WIN32
210 0 : static void sanitise(char *buf)
211 : {
212 0 : char *cp=NULL;
213 0 : for(cp=buf; *cp; cp++)
214 : {
215 0 : if(!isalnum(*cp)
216 : && !isblank(*cp)
217 0 : && *cp!='_'
218 0 : && *cp!='-'
219 0 : && *cp!='.'
220 0 : && *cp!=':'
221 0 : && *cp!='@')
222 0 : *cp='_';
223 : }
224 0 : }
225 :
226 : // This function taken from openvpn-2.2.1 and tidied up a bit.
227 0 : static int setenv_x509(X509_NAME *x509, const char *type)
228 : {
229 : int i, n;
230 : int fn_nid;
231 : ASN1_OBJECT *fn;
232 : ASN1_STRING *val;
233 : X509_NAME_ENTRY *ent;
234 : const char *objbuf;
235 : uint8_t *buf;
236 : char *name_expand;
237 : size_t name_expand_size;
238 :
239 0 : n=X509_NAME_entry_count (x509);
240 0 : for(i=0; i<n; ++i)
241 : {
242 0 : if(!(ent=X509_NAME_get_entry (x509, i))
243 0 : || !(fn=X509_NAME_ENTRY_get_object(ent))
244 0 : || !(val=X509_NAME_ENTRY_get_data(ent))
245 0 : || (fn_nid=OBJ_obj2nid(fn))==NID_undef
246 0 : || !(objbuf=OBJ_nid2sn(fn_nid)))
247 0 : continue;
248 0 : buf=(uint8_t *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
249 0 : if(ASN1_STRING_to_UTF8(&buf, val)<=0) continue;
250 0 : name_expand_size=64+strlen(objbuf);
251 0 : if(!(name_expand=(char *)malloc_w(name_expand_size, __func__)))
252 : return -1;
253 0 : snprintf(name_expand, name_expand_size,
254 : "X509_%s_%s", type, objbuf);
255 0 : sanitise(name_expand);
256 0 : sanitise((char*)buf);
257 0 : setenv(name_expand, (char*)buf, 1);
258 0 : free_w(&name_expand);
259 0 : OPENSSL_free(buf);
260 : }
261 : return 0;
262 : }
263 :
264 0 : static int setenv_x509_date(ASN1_TIME *tm, const char *env)
265 : {
266 0 : BIO *bio_out=NULL;
267 0 : BUF_MEM *bptr=NULL;
268 0 : char tmpbuf[256]="";
269 0 : if(!(bio_out=BIO_new(BIO_s_mem())))
270 : {
271 0 : log_out_of_memory(__func__);
272 0 : return -1;
273 : }
274 0 : ASN1_TIME_print(bio_out, tm);
275 0 : BIO_get_mem_ptr(bio_out, &bptr);
276 0 : BIO_gets(bio_out, tmpbuf, sizeof(tmpbuf)-1);
277 0 : BIO_free_all(bio_out);
278 0 : sanitise(tmpbuf);
279 0 : setenv(env, (char*)tmpbuf, 1);
280 0 : return 0;
281 : }
282 :
283 0 : static int setenv_x509_serialnumber(ASN1_INTEGER *i, const char *env)
284 : {
285 0 : BIO *bio_out=NULL;
286 0 : BUF_MEM *bptr=NULL;
287 0 : char tmpbuf[256]="";
288 0 : if(!(bio_out=BIO_new(BIO_s_mem())))
289 : {
290 0 : log_out_of_memory(__func__);
291 0 : return -1;
292 : }
293 0 : i2a_ASN1_INTEGER(bio_out, i);
294 0 : BIO_get_mem_ptr(bio_out, &bptr);
295 0 : BIO_gets(bio_out, tmpbuf, sizeof(tmpbuf)-1);
296 0 : BIO_free_all(bio_out);
297 0 : sanitise(tmpbuf);
298 0 : setenv(env, (char*)tmpbuf, 1);
299 0 : return 0;
300 : }
301 : #endif
302 :
303 0 : int ssl_check_cert(SSL *ssl, struct conf **confs, struct conf **cconfs)
304 : {
305 : X509 *peer;
306 : int result;
307 0 : char tmpbuf[256]="";
308 0 : const char *ssl_peer_cn=get_string(cconfs[OPT_SSL_PEER_CN]);
309 :
310 0 : if(!ssl_peer_cn)
311 : {
312 0 : logp("ssl_peer_cn not set.\n");
313 0 : return -1;
314 : }
315 :
316 0 : SSL_CIPHER_description(SSL_get_current_cipher(ssl),
317 : tmpbuf, sizeof(tmpbuf));
318 0 : logp("SSL is using cipher: %s\n", tmpbuf);
319 0 : if(!(peer=SSL_get_peer_certificate(ssl)))
320 : {
321 0 : logp("Could not get peer certificate.\n");
322 0 : return -1;
323 : }
324 0 : result=SSL_get_verify_result(ssl);
325 0 : if(result!=X509_V_OK)
326 : {
327 0 : logp_ssl_err("Certificate doesn't verify (%d).\n", result);
328 0 : return -1;
329 : }
330 :
331 0 : X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
332 : NID_commonName, tmpbuf, sizeof(tmpbuf));
333 0 : if(strcasecmp(tmpbuf, ssl_peer_cn))
334 : {
335 0 : logp("cert common name doesn't match configured ssl_peer_cn\n");
336 0 : logp("'%s'!='%s'\n", tmpbuf, ssl_peer_cn);
337 0 : return -1;
338 : }
339 :
340 : #ifndef HAVE_WIN32
341 : // Check the peer certificate against the CRL list only if set
342 : // in the configuration file. Thus if not set it is not
343 : // breaking the 'ssl_extra_checks_script' configuration.
344 0 : if(confs && ca_x509_verify_crl(confs, peer, ssl_peer_cn))
345 : return -1;
346 :
347 0 : if(setenv_x509(X509_get_subject_name(peer), "PEER")
348 0 : || setenv_x509(X509_get_issuer_name(peer), "ISSUER"))
349 : return -1;
350 :
351 0 : if(setenv_x509_date(X509_get_notBefore(peer), "X509_PEER_NOT_BEFORE")
352 0 : || setenv_x509_date(X509_get_notAfter(peer), "X509_PEER_NOT_AFTER"))
353 : return -1;
354 :
355 0 : if(setenv_x509_serialnumber(X509_get_serialNumber(peer),
356 : "X509_PEER_SERIALNUMBER"))
357 : return -1;
358 : #endif
359 : //if((comp=SSL_get_current_compression(ssl)))
360 : // logp("SSL is using compression: %s\n", comp->name);
361 :
362 0 : return 0;
363 : }
|