LCOV - code coverage report
Current view: top level - src/protocol1 - handy.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 92 163 56.4 %
Date: 2016-09-04 Functions: 5 6 83.3 %

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

Generated by: LCOV version 1.10