Line data Source code
1 : #include "burp.h"
2 : #include "alloc.h"
3 : #include "asfd.h"
4 : #include "async.h"
5 : #include "bfile.h"
6 : #include "cmd.h"
7 : #include "handy.h"
8 : #include "hexmap.h"
9 : #include "iobuf.h"
10 : #include "log.h"
11 : #include "md5.h"
12 : #include "handy_extra.h"
13 : #include "sbuf.h"
14 :
15 : #if OPENSSL_VERSION_NUMBER >= 0x30000000L
16 : #include <openssl/provider.h>
17 : #endif
18 :
19 0 : static int do_encryption(struct asfd *asfd, EVP_CIPHER_CTX *ctx,
20 : uint8_t *inbuf, int inlen, uint8_t *outbuf, int *outlen,
21 : struct md5 *md5)
22 : {
23 0 : if(!inlen) return 0;
24 0 : if(!EVP_CipherUpdate(ctx, outbuf, outlen, inbuf, inlen))
25 : {
26 0 : logp("Encryption failure.\n");
27 0 : return -1;
28 : }
29 0 : if(*outlen>0)
30 : {
31 0 : struct iobuf wbuf;
32 0 : iobuf_set(&wbuf, CMD_APPEND, (char *)outbuf, *outlen);
33 0 : if(asfd->write(asfd, &wbuf))
34 0 : return -1;
35 0 : if(!md5_update(md5, outbuf, *outlen))
36 : {
37 0 : logp("md5_update() failed\n");
38 0 : return -1;
39 : }
40 : }
41 : return 0;
42 : }
43 :
44 2 : EVP_CIPHER_CTX *enc_setup(int encrypt, const char *encryption_password,
45 : int key_deriv, uint64_t salt)
46 : {
47 2 : uint8_t enc_iv[9];
48 2 : uint8_t enc_key[256];
49 2 : EVP_CIPHER_CTX *ctx=NULL;
50 2 : const EVP_CIPHER *cipher=NULL;
51 2 : int key_len;
52 :
53 2 : switch(key_deriv)
54 : {
55 1 : case ENCRYPTION_NONE:
56 : case ENCRYPTION_KEY_DERIVED_BF_CBC:
57 1 : cipher=EVP_bf_cbc();
58 1 : break;
59 1 : case ENCRYPTION_KEY_DERIVED_AES_CBC_256:
60 1 : cipher=EVP_aes_256_cbc();
61 1 : break;
62 0 : default:
63 0 : logp("Could not determine cipher from: %d\n", key_deriv);
64 0 : break;
65 : }
66 :
67 2 : if(!encryption_password)
68 : {
69 1 : logp("No encryption password in %s()\n", __func__);
70 1 : goto error;
71 : }
72 :
73 1 : if(key_deriv)
74 : {
75 : // New, good way.
76 1 : uint64_t be_salt=htobe64(salt);
77 1 : const EVP_MD *dgst=EVP_sha256();
78 :
79 1 : if(!(key_len=EVP_BytesToKey(cipher, dgst, (uint8_t *)&be_salt,
80 : (const unsigned char *)encryption_password,
81 1 : strlen(encryption_password),
82 : 100, enc_key, enc_iv)))
83 : {
84 0 : logp("EVP_BytesToKey failed\n");
85 0 : goto error;
86 : }
87 : }
88 : else
89 : {
90 : // Old, bad way.
91 : // Declare enc_iv with individual characters so that the weird
92 : // last character can be specified as a hex number in order to
93 : // prevent compilation warnings on Macs.
94 0 : uint8_t new_enc[]={
95 : '[', 'l', 'k', 'd', '.', '$', 'G', 0xa3, '\0'
96 : };
97 0 : memcpy(enc_iv, new_enc, 9);
98 0 : strcpy((char*)enc_key, encryption_password);
99 0 : key_len=strlen(encryption_password);
100 : }
101 :
102 1 : if(!(ctx=(EVP_CIPHER_CTX *)EVP_CIPHER_CTX_new()))
103 : {
104 0 : logp("EVP_CIPHER_CTX_new() failed\n");
105 0 : goto error;
106 : }
107 :
108 : // Don't set key or IV because we will modify the parameters.
109 1 : EVP_CIPHER_CTX_init(ctx);
110 1 : if(!(EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, encrypt)))
111 : {
112 0 : logp("EVP_CipherInit_ex failed\n");
113 0 : goto error;
114 : }
115 1 : if(!EVP_CIPHER_CTX_set_key_length(ctx, key_len))
116 : {
117 0 : logp("EVP_CIPHER_CTX_set_key_length failed\n");
118 0 : goto error;
119 : }
120 : // We finished modifying parameters so now we can set key and IV
121 :
122 1 : if(!EVP_CipherInit_ex(ctx, NULL, NULL,
123 : enc_key, enc_iv, encrypt))
124 : {
125 0 : logp("Second EVP_CipherInit_ex failed\n");
126 0 : goto error;
127 : }
128 : return ctx;
129 0 : error:
130 1 : if(ctx)
131 : {
132 0 : EVP_CIPHER_CTX_cleanup(ctx);
133 0 : EVP_CIPHER_CTX_free(ctx);
134 0 : ctx=NULL;
135 : }
136 : return NULL;
137 : }
138 :
139 7426 : char *get_endfile_str(uint64_t bytes, uint8_t *checksum)
140 : {
141 7426 : static char endmsg[128]="";
142 7426 : snprintf(endmsg, sizeof(endmsg), "%" PRIu64 ":%s",
143 : (uint64_t)bytes,
144 7426 : checksum?bytes_to_md5str(checksum):"");
145 7426 : return endmsg;
146 : }
147 :
148 12 : int write_endfile(struct asfd *asfd, uint64_t bytes, uint8_t *checksum)
149 : {
150 12 : return asfd->write_str(asfd,
151 12 : CMD_END_FILE, get_endfile_str(bytes, checksum));
152 : }
153 :
154 : /* OK, this function is getting a bit out of control.
155 : One problem is that, if you give deflateInit2 compression=0, it still
156 : writes gzip headers and footers, so I had to add extra
157 : if(compression) and if(!compression) bits all over the place that would
158 : skip the actual compression.
159 : This is needed for the case where encryption is on and compression is off.
160 : Encryption off and compression off uses send_whole_file().
161 : Perhaps a separate function is needed for encryption on compression off.
162 : */
163 2 : enum send_e send_whole_file_gzl(struct asfd *asfd, const char *datapth,
164 : int quick_read, uint64_t *bytes, const char *encpassword,
165 : struct cntr *cntr, int compression, struct BFILE *bfd,
166 : const char *extrameta, size_t elen, int key_deriv, uint64_t salt)
167 : {
168 2 : enum send_e ret=SEND_OK;
169 2 : int zret=0;
170 2 : struct md5 *md5=NULL;
171 2 : size_t metalen=0;
172 2 : const char *metadata=NULL;
173 2 : struct iobuf wbuf;
174 :
175 2 : int have;
176 2 : z_stream strm;
177 2 : int flush=Z_NO_FLUSH;
178 2 : uint8_t in[ZCHUNK];
179 2 : uint8_t out[ZCHUNK];
180 2 : ssize_t r;
181 :
182 2 : int eoutlen;
183 2 : uint8_t eoutbuf[ZCHUNK+EVP_MAX_BLOCK_LENGTH];
184 :
185 2 : EVP_CIPHER_CTX *enc_ctx=NULL;
186 : #ifdef HAVE_WIN32
187 : int do_known_byte_count=0;
188 : size_t datalen=bfd->datalen;
189 : if(datalen>0) do_known_byte_count=1;
190 : #endif
191 :
192 2 : if(encpassword
193 0 : && !(enc_ctx=enc_setup(1, encpassword, key_deriv, salt)))
194 : return SEND_FATAL;
195 :
196 2 : if(!(md5=md5_alloc(__func__)))
197 : return SEND_FATAL;
198 :
199 2 : if(!md5_init(md5))
200 : {
201 0 : logp("md5_init() failed\n");
202 0 : md5_free(&md5);
203 0 : return SEND_FATAL;
204 : }
205 :
206 : //logp("send_whole_file_gz: %s%s\n", fname, extrameta?" (meta)":"");
207 :
208 2 : if((metadata=extrameta))
209 : {
210 0 : metalen=elen;
211 : }
212 :
213 : /* allocate deflate state */
214 2 : strm.zalloc = Z_NULL;
215 2 : strm.zfree = Z_NULL;
216 2 : strm.opaque = Z_NULL;
217 2 : if((zret=deflateInit2(&strm, compression, Z_DEFLATED, (15+16),
218 : 8, Z_DEFAULT_STRATEGY))!=Z_OK) {
219 0 : md5_free(&md5);
220 0 : return SEND_FATAL;
221 : }
222 :
223 4 : do
224 : {
225 4 : if(metadata)
226 : {
227 0 : if(metalen>ZCHUNK)
228 0 : strm.avail_in=ZCHUNK;
229 : else
230 0 : strm.avail_in=metalen;
231 0 : memcpy(in, metadata, strm.avail_in);
232 0 : metadata+=strm.avail_in;
233 0 : metalen-=strm.avail_in;
234 : }
235 : else
236 : {
237 : // Windows VSS headers give us how much data to
238 : // expect to read.
239 : #ifdef HAVE_WIN32
240 : if(do_known_byte_count)
241 : {
242 : if(datalen<=0)
243 : r=0;
244 : else
245 : {
246 : r=bfd->read(bfd, in,
247 : min((size_t)ZCHUNK, datalen));
248 : if(r>0)
249 : datalen-=r;
250 : }
251 : }
252 : else
253 : #endif
254 4 : r=bfd->read(bfd, in, ZCHUNK);
255 :
256 4 : if(r<0)
257 : {
258 0 : logw(asfd, cntr,
259 : "Error when reading %s in %s: %s\n",
260 0 : bfd->path, __func__, strerror(errno));
261 0 : ret=SEND_ERROR;
262 0 : break;
263 : }
264 4 : strm.avail_in=(uint32_t)r;
265 : }
266 4 : if(!compression && !strm.avail_in)
267 : break;
268 :
269 4 : *bytes+=strm.avail_in;
270 :
271 : // The checksum needs to be later if encryption is being used.
272 4 : if(!enc_ctx)
273 : {
274 4 : if(!md5_update(md5, in, strm.avail_in))
275 : {
276 0 : logp("md5_update() failed\n");
277 0 : ret=SEND_FATAL;
278 0 : break;
279 : }
280 : }
281 :
282 : #ifdef HAVE_WIN32
283 : if(do_known_byte_count && datalen<=0)
284 : flush=Z_FINISH;
285 : else
286 : #endif
287 4 : if(strm.avail_in) flush=Z_NO_FLUSH;
288 2 : else flush=Z_FINISH;
289 :
290 4 : strm.next_in=in;
291 :
292 : /* run deflate() on input until output buffer not full, finish
293 : compression if all of source has been read in */
294 4 : do
295 : {
296 4 : if(compression)
297 : {
298 4 : strm.avail_out = ZCHUNK;
299 4 : strm.next_out = out;
300 4 : zret = deflate(&strm, flush); /* no bad return value */
301 4 : if(zret==Z_STREAM_ERROR) /* state not clobbered */
302 : {
303 0 : logw(asfd, cntr, "z_stream_error when reading %s in %s\n", bfd->path, __func__);
304 0 : ret=SEND_ERROR;
305 0 : break;
306 : }
307 4 : have = ZCHUNK-strm.avail_out;
308 : }
309 : else
310 : {
311 0 : have=strm.avail_in;
312 0 : memcpy(out, in, have);
313 : }
314 :
315 4 : if(enc_ctx)
316 : {
317 0 : if(do_encryption(asfd, enc_ctx, out, have,
318 : eoutbuf, &eoutlen, md5))
319 : {
320 : ret=SEND_FATAL;
321 : break;
322 : }
323 : }
324 : else
325 : {
326 4 : iobuf_set(&wbuf, CMD_APPEND, (char *)out, have);
327 4 : if(asfd->write(asfd, &wbuf))
328 : {
329 : ret=SEND_FATAL;
330 : break;
331 : }
332 : }
333 4 : if(quick_read && datapth)
334 : {
335 4 : int qr;
336 4 : if((qr=do_quick_read(asfd, datapth, cntr))<0)
337 : {
338 : ret=SEND_FATAL;
339 : break;
340 : }
341 4 : if(qr) // client wants to interrupt
342 : {
343 0 : goto cleanup;
344 : }
345 : }
346 4 : if(!compression) break;
347 4 : } while (!strm.avail_out);
348 :
349 4 : if(ret!=SEND_OK) break;
350 :
351 4 : if(!compression) continue;
352 :
353 4 : if(strm.avail_in) /* all input will be used */
354 : {
355 0 : ret=SEND_FATAL;
356 0 : logp("strm.avail_in=%d\n", strm.avail_in);
357 0 : break;
358 : }
359 4 : } while(flush!=Z_FINISH);
360 :
361 2 : if(ret==SEND_OK)
362 : {
363 2 : if(compression && zret!=Z_STREAM_END)
364 : {
365 0 : logp("ret OK, but zstream not finished: %d\n", zret);
366 0 : ret=SEND_FATAL;
367 : }
368 2 : else if(enc_ctx)
369 : {
370 0 : if(!EVP_CipherFinal_ex(enc_ctx, eoutbuf, &eoutlen))
371 : {
372 0 : logp("Encryption failure at the end\n");
373 0 : ret=SEND_FATAL;
374 : }
375 0 : else if(eoutlen>0)
376 : {
377 0 : iobuf_set(&wbuf, CMD_APPEND,
378 : (char *)eoutbuf, (size_t)eoutlen);
379 0 : if(asfd->write(asfd, &wbuf))
380 : ret=SEND_FATAL;
381 0 : else if(!md5_update(md5, eoutbuf, eoutlen))
382 : {
383 0 : logp("md5_update() failed\n");
384 0 : ret=SEND_FATAL;
385 : }
386 : }
387 : }
388 : }
389 :
390 2 : cleanup:
391 2 : deflateEnd(&strm);
392 :
393 2 : if(enc_ctx)
394 : {
395 0 : EVP_CIPHER_CTX_cleanup(enc_ctx);
396 0 : EVP_CIPHER_CTX_free(enc_ctx);
397 0 : enc_ctx=NULL;
398 : }
399 :
400 2 : if(ret==SEND_OK)
401 : {
402 2 : uint8_t checksum[MD5_DIGEST_LENGTH];
403 2 : if(!md5_final(md5, checksum))
404 : {
405 0 : logp("md5_final() failed\n");
406 0 : md5_free(&md5);
407 0 : return SEND_FATAL;
408 : }
409 2 : if(write_endfile(asfd, *bytes, checksum))
410 : return SEND_FATAL;
411 : }
412 2 : md5_free(&md5);
413 2 : return ret;
414 : }
415 :
416 : #ifdef HAVE_WIN32
417 : struct winbuf
418 : {
419 : struct md5 *md5;
420 : int quick_read;
421 : const char *datapth;
422 : struct cntr *cntr;
423 : uint64_t *bytes;
424 : struct asfd *asfd;
425 : };
426 :
427 : static DWORD WINAPI write_efs(PBYTE pbData,
428 : PVOID pvCallbackContext, ULONG ulLength)
429 : {
430 : struct iobuf wbuf;
431 : struct winbuf *mybuf=(struct winbuf *)pvCallbackContext;
432 : (*(mybuf->bytes))+=ulLength;
433 : if(!md5_update(mybuf->md5, pbData, ulLength))
434 : {
435 : logp("md5_update() failed\n");
436 : return ERROR_FUNCTION_FAILED;
437 : }
438 : iobuf_set(&wbuf, CMD_APPEND, (char *)pbData, (size_t)ulLength);
439 : if(mybuf->asfd->write(mybuf->asfd, &wbuf))
440 : {
441 : return ERROR_FUNCTION_FAILED;
442 : }
443 : if(mybuf->quick_read)
444 : {
445 : int qr;
446 : if((qr=do_quick_read(mybuf->asfd,
447 : mybuf->datapth, mybuf->cntr))<0)
448 : return ERROR_FUNCTION_FAILED;
449 : if(qr) // client wants to interrupt
450 : return ERROR_FUNCTION_FAILED;
451 : }
452 : return ERROR_SUCCESS;
453 : }
454 : #endif
455 :
456 9 : enum send_e send_whole_filel(struct asfd *asfd,
457 : #ifdef HAVE_WIN32
458 : enum cmd cmd,
459 : #endif
460 : const char *datapth,
461 : int quick_read, uint64_t *bytes, struct cntr *cntr,
462 : struct BFILE *bfd, const char *extrameta, size_t elen)
463 : {
464 9 : enum send_e ret=SEND_OK;
465 9 : ssize_t s=0;
466 9 : struct md5 *md5=NULL;
467 9 : char buf[4096]="";
468 9 : struct iobuf wbuf;
469 :
470 9 : if(!bfd)
471 : {
472 1 : logp("No bfd in %s()\n", __func__);
473 1 : return SEND_FATAL;
474 : }
475 :
476 8 : if(!(md5=md5_alloc(__func__)))
477 : return SEND_FATAL;
478 8 : if(!md5_init(md5))
479 : {
480 0 : logp("md5_init() failed\n");
481 0 : md5_free(&md5);
482 0 : return SEND_FATAL;
483 : }
484 :
485 8 : if(extrameta)
486 : {
487 : size_t metalen=0;
488 : const char *metadata=NULL;
489 :
490 : metadata=extrameta;
491 : metalen=elen;
492 :
493 : // Send metadata in chunks, rather than all at once.
494 0 : while(metalen>0)
495 : {
496 0 : if(metalen>ZCHUNK) s=ZCHUNK;
497 : else s=metalen;
498 :
499 0 : if(!md5_update(md5, metadata, s))
500 : {
501 0 : logp("md5_update() failed\n");
502 0 : ret=SEND_FATAL;
503 : }
504 0 : iobuf_set(&wbuf, CMD_APPEND, (char *)metadata, s);
505 0 : if(asfd->write(asfd, &wbuf))
506 0 : ret=SEND_FATAL;
507 :
508 0 : metadata+=s;
509 0 : metalen-=s;
510 :
511 0 : *bytes+=s;
512 : }
513 : }
514 : else
515 : {
516 : #ifdef HAVE_WIN32
517 : if(ret==SEND_OK && cmd==CMD_EFS_FILE)
518 : {
519 : struct winbuf mybuf;
520 : mybuf.md5=md5;
521 : mybuf.quick_read=quick_read;
522 : mybuf.datapth=datapth;
523 : mybuf.cntr=cntr;
524 : mybuf.bytes=bytes;
525 : mybuf.asfd=asfd;
526 : // The EFS read function, ReadEncryptedFileRaw(),
527 : // works in an annoying way. You have to give it a
528 : // function that it calls repeatedly every time the
529 : // read buffer is called.
530 : // So ReadEncryptedFileRaw() will not return until
531 : // it has read the whole file. I have no idea why
532 : // they do not have a plain 'read()' function for it.
533 :
534 : ReadEncryptedFileRaw((PFE_EXPORT_FUNC)write_efs,
535 : &mybuf, bfd->pvContext);
536 : }
537 : else
538 : #endif
539 :
540 : if(ret==SEND_OK)
541 : {
542 : #ifdef HAVE_WIN32
543 : int do_known_byte_count=0;
544 : size_t datalen=bfd->datalen;
545 : if(datalen>0) do_known_byte_count=1;
546 : #endif
547 10 : while(1)
548 : {
549 : #ifdef HAVE_WIN32
550 : if(do_known_byte_count)
551 : {
552 : s=bfd->read(bfd,
553 : buf, min((size_t)4096, datalen));
554 : if(s>0)
555 : datalen-=s;
556 : }
557 : else
558 : {
559 : #endif
560 10 : s=bfd->read(bfd, buf, 4096);
561 : #ifdef HAVE_WIN32
562 : }
563 : #endif
564 10 : if(!s)
565 : break;
566 2 : else if(s<0)
567 : {
568 0 : logw(asfd, cntr,
569 : "Error when reading %s in %s: %s\n",
570 0 : bfd->path, __func__, strerror(errno));
571 0 : ret=SEND_ERROR;
572 0 : break;
573 : }
574 :
575 2 : *bytes+=s;
576 2 : if(!md5_update(md5, buf, s))
577 : {
578 0 : logp("md5_update() failed\n");
579 0 : ret=SEND_FATAL;
580 0 : break;
581 : }
582 2 : iobuf_set(&wbuf, CMD_APPEND, buf, s);
583 2 : if(asfd->write(asfd, &wbuf))
584 : {
585 : ret=SEND_FATAL;
586 : break;
587 : }
588 2 : if(quick_read)
589 : {
590 2 : int qr;
591 2 : if((qr=do_quick_read(asfd, datapth, cntr))<0)
592 : {
593 : ret=SEND_FATAL;
594 : break;
595 : }
596 2 : if(qr)
597 : {
598 : // client wants to interrupt
599 : break;
600 : }
601 : }
602 : #ifdef HAVE_WIN32
603 : // Windows VSS headers tell us how many bytes to
604 : // expect.
605 : if(do_known_byte_count && datalen<=0) break;
606 : #endif
607 : }
608 : }
609 : }
610 8 : if(ret!=SEND_FATAL)
611 : {
612 8 : uint8_t checksum[MD5_DIGEST_LENGTH];
613 8 : if(!md5_final(md5, checksum))
614 : {
615 0 : logp("md5_final() failed\n");
616 0 : md5_free(&md5);
617 0 : return SEND_FATAL;
618 : }
619 8 : if(write_endfile(asfd, *bytes, checksum))
620 : return SEND_FATAL;
621 : }
622 8 : md5_free(&md5);
623 8 : return ret;
624 : }
|