summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGernot Tenchio <gernot.tenchio@securepoint.de>2011-08-30 12:43:08 +0200
committerGernot Tenchio <gernot.tenchio@securepoint.de>2011-08-30 12:43:08 +0200
commit3eec97655871f4b5f39e20e44336d8b3ffacd537 (patch)
treed4017cbb6cfc5819bad8d762939f499bbc658800
parentfd73186769e00888a35067ef4c22cd668cb5d2ca (diff)
parent7d1c1033c5ee8689fd7896b2d7fadf8bd552382b (diff)
downloadlibtdevnc-3eec97655871f4b5f39e20e44336d8b3ffacd537.tar.gz
libtdevnc-3eec97655871f4b5f39e20e44336d8b3ffacd537.zip
Merge branch 'kanaka/websockets' into websockets
Conflicts: libvncserver/websockets.c
-rw-r--r--CMakeLists.txt1
-rw-r--r--common/sha1.c411
-rw-r--r--common/sha1.h101
-rw-r--r--libvncserver/Makefile.am2
-rw-r--r--libvncserver/rfbssl_gnutls.c88
-rwxr-xr-xlibvncserver/websockets.c332
6 files changed, 684 insertions, 251 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2db8d4f..3b1a0ef 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -193,6 +193,7 @@ if(LIBVNCSERVER_WITH_WEBSOCKETS)
${LIBVNCSERVER_DIR}/websockets.c
${LIBVNCSERVER_DIR}/${WSSRCS}
${COMMON_DIR}/md5.c
+ ${COMMON_DIR}/sha1.c
)
endif(LIBVNCSERVER_WITH_WEBSOCKETS)
diff --git a/common/sha1.c b/common/sha1.c
new file mode 100644
index 0000000..988b188
--- /dev/null
+++ b/common/sha1.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) The Internet Society (2001). All Rights Reserved.
+ *
+ * This document and translations of it may be copied and furnished to
+ * others, and derivative works that comment on or otherwise explain it
+ * or assist in its implementation may be prepared, copied, published
+ * and distributed, in whole or in part, without restriction of any
+ * kind, provided that the above copyright notice and this paragraph are
+ * included on all such copies and derivative works. However, this
+ * document itself may not be modified in any way, such as by removing
+ * the copyright notice or references to the Internet Society or other
+ * Internet organizations, except as needed for the purpose of
+ * developing Internet standards in which case the procedures for
+ * copyrights defined in the Internet Standards process must be
+ * followed, or as required to translate it into languages other than
+ * English.
+ *
+ * The limited permissions granted above are perpetual and will not be
+ * revoked by the Internet Society or its successors or assigns.
+ *
+ * This document and the information contained herein is provided on an
+ * "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ * TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ * HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * sha1.c
+ *
+ * Description:
+ * This file implements the Secure Hashing Algorithm 1 as
+ * defined in FIPS PUB 180-1 published April 17, 1995.
+ *
+ * The SHA-1, produces a 160-bit message digest for a given
+ * data stream. It should take about 2**n steps to find a
+ * message with the same digest as a given message and
+ * 2**(n/2) to find any two messages with the same digest,
+ * when n is the digest size in bits. Therefore, this
+ * algorithm can serve as a means of providing a
+ * "fingerprint" for a message.
+ *
+ * Portability Issues:
+ * SHA-1 is defined in terms of 32-bit "words". This code
+ * uses <stdint.h> (included via "sha1.h" to define 32 and 8
+ * bit unsigned integer types. If your C compiler does not
+ * support 32 bit unsigned integers, this code is not
+ * appropriate.
+ *
+ * Caveats:
+ * SHA-1 is designed to work with messages less than 2^64 bits
+ * long. Although SHA-1 allows a message digest to be generated
+ * for messages of any number of bits less than 2^64, this
+ * implementation only works with messages with a length that is
+ * a multiple of the size of an 8-bit character.
+ *
+ */
+
+#include "sha1.h"
+
+/*
+ * Define the SHA1 circular left shift macro
+ */
+#define SHA1CircularShift(bits,word) \
+ (((word) << (bits)) | ((word) >> (32-(bits))))
+
+/* Local Function Prototyptes */
+void SHA1PadMessage(SHA1Context *);
+void SHA1ProcessMessageBlock(SHA1Context *);
+
+/*
+ * SHA1Reset
+ *
+ * Description:
+ * This function will initialize the SHA1Context in preparation
+ * for computing a new SHA1 message digest.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Reset(SHA1Context *context)
+{
+ if (!context)
+ {
+ return shaNull;
+ }
+
+ context->Length_Low = 0;
+ context->Length_High = 0;
+ context->Message_Block_Index = 0;
+
+ context->Intermediate_Hash[0] = 0x67452301;
+ context->Intermediate_Hash[1] = 0xEFCDAB89;
+ context->Intermediate_Hash[2] = 0x98BADCFE;
+ context->Intermediate_Hash[3] = 0x10325476;
+ context->Intermediate_Hash[4] = 0xC3D2E1F0;
+
+ context->Computed = 0;
+ context->Corrupted = 0;
+ return shaSuccess;
+}
+
+/*
+ * SHA1Result
+ *
+ * Description:
+ * This function will return the 160-bit message digest into the
+ * Message_Digest array provided by the caller.
+ * NOTE: The first octet of hash is stored in the 0th element,
+ * the last octet of hash in the 19th element.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to use to calculate the SHA-1 hash.
+ * Message_Digest: [out]
+ * Where the digest is returned.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Result( SHA1Context *context,
+ uint8_t Message_Digest[SHA1HashSize])
+{
+ int i;
+
+ if (!context || !Message_Digest)
+ {
+ return shaNull;
+ }
+
+ if (context->Corrupted)
+ {
+ return context->Corrupted;
+ }
+
+ if (!context->Computed)
+ {
+ SHA1PadMessage(context);
+ for(i=0; i<64; ++i)
+ {
+ /* message may be sensitive, clear it out */
+ context->Message_Block[i] = 0;
+ }
+ context->Length_Low = 0; /* and clear length */
+ context->Length_High = 0;
+ context->Computed = 1;
+ }
+
+ for(i = 0; i < SHA1HashSize; ++i)
+ {
+ Message_Digest[i] = context->Intermediate_Hash[i>>2]
+ >> 8 * ( 3 - ( i & 0x03 ) );
+ }
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1Input
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion
+ * of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update
+ * message_array: [in]
+ * An array of characters representing the next portion of
+ * the message.
+ * length: [in]
+ * The length of the message in message_array
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Input( SHA1Context *context,
+ const uint8_t *message_array,
+ unsigned length)
+{
+ if (!length)
+ {
+ return shaSuccess;
+ }
+
+ if (!context || !message_array)
+ {
+ return shaNull;
+ }
+
+ if (context->Computed)
+ {
+ context->Corrupted = shaStateError;
+ return shaStateError;
+ }
+
+ if (context->Corrupted)
+ {
+ return context->Corrupted;
+ }
+ while(length-- && !context->Corrupted)
+ {
+ context->Message_Block[context->Message_Block_Index++] =
+ (*message_array & 0xFF);
+
+ context->Length_Low += 8;
+ if (context->Length_Low == 0)
+ {
+ context->Length_High++;
+ if (context->Length_High == 0)
+ {
+ /* Message is too long */
+ context->Corrupted = 1;
+ }
+ }
+
+ if (context->Message_Block_Index == 64)
+ {
+ SHA1ProcessMessageBlock(context);
+ }
+
+ message_array++;
+ }
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1ProcessMessageBlock
+ *
+ * Description:
+ * This function will process the next 512 bits of the message
+ * stored in the Message_Block array.
+ *
+ * Parameters:
+ * None.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the
+ * names used in the publication.
+ *
+ *
+ */
+void SHA1ProcessMessageBlock(SHA1Context *context)
+{
+ const uint32_t K[] = { /* Constants defined in SHA-1 */
+ 0x5A827999,
+ 0x6ED9EBA1,
+ 0x8F1BBCDC,
+ 0xCA62C1D6
+ };
+ int t; /* Loop counter */
+ uint32_t temp; /* Temporary word value */
+ uint32_t W[80]; /* Word sequence */
+ uint32_t A, B, C, D, E; /* Word buffers */
+
+ /*
+ * Initialize the first 16 words in the array W
+ */
+ for(t = 0; t < 16; t++)
+ {
+ W[t] = context->Message_Block[t * 4] << 24;
+ W[t] |= context->Message_Block[t * 4 + 1] << 16;
+ W[t] |= context->Message_Block[t * 4 + 2] << 8;
+ W[t] |= context->Message_Block[t * 4 + 3];
+ }
+
+ for(t = 16; t < 80; t++)
+ {
+ W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+ }
+
+ A = context->Intermediate_Hash[0];
+ B = context->Intermediate_Hash[1];
+ C = context->Intermediate_Hash[2];
+ D = context->Intermediate_Hash[3];
+ E = context->Intermediate_Hash[4];
+
+ for(t = 0; t < 20; t++)
+ {
+ temp = SHA1CircularShift(5,A) +
+ ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for(t = 20; t < 40; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for(t = 40; t < 60; t++)
+ {
+ temp = SHA1CircularShift(5,A) +
+ ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for(t = 60; t < 80; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ context->Intermediate_Hash[0] += A;
+ context->Intermediate_Hash[1] += B;
+ context->Intermediate_Hash[2] += C;
+ context->Intermediate_Hash[3] += D;
+ context->Intermediate_Hash[4] += E;
+
+ context->Message_Block_Index = 0;
+}
+
+
+/*
+ * SHA1PadMessage
+ *
+ * Description:
+ * According to the standard, the message must be padded to an even
+ * 512 bits. The first padding bit must be a '1'. The last 64
+ * bits represent the length of the original message. All bits in
+ * between should be 0. This function will pad the message
+ * according to those rules by filling the Message_Block array
+ * accordingly. It will also call the ProcessMessageBlock function
+ * provided appropriately. When it returns, it can be assumed that
+ * the message digest has been computed.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to pad
+ * ProcessMessageBlock: [in]
+ * The appropriate SHA*ProcessMessageBlock function
+ * Returns:
+ * Nothing.
+ *
+ */
+
+void SHA1PadMessage(SHA1Context *context)
+{
+ /*
+ * Check to see if the current message block is too small to hold
+ * the initial padding bits and length. If so, we will pad the
+ * block, process it, and then continue padding into a second
+ * block.
+ */
+ if (context->Message_Block_Index > 55)
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0x80;
+ while(context->Message_Block_Index < 64)
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+
+ SHA1ProcessMessageBlock(context);
+
+ while(context->Message_Block_Index < 56)
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+ }
+ else
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0x80;
+ while(context->Message_Block_Index < 56)
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+ }
+
+ /*
+ * Store the message length as the last 8 octets
+ */
+ context->Message_Block[56] = context->Length_High >> 24;
+ context->Message_Block[57] = context->Length_High >> 16;
+ context->Message_Block[58] = context->Length_High >> 8;
+ context->Message_Block[59] = context->Length_High;
+ context->Message_Block[60] = context->Length_Low >> 24;
+ context->Message_Block[61] = context->Length_Low >> 16;
+ context->Message_Block[62] = context->Length_Low >> 8;
+ context->Message_Block[63] = context->Length_Low;
+
+ SHA1ProcessMessageBlock(context);
+}
diff --git a/common/sha1.h b/common/sha1.h
new file mode 100644
index 0000000..1d49b1b
--- /dev/null
+++ b/common/sha1.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) The Internet Society (2001). All Rights Reserved.
+ *
+ * This document and translations of it may be copied and furnished to
+ * others, and derivative works that comment on or otherwise explain it
+ * or assist in its implementation may be prepared, copied, published
+ * and distributed, in whole or in part, without restriction of any
+ * kind, provided that the above copyright notice and this paragraph are
+ * included on all such copies and derivative works. However, this
+ * document itself may not be modified in any way, such as by removing
+ * the copyright notice or references to the Internet Society or other
+ * Internet organizations, except as needed for the purpose of
+ * developing Internet standards in which case the procedures for
+ * copyrights defined in the Internet Standards process must be
+ * followed, or as required to translate it into languages other than
+ * English.
+ *
+ * The limited permissions granted above are perpetual and will not be
+ * revoked by the Internet Society or its successors or assigns.
+ *
+ * This document and the information contained herein is provided on an
+ * "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ * TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ * HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * sha1.h
+ *
+ * Description:
+ * This is the header file for code which implements the Secure
+ * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
+ * April 17, 1995.
+ *
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the names
+ * used in the publication.
+ *
+ * Please read the file sha1.c for more information.
+ *
+ */
+
+
+#ifndef _SHA1_H_
+#define _SHA1_H_
+
+#include <stdint.h>
+/*
+ * If you do not have the ISO standard stdint.h header file, then you
+ * must typdef the following:
+ * name meaning
+ * uint32_t unsigned 32 bit integer
+ * uint8_t unsigned 8 bit integer (i.e., unsigned char)
+ * int_least16_t integer of >= 16 bits
+ *
+ */
+
+#ifndef _SHA_enum_
+#define _SHA_enum_
+enum
+{
+ shaSuccess = 0,
+ shaNull, /* Null pointer parameter */
+ shaInputTooLong, /* input data too long */
+ shaStateError /* called Input after Result */
+};
+#endif
+#define SHA1HashSize 20
+
+/*
+ * This structure will hold context information for the SHA-1
+ * hashing operation
+ */
+typedef struct SHA1Context
+{
+ uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
+
+ uint32_t Length_Low; /* Message length in bits */
+ uint32_t Length_High; /* Message length in bits */
+
+ /* Index into message block array */
+ int_least16_t Message_Block_Index;
+ uint8_t Message_Block[64]; /* 512-bit message blocks */
+
+ int Computed; /* Is the digest computed? */
+ int Corrupted; /* Is the message digest corrupted? */
+} SHA1Context;
+
+/*
+ * Function Prototypes
+ */
+int SHA1Reset( SHA1Context *);
+int SHA1Input( SHA1Context *,
+ const uint8_t *,
+ unsigned int);
+int SHA1Result( SHA1Context *,
+ uint8_t Message_Digest[SHA1HashSize]);
+
+#endif
diff --git a/libvncserver/Makefile.am b/libvncserver/Makefile.am
index a9feac1..4a031af 100644
--- a/libvncserver/Makefile.am
+++ b/libvncserver/Makefile.am
@@ -24,7 +24,7 @@ WEBSOCKETSSSLSRCS = rfbssl_none.c
#endif
endif
-WEBSOCKETSSRCS = websockets.c ../common/md5.c $(WEBSOCKETSSSLSRCS)
+WEBSOCKETSSRCS = websockets.c ../common/md5.c ../common/sha1.c $(WEBSOCKETSSSLSRCS)
endif
includedir=$(prefix)/include/rfb
diff --git a/libvncserver/rfbssl_gnutls.c b/libvncserver/rfbssl_gnutls.c
index 33e076e..0689c01 100644
--- a/libvncserver/rfbssl_gnutls.c
+++ b/libvncserver/rfbssl_gnutls.c
@@ -190,11 +190,8 @@ int rfbssl_write(rfbClientPtr cl, const char *buf, int bufsize)
return ret;
}
-int rfbssl_peek(rfbClientPtr cl, char *buf, int bufsize)
+static void rfbssl_gc_peekbuf(struct rfbssl_ctx *ctx, int bufsize)
{
- int ret = -1;
- struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx;
-
if (ctx->peekstart) {
int spaceleft = sizeof(ctx->peekbuf) - ctx->peeklen - ctx->peekstart;
if (spaceleft < bufsize) {
@@ -202,44 +199,40 @@ int rfbssl_peek(rfbClientPtr cl, char *buf, int bufsize)
ctx->peekstart = 0;
}
}
+}
+
+static int __rfbssl_read(rfbClientPtr cl, char *buf, int bufsize, int peek)
+{
+ int ret = 0;
+ struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx;
+
+ rfbssl_gc_peekbuf(ctx, bufsize);
- /* If we have any peek data, simply return that. */
if (ctx->peeklen) {
- if (bufsize > ctx->peeklen) {
- /* more than we have, so we are trying to read the remaining
- * bytes
- **/
- int required = bufsize - ctx->peeklen;
- int total = ctx->peekstart + ctx->peeklen;
- int n, avail = sizeof(ctx->peekbuf) - total;
-
- if (required > avail)
- required = avail;
-
- if (!required) {
- rfbErr("%s: no space left\n", __func__);
- } else if ((n = rfbssl_do_read(cl, ctx->peekbuf + total, required)) < 0) {
- rfbErr("%s: read error\n", __func__);
- return n;
- } else {
- ctx->peeklen += n;
- }
- ret = ctx->peeklen;
- } else {
- /* simply return what we have */
- ret = bufsize;
+ /* If we have any peek data, simply return that. */
+ ret = bufsize < ctx->peeklen ? bufsize : ctx->peeklen;
+ memcpy (buf, ctx->peekbuf + ctx->peekstart, ret);
+ if (!peek) {
+ ctx->peeklen -= ret;
+ if (ctx->peeklen != 0)
+ ctx->peekstart += ret;
+ else
+ ctx->peekstart = 0;
}
- } else {
- ret = bufsize;
- if (ret > sizeof(ctx->peekbuf))
- ret = sizeof(ctx->peekbuf);
-
- if ((ret = rfbssl_do_read(cl, ctx->peekbuf, ret)) > 0)
- ctx->peeklen = ret;
}
- if (ret >= 0) {
- memcpy(buf, ctx->peekbuf + ctx->peekstart, ret);
+ if (ret < bufsize) {
+ int n;
+ /* read the remaining data */
+ if ((n = rfbssl_do_read(cl, buf + ret, bufsize - ret)) <= 0) {
+ rfbErr("rfbssl_%s: %s error\n", __func__, peek ? "peek" : "read");
+ return n;
+ }
+ if (peek) {
+ memcpy(ctx->peekbuf + ctx->peekstart + ctx->peeklen, buf + ret, n);
+ ctx->peeklen += n;
+ }
+ ret += n;
}
return ret;
@@ -247,23 +240,12 @@ int rfbssl_peek(rfbClientPtr cl, char *buf, int bufsize)
int rfbssl_read(rfbClientPtr cl, char *buf, int bufsize)
{
- int ret;
- struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx;
-
- if (ctx->peeklen) {
- /* If we have any peek data, simply return that. */
- ret = bufsize < ctx->peeklen ? bufsize : ctx->peeklen;
- memcpy (buf, ctx->peekbuf + ctx->peekstart, ret);
- ctx->peeklen -= ret;
- if (ctx->peeklen != 0)
- ctx->peekstart += ret;
- else
- ctx->peekstart = 0;
- } else {
- ret = rfbssl_do_read(cl, buf, bufsize);
- }
+ return __rfbssl_read(cl, buf, bufsize, 0);
+}
- return ret;
+int rfbssl_peek(rfbClientPtr cl, char *buf, int bufsize)
+{
+ return __rfbssl_read(cl, buf, bufsize, 1);
}
int rfbssl_pending(rfbClientPtr cl)
diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c
index 414e573..4d35226 100755
--- a/libvncserver/websockets.c
+++ b/libvncserver/websockets.c
@@ -31,8 +31,10 @@
/* errno */
#include <errno.h>
-#include <md5.h>
#include <byteswap.h>
+#include <string.h>
+#include "md5.h"
+#include "sha1.h"
#include "rfbconfig.h"
#include "rfbssl.h"
@@ -58,10 +60,12 @@ enum {
WEBSOCKETS_VERSION_HYBI
};
+#if 0
#include <sys/syscall.h>
static int gettid() {
return (int)syscall(SYS_gettid);
}
+#endif
typedef int (*wsEncodeFunc)(rfbClientPtr cl, const char *src, int len, char **dst);
typedef int (*wsDecodeFunc)(rfbClientPtr cl, char *dst, int len);
@@ -162,38 +166,35 @@ min (int a, int b) {
return a < b ? a : b;
}
-#ifdef LIBVNCSERVER_WITH_CLIENT_GCRYPT
-#include <gcrypt.h>
-#ifndef SHA_DIGEST_LENGTH
-#define SHA_DIGEST_LENGTH 20
-#endif
-static void webSocketsGenSha1Key(char *target, int size, char *key)
+void
+webSocketsGenSha1Key(char * target, int size, char *key)
{
- gcry_md_hd_t c;
- unsigned char tmp[SHA_DIGEST_LENGTH];
- gcry_md_open(&c, GCRY_MD_SHA1, 0);
- gcry_md_write(c, key, strlen(key));
- gcry_md_write(c, GUID, sizeof(GUID) - 1);
- gcry_md_final(c);
- if (-1 == __b64_ntop(gcry_md_read(c, 0), SHA_DIGEST_LENGTH, target, size))
- rfbErr("b64_ntop failed\n");
-}
-#else
-#include <openssl/sha.h>
+ int len;
+ SHA1Context sha;
+ uint8_t digest[SHA1HashSize];
+
+ if (size < B64LEN(SHA1HashSize) + 1) {
+ rfbErr("webSocketsGenSha1Key: not enough space in target\n");
+ target[0] = '\0';
+ return;
+ }
-static void webSocketsGenSha1Key(char *target, int size, char *key)
-{
- SHA_CTX c;
- unsigned char tmp[SHA_DIGEST_LENGTH];
-
- SHA1_Init(&c);
- SHA1_Update(&c, key, strlen(key));
- SHA1_Update(&c, GUID, sizeof(GUID) - 1);
- SHA1_Final(tmp, &c);
- if (-1 == __b64_ntop(tmp, SHA_DIGEST_LENGTH, target, size))
- rfbErr("b64_ntop failed\n");
+ SHA1Reset(&sha);
+ SHA1Input(&sha, (unsigned char *)key, strlen(key));
+ SHA1Input(&sha, (unsigned char *)GUID, strlen(GUID));
+ SHA1Result(&sha, digest);
+
+ len = __b64_ntop((unsigned char *)digest, SHA1HashSize, target, size);
+ if (len < size - 1) {
+ rfbErr("webSocketsGenSha1Key: b64_ntop failed\n");
+ target[0] = '\0';
+ return;
+ }
+
+ target[len] = '\0';
+ return;
}
-#endif
+
/*
* rfbWebSocketsHandshake is called to handle new WebSockets connections
@@ -252,7 +253,7 @@ static rfbBool
webSocketsHandshake(rfbClientPtr cl, char *scheme)
{
char *buf, *response, *line;
- int n, linestart = 0, len = 0, llen, base64 = 0;
+ int n, linestart = 0, len = 0, llen, base64 = TRUE;
char prefix[5], trailer[17];
char *path = NULL, *host = NULL, *origin = NULL, *protocol = NULL;
char *key1 = NULL, *key2 = NULL, *key3 = NULL;
@@ -283,6 +284,8 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme)
rfbLog("webSocketsHandshake: client gone\n");
else
rfbLogPerror("webSocketsHandshake: read");
+ free(response);
+ free(buf);
return FALSE;
}
@@ -300,6 +303,8 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme)
rfbLog("webSocketsHandshake: client gone\n");
else
rfbLogPerror("webSocketsHandshake: read");
+ free(response);
+ free(buf);
return FALSE;
}
rfbLog("Got key3\n");
@@ -313,7 +318,6 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme)
/* 16 = 4 ("GET ") + 1 ("/.*") + 11 (" HTTP/1.1\r\n") */
path = line+4;
buf[len-11] = '\0'; /* Trim trailing " HTTP/1.1\r\n" */
- base64 = TRUE;
cl->wspath = strdup(path);
/* rfbLog("Got path: %s\n", path); */
} else if ((strncasecmp("host: ", line, min(llen,6))) == 0) {
@@ -360,14 +364,25 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme)
return FALSE;
}
- /*
- if ((!protocol) || (!strcasestr(protocol, "base64"))) {
- rfbErr("webSocketsHandshake: base64 subprotocol not supported by client\n");
- free(response);
- free(buf);
- return FALSE;
+ if ((protocol) && (strstr(protocol, "binary"))) {
+ if (! sec_ws_version) {
+ rfbErr("webSocketsHandshake: 'binary' protocol not supported with Hixie\n");
+ free(response);
+ free(buf);
+ return FALSE;
+ }
+ rfbLog(" - webSocketsHandshake: using binary/raw encoding\n");
+ base64 = FALSE;
+ protocol = "binary";
+ } else {
+ rfbLog(" - webSocketsHandshake: using base64 encoding\n");
+ base64 = TRUE;
+ if ((protocol) && (strstr(protocol, "base64"))) {
+ protocol = "base64";
+ } else {
+ protocol = "";
+ }
}
- */
/*
* Generate the WebSockets server response based on the the headers sent
@@ -375,7 +390,7 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme)
*/
if (sec_ws_version) {
- char accept[SHA_DIGEST_LENGTH * 3];
+ char accept[B64LEN(SHA1HashSize) + 1];
rfbLog(" - WebSockets client version hybi-%02d\n", sec_ws_version);
webSocketsGenSha1Key(accept, sizeof(accept), sec_ws_key);
len = snprintf(response, WEBSOCKETS_MAX_HANDSHAKE_LEN,
@@ -472,38 +487,16 @@ webSocketsGenMd5(char * target, char *key1, char *key2, char *key3)
static int
webSocketsEncodeHixie(rfbClientPtr cl, const char *src, int len, char **dst)
{
- int i, sz = 0;
- unsigned char chr;
+ int sz = 0;
ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx;
wsctx->encodeBuf[sz++] = '\x00';
- if (wsctx->base64) {
- len = __b64_ntop((unsigned char *)src, len, wsctx->encodeBuf+sz, sizeof(wsctx->encodeBuf) - (sz + 1));
- if (len < 0) {
- return len;
- }
- sz += len;
- } else {
- for (i=0; i < len; i++) {
- chr = src[i];
- if (chr < 128) {
- if (chr == 0x00) {
- wsctx->encodeBuf[sz++] = '\xc4';
- wsctx->encodeBuf[sz++] = '\x80';
- } else {
- wsctx->encodeBuf[sz++] = chr;
- }
- } else {
- if (chr < 192) {
- wsctx->encodeBuf[sz++] = '\xc2';
- wsctx->encodeBuf[sz++] = chr;
- } else {
- wsctx->encodeBuf[sz++] = '\xc3';
- wsctx->encodeBuf[sz++] = chr - 64;
- }
- }
- }
+ len = __b64_ntop((unsigned char *)src, len, wsctx->encodeBuf+sz, sizeof(wsctx->encodeBuf) - (sz + 1));
+ if (len < 0) {
+ return len;
}
+ sz += len;
+
wsctx->encodeBuf[sz++] = '\xff';
*dst = wsctx->encodeBuf;
return sz;
@@ -539,9 +532,8 @@ ws_peek(rfbClientPtr cl, char *buf, int len)
static int
webSocketsDecodeHixie(rfbClientPtr cl, char *dst, int len)
{
- int retlen = 0, n, i, avail, modlen, needlen, actual;
+ int retlen = 0, n, i, avail, modlen, needlen;
char *buf, *end = NULL;
- unsigned char chr, chr2;
ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx;
buf = wsctx->decodeBuf;
@@ -554,133 +546,75 @@ webSocketsDecodeHixie(rfbClientPtr cl, char *dst, int len)
}
- if (wsctx->base64) {
- /* Base64 encoded WebSockets stream */
-
- if (buf[0] == '\xff') {
- i = ws_read(cl, buf, 1); /* Consume marker */
- buf++;
- n--;
- }
- if (n == 0) {
- errno = EAGAIN;
- return -1;
- }
- if (buf[0] == '\x00') {
- i = ws_read(cl, buf, 1); /* Consume marker */
- buf++;
- n--;
- }
- if (n == 0) {
- errno = EAGAIN;
- return -1;
- }
-
- /* end = memchr(buf, '\xff', len*2+2); */
- end = memchr(buf, '\xff', n);
- if (!end) {
- end = buf + n;
- }
- avail = end - buf;
-
- len -= wsctx->carrylen;
+ /* Base64 encoded WebSockets stream */
- /* Determine how much base64 data we need */
- modlen = len + (len+2)/3;
- needlen = modlen;
- if (needlen % 4) {
- needlen += 4 - (needlen % 4);
- }
+ if (buf[0] == '\xff') {
+ i = ws_read(cl, buf, 1); /* Consume marker */
+ buf++;
+ n--;
+ }
+ if (n == 0) {
+ errno = EAGAIN;
+ return -1;
+ }
+ if (buf[0] == '\x00') {
+ i = ws_read(cl, buf, 1); /* Consume marker */
+ buf++;
+ n--;
+ }
+ if (n == 0) {
+ errno = EAGAIN;
+ return -1;
+ }
- if (needlen > avail) {
- /* rfbLog("Waiting for more base64 data\n"); */
- errno = EAGAIN;
- return -1;
- }
+ /* end = memchr(buf, '\xff', len*2+2); */
+ end = memchr(buf, '\xff', n);
+ if (!end) {
+ end = buf + n;
+ }
+ avail = end - buf;
- /* Any carryover from previous decode */
- for (i=0; i < wsctx->carrylen; i++) {
- /* rfbLog("Adding carryover %d\n", wsctx->carryBuf[i]); */
- dst[i] = wsctx->carryBuf[i];
- retlen += 1;
- }
+ len -= wsctx->carrylen;
- /* Decode the rest of what we need */
- buf[needlen] = '\x00'; /* Replace end marker with end of string */
- /* rfbLog("buf: %s\n", buf); */
- n = __b64_pton(buf, (unsigned char *)dst+retlen, 2+len);
- if (n < len) {
- rfbErr("Base64 decode error\n");
- errno = EIO;
- return -1;
- }
- retlen += n;
+ /* Determine how much base64 data we need */
+ modlen = len + (len+2)/3;
+ needlen = modlen;
+ if (needlen % 4) {
+ needlen += 4 - (needlen % 4);
+ }
- /* Consume the data from socket */
- i = ws_read(cl, buf, needlen);
+ if (needlen > avail) {
+ /* rfbLog("Waiting for more base64 data\n"); */
+ errno = EAGAIN;
+ return -1;
+ }
- wsctx->carrylen = n - len;
- retlen -= wsctx->carrylen;
- for (i=0; i < wsctx->carrylen; i++) {
- /* rfbLog("Saving carryover %d\n", dst[retlen + i]); */
- wsctx->carryBuf[i] = dst[retlen + i];
- }
- } else {
- /* UTF-8 encoded WebSockets stream */
-
- actual = 0;
- for (needlen = 0; needlen < n && actual < len; needlen++) {
- chr = buf[needlen];
- if ((chr > 0) && (chr < 128)) {
- actual++;
- } else if ((chr > 127) && (chr < 255)) {
- if (needlen + 1 >= n) {
- break;
- }
- needlen++;
- actual++;
- }
- }
+ /* Any carryover from previous decode */
+ for (i=0; i < wsctx->carrylen; i++) {
+ /* rfbLog("Adding carryover %d\n", wsctx->carryBuf[i]); */
+ dst[i] = wsctx->carryBuf[i];
+ retlen += 1;
+ }
- if (actual < len) {
- errno = EAGAIN;
- return -1;
- }
+ /* Decode the rest of what we need */
+ buf[needlen] = '\x00'; /* Replace end marker with end of string */
+ /* rfbLog("buf: %s\n", buf); */
+ n = __b64_pton(buf, (unsigned char *)dst+retlen, 2+len);
+ if (n < len) {
+ rfbErr("Base64 decode error\n");
+ errno = EIO;
+ return -1;
+ }
+ retlen += n;
- /* Consume what we need */
- if ((n = ws_read(cl, buf, needlen)) < needlen) {
- return n;
- }
+ /* Consume the data from socket */
+ i = ws_read(cl, buf, needlen);
- while (retlen < len) {
- chr = buf[0];
- buf += 1;
- if (chr == 0) {
- /* Begin frame marker, just skip it */
- } else if (chr == 255) {
- /* Begin frame marker, just skip it */
- } else if (chr < 128) {
- dst[retlen++] = chr;
- } else {
- chr2 = buf[0];
- buf += 1;
- switch (chr) {
- case (unsigned char) '\xc2':
- dst[retlen++] = chr2;
- break;
- case (unsigned char) '\xc3':
- dst[retlen++] = chr2 + 64;
- break;
- case (unsigned char) '\xc4':
- dst[retlen++] = 0;
- break;
- default:
- rfbErr("Invalid UTF-8 encoding\n");
- errno = EIO;
- return -1;
- }
- }
- }
+ wsctx->carrylen = n - len;
+ retlen -= wsctx->carrylen;
+ for (i=0; i < wsctx->carrylen; i++) {
+ /* rfbLog("Saving carryover %d\n", dst[retlen + i]); */
+ wsctx->carryBuf[i] = dst[retlen + i];
}
/* rfbLog("<< webSocketsDecode, retlen: %d\n", retlen); */
@@ -690,15 +624,16 @@ webSocketsDecodeHixie(rfbClientPtr cl, char *dst, int len)
static int
webSocketsDecodeHybi(rfbClientPtr cl, char *dst, int len)
{
- char *buf, *payload, *rbuf;
+ char *buf, *payload;
+ uint32_t *payload32;
int ret = -1, result = -1;
int total = 0;
ws_mask_t mask;
ws_header_t *header;
- int i, j;
+ int i;
unsigned char opcode;
ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx;
- int flength, fin, fhlen, blen;
+ int flength, fin, fhlen;
// rfbLog(" <== %s[%d]: %d cl: %p, wsctx: %p-%p (%d)\n", __func__, gettid(), len, cl, wsctx, (char *)wsctx + sizeof(ws_ctx_t), sizeof(ws_ctx_t));
@@ -779,11 +714,14 @@ webSocketsDecodeHybi(rfbClientPtr cl, char *dst, int len)
buf[ret] = '\0';
}
- /* process 1 frame */
- /* GT TODO: improve it with 32 bit operations */
- for (i = 0; i < flength; i++) {
- j = i % 4;
- payload[i] ^= mask.c[j];
+ /* process 1 frame (32 bit op) */
+ payload32 = (uint32_t *)payload;
+ for (i = 0; i < flength / 4; i++) {
+ payload32[i] ^= mask.u;
+ }
+ /* process the remaining bytes (if any) */
+ for (i*=4; i < flength; i++) {
+ payload[i] ^= mask.c[i % 4];
}
switch (opcode) {
@@ -937,7 +875,7 @@ webSocketCheckDisconnect(rfbClientPtr cl)
doclose = 1;
break;
default:
- ;
+ return FALSE;
}
if (cl->sslctx)