LCOV - code coverage report
Current view: top level - src/protocol1 - handy.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 3 178 1.7 %
Date: 2015-10-31 Functions: 1 6 16.7 %

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

Generated by: LCOV version 1.10