LCOV - code coverage report
Current view: top level - src/protocol1 - handy.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 27 186 14.5 %
Date: 2015-11-30 Functions: 3 6 50.0 %

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

Generated by: LCOV version 1.10