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