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