Overview
SHA1 Hash: | 9a23c348b1bb1daa7a7a8517f1bc27862a2655c9 |
---|---|
Date: | 2009-03-27 14:32:33 |
User: | drh |
Comment: | Infrastructure in place on the client side to encrypt sync traffic. This is mostly untested so far because we do not yet have a server that understands encrypted traffic. |
Timelines: | ancestors | descendants | both | experimental |
Other Links: | files | ZIP archive | manifest |
Tags And Properties
- bgcolor=#ffc0d0 inherited from [5468ec7c5e]
- branch=experimental inherited from [5468ec7c5e]
- sym-experimental inherited from [5468ec7c5e]
Changes
[hide diffs]Modified src/blob.c from [2ed932bfd8] to [10f9b677e2].
@@ -929,17 +929,20 @@ ** Because of the prepended nonce, the output will be 20 bytes larger ** than the input. ** ** pOut should be initialized prior to invoking this routine. pOut might ** already contain other content. The encryption is appended to pOut. +** The encryption cannot be done in place; pOut cannot be the same blob +** as pIn. */ void blob_encrypt(Blob *pIn, const char *zPassword, Blob *pOut){ char *aNonce; char *aIn; int nIn; char *aOut; + assert( pIn!=pOut ); aIn = pIn->aData; aIn += pIn->iCursor; nIn = pIn->nUsed - pIn->iCursor; if( nIn<=0 ) return; blob_resize(pOut, pOut->nUsed+nIn+N_NONCE); @@ -961,11 +964,13 @@ ** Only that portion of pIn beginning at the current cursor location and ** extending to the end of the blob is decrypted. Any content of pIn ** prior to the current cursor position is ignored. ** ** pOut should be initialized prior to invoking this routine. pOut might -** already contain other content. The encryption is appended to pOut. +** already contain other content. The decryption is appended to pOut +** starting at its current cursor position. Decryption can be done +** in place; it is acceptable for pOut and pIn to be the same blob. */ void blob_decrypt(Blob *pIn, const char *zPassword, Blob *pOut){ char *aNonce; char *aIn; int nIn; @@ -973,14 +978,21 @@ aIn = pIn->aData; aNonce = aIn + pIn->iCursor; aIn = aNonce + N_NONCE; nIn = pIn->nUsed - pIn->iCursor - N_NONCE; - blob_resize(pOut, pOut->iCursor + nIn); + if( pOut!=pIn ){ + blob_resize(pOut, pOut->iCursor + nIn); + } aOut = pOut->aData; aOut += pOut->iCursor; rc4_coder(zPassword, aNonce, N_NONCE, aIn, nIn, aOut); + if( pOut==pIn ){ + pOut->nUsed = pOut->iCursor + nIn; + aOut[nIn] = 0; + pOut->iCursor = pOut->nUsed; + } } /* ** COMMAND: test-encrypt PASSWORD PLAINTEXT CYPHERTEXT
Modified src/http.c from [a7c94bef96] to [2a16b7f520].
@@ -172,16 +172,37 @@ return blob_size(pBlob); } #endif /* +** zLine is a line from the header of an HTTP reply. Find the +** "argument" to this header line. The argument is the first non-whitespace +** character following the first ":" in the line. The argument consists of +** non-whitespace and non-semicolon characters. Zero-terminate the argument +** before returning. +*/ +static char *header_arg(char *zIn){ + char *z; + while( *zIn && *zIn!=':' ){ zIn++; } + if( *zIn==':' ){ zIn++; } + while( isspace(*zIn) ){ zIn++; } + for(z=zIn; *z && *z!=';' && !isspace(*z); z++){} + *z = 0; + return zIn; +} + +/* ** Make a single attempt to talk to the server. Return TRUE on success ** and FALSE on a failure. ** ** pHeader contains the HTTP header. pPayload contains the content. ** The content of the reply is written into pReply. pReply is assumed ** to be uninitialized prior to this call. +** +** pPayload has already been compressed and/or encrypted prior to being +** passed into this function. pReply will be decrypted and/or decompressed +** as required by this function, based on the Content-Type of the reply. ** ** If an error occurs, this routine return false, resets pReply and ** closes the persistent connection, if any. */ static int http_send_recv(Blob *pHeader, Blob *pPayload, Blob *pReply){ @@ -189,10 +210,12 @@ int rc; int iLength; int iHttpVersion; int i; int nRead; + int needDecrypt = 0; + int needDecompress = 0; char zLine[2000]; if( pSocket==0 && http_open_socket() ){ return 0; } @@ -219,18 +242,27 @@ if( iHttpVersion==0 ){ closeConnection = 1; }else{ closeConnection = 0; } - } else if( strncasecmp(zLine, "content-length:", 15)==0 ){ - iLength = atoi(&zLine[16]); + }else if( strncasecmp(zLine,"content-length:",15)==0 ){ + iLength = atoi(header_arg(zLine)); }else if( strncasecmp(zLine, "connection:", 11)==0 ){ - for(i=12; isspace(zLine[i]); i++){} - if( zLine[i]=='c' || zLine[i]=='C' ){ - closeConnection = 1; - }else if( zLine[i]=='k' || zLine[i]=='K' ){ - closeConnection = 0; + int c = header_arg(zLine)[0]; + if( c=='c' || c=='C' ){ + closeConnection = 1; /* Connection: close */ + }else if( c=='k' || c=='K' ){ + closeConnection = 0; /* Connection: keep-alive */ + } + }else if( strncasecmp(zLine, "content-type:", 13)==0 ){ + const char *zType = header_arg(zLine); + if( strcmp(zType, "application/x-fossil")==0 ){ + needDecompress = 1; + needDecrypt = 0; + }else if( strcmp(zType, "application/x-fossil-secure")==0 ){ + needDecompress = 1; + needDecrypt = 1; } } } if( iLength<0 ) goto write_err; nRead = socket_read_blob(pReply, pSocket, iLength); @@ -251,17 +283,26 @@ while( fgets(zLine, sizeof(zLine), pSocket) ){ for(i=0; zLine[i] && zLine[i]!='\n' && zLine[i]!='\r'; i++){} if( i==0 ) break; zLine[i] = 0; if( strncasecmp(zLine,"content-length:",15)==0 ){ - iLength = atoi(&zLine[16]); + iLength = atoi(header_arg(zLine)); }else if( strncasecmp(zLine, "connection:", 11)==0 ){ - for(i=12; isspace(zLine[i]); i++){} - if( zLine[i]=='c' || zLine[i]=='C' ){ + int c = header_arg(zLine)[0]; + if( c=='c' || c=='C' ){ closeConnection = 1; /* Connection: close */ - }else if( zLine[i]=='k' || zLine[i]=='K' ){ + }else if( c=='k' || c=='K' ){ closeConnection = 0; /* Connection: keep-alive */ + } + }else if( strncasecmp(zLine, "content-type:", 13)==0 ){ + const char *zType = header_arg(zLine); + if( strcmp(zType, "application/x-fossil")==0 ){ + needDecompress = 1; + needDecrypt = 0; + }else if( strcmp(zType, "application/x-fossil-secure")==0 ){ + needDecompress = 1; + needDecrypt = 1; } } } if( iLength<0 ) goto write_err; nRead = blob_read_from_channel(pReply, pSocket, iLength); @@ -270,10 +311,16 @@ blob_reset(pReply); goto write_err; } if( closeConnection ){ http_close(); + } + if( needDecrypt ){ + blob_decrypt(pReply, g.urlPasswd, pReply); + } + if( needDecompress ){ + blob_uncompress(pReply, pReply); } return 1; write_err: http_close(); @@ -341,11 +388,15 @@ blob_reset(&pw); blob_reset(&sig); /* Construct the payload, which includes the login card. */ - if( g.fHttpTrace ){ + if( g.fHttpSecure && g.urlPasswd[0] ){ + blob_compress(pSend, pSend); + payload = login; + blob_encrypt(pSend, g.urlPasswd, &payload); + }else if( g.fHttpTrace ){ payload = login; blob_append(&payload, blob_buffer(pSend), blob_size(pSend)); }else{ blob_compress2(&login, pSend, &payload); blob_reset(&login); @@ -361,11 +412,13 @@ zSep = "/"; } blob_appendf(&hdr, "POST %s%sxfer HTTP/1.1\r\n", g.urlPath, zSep); blob_appendf(&hdr, "Host: %s\r\n", g.urlHostname); blob_appendf(&hdr, "User-Agent: Fossil/" MANIFEST_VERSION "\r\n"); - if( g.fHttpTrace ){ + if( g.fHttpSecure && g.urlPasswd[0] ){ + blob_appendf(&hdr, "Content-Type: application/x-fossil-secure\r\n"); + }else if( g.fHttpTrace ){ blob_appendf(&hdr, "Content-Type: application/x-fossil-debug\r\n"); }else{ blob_appendf(&hdr, "Content-Type: application/x-fossil\r\n"); } blob_appendf(&hdr, "Content-Length: %d\r\n\r\n", blob_size(&payload)); @@ -403,16 +456,15 @@ } blob_reset(&hdr); blob_reset(&payload); /* Process the reply. pRecv contains only the payload of the - ** reply message, not the header. + ** reply message, not the header. pRecv has already been decrypted + ** and decompressed */ if( g.fHttpTrace ){ printf("HTTP RECEIVE:\n%s\n=======================\n", blob_str(pRecv)); - }else{ - blob_uncompress(pRecv, pRecv); } } /*
Modified src/main.c from [828c799fea] to [ac2f572b24].
@@ -62,10 +62,11 @@ char *zLocalRoot; /* The directory holding the local database */ int minPrefix; /* Number of digits needed for a distinct UUID */ int fSqlTrace; /* True if -sqltrace flag is present */ int fSqlPrint; /* True if -sqlprint flag is present */ int fHttpTrace; /* Trace outbound HTTP requests */ + int fHttpSecure; /* Encrypt sync traffic */ int fNoSync; /* Do not do an autosync even. --nosync */ char *zPath; /* Name of webpage being served */ char *zExtra; /* Extra path information past the webpage name */ char *zBaseURL; /* Full text of the URL being served */ char *zTop; /* Parent directory of zPath */