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

Generated by: LCOV version 1.10