summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2000-04-09 11:49:42 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2000-04-09 11:49:42 +0000
commitccb26d30efc4aeda237196cab4cb88fb40dc9f25 (patch)
tree29ace3c191e2ce6acb203093d7a9ce23644d0245 /lib
parentaf145d777894217cc337ce6505566d6799d8831b (diff)
downloadgnutls-ccb26d30efc4aeda237196cab4cb88fb40dc9f25.tar.gz
Changed directory structure.
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am5
-rw-r--r--lib/debug.c91
-rw-r--r--lib/debug.h5
-rw-r--r--lib/defines.h75
-rw-r--r--lib/gnutls.c663
-rw-r--r--lib/gnutls.h42
-rw-r--r--lib/gnutls_algorithms.c161
-rw-r--r--lib/gnutls_algorithms.h76
-rw-r--r--lib/gnutls_buffers.c88
-rw-r--r--lib/gnutls_buffers.h5
-rw-r--r--lib/gnutls_cipher.c589
-rw-r--r--lib/gnutls_cipher.h15
-rw-r--r--lib/gnutls_compress.c79
-rw-r--r--lib/gnutls_compress.h11
-rw-r--r--lib/gnutls_dh.c662
-rw-r--r--lib/gnutls_errors.c31
-rw-r--r--lib/gnutls_errors.h19
-rw-r--r--lib/gnutls_handshake.c710
-rw-r--r--lib/gnutls_handshake.h9
-rw-r--r--lib/gnutls_int.h254
-rw-r--r--lib/gnutls_num.c21
-rw-r--r--lib/gnutls_num.h2
-rw-r--r--lib/gnutls_plaintext.c51
-rw-r--r--lib/gnutls_plaintext.h3
24 files changed, 3667 insertions, 0 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index e69de29bb2..96d22e33fe 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -0,0 +1,5 @@
+include_HEADERS = gnutls.h
+EXTRA_DIST = debug.h gnutls_compress.h defines.h gnutls_plaintext.h gnutls_cipher.h gnutls_buffers.h gnutls_errors.h gnutls_int.h gnutls_handshake.h gnutls_num.h gnutls_algorithms.h
+lib_LTLIBRARIES = libgnutls.la
+libgnutls_la_SOURCES = gnutls.c gnutls_compress.c debug.c gnutls_plaintext.c gnutls_cipher.c gnutls_buffers.c gnutls_handshake.c gnutls_num.c gnutls_errors.c gnutls_algorithms.c
+libgnutls_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
diff --git a/lib/debug.c b/lib/debug.c
new file mode 100644
index 0000000000..9343de237d
--- /dev/null
+++ b/lib/debug.c
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <defines.h>
+#include <mhash.h>
+#include "gnutls_int.h"
+#include "gnutls_errors.h"
+
+
+static char hexconvtab[] = "0123456789abcdef";
+
+char * bin2hex(const unsigned char *old, const size_t oldlen)
+{
+ unsigned char *new = NULL;
+ int i, j;
+
+ new = malloc(oldlen * 2 * sizeof(char) + 1);
+ if (!new)
+ return (new);
+
+ for (i = j = 0; i < oldlen; i++) {
+ new[j++] = hexconvtab[old[i] >> 4];
+ new[j++] = hexconvtab[old[i] & 15];
+ }
+ new[j] = '\0';
+
+ return (new);
+}
+
+
+void _print_state(GNUTLS_STATE state)
+{
+
+ fprintf(stderr, "GNUTLS State:\n");
+ fprintf(stderr, "Connection End: %d\n",
+ state->security_parameters.entity);
+ fprintf(stderr, "Cipher Algorithm: %d\n",
+ state->security_parameters.bulk_cipher_algorithm);
+ fprintf(stderr, "Cipher Type: %d\n",
+ state->security_parameters.cipher_type);
+ fprintf(stderr, "Key Size: %d\n",
+ state->security_parameters.key_size);
+ fprintf(stderr, "Key Material: %d\n",
+ state->security_parameters.key_material_length);
+ fprintf(stderr, "Exportable: %d\n",
+ state->security_parameters.is_exportable);
+ fprintf(stderr, "MAC algorithm: %d\n",
+ state->security_parameters.mac_algorithm);
+ fprintf(stderr, "Hash size: %d\n",
+ state->security_parameters.hash_size);
+ fprintf(stderr, "Compression Algorithm: %d\n",
+ state->security_parameters.compression_algorithm);
+ fprintf(stderr, "\n");
+
+}
+
+void _print_TLSCompressed(GNUTLSCompressed * compressed)
+{
+ fprintf(stderr, "TLSCompressed packet:\n");
+ fprintf(stderr, "type: %d\n", compressed->type);
+ fprintf(stderr, "version: %d,%d\n", compressed->version.major,
+ compressed->version.minor);
+ fprintf(stderr, "length: %d\n", compressed->length);
+ fprintf(stderr, "fragment: %s\n", bin2hex(compressed->fragment, compressed->length));
+ fprintf(stderr, "\n");
+}
+
+
+void _print_TLSPlaintext(GNUTLSPlaintext * plaintext)
+{
+ fprintf(stderr, "TLSPlaintext packet:\n");
+ fprintf(stderr, "type: %d\n", plaintext->type);
+ fprintf(stderr, "version: %d,%d\n", plaintext->version.major,
+ plaintext->version.minor);
+ fprintf(stderr, "length: %d\n", plaintext->length);
+ fprintf(stderr, "fragment: %s\n", bin2hex(plaintext->fragment, plaintext->length));
+ fprintf(stderr, "\n");
+}
+
+
+void _print_TLSCiphertext( GNUTLSCiphertext * ciphertext)
+{
+
+ fprintf(stderr, "TLSCiphertext packet:\n");
+ fprintf(stderr, "type: %d\n", ciphertext->type);
+ fprintf(stderr, "version: %d,%d\n", ciphertext->version.major,
+ ciphertext->version.minor);
+ fprintf(stderr, "length: %d\n", ciphertext->length);
+
+ fprintf(stderr, "fragment: %s\n", bin2hex(ciphertext->fragment, ciphertext->length));
+ fprintf(stderr, "\n");
+}
diff --git a/lib/debug.h b/lib/debug.h
new file mode 100644
index 0000000000..3c19e39e8d
--- /dev/null
+++ b/lib/debug.h
@@ -0,0 +1,5 @@
+void _print_state(GNUTLS_STATE state);
+void _print_TLSCompressed(GNUTLSCompressed * compressed);
+void _print_TLSPlaintext(GNUTLSPlaintext * plaintext);
+void _print_TLSCiphertext( GNUTLSCiphertext *);
+char * bin2hex(const unsigned char *old, const size_t oldlen);
diff --git a/lib/defines.h b/lib/defines.h
new file mode 100644
index 0000000000..546aaed186
--- /dev/null
+++ b/lib/defines.h
@@ -0,0 +1,75 @@
+#include <config.h>
+
+#ifdef STDC_HEADERS
+# include <string.h>
+# include <stdlib.h>
+# include <stdio.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#include <time.h>
+
+
+/* for open */
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <gcrypt.h>
+
+#if SIZEOF_UNSIGNED_LONG_INT == 8
+ typedef unsigned long int uint64;
+ typedef signed long int sint64;
+#elif SIZEOF_UNSIGNED_LONG_LONG == 8
+ typedef unsigned long long uint64;
+ typedef signed long long sint64;
+#else
+# error "Cannot find a 64 bit integer in your system, sorry."
+#endif
+
+
+#if SIZEOF_UNSIGNED_LONG_INT == 4
+ typedef unsigned long int uint32;
+ typedef signed long int sint32;
+#elif SIZEOF_UNSIGNED_INT == 4
+ typedef unsigned int uint32;
+ typedef signed int sint32;
+#else
+# error "Cannot find a 32 bit integer in your system, sorry."
+#endif
+
+#if SIZEOF_UNSIGNED_INT == 2
+ typedef unsigned int uint16;
+ typedef signed int sint16;
+#elif SIZEOF_UNSIGNED_SHORT_INT == 2
+ typedef unsigned short int uint16;
+ typedef signed short int sint16;
+#else
+# error "Cannot find a 16 bit integer in your system, sorry."
+#endif
+
+#if SIZEOF_UNSIGNED_CHAR == 1
+ typedef unsigned char uint8;
+ typedef signed char int8;
+#else
+# error "Cannot find an 8 bit char in your system, sorry."
+#endif
+
+#ifndef HAVE_MEMMOVE
+# ifdef HAVE_BCOPY
+# define memmove(d, s, n) bcopy ((s), (d), (n))
+# else
+# error "Neither memmove nor bcopy exists on your system."
+# endif
+#endif
diff --git a/lib/gnutls.c b/lib/gnutls.c
new file mode 100644
index 0000000000..d9a2b8c8aa
--- /dev/null
+++ b/lib/gnutls.c
@@ -0,0 +1,663 @@
+#include <defines.h>
+#include <mhash.h>
+#include "gnutls_int.h"
+#include "gnutls_errors.h"
+#include "debug.h"
+#include "gnutls_compress.h"
+#include "gnutls_plaintext.h"
+#include "gnutls_cipher.h"
+#include "gnutls_buffers.h"
+#include "gnutls_handshake.h"
+
+int gnutls_init(GNUTLS_STATE * state, ConnectionEnd con_end)
+{
+ *state = gnutls_calloc(1, sizeof(GNUTLS_STATE_INT));
+ memset(*state, 0, sizeof(GNUTLS_STATE));
+ (*state)->security_parameters.entity = con_end;
+
+/* Set the defaults (only to remind me that they should be allocated ) */
+ (*state)->security_parameters.bulk_cipher_algorithm = CIPHER_NULL;
+ (*state)->security_parameters.mac_algorithm = MAC_NULL;
+ (*state)->security_parameters.compression_algorithm = COMPRESSION_NULL;
+
+ (*state)->connection_state.read_compression_state = NULL;
+ (*state)->connection_state.read_mac_secret = NULL;
+ (*state)->connection_state.write_compression_state = NULL;
+ (*state)->connection_state.write_mac_secret = NULL;
+
+ (*state)->cipher_specs.server_write_mac_secret = NULL;
+ (*state)->cipher_specs.client_write_mac_secret = NULL;
+ (*state)->cipher_specs.server_write_IV = NULL;
+ (*state)->cipher_specs.client_write_IV = NULL;
+ (*state)->cipher_specs.server_write_key = NULL;
+ (*state)->cipher_specs.client_write_key = NULL;
+
+ (*state)->gnutls_internals.buffer = NULL;
+ (*state)->gnutls_internals.client_md_md5 = NULL;
+ (*state)->gnutls_internals.client_md_sha1 = NULL;
+ (*state)->gnutls_internals.server_md_md5 = NULL;
+ (*state)->gnutls_internals.server_md_sha1 = NULL;
+ (*state)->gnutls_internals.server_hash = 0;
+ (*state)->gnutls_internals.client_hash = 0;
+ (*state)->gnutls_internals.resumable = RESUME_TRUE;
+}
+
+int gnutls_deinit(GNUTLS_STATE * state)
+{
+ gnutls_free((*state)->connection_state.read_compression_state);
+ gnutls_free((*state)->connection_state.read_mac_secret);
+ gnutls_free((*state)->connection_state.write_compression_state);
+ gnutls_free((*state)->connection_state.write_mac_secret);
+
+ gnutls_free((*state)->gnutls_internals.buffer);
+
+ if ((*state)->connection_state.read_cipher_state != NULL)
+ gcry_cipher_close((*state)->connection_state.
+ read_cipher_state);
+ if ((*state)->connection_state.write_cipher_state != NULL)
+ gcry_cipher_close((*state)->connection_state.
+ write_cipher_state);
+
+ secure_free((*state)->cipher_specs.server_write_mac_secret);
+ secure_free((*state)->cipher_specs.client_write_mac_secret);
+ secure_free((*state)->cipher_specs.server_write_IV);
+ secure_free((*state)->cipher_specs.client_write_IV);
+ secure_free((*state)->cipher_specs.server_write_key);
+ secure_free((*state)->cipher_specs.client_write_key);
+
+ gnutls_free(*state);
+}
+
+/* Produces "total_bytes" bytes using the hash algorithm specified.
+ * (used in the PRF function)
+ */
+svoid *gnutls_P_hash(hashid algorithm, opaque * secret, int secret_size,
+ opaque * seed, int seed_size, int total_bytes)
+{
+
+ MHASH td1, td2;
+ char *ret = secure_malloc(total_bytes);
+ void *A;
+ int i = 0, times, copy_bytes = 0, how;
+ void *final;
+
+ do {
+ i += mhash_get_block_size(algorithm);
+ } while (i < total_bytes);
+
+ A = seed;
+ times = i / mhash_get_block_size(algorithm);
+
+ for (i = 0; i < times; i++) {
+ td2 =
+ mhash_hmac_init(algorithm, secret, secret_size,
+ mhash_get_hash_pblock(algorithm));
+
+ td1 =
+ mhash_hmac_init(algorithm, secret, secret_size,
+ mhash_get_hash_pblock(algorithm));
+ mhash(td1, A, seed_size);
+
+ A = mhash_hmac_end(td1);
+
+ mhash(td2, A, mhash_get_block_size(algorithm));
+ mhash(td2, seed, seed_size);
+ final = mhash_hmac_end(td2);
+
+ copy_bytes = mhash_get_block_size(algorithm);
+ if ((i + 1) * copy_bytes < total_bytes) {
+ how = mhash_get_block_size(algorithm);
+ } else {
+ how = total_bytes - (i) * copy_bytes;
+ }
+
+ if (how > 0) {
+ memmove(&ret[i * copy_bytes], final, how);
+ }
+ free(final);
+ if (i > 0)
+ free(A);
+ }
+
+ return ret;
+}
+
+
+/* The PRF function expands a given secret */
+svoid *gnutls_PRF(opaque * secret, int secret_size, uint8 * label,
+ int label_size, opaque * seed, int seed_size,
+ int total_bytes)
+{
+ int l_s1, l_s2, i, s_seed_size;
+ char *o1, *o2;
+ char *s1, *s2;
+ char *ret;
+ char *s_seed;
+
+ /* label+seed = s_seed */
+ s_seed_size = seed_size + label_size;
+ s_seed = gnutls_malloc(s_seed_size);
+ memmove(s_seed, label, label_size);
+ memmove(&s_seed[label_size], seed, seed_size);
+
+
+ if (secret_size % 2 == 0) {
+ l_s1 = l_s2 = secret_size / 2;
+ s1 = &secret[0];
+ s2 = &secret[l_s1 + 1];
+ } else {
+ l_s1 = l_s2 = (secret_size / 2) + 1;
+ s1 = &secret[0];
+ s2 = &secret[l_s1];
+ }
+
+ o1 =
+ gnutls_P_hash(MHASH_MD5, s1, l_s1, s_seed, s_seed_size,
+ total_bytes);
+ o2 =
+ gnutls_P_hash(MHASH_SHA1, s2, l_s2, s_seed, s_seed_size,
+ total_bytes);
+
+ ret = secure_malloc(total_bytes);
+ gnutls_free(s_seed);
+ for (i = 0; i < total_bytes; i++) {
+ ret[i] = o1[i] ^ o2[i];
+ }
+
+ secure_free(o1);
+ secure_free(o2);
+
+ return ret;
+
+}
+
+/* if master_secret, client_random and server_random have been initialized,
+ * this function creates the keys and stores them into state->cipher_specs
+ */
+int _gnutls_set_keys(GNUTLS_STATE state)
+{
+ char *key_block;
+ char keyexp[] = "key expansion";
+ char *random = gnutls_malloc(64);
+ int hash_size;
+ int IV_size;
+ int key_size;
+
+ hash_size = state->security_parameters.hash_size;
+ IV_size = state->security_parameters.IV_size;
+ key_size = state->security_parameters.key_material_length;
+
+ memmove(random, state->security_parameters.server_random, 32);
+ memmove(&random[32], state->security_parameters.client_random, 32);
+
+ key_block =
+ gnutls_PRF(state->security_parameters.master_secret, 48,
+ keyexp, strlen(keyexp), random, 64,
+ 2 * hash_size + 2 * key_size + 2 * IV_size);
+
+ state->cipher_specs.client_write_mac_secret =
+ secure_malloc(hash_size);
+ memmove(state->cipher_specs.client_write_mac_secret, &key_block[0],
+ hash_size);
+
+ state->cipher_specs.server_write_mac_secret =
+ secure_malloc(hash_size);
+ memmove(state->cipher_specs.server_write_mac_secret,
+ &key_block[hash_size], hash_size);
+
+ state->cipher_specs.client_write_key = secure_malloc(key_size);
+ memmove(state->cipher_specs.client_write_key,
+ &key_block[2 * hash_size], key_size);
+
+ state->cipher_specs.server_write_key = secure_malloc(key_size);
+ memmove(state->cipher_specs.server_write_key,
+ &key_block[2 * hash_size + key_size], key_size);
+
+ state->cipher_specs.client_write_IV = secure_malloc(IV_size);
+ memmove(state->cipher_specs.client_write_IV,
+ &key_block[2 * key_size + 2 * hash_size], IV_size);
+
+ state->cipher_specs.server_write_IV = secure_malloc(IV_size);
+ memmove(state->cipher_specs.server_write_IV,
+ &key_block[2 * hash_size + 2 * key_size + IV_size],
+ IV_size);
+
+ secure_free(key_block);
+ return 0;
+}
+
+int _gnutls_send_alert(int cd, GNUTLS_STATE state, AlertLevel level,
+ AlertDescription desc)
+{
+ uint8 data[2];
+
+ memmove(&data[0], &level, 1);
+ memmove(&data[1], &desc, 1);
+
+ return gnutls_send_int(cd, state, GNUTLS_ALERT, data, 2);
+
+}
+
+int gnutls_close(int cd, GNUTLS_STATE state)
+{
+ int ret;
+
+ ret =
+ _gnutls_send_alert(cd, state, GNUTLS_WARNING,
+ GNUTLS_CLOSE_NOTIFY);
+
+ /* receive pending data or the closure alert */
+ gnutls_recv_int(cd, state, GNUTLS_ALERT, NULL, 0);
+
+ state->gnutls_internals.valid_connection = VALID_FALSE;
+ return ret;
+
+}
+
+ssize_t gnutls_send_int(int cd, GNUTLS_STATE state, ContentType type,
+ char *data, size_t sizeofdata)
+{
+ GNUTLSPlaintext *gtxt;
+ GNUTLSCompressed *gcomp;
+ GNUTLSCiphertext *gcipher;
+ int iterations, i, err;
+ uint16 length;
+ int ret = 0, Size;
+
+
+ if (sizeofdata == 0)
+ return 0;
+ if (state->gnutls_internals.valid_connection == VALID_FALSE)
+ return GNUTLS_E_INVALID_SESSION;
+
+ if (sizeofdata < 16384) {
+ iterations = 1;
+ Size = sizeofdata;
+ } else {
+ iterations = sizeofdata / 16384;
+ Size = 16384;
+ }
+ for (i = 0; i < iterations; i++) {
+ err =
+ _gnutls_text2TLSPlaintext(type, &gtxt, &data[i * Size],
+ Size);
+ if (err < 0) {
+ /*gnutls_perror(err); */
+ return err;
+ }
+
+ err =
+ _gnutls_TLSPlaintext2TLSCompressed(state, &gcomp,
+ gtxt);
+ if (err < 0) {
+ /*gnutls_perror(err); */
+ return err;
+ }
+
+ _gnutls_freeTLSPlaintext(gtxt);
+
+ err =
+ _gnutls_TLSCompressed2TLSCiphertext(state, &gcipher,
+ gcomp);
+ if (err < 0) {
+ /*gnutls_perror(err); */
+ return err;
+ }
+
+ _gnutls_freeTLSCompressed(gcomp);
+
+ if (Write(cd, &gcipher->type, sizeof(ContentType)) !=
+ sizeof(ContentType)) {
+ state->gnutls_internals.valid_connection =
+ VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNABLE_SEND_DATA;
+ }
+
+ if (Write(cd, &gcipher->version.major, 1) != 1) {
+ state->gnutls_internals.valid_connection =
+ VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNABLE_SEND_DATA;
+ }
+
+ if (Write(cd, &gcipher->version.minor, 1) != 1) {
+ state->gnutls_internals.valid_connection =
+ VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNABLE_SEND_DATA;
+ }
+#ifdef WORDS_BIGENDIAN
+ length = gcipher->length;
+#else
+ length = byteswap16(gcipher->length);
+#endif
+ if (Write(cd, &length, sizeof(uint16)) != sizeof(uint16)) {
+ state->gnutls_internals.valid_connection =
+ VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNABLE_SEND_DATA;
+ }
+
+ if (Write(cd, gcipher->fragment, gcipher->length) !=
+ gcipher->length) {
+ state->gnutls_internals.valid_connection =
+ VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNABLE_SEND_DATA;
+ }
+ state->connection_state.write_sequence_number++;
+ ret += Size;
+
+ _gnutls_freeTLSCiphertext(gcipher);
+ }
+ /* rest data */
+ if (iterations > 1) {
+ Size = sizeofdata % 16384;
+ err =
+ _gnutls_text2TLSPlaintext(type, &gtxt, &data[ret],
+ Size);
+ if (err < 0) {
+ /*gnutls_perror(err); */
+ return err;
+ }
+
+ err =
+ _gnutls_TLSPlaintext2TLSCompressed(state, &gcomp,
+ gtxt);
+ if (err < 0) {
+ /*gnutls_perror(err); */
+ return err;
+ }
+
+ _gnutls_freeTLSPlaintext(gtxt);
+
+ err =
+ _gnutls_TLSCompressed2TLSCiphertext(state, &gcipher,
+ gcomp);
+ if (err < 0) {
+ /*gnutls_perror(err); */
+ return err;
+ }
+ _gnutls_freeTLSCompressed(gcomp);
+#ifdef WORDS_BIGENDIAN
+ length = gcipher->length;
+#else
+ length = byteswap16(gcipher->length);
+#endif
+ if (Write(cd, &gcipher->type, sizeof(ContentType)) !=
+ sizeof(ContentType)) {
+ state->gnutls_internals.valid_connection =
+ VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNABLE_SEND_DATA;
+ }
+ if (Write(cd, &gcipher->version.major, 1) != 1) {
+ state->gnutls_internals.valid_connection =
+ VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNABLE_SEND_DATA;
+ }
+ if (Write(cd, &gcipher->version.minor, 1) != 1) {
+ state->gnutls_internals.valid_connection =
+ VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNABLE_SEND_DATA;
+ }
+ if (Write(cd, &length, sizeof(uint16)) != sizeof(uint16)) {
+ state->gnutls_internals.valid_connection =
+ VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNABLE_SEND_DATA;
+ }
+ if (Write(cd, gcipher->fragment, gcipher->length) !=
+ gcipher->length) {
+ state->gnutls_internals.valid_connection =
+ VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNABLE_SEND_DATA;
+ }
+ state->connection_state.write_sequence_number++;
+ ret += Size;
+
+ _gnutls_freeTLSCiphertext(gcipher);
+ }
+
+ return ret;
+}
+
+
+ssize_t gnutls_recv_int(int cd, GNUTLS_STATE state, ContentType type,
+ char *data, size_t sizeofdata)
+{
+ GNUTLSPlaintext *gtxt;
+ GNUTLSCompressed *gcomp;
+ GNUTLSCiphertext gcipher;
+ int iterations, i, err;
+ uint8 *tmpdata;
+ int tmplen;
+ int ret = 0;
+
+ /* If we have enough data in the cache do not bother receiving
+ * a new packet. (in order to flush the cache)
+ */
+ if (type == GNUTLS_APPLICATION_DATA && gnutls_getDataBufferSize(type, state) > 0) {
+ ret = gnutls_getDataFromBuffer(state, data, sizeofdata);
+ return ret;
+ }
+
+ if (state->gnutls_internals.valid_connection == VALID_FALSE)
+ return GNUTLS_E_INVALID_SESSION;
+
+ if (Read(cd, &gcipher.type, sizeof(ContentType)) !=
+ sizeof(ContentType)) {
+ state->gnutls_internals.valid_connection = VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+
+ if (Read(cd, &gcipher.version.major, 1) != 1) {
+ state->gnutls_internals.valid_connection = VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+
+ if (Read(cd, &gcipher.version.minor, 1) != 1) {
+ state->gnutls_internals.valid_connection = VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+
+ if (gcipher.version.major != GNUTLS_VERSION_MAJOR
+ || gcipher.version.minor != GNUTLS_VERSION_MINOR) {
+
+ _gnutls_send_alert(cd, state, GNUTLS_FATAL,
+ GNUTLS_PROTOCOL_VERSION);
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
+ }
+
+ if (Read(cd, &gcipher.length, 2) != 2) {
+ state->gnutls_internals.valid_connection = VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+#ifndef WORDS_BIGENDIAN
+ gcipher.length = byteswap16(gcipher.length);
+#endif
+
+ if (gcipher.length > 18432) { /* 2^14+2048 */
+#ifdef DEBUG
+ fprintf(stderr,
+ "Received packet with length: %d\n",
+ gcipher.length);
+#endif
+ _gnutls_send_alert(cd, state, GNUTLS_FATAL,
+ GNUTLS_RECORD_OVERFLOW);
+ state->gnutls_internals.valid_connection = VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+ gcipher.fragment = gnutls_malloc(gcipher.length);
+
+ /* read ciphertext */
+
+ ret = Read(cd, gcipher.fragment, gcipher.length);
+
+ if (ret != gcipher.length) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "Received packet with length: %d\nExpected %d\n",
+ ret, gcipher.length);
+#endif
+ gnutls_free(gcipher.fragment);
+ state->gnutls_internals.valid_connection = VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+
+ if (ret =
+ _gnutls_TLSCiphertext2TLSCompressed(state,
+ &gcomp, &gcipher) < 0) {
+ gnutls_free(gcipher.fragment);
+ if (ret == GNUTLS_E_MAC_FAILED) {
+ _gnutls_send_alert(cd, state,
+ GNUTLS_FATAL,
+ GNUTLS_BAD_RECORD_MAC);
+ } else {
+ _gnutls_send_alert(cd, state,
+ GNUTLS_FATAL,
+ GNUTLS_DECRYPTION_FAILED);
+ }
+ state->gnutls_internals.valid_connection = VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return ret;
+ }
+ gnutls_free(gcipher.fragment);
+
+ if (ret =
+ _gnutls_TLSCompressed2TLSPlaintext(state, &gtxt, gcomp) < 0) {
+ _gnutls_send_alert(cd, state, GNUTLS_FATAL,
+ GNUTLS_DECOMPRESSION_FAILURE);
+ state->gnutls_internals.valid_connection = VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return ret;
+ }
+ _gnutls_freeTLSCompressed(gcomp);
+
+ if (ret = _gnutls_TLSPlaintext2text((void *) &tmpdata, gtxt) < 0) {
+ _gnutls_send_alert(cd, state, GNUTLS_FATAL,
+ GNUTLS_INTERNAL_ERROR);
+ state->gnutls_internals.valid_connection = VALID_FALSE;
+ state->gnutls_internals.resumable = RESUME_FALSE;
+ return ret;
+ }
+ tmplen = gtxt->length;
+
+ _gnutls_freeTLSPlaintext(gtxt);
+
+ if (gcipher.type == type && type == GNUTLS_APPLICATION_DATA) {
+ gnutls_insertDataBuffer(state, tmpdata, tmplen);
+ } else {
+ switch (gcipher.type) {
+ case GNUTLS_ALERT:
+#ifdef DEBUG
+ fprintf(stderr,
+ "Alert[%d|%d] was received\n",
+ tmpdata[0], tmpdata[1]);
+#endif
+ state->gnutls_internals.last_alert = tmpdata[1];
+
+ if (tmpdata[1] ==
+ GNUTLS_CLOSE_NOTIFY
+ && tmpdata[0] != GNUTLS_FATAL) {
+ /* If we have been expecting for an alert do not call close() */
+ if (type != GNUTLS_ALERT)
+ gnutls_close(cd, state);
+ return GNUTLS_E_CLOSURE_ALERT_RECEIVED;
+ } else {
+ if (tmpdata[0] == GNUTLS_FATAL) {
+ state->gnutls_internals.
+ valid_connection = VALID_FALSE;
+
+ state->gnutls_internals.resumable
+ = RESUME_FALSE;
+ return
+ GNUTLS_E_FATAL_ALERT_RECEIVED;
+ }
+ return GNUTLS_E_WARNING_ALERT_RECEIVED;
+ }
+ break;
+
+ case GNUTLS_CHANGE_CIPHER_SPEC:
+
+ if (type != GNUTLS_CHANGE_CIPHER_SPEC) {
+ return GNUTLS_E_UNEXPECTED_PACKET;
+ }
+ if (((ChangeCipherSpecType)
+ tmpdata[0]) == GNUTLS_TYPE_CHANGE_CIPHER_SPEC && tmplen == 1) {
+ ret = 0; // _gnutls_connection_state_init(state);
+
+ } else {
+ state->gnutls_internals.valid_connection
+ = VALID_FALSE;
+ state->gnutls_internals.resumable =
+ RESUME_FALSE;
+ ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+ state->connection_state.read_sequence_number++;
+ return ret;
+
+ case GNUTLS_HANDSHAKE:
+
+ if (type == GNUTLS_HANDSHAKE) {
+ ret =
+ _gnutls_recv_handshake_int
+ (cd, state, tmpdata, tmplen, data, sizeofdata);
+
+ gnutls_free(tmpdata);
+ state->
+ connection_state.read_sequence_number++;
+ } else {
+
+ ret = GNUTLS_E_RECEIVED_BAD_MESSAGE;
+ }
+ return ret;
+ }
+ }
+
+
+
+ /* Incread sequence number */
+ state->connection_state.read_sequence_number++;
+
+
+
+ /* Insert Application data to buffer */
+ if (type == GNUTLS_APPLICATION_DATA && gcipher.type==type) {
+ ret = gnutls_getDataFromBuffer(state, data, sizeofdata);
+ gnutls_free(tmpdata);
+ } else {
+ if (gcipher.type != type) {
+ return GNUTLS_E_RECEIVED_BAD_MESSAGE;
+#ifdef DEBUG
+ fprintf(stderr,
+ "Received unexpected packet type\n");
+#endif
+ }
+ /* this is an error because we have messages of fixed
+ * length */
+
+ ret = GNUTLS_E_RECEIVED_BAD_MESSAGE;
+ }
+
+ return ret;
+}
+
+int _gnutls_send_change_cipher_spec(int cd, GNUTLS_STATE state)
+{
+ ChangeCipherSpecType x = GNUTLS_TYPE_CHANGE_CIPHER_SPEC;
+
+ return gnutls_send_int(cd, state, GNUTLS_CHANGE_CIPHER_SPEC,
+ (void *) &x, 1);
+}
diff --git a/lib/gnutls.h b/lib/gnutls.h
new file mode 100644
index 0000000000..fd8f4247af
--- /dev/null
+++ b/lib/gnutls.h
@@ -0,0 +1,42 @@
+enum ContentType { GNUTLS_APPLICATION_DATA=23 };
+typedef enum ContentType ContentType;
+enum BulkCipherAlgorithm { CIPHER_NULL, CIPHER_3DES = 4 };
+typedef enum BulkCipherAlgorithm BulkCipherAlgorithm;
+enum MACAlgorithm { MAC_NULL, MAC_MD5, MAC_SHA };
+typedef enum MACAlgorithm MACAlgorithm;
+enum CompressionMethod { COMPRESSION_NULL };
+typedef enum CompressionMethod CompressionMethod;
+enum ConnectionEnd { GNUTLS_SERVER, GNUTLS_CLIENT };
+typedef enum ConnectionEnd ConnectionEnd;
+
+struct GNUTLS_STATE_INT;
+typedef struct GNUTLS_STATE_INT* GNUTLS_STATE;
+
+int gnutls_init(GNUTLS_STATE * state, ConnectionEnd con_end);
+int gnutls_deinit(GNUTLS_STATE * state);
+ssize_t gnutls_send_int(int cd, GNUTLS_STATE state, ContentType type, char* data, size_t sizeofdata);
+ssize_t gnutls_recv_int(int cd, GNUTLS_STATE state, ContentType type, char* data, size_t sizeofdata);
+int gnutls_close(int cd, GNUTLS_STATE state);
+int gnutls_handshake(int cd, GNUTLS_STATE state);
+
+#define gnutls_send( x, y, z, w) gnutls_send_int( x, y, GNUTLS_APPLICATION_DATA, z, w)
+#define gnutls_recv( x, y, z, w) gnutls_recv_int( x, y, GNUTLS_APPLICATION_DATA, z, w)
+
+
+#define GNUTLS_E_MAC_FAILED -1
+#define GNUTLS_E_UNKNOWN_CIPHER -2
+#define GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM -3
+#define GNUTLS_E_UNKNOWN_MAC_ALGORITHM -4
+#define GNUTLS_E_UNKNOWN_ERROR -5
+#define GNUTLS_E_UNKNOWN_CIPHER_TYPE -6
+#define GNUTLS_E_LARGE_PACKET -7
+#define GNUTLS_E_UNSUPPORTED_VERSION_PACKET -8
+#define GNUTLS_E_UNEXPECTED_PACKET_LENGTH -9
+#define GNUTLS_E_INVALID_SESSION -10
+#define GNUTLS_E_UNABLE_SEND_DATA -11
+#define GNUTLS_E_FATAL_ALERT_RECEIVED -12
+#define GNUTLS_E_RECEIVED_BAD_MESSAGE -13
+#define GNUTLS_E_RECEIVED_MORE_DATA -14
+#define GNUTLS_E_UNEXPECTED_PACKET -15
+#define GNUTLS_E_WARNING_ALERT_RECEIVED -16
+#define GNUTLS_E_CLOSURE_ALERT_RECEIVED -17
diff --git a/lib/gnutls_algorithms.c b/lib/gnutls_algorithms.c
new file mode 100644
index 0000000000..d3de151836
--- /dev/null
+++ b/lib/gnutls_algorithms.c
@@ -0,0 +1,161 @@
+#include <defines.h>
+#include <mhash.h>
+#include "gnutls_int.h"
+#include "gnutls_algorithms.h"
+
+
+void tolow(char *str, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ str[i] = tolower(str[i]);
+ }
+}
+
+
+int _gnutls_cipher_get_block_size(BulkCipherAlgorithm algorithm)
+{
+ size_t ret = 0;
+ GNUTLS_ALG_LOOP(ret = p->blocksize);
+ return ret;
+
+}
+
+int _gnutls_cipher_is_block(BulkCipherAlgorithm algorithm)
+{
+ size_t ret = 0;
+
+ GNUTLS_ALG_LOOP(ret = p->block);
+ return ret;
+
+}
+
+int _gnutls_cipher_get_key_size(BulkCipherAlgorithm algorithm)
+{ /* In bytes */
+ size_t ret = 0;
+ GNUTLS_ALG_LOOP(ret = p->keysize);
+ return ret;
+
+}
+
+int _gnutls_cipher_get_iv_size(BulkCipherAlgorithm algorithm)
+{ /* In bytes */
+ size_t ret = 0;
+ GNUTLS_ALG_LOOP(ret = p->iv);
+ return ret;
+
+}
+
+char *_gnutls_cipher_get_name(BulkCipherAlgorithm algorithm)
+{
+ char *ret = NULL;
+ char *pointerTo_;
+
+ /* avoid prefix */
+ GNUTLS_ALG_LOOP(ret = strdup(p->name + sizeof("CIPHER_") - 1));
+
+
+ if (ret != NULL) {
+ tolow(ret, strlen(ret));
+ pointerTo_ = strchr(ret, '_');
+
+ while (pointerTo_ != NULL) {
+ *pointerTo_ = '-';
+ pointerTo_ = strchr(ret, '_');
+ }
+ }
+ return ret;
+}
+
+
+int _gnutls_cipher_is_ok(BulkCipherAlgorithm algorithm)
+{
+ char *y = _gnutls_cipher_get_name(algorithm);
+
+ if (y != NULL) {
+ free(y);
+ return 0;
+ } else {
+ return 1;
+ }
+
+}
+
+
+
+int _gnutls_kx_algo_server_certificate(KX_Algorithm algorithm)
+{
+ size_t ret = 0;
+ GNUTLS_KX_ALG_LOOP(ret = p->server_cert);
+ return ret;
+
+}
+
+int _gnutls_kx_algo_server_key_exchange(KX_Algorithm algorithm)
+{
+ size_t ret = 0;
+
+ GNUTLS_KX_ALG_LOOP(ret = p->server_kx);
+ return ret;
+
+}
+
+int _gnutls_kx_algo_client_certificate(KX_Algorithm algorithm)
+{ /* In bytes */
+ size_t ret = 0;
+ GNUTLS_KX_ALG_LOOP(ret = p->client_cert);
+ return ret;
+
+}
+
+int _gnutls_kx_algo_RSA_premaster(KX_Algorithm algorithm)
+{ /* In bytes */
+ size_t ret = 0;
+ GNUTLS_KX_ALG_LOOP(ret = p->RSA_premaster);
+ return ret;
+
+}
+
+int _gnutls_kx_algo_DH_public_value(KX_Algorithm algorithm)
+{ /* In bytes */
+ size_t ret = 0;
+ GNUTLS_KX_ALG_LOOP(ret = p->DH_public_value);
+ return ret;
+
+}
+
+char *_gnutls_kx_algo_get_name(KX_Algorithm algorithm)
+{
+ char *ret = NULL;
+ char *pointerTo_;
+
+ /* avoid prefix */
+ GNUTLS_KX_ALG_LOOP(ret = strdup(p->name + sizeof("KX_") - 1));
+
+
+ if (ret != NULL) {
+ tolow(ret, strlen(ret));
+ pointerTo_ = strchr(ret, '_');
+
+ while (pointerTo_ != NULL) {
+ *pointerTo_ = '-';
+ pointerTo_ = strchr(ret, '_');
+ }
+ }
+ return ret;
+}
+
+
+int _gnutls_kx_algo_is_ok(KX_Algorithm algorithm)
+{
+ char *y = _gnutls_kx_algo_get_name(algorithm);
+
+ if (y != NULL) {
+ free(y);
+ return 0;
+ } else {
+ return 1;
+ }
+
+}
diff --git a/lib/gnutls_algorithms.h b/lib/gnutls_algorithms.h
new file mode 100644
index 0000000000..7bc613ad16
--- /dev/null
+++ b/lib/gnutls_algorithms.h
@@ -0,0 +1,76 @@
+#define GNUTLS_CIPHER_ENTRY(name, blksize, keysize, block, iv) \
+ { #name, name, blksize, keysize, block, iv }
+
+struct gnutls_cipher_entry {
+ char *name;
+ BulkCipherAlgorithm id;
+ size_t blocksize;
+ size_t keysize;
+ size_t block;
+ size_t iv;
+};
+typedef struct gnutls_cipher_entry gnutls_cipher_entry;
+
+static gnutls_cipher_entry algorithms[] = {
+ GNUTLS_CIPHER_ENTRY(CIPHER_3DES, 8, 24, 1, 8),
+ GNUTLS_CIPHER_ENTRY(CIPHER_NULL, 1, 0, 0, 0),
+ {0}
+};
+
+#define GNUTLS_LOOP(b) \
+ gnutls_cipher_entry *p; \
+ for(p = algorithms; p->name != NULL; p++) { b ; }
+
+#define GNUTLS_ALG_LOOP(a) \
+ GNUTLS_LOOP( if(p->id == algorithm) { a; break; } )
+
+
+
+
+#define GNUTLS_KX_ALGO_ENTRY(name, server_cert, server_kx, client_cert, RSA_premaster, DH_public_value) \
+ { #name, name, server_cert, server_kx, client_cert, RSA_premaster, DH_public_value }
+
+struct gnutls_kx_algo_entry {
+ char *name;
+ KX_Algorithm algorithm;
+ int server_cert;
+ int server_kx;
+ int client_cert;
+ int RSA_premaster;
+ int DH_public_value;
+};
+typedef struct gnutls_kx_algo_entry gnutls_kx_algo_entry;
+
+static gnutls_kx_algo_entry kx_algorithms[] = {
+ GNUTLS_KX_ALGO_ENTRY( KX_ANON_DH, 0, 1, 0, 0, 1),
+ GNUTLS_KX_ALGO_ENTRY( KX_RSA , 1, 0, 1, 1, 0),
+ GNUTLS_KX_ALGO_ENTRY( KX_DHE_DSS, 1, 1, 1, 0, 0),
+ GNUTLS_KX_ALGO_ENTRY( KX_DHE_RSA, 1, 1, 1, 0, 0),
+ GNUTLS_KX_ALGO_ENTRY( KX_DH_DSS , 1, 0, 1, 0, 0),
+ GNUTLS_KX_ALGO_ENTRY( KX_DH_RSA , 1, 0, 1, 0, 0),
+ {0}
+};
+
+#define GNUTLS_KX_LOOP(b) \
+ gnutls_kx_algo_entry *p; \
+ for(p = kx_algorithms; p->name != NULL; p++) { b ; }
+
+#define GNUTLS_KX_ALG_LOOP(a) \
+ GNUTLS_KX_LOOP( if(p->algorithm == algorithm) { a; break; } )
+
+
+int _gnutls_cipher_get_block_size(BulkCipherAlgorithm algorithm);
+int _gnutls_cipher_is_block(BulkCipherAlgorithm algorithm);
+int _gnutls_cipher_is_ok(BulkCipherAlgorithm algorithm);
+int _gnutls_cipher_get_key_size(BulkCipherAlgorithm algorithm);
+int _gnutls_cipher_get_iv_size(BulkCipherAlgorithm algorithm);
+char *_gnutls_cipher_get_name(BulkCipherAlgorithm algorithm);
+
+
+int _gnutls_kx_get_block_size(KX_Algorithm algorithm);
+int _gnutls_kx_is_block(KX_Algorithm algorithm);
+int _gnutls_kx_is_ok(KX_Algorithm algorithm);
+int _gnutls_kx_get_key_size(KX_Algorithm algorithm);
+int _gnutls_kx_get_iv_size(KX_Algorithm algorithm);
+char *_gnutls_kx_get_name(KX_Algorithm algorithm);
+
diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c
new file mode 100644
index 0000000000..9b8b3fd6f1
--- /dev/null
+++ b/lib/gnutls_buffers.c
@@ -0,0 +1,88 @@
+#include <defines.h>
+#include <mhash.h>
+#include "gnutls_int.h"
+#include "gnutls_errors.h"
+
+int gnutls_insertDataBuffer(GNUTLS_STATE state, char *data, int length)
+{
+ int old_buffer = state->gnutls_internals.bufferSize;
+
+ state->gnutls_internals.bufferSize += length;
+ state->gnutls_internals.buffer =
+ gnutls_realloc(state->gnutls_internals.buffer,
+ state->gnutls_internals.bufferSize);
+ memmove(&state->gnutls_internals.buffer[old_buffer], data, length);
+
+ return 0;
+
+}
+
+int gnutls_getDataBufferSize(ContentType type, GNUTLS_STATE state)
+{
+ if (type == GNUTLS_APPLICATION_DATA)
+ return state->gnutls_internals.bufferSize;
+ return 0;
+}
+
+int gnutls_getDataFromBuffer(GNUTLS_STATE state, char *data, int length)
+{
+ if (length > state->gnutls_internals.bufferSize) {
+ length = state->gnutls_internals.bufferSize;
+ }
+
+ state->gnutls_internals.bufferSize -= length;
+ memmove(data, state->gnutls_internals.buffer, length);
+
+ /* overwrite buffer */
+ memmove(state->gnutls_internals.buffer,
+ &state->gnutls_internals.buffer[length],
+ state->gnutls_internals.bufferSize);
+ state->gnutls_internals.buffer =
+ gnutls_realloc(state->gnutls_internals.buffer,
+ state->gnutls_internals.bufferSize);
+
+ return length;
+}
+
+ssize_t Read(int fd, void *iptr, size_t sizeOfPtr)
+{
+ size_t left;
+ ssize_t i=0;
+ char *ptr = iptr;
+
+ left = sizeOfPtr;
+ while (left > 0) {
+ i = read(fd, &ptr[i], left);
+ if (i < 0) {
+ return -1;
+ } else {
+ if (i == 0)
+ break; /* EOF */
+ }
+
+ left -= i;
+
+ }
+
+ return (sizeOfPtr - left);
+}
+
+
+ssize_t Write(int fd, const void *iptr, size_t n)
+{
+ size_t left;
+ ssize_t i = 0;
+ const char *ptr = iptr;
+
+ left = n;
+ while (left > 0) {
+ i = write(fd, &ptr[i], left);
+ if (i <= 0) {
+ return -1;
+ }
+ left -= i;
+ }
+
+ return n;
+
+}
diff --git a/lib/gnutls_buffers.h b/lib/gnutls_buffers.h
new file mode 100644
index 0000000000..24ad57b878
--- /dev/null
+++ b/lib/gnutls_buffers.h
@@ -0,0 +1,5 @@
+int gnutls_insertDataBuffer(GNUTLS_STATE state, char *data, int length);
+int gnutls_getDataBufferSize(ContentType type, GNUTLS_STATE state);
+int gnutls_getDataFromBuffer(GNUTLS_STATE state, char *data, int length);
+ssize_t Read(int fd, void *iptr, size_t n);
+ssize_t Write(int fd, const void *iptr, size_t n);
diff --git a/lib/gnutls_cipher.c b/lib/gnutls_cipher.c
new file mode 100644
index 0000000000..855ab27647
--- /dev/null
+++ b/lib/gnutls_cipher.c
@@ -0,0 +1,589 @@
+#include <defines.h>
+#include <mhash.h>
+#include "gnutls_int.h"
+#include "gnutls_errors.h"
+#include "gnutls_compress.h"
+#include "gnutls_cipher.h"
+#include "gnutls_algorithms.h"
+
+#define MD5_DIGEST 16
+#define SHA_DIGEST 20
+
+/* Sets the specified cipher into the pending state */
+int _gnutls_set_cipher(GNUTLS_STATE state, BulkCipherAlgorithm algo)
+{
+
+ if (_gnutls_cipher_is_ok(algo) == 0) {
+ state->security_parameters.bulk_cipher_algorithm = algo;
+ if (_gnutls_cipher_is_block(algo) == 0) {
+ state->security_parameters.cipher_type =
+ CIPHER_BLOCK;
+ } else {
+ state->security_parameters.cipher_type =
+ CIPHER_STREAM;
+ }
+ state->security_parameters.is_exportable =
+ EXPORTABLE_FALSE;
+ state->security_parameters.key_material_length =
+ state->security_parameters.key_size =
+ _gnutls_cipher_get_key_size(algo);
+ state->security_parameters.IV_size =
+ _gnutls_cipher_get_iv_size(algo);
+ } else {
+ return GNUTLS_E_UNKNOWN_CIPHER;
+ }
+
+ return 0;
+
+}
+
+/* Sets the specified algorithm into pending compression state */
+int _gnutls_set_compression(GNUTLS_STATE state, CompressionMethod algo)
+{
+
+ switch (algo) {
+ case COMPRESSION_NULL:
+ break;
+
+ default:
+ return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
+ }
+ return 0;
+
+}
+
+/* Sets the specified mac algorithm into pending state */
+int _gnutls_set_mac(GNUTLS_STATE state, MACAlgorithm algo)
+{
+
+ switch (algo) {
+ case MAC_NULL:
+ state->security_parameters.mac_algorithm = MAC_NULL;
+ state->security_parameters.hash_size = 0;
+ break;
+
+ case MAC_MD5:
+ state->security_parameters.mac_algorithm = MAC_MD5;
+ state->security_parameters.hash_size = MD5_DIGEST;
+ break;
+
+ case MAC_SHA:
+ state->security_parameters.mac_algorithm = MAC_SHA;
+ state->security_parameters.hash_size = SHA_DIGEST;
+ break;
+
+ default:
+ return GNUTLS_E_UNKNOWN_MAC_ALGORITHM;
+ }
+
+ return 0;
+
+}
+
+/* Sets the current connection state to conform with the
+ * Security parameters(pending state), and initializes encryption.
+ */
+int _gnutls_connection_state_init(GNUTLS_STATE state)
+{
+ int rc;
+
+ gnutls_free(state->connection_state.write_mac_secret);
+ gnutls_free(state->connection_state.read_mac_secret);
+
+ if (state->connection_state.read_cipher_state != NULL)
+ gcry_cipher_close(state->connection_state.
+ read_cipher_state);
+
+ if (state->connection_state.write_cipher_state != NULL)
+ gcry_cipher_close(state->connection_state.
+ write_cipher_state);
+
+ gnutls_free(state->connection_state.read_compression_state);
+ gnutls_free(state->connection_state.write_compression_state);
+
+ switch (state->security_parameters.compression_algorithm) {
+ case COMPRESSION_NULL:
+ state->connection_state.read_compression_state = NULL;
+ state->connection_state.write_compression_state = NULL;
+ break;
+ default:
+ return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
+ }
+
+ switch (state->security_parameters.mac_algorithm) {
+ case MAC_NULL:
+ state->connection_state.read_mac_secret = NULL;
+ state->connection_state.write_mac_secret = NULL;
+ state->connection_state.mac_secret_size = 0;
+ break;
+ case MAC_MD5:
+ state->connection_state.read_mac_secret =
+ gnutls_malloc(MD5_DIGEST);
+ state->connection_state.write_mac_secret =
+ gnutls_malloc(MD5_DIGEST);
+ state->connection_state.mac_secret_size = MD5_DIGEST;
+ break;
+ case MAC_SHA:
+ state->connection_state.read_mac_secret =
+ gnutls_malloc(SHA_DIGEST);
+ state->connection_state.write_mac_secret =
+ gnutls_malloc(SHA_DIGEST);
+ state->connection_state.mac_secret_size = SHA_DIGEST;
+ break;
+ default:
+ return GNUTLS_E_UNKNOWN_MAC_ALGORITHM;
+ }
+
+ switch (state->security_parameters.bulk_cipher_algorithm) {
+ case CIPHER_NULL:
+ state->connection_state.read_cipher_state = NULL;
+ state->connection_state.write_cipher_state = NULL;
+ break;
+ case CIPHER_3DES:
+ state->connection_state.read_cipher_state =
+ gcry_cipher_open(GCRY_CIPHER_3DES,
+ GCRY_CIPHER_MODE_CBC, 0);
+ state->connection_state.write_cipher_state =
+ gcry_cipher_open(GCRY_CIPHER_3DES,
+ GCRY_CIPHER_MODE_CBC, 0);
+ break;
+ default:
+ return GNUTLS_E_UNKNOWN_CIPHER;
+ }
+
+
+ switch (state->security_parameters.entity) {
+ case GNUTLS_SERVER:
+ if (state->connection_state.write_cipher_state != NULL) {
+ rc =
+ gcry_cipher_setkey(state->connection_state.
+ write_cipher_state,
+ state->cipher_specs.
+ server_write_key,
+ state->security_parameters.
+ key_size);
+ gcry_cipher_setiv(state->connection_state.
+ write_cipher_state,
+ state->cipher_specs.
+ server_write_IV,
+ state->security_parameters.
+ IV_size);
+ }
+ if (state->connection_state.mac_secret_size > 0) {
+ memmove(state->connection_state.read_mac_secret,
+ state->cipher_specs.
+ client_write_mac_secret,
+ state->connection_state.mac_secret_size);
+ memmove(state->connection_state.write_mac_secret,
+ state->cipher_specs.
+ server_write_mac_secret,
+ state->connection_state.mac_secret_size);
+ }
+
+ if (state->connection_state.read_cipher_state != NULL) {
+ rc =
+ gcry_cipher_setkey(state->connection_state.
+ read_cipher_state,
+ state->cipher_specs.
+ client_write_key,
+ state->security_parameters.
+ key_size);
+ gcry_cipher_setiv(state->connection_state.
+ read_cipher_state,
+ state->cipher_specs.
+ client_write_IV,
+ state->security_parameters.
+ IV_size);
+ }
+ break;
+
+ case GNUTLS_CLIENT:
+ if (state->connection_state.read_cipher_state != NULL) {
+ rc =
+ gcry_cipher_setkey(state->connection_state.
+ read_cipher_state,
+ state->cipher_specs.
+ server_write_key,
+ state->security_parameters.
+ key_size);
+ gcry_cipher_setiv(state->connection_state.
+ read_cipher_state,
+ state->cipher_specs.
+ server_write_IV,
+ state->security_parameters.
+ IV_size);
+ }
+ if (state->connection_state.mac_secret_size > 0) {
+ memmove(state->connection_state.read_mac_secret,
+ state->cipher_specs.
+ server_write_mac_secret,
+ state->connection_state.mac_secret_size);
+ memmove(state->connection_state.write_mac_secret,
+ state->cipher_specs.
+ client_write_mac_secret,
+ state->connection_state.mac_secret_size);
+ }
+
+ if (state->connection_state.write_cipher_state != NULL) {
+ gcry_cipher_setiv(state->connection_state.
+ write_cipher_state,
+ state->cipher_specs.
+ client_write_IV,
+ state->security_parameters.
+ IV_size);
+ rc =
+ gcry_cipher_setkey(state->connection_state.
+ write_cipher_state,
+ state->cipher_specs.
+ client_write_key,
+ state->security_parameters.
+ key_size);
+ }
+ break;
+
+ default:
+ return GNUTLS_E_UNKNOWN_ERROR;
+ }
+
+ return 0;
+}
+
+int _gnutls_TLSCompressed2TLSCiphertext(GNUTLS_STATE state,
+ GNUTLSCiphertext **
+ cipher,
+ GNUTLSCompressed * compressed)
+{
+ GNUTLSCiphertext *ciphertext;
+ uint8 *padding, *content, *MAC;
+ uint8 padding_length;
+ uint16 c_length;
+ int rc;
+ uint8 *data;
+ uint8 *macpointer;
+ uint8 pad;
+ uint8 *rand;
+ uint64 seq_num;
+ int length;
+ MHASH td;
+
+
+ content = gnutls_malloc(compressed->length);
+ memmove(content, compressed->fragment, compressed->length);
+
+/* if (state->connection_state.mac_secret_size>0) {
+ MAC = gnutls_malloc(state->connection_state.mac_secret_size);
+ }*/
+
+ *cipher = gnutls_malloc(sizeof(GNUTLSCiphertext));
+ ciphertext = *cipher;
+
+ switch (state->security_parameters.mac_algorithm) {
+ case MAC_NULL:
+ td = MHASH_FAILED;
+ break;
+ case MAC_SHA:
+ td =
+ mhash_hmac_init(MHASH_SHA1,
+ state->connection_state.
+ write_mac_secret,
+ state->connection_state.
+ mac_secret_size,
+ mhash_get_hash_pblock(MHASH_SHA1));
+ break;
+ case MAC_MD5:
+ td =
+ mhash_hmac_init(MHASH_MD5,
+ state->connection_state.
+ write_mac_secret,
+ state->connection_state.
+ mac_secret_size,
+ mhash_get_hash_pblock(MHASH_MD5));
+ break;
+ default:
+ gnutls_free(*cipher);
+ gnutls_free(content);
+ return GNUTLS_E_UNKNOWN_MAC_ALGORITHM;
+ }
+
+#ifdef WORDS_BIGENDIAN
+ seq_num = state->connection_state.write_sequence_number;
+ c_length = compressed->length;
+#else
+ seq_num =
+ byteswap64(state->connection_state.write_sequence_number);
+ c_length = byteswap16(compressed->length);
+#endif
+ if (td != MHASH_FAILED) {
+ mhash(td, &seq_num, 8);
+ mhash(td, &compressed->type, 1);
+ mhash(td, &compressed->version.major, 1);
+ mhash(td, &compressed->version.minor, 1);
+ mhash(td, &c_length, 2);
+ mhash(td, &compressed->fragment, compressed->length);
+ MAC = mhash_hmac_end(td);
+ }
+ switch (state->security_parameters.cipher_type) {
+ case CIPHER_STREAM:
+ switch (state->security_parameters.bulk_cipher_algorithm) {
+ case CIPHER_NULL:
+ length =
+ compressed->length +
+ state->connection_state.mac_secret_size;
+ data = gnutls_malloc(length);
+ memmove(data, content, compressed->length);
+ memmove(&data[compressed->length], MAC,
+ state->connection_state.mac_secret_size);
+ ciphertext->fragment = data;
+ ciphertext->length = length;
+ ciphertext->type = compressed->type;
+ ciphertext->version.major =
+ compressed->version.major;
+ ciphertext->version.minor =
+ compressed->version.minor;
+ break;
+ default:
+ gnutls_free(*cipher);
+ gnutls_free(content);
+ return GNUTLS_E_UNKNOWN_CIPHER;
+
+ }
+ break;
+ case CIPHER_BLOCK:
+ switch (state->security_parameters.bulk_cipher_algorithm) {
+ case CIPHER_3DES:
+
+ rand = gcry_random_bytes(1, GCRY_STRONG_RANDOM);
+ length =
+ compressed->length +
+ state->connection_state.mac_secret_size +
+ rand[0] + 1;
+ length =
+ (length /
+ _gnutls_cipher_get_block_size(CIPHER_3DES)) *
+ _gnutls_cipher_get_block_size(CIPHER_3DES);
+ pad =
+ length - compressed->length -
+ state->connection_state.mac_secret_size - 1;
+
+ /* set pad bytes pad */
+ padding = gnutls_malloc(pad);
+ memset(padding, pad, pad);
+ padding_length = pad;
+
+ data = gnutls_malloc(length);
+ memmove(data, content, compressed->length);
+ memmove(&data[compressed->length], MAC,
+ state->connection_state.mac_secret_size);
+ memmove(&data
+ [state->connection_state.mac_secret_size +
+ compressed->length], padding, pad);
+ memmove(&data
+ [pad +
+ state->connection_state.mac_secret_size +
+ compressed->length], &padding_length, 1);
+
+ gnutls_free(padding);
+
+ gcry_cipher_encrypt(state->connection_state.
+ write_cipher_state, data,
+ length, data, length);
+
+ ciphertext->fragment = data;
+ ciphertext->length = length;
+ ciphertext->type = compressed->type;
+ ciphertext->version.major =
+ compressed->version.major;
+ ciphertext->version.minor =
+ compressed->version.minor;
+
+ gcry_free(rand);
+ break;
+ default:
+ gnutls_free(*cipher);
+ gnutls_free(content);
+ return GNUTLS_E_UNKNOWN_CIPHER;
+ }
+ break;
+ default:
+ gnutls_free(*cipher);
+ gnutls_free(content);
+ return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
+ }
+
+// gnutls_free( MAC);
+ if (td != MHASH_FAILED)
+ free(MAC);
+ gnutls_free(content);
+
+ return 0;
+}
+
+int _gnutls_TLSCiphertext2TLSCompressed(GNUTLS_STATE state,
+ GNUTLSCompressed **
+ compress,
+ GNUTLSCiphertext * ciphertext)
+{
+ GNUTLSCompressed *compressed;
+ uint8 *content, *MAC;
+ uint16 c_length;
+ int rc;
+ uint8 *data;
+ uint8 *macpointer;
+ uint8 pad;
+ uint64 seq_num;
+ int length;
+ MHASH td;
+
+
+ content = gnutls_malloc(ciphertext->length);
+ memmove(content, ciphertext->fragment, ciphertext->length);
+
+/* if (state->connection_state.mac_secret_size>0) {
+ MAC = gnutls_malloc(state->connection_state.mac_secret_size);
+ }*/
+
+ *compress = gnutls_malloc(sizeof(GNUTLSCompressed));
+ compressed = *compress;
+
+
+ switch (state->security_parameters.mac_algorithm) {
+ case MAC_NULL:
+ td = MHASH_FAILED;
+ break;
+ case MAC_SHA:
+ td =
+ mhash_hmac_init(MHASH_SHA1,
+ state->connection_state.
+ read_mac_secret,
+ state->connection_state.
+ mac_secret_size,
+ mhash_get_hash_pblock(MHASH_SHA1));
+ break;
+ case MAC_MD5:
+ td =
+ mhash_hmac_init(MHASH_MD5,
+ state->connection_state.
+ read_mac_secret,
+ state->connection_state.
+ mac_secret_size,
+ mhash_get_hash_pblock(MHASH_MD5));
+ break;
+ default:
+ gnutls_free(*compress);
+ gnutls_free(content);
+ return GNUTLS_E_UNKNOWN_MAC_ALGORITHM;
+ }
+
+#ifdef WORDS_BIGENDIAN
+ seq_num = state->connection_state.read_sequence_number;
+ c_length = ciphertext->length;
+#else
+ seq_num = byteswap64(state->connection_state.read_sequence_number);
+ c_length = byteswap16(ciphertext->length);
+#endif
+ if (td != MHASH_FAILED) {
+ mhash(td, &seq_num, 8);
+ mhash(td, &ciphertext->type, 1);
+ mhash(td, &ciphertext->version.major, 1);
+ mhash(td, &ciphertext->version.minor, 1);
+ mhash(td, &c_length, 2);
+ mhash(td, &ciphertext->fragment, ciphertext->length);
+ MAC = mhash_hmac_end(td);
+ }
+ switch (state->security_parameters.cipher_type) {
+ case CIPHER_STREAM:
+ switch (state->security_parameters.bulk_cipher_algorithm) {
+ case CIPHER_NULL:
+ length =
+ ciphertext->length -
+ state->connection_state.mac_secret_size;
+ data = gnutls_malloc(length);
+ memmove(data, content, length);
+
+ /* HMAC was not the same. */
+ if (memcmp
+ (MAC, &data[length],
+ state->connection_state.mac_secret_size) != 0)
+ return GNUTLS_E_MAC_FAILED;
+
+ compressed->fragment = data;
+ compressed->length = length;
+ compressed->type = ciphertext->type;
+ compressed->version.major =
+ ciphertext->version.major;
+ compressed->version.minor =
+ ciphertext->version.minor;
+ break;
+ default:
+ gnutls_free(*compress);
+ gnutls_free(content);
+ return GNUTLS_E_UNKNOWN_CIPHER;
+
+ }
+ break;
+ case CIPHER_BLOCK:
+ switch (state->security_parameters.bulk_cipher_algorithm) {
+ case CIPHER_3DES:
+
+ gcry_cipher_decrypt(state->connection_state.
+ read_cipher_state, content,
+ ciphertext->length, content,
+ ciphertext->length);
+
+ pad = content[ciphertext->length - 1]; /* pad */
+ length =
+ ciphertext->length -
+ state->connection_state.mac_secret_size - pad -
+ 1;
+
+ /* HMAC was not the same. */
+ if (memcmp
+ (MAC, &data[length],
+ state->connection_state.mac_secret_size) != 0)
+ return GNUTLS_E_MAC_FAILED;
+
+ data = gnutls_malloc(length);
+ memmove(data, content, length);
+
+ compressed->fragment = data;
+ compressed->length = length;
+ compressed->type = ciphertext->type;
+ compressed->version.major =
+ ciphertext->version.major;
+ compressed->version.minor =
+ ciphertext->version.minor;
+
+ break;
+ default:
+ gnutls_free(*compress);
+ gnutls_free(content);
+ return GNUTLS_E_UNKNOWN_CIPHER;
+ }
+ break;
+ default:
+ gnutls_free(*compress);
+ gnutls_free(content);
+ return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
+ }
+
+// gnutls_free( MAC);
+ if (td != MHASH_FAILED)
+ free(MAC);
+ gnutls_free(content);
+
+ return 0;
+}
+
+
+
+
+int _gnutls_freeTLSCiphertext(GNUTLSCiphertext * ciphertext)
+{
+ if (ciphertext == NULL)
+ return 0;
+
+ gnutls_free(ciphertext->fragment);
+ gnutls_free(ciphertext);
+
+ return 0;
+}
diff --git a/lib/gnutls_cipher.h b/lib/gnutls_cipher.h
new file mode 100644
index 0000000000..1ba32edab2
--- /dev/null
+++ b/lib/gnutls_cipher.h
@@ -0,0 +1,15 @@
+int _gnutls_TLSCompressed2TLSCiphertext(GNUTLS_STATE state,
+ GNUTLSCiphertext**
+ cipher,
+ GNUTLSCompressed *
+ compressed);
+int _gnutls_freeTLSCiphertext(GNUTLSCiphertext * ciphertext);
+int _gnutls_set_cipher( GNUTLS_STATE state, BulkCipherAlgorithm algo);
+int _gnutls_set_mac( GNUTLS_STATE state, MACAlgorithm algo);
+int _gnutls_set_compression( GNUTLS_STATE state, CompressionMethod algo);
+int _gnutls_connection_state_init(GNUTLS_STATE state);
+int _gnutls_TLSCiphertext2TLSCompressed(GNUTLS_STATE state,
+ GNUTLSCompressed**
+ compress,
+ GNUTLSCiphertext *
+ ciphertext);
diff --git a/lib/gnutls_compress.c b/lib/gnutls_compress.c
new file mode 100644
index 0000000000..fa0d2bb11b
--- /dev/null
+++ b/lib/gnutls_compress.c
@@ -0,0 +1,79 @@
+#include <defines.h>
+#include <mhash.h>
+#include "gnutls_int.h"
+#include "gnutls_compress.h"
+#include "gnutls_errors.h"
+
+int _gnutls_TLSPlaintext2TLSCompressed(GNUTLS_STATE state,
+ GNUTLSCompressed **
+ compress,
+ GNUTLSPlaintext *
+ plaintext)
+{
+ GNUTLSCompressed *compressed;
+
+ *compress = gnutls_malloc(sizeof(GNUTLSCompressed));
+ compressed = *compress;
+
+ switch (state->security_parameters.compression_algorithm) {
+ case COMPRESSION_NULL:
+
+ compressed->fragment = gnutls_malloc(plaintext->length);
+
+ memmove(compressed->fragment, plaintext->fragment,
+ plaintext->length);
+ compressed->length = plaintext->length;
+ compressed->type = plaintext->type;
+ compressed->version.major = plaintext->version.major;
+ compressed->version.minor = plaintext->version.minor;
+ break;
+ default:
+ gnutls_free(*compress);
+ return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
+ }
+
+ return 0;
+}
+
+int _gnutls_TLSCompressed2TLSPlaintext(GNUTLS_STATE state,
+ GNUTLSPlaintext**
+ plain,
+ GNUTLSCompressed *
+ compressed)
+{
+ GNUTLSPlaintext *plaintext;
+
+ *plain = gnutls_malloc(sizeof(GNUTLSPlaintext));
+ plaintext = *plain;
+
+ switch (state->security_parameters.compression_algorithm) {
+ case COMPRESSION_NULL:
+ plaintext->fragment = gnutls_malloc(compressed->length);
+ memmove(plaintext->fragment, compressed->fragment,
+ compressed->length);
+ plaintext->length = compressed->length;
+ plaintext->type = compressed->type;
+ plaintext->version.major = compressed->version.major;
+ plaintext->version.minor = compressed->version.minor;
+ break;
+ default:
+ gnutls_free(*plain);
+ return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
+ }
+
+ return 0;
+}
+
+
+
+
+int _gnutls_freeTLSCompressed(GNUTLSCompressed * compressed)
+{
+ if (compressed == NULL)
+ return 0;
+
+ gnutls_free(compressed->fragment);
+ gnutls_free(compressed);
+
+ return 0;
+}
diff --git a/lib/gnutls_compress.h b/lib/gnutls_compress.h
new file mode 100644
index 0000000000..ef15cac254
--- /dev/null
+++ b/lib/gnutls_compress.h
@@ -0,0 +1,11 @@
+int _gnutls_freeTLSCompressed(GNUTLSCompressed * compressed);
+int _gnutls_TLSPlaintext2TLSCompressed(GNUTLS_STATE state,
+ GNUTLSCompressed **
+ compress,
+ GNUTLSPlaintext *
+ plaintext);
+int _gnutls_TLSCompressed2TLSPlaintext(GNUTLS_STATE state,
+ GNUTLSPlaintext**
+ plain,
+ GNUTLSCompressed *
+ compressed);
diff --git a/lib/gnutls_dh.c b/lib/gnutls_dh.c
new file mode 100644
index 0000000000..754f363dc7
--- /dev/null
+++ b/lib/gnutls_dh.c
@@ -0,0 +1,662 @@
+#include <defines.h>
+#include <gcrypt.h>
+
+static const byte diffie_hellman_group1_prime[130] = { 0x04, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
+ 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
+ 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
+ 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
+ 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
+ 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+
+/****************
+ * Choose a random value x and calculate e = g^x mod p.
+ * Return: e and if ret_x is not NULL x.
+ */
+static MPI
+calc_dh_secret( MPI *ret_x )
+{
+ MPI e, g, x, prime;
+ size_t n = sizeof diffie_hellman_group1_prime;
+
+ if( gcry_mpi_scan( &prime, GCRYMPI_FMT_STD,
+ diffie_hellman_group1_prime, &n ) )
+ abort();
+ /*dump_mpi(stderr, "prime=", prime );*/
+
+ g = mpi_set_ui( NULL, 2 );
+ x = mpi_new( 200 ); /* FIXME: allocate in secure memory */
+ gcry_mpi_randomize( x, 200, GCRY_STRONG_RANDOM );
+ /* fixme: set high bit of x and select a larger one */
+
+ e = mpi_new(1024);
+ mpi_powm( e, g, x, prime );
+
+ if( ret_x )
+ *ret_x = x;
+ else
+ mpi_release(x);
+ mpi_release(g);
+ mpi_release(prime);
+ return e;
+}
+
+
+
+static void
+hash_mpi( GCRY_MD_HD md, MPI a )
+{
+ char buf[400];
+ size_t n = sizeof buf;
+
+ if( gcry_mpi_print( GCRYMPI_FMT_SSH, buf, &n, a ) )
+ fprintf(stderr,"Oops: MPI too large for hashing\n");
+ else
+ gcry_md_write( md, buf, n );
+}
+
+
+static void
+hash_bstring( GCRY_MD_HD md, BSTRING a )
+{
+ byte buf[4];
+ size_t n = a->len;
+
+ buf[0] = n >> 24;
+ buf[1] = n >> 16;
+ buf[2] = n >> 8;
+ buf[3] = n;
+ gcry_md_write( md, buf, 4 );
+ gcry_md_write( md, a->d, n );
+}
+
+
+
+static MPI
+calc_dh_key( MPI f, MPI x )
+{
+ MPI k, prime;
+ size_t n = sizeof diffie_hellman_group1_prime;
+
+ if( gcry_mpi_scan( &prime, GCRYMPI_FMT_STD,
+ diffie_hellman_group1_prime, &n ) )
+ abort();
+
+ k = mpi_new( 1024 ); /* FIXME: allocate in secure memory */
+ mpi_powm( k, f, x, prime );
+ mpi_release(prime);
+ return k;
+}
+
+
+
+
+/****************
+ * calculate the exchange hash value and put it into the handle.
+ */
+static int
+calc_exchange_hash( GSTIHD hd, BSTRING i_c, BSTRING i_s,
+ BSTRING k_s, MPI e, MPI f )
+{
+ GCRY_MD_HD md;
+ int algo = GCRY_MD_SHA1;
+
+ md = gcry_md_open( algo, 0 );
+ if( !md )
+ return map_gcry_rc( gcry_errno() );
+
+ if( hd->we_are_server ) {
+ BSTRING pp;
+ hash_bstring( md, hd->peer_version_string );
+ pp = make_bstring( host_version_string, strlen(host_version_string) );
+ hash_bstring( md, pp );
+ gsti_free(pp);
+ }
+ else {
+ BSTRING pp;
+ pp = make_bstring( host_version_string, strlen(host_version_string) );
+ hash_bstring( md, pp );
+ gsti_free(pp);
+ hash_bstring( md, hd->peer_version_string );
+ }
+ hash_bstring( md, i_c );
+ hash_bstring( md, i_s );
+ hash_bstring( md, k_s );
+ hash_mpi( md, e );
+ hash_mpi( md, f );
+ hash_mpi( md, hd->kex.k );
+
+ hd->kex.h = make_bstring( gcry_md_read( md, algo ),
+ gcry_md_get_algo_dlen(algo) );
+ if( !hd->session_id ) /* initialize the session id the first time */
+ hd->session_id = make_bstring( gcry_md_read( md, algo ),
+ gcry_md_get_algo_dlen(algo));
+ gcry_md_close( md );
+/* dump_hexbuf( stderr, "SesID=", hd->session_id->d, hd->session_id->len );*/
+ return 0;
+}
+
+
+/* Hmm. We need to have a new_kex structure so that the old
+ * kex data can be used untip we have send the NEWKEYs msg
+ * Well, doesn't matter for now.
+ */
+static BSTRING
+construct_one_key( GSTIHD hd, GCRY_MD_HD md1, int algo,
+ const byte *letter, size_t size )
+{
+ BSTRING hash;
+ GCRY_MD_HD md = gcry_md_copy( md1 );
+ size_t n, n1;
+
+ hash = make_bstring( NULL, size );
+ gcry_md_write( md, letter, 1 );
+ gcry_md_write( md, hd->session_id->d, hd->session_id->len );
+ n = gcry_md_get_algo_dlen(algo);
+ if( n > size )
+ n = size;
+ memcpy( hash->d, gcry_md_read(md, algo), n );
+ while( n < size ) {
+ gcry_md_close( md );
+ md = gcry_md_copy( md1 );
+ gcry_md_write( md, hash->d, n );
+ n1 = gcry_md_get_algo_dlen(algo);
+ if( n1 > size-n )
+ n1 = size-n;
+ memcpy( hash->d+n, gcry_md_read(md, algo), n1 );
+ n += n1;
+ }
+ gcry_md_close( md );
+
+ return hash;
+}
+
+
+static int
+construct_keys( GSTIHD hd )
+{
+ GCRY_MD_HD md;
+ int algo = GCRY_MD_SHA1;
+
+ if( hd->kex.key_a )
+ return 0; /* already constructed */
+
+ md = gcry_md_open( algo, 0 );
+ if( !md )
+ return map_gcry_rc( gcry_errno() );
+
+ hash_mpi( md, hd->kex.k );
+ gcry_md_write( md, hd->kex.h->d, hd->kex.h->len );
+
+ hd->kex.key_a = construct_one_key( hd, md, algo, "\x41", 8 );
+ hd->kex.key_b = construct_one_key( hd, md, algo, "\x42", 8 );
+ hd->kex.key_c = construct_one_key( hd, md, algo, "\x43", 24 ); /* des*/
+ hd->kex.key_d = construct_one_key( hd, md, algo, "\x44", 24 );
+ hd->kex.key_e = construct_one_key( hd, md, algo, "\x45", 20 );
+ hd->kex.key_f = construct_one_key( hd, md, algo, "\x46", 20 );
+ gcry_md_close( md );
+ #if 0
+ dump_hexbuf( stderr, "key A=", hd->kex.key_a->d, hd->kex.key_a->len );
+ dump_hexbuf( stderr, "key B=", hd->kex.key_b->d, hd->kex.key_b->len );
+ dump_hexbuf( stderr, "key C=", hd->kex.key_c->d, hd->kex.key_c->len );
+ dump_hexbuf( stderr, "key D=", hd->kex.key_d->d, hd->kex.key_d->len );
+ dump_hexbuf( stderr, "key E=", hd->kex.key_e->d, hd->kex.key_e->len );
+ dump_hexbuf( stderr, "key F=", hd->kex.key_f->d, hd->kex.key_f->len );
+ #endif
+ return 0;
+}
+
+
+static int
+prepare_hmac_pad( GCRY_MD_HD *rhd, BSTRING key, int pad )
+{
+ int algo = GCRY_MD_SHA1;
+ int i;
+ byte buf[64]; /* fixme */
+
+ assert( key->len <= sizeof buf );
+ *rhd = gcry_md_open( algo, 0 );
+ if( !*rhd )
+ return map_gcry_rc( gcry_errno() );
+
+ memset( buf, 0, sizeof buf );
+ memcpy( buf, key->d, key->len );
+ for(i=0; i < sizeof buf; i++ )
+ buf[i] ^= pad;
+ gcry_md_write( *rhd, buf, sizeof buf );
+ return 0;
+}
+
+/****************
+ * Prepare a HMAC
+ */
+static int
+prepare_mac( GCRY_MD_HD *inner_hd, GCRY_MD_HD *outer_hd, BSTRING key )
+{
+ int rc;
+
+ rc = prepare_hmac_pad( inner_hd, key, '\x36');
+ if( !rc )
+ rc = prepare_hmac_pad( outer_hd, key, '\x5c');
+ return rc;
+}
+
+
+/* fixme: must release some data in case of error or when at end */
+int
+kex_send_init_packet( GSTIHD hd )
+{
+ MSG_kexinit kex;
+ int rc=0;
+
+ /* first send our kexinit packet */
+ memset( &kex, 0, sizeof kex );
+ memset( kex.cookie, 'w', 16 ); /* fixme: send a random one */
+ kex.kex_algorithm = insert_strlist( NULL, "diffie-hellman-group1-sha1" );
+ kex.server_host_key_algorithms = insert_strlist( NULL, "ssh-dss");
+ kex.encryption_algorithms_client_to_server = insert_strlist( NULL, "3des-cbc");
+ kex.encryption_algorithms_server_to_client = insert_strlist( NULL, "3des-cbc");
+ kex.mac_algorithms_client_to_server = insert_strlist( NULL, "hmac-sha1");
+ kex.mac_algorithms_server_to_client = insert_strlist( NULL, "hmac-sha1");
+ kex.compression_algorithms_client_to_server = insert_strlist( NULL, "none");
+ kex.compression_algorithms_server_to_client = insert_strlist( NULL, "none");
+ rc = build_msg_kexinit( &kex, &hd->pkt );
+ if( rc )
+ return rc;
+ rc = write_packet( hd );
+ if( rc )
+ return rc;
+ /* must do it here because write_packet fills in the packet type */
+ hd->host_kexinit_data = make_bstring( hd->pkt.payload, hd->pkt.payload_len );
+ rc = flush_packet( hd );
+ return rc;
+}
+
+
+/****************
+ * Process a received keyinit packet.
+ */
+int
+kex_proc_init_packet( GSTIHD hd )
+{
+ MSG_kexinit kex;
+ int rc;
+
+ if( hd->pkt.type != SSH_MSG_KEXINIT )
+ return GSTI_BUG; /* oops */
+ rc = parse_msg_kexinit( &kex, hd->pkt.payload, hd->pkt.payload_len );
+ if( rc )
+ return rc;
+ /* make a copy of the received payload which we will need later */
+ hd->peer_kexinit_data = make_bstring( hd->pkt.payload,
+ hd->pkt.payload_len );
+
+ dump_msg_kexinit( &kex );
+ return 0;
+}
+
+
+/****************
+ * Send a KEX init packet (we are in the client role)
+ */
+int
+kex_send_kexdh_init( GSTIHD hd )
+{
+ MSG_kexdh_init kexdh;
+ int rc=0;
+
+ memset( &kexdh, 0, sizeof kexdh );
+ /* FIXME: move secret_x it to secure memory */
+ kexdh.e = hd->kexdh_e = calc_dh_secret( &hd->secret_x );
+ rc = build_msg_kexdh_init( &kexdh, &hd->pkt );
+ if( rc )
+ return rc;
+ rc = write_packet( hd );
+ if( rc )
+ return rc;
+ rc = flush_packet( hd );
+ return rc;
+}
+
+
+/****************
+ * Process the received DH init (we are in the server role)
+ */
+int
+kex_proc_kexdh_init( GSTIHD hd )
+{
+ int rc;
+ MSG_kexdh_init kexdh;
+
+ if( hd->pkt.type != SSH_MSG_KEXDH_INIT )
+ return GSTI_BUG; /* oops */
+
+ rc = parse_msg_kexdh_init( &kexdh, hd->pkt.payload, hd->pkt.payload_len );
+ if( rc )
+ return rc;
+
+ /* we need the received e later */
+ hd->kexdh_e = kexdh.e;
+
+ dump_msg_kexdh_init( &kexdh );
+ return 0;
+}
+
+
+/****************
+ * Send a DH init packet (we are in the server role)
+ */
+int
+kex_send_kexdh_reply( GSTIHD hd )
+{
+ MSG_kexdh_reply dhr;
+ int rc;
+ MPI y;
+
+ memset( &dhr, 0, sizeof dhr );
+ dhr.k_s = make_bstring( "servers-pk", 10 ); /* fixme: Get from a DB */
+
+ /* generate our secret and the public value for it */
+ dhr.f = calc_dh_secret( &y );
+ /* now we can calculate the shared secret */
+ hd->kex.k = calc_dh_key( hd->kexdh_e, y );
+ mpi_release( y );
+ /* and the hash */
+ rc = calc_exchange_hash( hd, hd->host_kexinit_data, hd->peer_kexinit_data,
+ dhr.k_s, hd->kexdh_e, dhr.f );
+ mpi_release( hd->kexdh_e );
+ if( rc )
+ return rc;
+ dhr.sig_h = make_bstring("signature_of_H", 14 ); /*FIXME*/
+
+ rc = build_msg_kexdh_reply( &dhr, &hd->pkt );
+ if( !rc )
+ dump_msg_kexdh_reply( &dhr );
+ if( !rc )
+ rc = write_packet( hd );
+ if( !rc )
+ rc = flush_packet( hd );
+ return rc;
+}
+
+/****************
+ * Process the received DH value and take the encryption kes into use.
+ * (we are in the client role)
+ */
+int
+kex_proc_kexdh_reply( GSTIHD hd )
+{
+ int rc;
+ MSG_kexdh_reply dhr;
+
+ if( hd->pkt.type != SSH_MSG_KEXDH_REPLY )
+ return GSTI_BUG; /* oops */
+
+ rc = parse_msg_kexdh_reply( &dhr, hd->pkt.payload, hd->pkt.payload_len );
+ if( rc )
+ return rc;
+
+ dump_msg_kexdh_reply( &dhr );
+
+ hd->kex.k = calc_dh_key( dhr.f, hd->secret_x );
+ mpi_release( hd->secret_x );
+
+ rc = calc_exchange_hash( hd, hd->host_kexinit_data, hd->peer_kexinit_data,
+ dhr.k_s, hd->kexdh_e, dhr.f );
+ mpi_release( hd->kexdh_e );
+ if( rc )
+ return rc;
+
+ /* FIXME: check that this is the real host */
+
+ return rc;
+}
+
+
+int
+kex_send_newkeys( GSTIHD hd )
+{
+ int rc;
+
+ rc = construct_keys( hd );
+ if( rc )
+ return rc;
+
+ hd->pkt.type = SSH_MSG_NEWKEYS;
+ hd->pkt.payload_len = 1;
+ rc = write_packet( hd );
+ if( !rc )
+ rc = flush_packet( hd );
+ if( rc )
+ return rc;
+
+ /* now we have to take the encryption keys into use */
+ hd->encrypt_hd = gcry_cipher_open( GCRY_CIPHER_3DES,
+ GCRY_CIPHER_MODE_CBC, 0 );
+ if( !hd->encrypt_hd )
+ rc = map_gcry_rc( gcry_errno() );
+ else if( hd->we_are_server ) {
+ if( !rc )
+ rc = gcry_cipher_setkey( hd->encrypt_hd, hd->kex.key_d->d,
+ hd->kex.key_d->len );
+ if( !rc )
+ rc = gcry_cipher_setiv( hd->encrypt_hd, hd->kex.key_b->d,
+ hd->kex.key_b->len );
+ rc = map_gcry_rc(rc);
+ if( !rc )
+ rc = prepare_mac( &hd->send_mac_inner_hd, &hd->send_mac_outer_hd,
+ hd->kex.key_f );
+ }
+ else {
+ if( !rc )
+ rc = gcry_cipher_setkey( hd->encrypt_hd, hd->kex.key_c->d,
+ hd->kex.key_c->len );
+ if( !rc )
+ rc = gcry_cipher_setiv( hd->encrypt_hd, hd->kex.key_a->d,
+ hd->kex.key_a->len );
+ rc = map_gcry_rc(rc);
+ if( !rc )
+ rc = prepare_mac( &hd->send_mac_inner_hd, &hd->send_mac_outer_hd,
+ hd->kex.key_e );
+ }
+ if( rc )
+ return debug_rc(rc,"setup encryption keys failed");
+ return rc;
+}
+
+/****************
+ * Process a received newkeys message and take the decryption keys in use
+ */
+int
+kex_proc_newkeys( GSTIHD hd )
+{
+ int rc;
+
+ if( hd->pkt.type != SSH_MSG_NEWKEYS )
+ return GSTI_BUG; /* ooops */
+
+ rc = construct_keys( hd );
+ if( rc )
+ return rc;
+
+ hd->decrypt_hd = gcry_cipher_open( GCRY_CIPHER_3DES,
+ GCRY_CIPHER_MODE_CBC, 0 );
+ if( !hd->encrypt_hd )
+ rc = map_gcry_rc( gcry_errno() );
+ else if( hd->we_are_server ) {
+ if( !rc )
+ rc = gcry_cipher_setkey( hd->decrypt_hd, hd->kex.key_c->d,
+ hd->kex.key_c->len );
+ if( !rc )
+ rc = gcry_cipher_setiv( hd->decrypt_hd, hd->kex.key_a->d,
+ hd->kex.key_a->len );
+ rc = map_gcry_rc(rc);
+ if( !rc )
+ rc = prepare_mac( &hd->recv_mac_inner_hd, &hd->recv_mac_outer_hd,
+ hd->kex.key_e );
+ }
+ else {
+ if( !rc )
+ rc = gcry_cipher_setkey( hd->decrypt_hd, hd->kex.key_d->d,
+ hd->kex.key_d->len );
+ if( !rc )
+ rc = gcry_cipher_setiv( hd->decrypt_hd, hd->kex.key_b->d,
+ hd->kex.key_b->len );
+ rc = map_gcry_rc(rc);
+ if( !rc )
+ rc = prepare_mac( &hd->recv_mac_inner_hd, &hd->recv_mac_outer_hd,
+ hd->kex.key_f );
+ }
+
+ if( rc )
+ return debug_rc(rc,"setup decryption keys failed");
+ return rc;
+}
+
+
+
+/****************
+ * Parse a SSH_MSG_SERVICE_{ACCEPT,REQUEST} and return the service name.
+ * Returns: 0 on success or an errorcode.
+ */
+static int
+parse_msg_service( BSTRING *svcname, const byte *msg, size_t msglen, int type )
+{
+ size_t n;
+ int rc = 0;
+
+ *svcname = NULL;
+ if( msglen < (1+4) )
+ return GSTI_TOO_SHORT;
+ if( *msg != type )
+ return GSTI_BUG;
+ msg++; msglen--;
+
+ n = msglen;
+ *svcname = parse_bstring( msg, &n );
+ if( !*svcname )
+ return GSTI_TOO_SHORT;
+ msg += n; msglen -= n;
+
+ /* make sure the msg length matches */
+ if( msglen ) {
+ fprintf(stderr,"parse_msg_service: hmmm, %lu bytes remaining\n",
+ (ulong)msglen );
+ }
+ return rc;
+}
+
+/****************
+ * Build a SERVICE_{Accept,REQUEST} packet.
+ */
+static int
+build_msg_service( BSTRING svcname, struct packet_buffer_s *pkt, int type )
+{
+ size_t n;
+ byte *p = pkt->payload;
+ size_t length = pkt->size;
+
+ assert( pkt->size > 100 );
+ if( !svcname ) {
+ fprintf(stderr,"build_msg_service: no service name\n");
+ return GSTI_BUG;
+ }
+
+ pkt->type = type;
+ p++; pkt->payload_len = 1;
+
+ n = build_bstring( p, length, svcname );
+ if( !n )
+ return GSTI_TOO_SHORT; /* provided buffer is too short */
+ p += n; length -= n; pkt->payload_len += n;
+ return 0;
+}
+
+
+
+int
+kex_send_service_request( GSTIHD hd, const char *name )
+{
+ int rc;
+
+ hd->service_name = make_bstring( name, strlen(name) );
+ rc = build_msg_service( hd->service_name, &hd->pkt,SSH_MSG_SERVICE_REQUEST);
+ if( !rc )
+ rc = write_packet( hd );
+ if( !rc )
+ rc = flush_packet( hd );
+
+ if( rc ) {
+ gsti_free( hd->service_name );
+ hd->service_name = NULL;
+ }
+ return rc;
+}
+
+int
+kex_proc_service_request( GSTIHD hd )
+{
+ int rc;
+ BSTRING svcname;
+
+ if( hd->pkt.type != SSH_MSG_SERVICE_REQUEST )
+ return GSTI_BUG; /* oops */
+ rc = parse_msg_service( &svcname, hd->pkt.payload, hd->pkt.payload_len,
+ SSH_MSG_SERVICE_REQUEST );
+ if( rc )
+ return rc;
+
+ /* FIXME: here we should whether we provide this service */
+
+ /* store the servicename, so that it can later be answered */
+ if( hd->service_name )
+ return debug_rc( GSTI_BUG, "a service is already in use");
+
+ hd->service_name = svcname;
+ return rc;
+}
+
+
+
+int
+kex_send_service_accept( GSTIHD hd )
+{
+ int rc;
+
+ rc = build_msg_service( hd->service_name, &hd->pkt, SSH_MSG_SERVICE_ACCEPT);
+ if( !rc )
+ rc = write_packet( hd );
+ if( !rc )
+ rc = flush_packet( hd );
+ return rc;
+}
+
+int
+kex_proc_service_accept( GSTIHD hd )
+{
+ int rc;
+ BSTRING svcname;
+
+ if( hd->pkt.type != SSH_MSG_SERVICE_ACCEPT )
+ return GSTI_BUG; /* oops */
+ rc = parse_msg_service( &svcname, hd->pkt.payload, hd->pkt.payload_len,
+ SSH_MSG_SERVICE_ACCEPT );
+ if( rc )
+ return rc;
+
+ if( !hd->service_name )
+ return debug_rc( GSTI_BUG, "no service request sent");
+ rc = cmp_bstring( hd->service_name, svcname );
+ gsti_free( svcname );
+ if( rc )
+ return debug_rc( GSTI_PROT_VIOL,
+ "service name does not match requested one" );
+ return 0;
+}
+
diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c
new file mode 100644
index 0000000000..b571eb7adf
--- /dev/null
+++ b/lib/gnutls_errors.c
@@ -0,0 +1,31 @@
+#include "gnutls_errors.h"
+
+int gnutls_is_fatal_error( int error) {
+
+ switch (error) {
+ case GNUTLS_E_MAC_FAILED:
+ case GNUTLS_E_UNKNOWN_CIPHER:
+ case GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM:
+ case GNUTLS_E_UNKNOWN_MAC_ALGORITHM:
+ case GNUTLS_E_UNKNOWN_ERROR:
+ case GNUTLS_E_UNKNOWN_CIPHER_TYPE:
+ case GNUTLS_E_LARGE_PACKET:
+ case GNUTLS_E_UNSUPPORTED_VERSION_PACKET:
+ case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
+ case GNUTLS_E_INVALID_SESSION:
+ case GNUTLS_E_UNABLE_SEND_DATA:
+ case GNUTLS_E_FATAL_ALERT_RECEIVED:
+ case GNUTLS_E_RECEIVED_BAD_MESSAGE:
+ case GNUTLS_E_RECEIVED_MORE_DATA:
+ case GNUTLS_E_UNEXPECTED_PACKET:
+ case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
+ case GNUTLS_E_CLOSURE_ALERT_RECEIVED:
+ case GNUTLS_E_ERROR_IN_FINISHED_PACKET:
+ return 1;
+ case GNUTLS_E_WARNING_ALERT_RECEIVED:
+ return 0;
+ default:
+ return 0;
+
+ }
+}
diff --git a/lib/gnutls_errors.h b/lib/gnutls_errors.h
new file mode 100644
index 0000000000..7a251a27b9
--- /dev/null
+++ b/lib/gnutls_errors.h
@@ -0,0 +1,19 @@
+#define GNUTLS_E_MAC_FAILED -1
+#define GNUTLS_E_UNKNOWN_CIPHER -2
+#define GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM -3
+#define GNUTLS_E_UNKNOWN_MAC_ALGORITHM -4
+#define GNUTLS_E_UNKNOWN_ERROR -5
+#define GNUTLS_E_UNKNOWN_CIPHER_TYPE -6
+#define GNUTLS_E_LARGE_PACKET -7
+#define GNUTLS_E_UNSUPPORTED_VERSION_PACKET -8
+#define GNUTLS_E_UNEXPECTED_PACKET_LENGTH -9
+#define GNUTLS_E_INVALID_SESSION -10
+#define GNUTLS_E_UNABLE_SEND_DATA -11
+#define GNUTLS_E_FATAL_ALERT_RECEIVED -12
+#define GNUTLS_E_RECEIVED_BAD_MESSAGE -13
+#define GNUTLS_E_RECEIVED_MORE_DATA -14
+#define GNUTLS_E_UNEXPECTED_PACKET -15
+#define GNUTLS_E_WARNING_ALERT_RECEIVED -16
+#define GNUTLS_E_CLOSURE_ALERT_RECEIVED -17
+#define GNUTLS_E_ERROR_IN_FINISHED_PACKET -18
+#define GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET -19
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
new file mode 100644
index 0000000000..5c44c4b027
--- /dev/null
+++ b/lib/gnutls_handshake.c
@@ -0,0 +1,710 @@
+#include <defines.h>
+#include <mhash.h>
+#include "gnutls_int.h"
+#include "gnutls_errors.h"
+#include "debug.h"
+#include "gnutls_compress.h"
+#include "gnutls_plaintext.h"
+#include "gnutls_cipher.h"
+#include "gnutls_buffers.h"
+#include "gnutls_handshake.h"
+#include "gnutls_num.h"
+
+#ifdef DEBUG
+#define ERR(x, y) fprintf(stderr, "GNUTLS Error: %s (%d)\n", x,y)
+#else
+#define ERR(x, y)
+#endif
+
+#define HASH_TRUE 1
+#define HASH_FALSE 0
+
+
+#define SERVER_MSG "server finished"
+#define CLIENT_MSG "client finished"
+_gnutls_send_finished( int cd, GNUTLS_STATE state) {
+uint8* data;
+uint8 concat[36]; /* md5+sha1 */
+int ret;
+
+
+ memset(concat, 0, 36);
+
+ if (state->security_parameters.entity == GNUTLS_CLIENT) {
+ memmove( concat, state->gnutls_internals.client_md_md5, 16);
+ memmove( &concat[16], state->gnutls_internals.client_md_sha1, 20);
+
+ data = gnutls_PRF(state->security_parameters.master_secret, 48,
+ CLIENT_MSG, strlen(CLIENT_MSG), concat, 36,
+ 12);
+ } else { /* server */
+ memmove( concat, state->gnutls_internals.server_md_md5, 16);
+ memmove( &concat[16], state->gnutls_internals.server_md_sha1, 20);
+
+ data = gnutls_PRF(state->security_parameters.master_secret, 48,
+ SERVER_MSG, strlen(SERVER_MSG), concat, 36,
+ 12);
+ }
+
+ ret = _gnutls_send_handshake( cd, state, data, 12, GNUTLS_FINISHED);
+ gnutls_free(data);
+
+ return ret;
+}
+
+int _gnutls_recv_handshake( int cd, GNUTLS_STATE state, void* data, uint32 datalen, HandshakeType type) {
+int ret;
+ state->gnutls_internals.next_handshake_type = type;
+ ret = gnutls_recv_int( cd, state, GNUTLS_HANDSHAKE, data, datalen);
+ state->gnutls_internals.next_handshake_type = GNUTLS_NONE;
+
+ return ret;
+}
+
+_gnutls_recv_finished( int cd, GNUTLS_STATE state) {
+uint8* data, vrfy[12];
+uint8 concat[36]; /* md5+sha1 */
+int ret=0;
+
+ memset( concat, 0, 36);
+ memset( vrfy, 0, 12);
+
+ ret = _gnutls_recv_handshake( cd, state, vrfy, 12, GNUTLS_FINISHED);
+ if (ret<0) {
+ ERR("recv finished int", ret);
+ return ret;
+ }
+ if (ret!=12) return GNUTLS_E_ERROR_IN_FINISHED_PACKET;
+
+ if (state->security_parameters.entity == GNUTLS_CLIENT) {
+ memmove( concat, state->gnutls_internals.server_md_md5, 16);
+ memmove( &concat[16], state->gnutls_internals.server_md_sha1, 20);
+
+ data = gnutls_PRF(state->security_parameters.master_secret, 48,
+ SERVER_MSG, strlen(SERVER_MSG), concat, 36,
+ 12);
+ } else { /* server */
+ memmove( concat, state->gnutls_internals.client_md_md5, 16);
+ memmove( &concat[16], state->gnutls_internals.client_md_sha1, 20);
+
+ data = gnutls_PRF(state->security_parameters.master_secret, 48,
+ CLIENT_MSG, strlen(CLIENT_MSG), concat, 36,
+ 12);
+ }
+
+ if ( memcmp( vrfy, data, 12) != 0) ret = GNUTLS_E_ERROR_IN_FINISHED_PACKET;
+
+ gnutls_free(data);
+
+ return ret;
+}
+
+
+
+int SelectSuite( opaque ret[2], char* data, int datalen) {
+int x, pos=0, i,j;
+GNUTLS_CipherSuite *ciphers;
+
+ x = _gnutls_supported_ciphersuites(&ciphers);
+ memset( ret, '\0', sizeof(GNUTLS_CipherSuite));
+
+ for ( j=0;j<datalen;j+=2) {
+ for (i=0;i<x;i++) {
+ if ( memcmp( &ciphers[i].CipherSuite, &data[j], 2) == 0) {
+ memmove( ret, &ciphers[i].CipherSuite, 2);
+ gnutls_free(ciphers);
+ return 0;
+ }
+ }
+ }
+
+
+ gnutls_free(ciphers);
+ return GNUTLS_E_UNKNOWN_CIPHER;
+
+}
+
+int SelectCompMethod( CompressionMethod* ret, char* data, int datalen) {
+int x, pos=0, i,j;
+CompressionMethod *ciphers;
+
+ x = _gnutls_supported_compression_methods(&ciphers);
+ memset( ret, '\0', sizeof(CompressionMethod));
+
+ for ( j=0;j<datalen;j++) {
+ for (i=0;i<x;i++) {
+ if ( memcmp( &ciphers[i], &data[j], 1) == 0) {
+ memmove( ret, &ciphers[i], 1);
+ gnutls_free(ciphers);
+ return 0;
+ }
+ }
+ }
+
+
+ gnutls_free(ciphers);
+ return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
+
+}
+
+
+#define SUPPORTED_CIPHERSUITES 1
+int _gnutls_supported_ciphersuites(GNUTLS_CipherSuite **ciphers) {
+
+ int i;
+
+ *ciphers = gnutls_malloc( SUPPORTED_CIPHERSUITES * sizeof(GNUTLS_CipherSuite));
+
+ for (i=0;i<SUPPORTED_CIPHERSUITES;i++) {
+ (*ciphers)[i].CipherSuite[0] = 0x00;
+ }
+
+ /* GNUTLS_DH_anon_WITH_3DES_EDE_CBC_SHA */
+// (*ciphers)[0].CipherSuite[1] = 0x1B;
+
+ /* GNUTLS_NULL_WITH_NULL_NULL */
+ (*ciphers)[0].CipherSuite[1] = 0x0;
+
+ return SUPPORTED_CIPHERSUITES;
+}
+
+
+#define SUPPORTED_COMPRESSION_METHODS 1
+int _gnutls_supported_compression_methods(CompressionMethod **comp) {
+
+ int i;
+
+ *comp = gnutls_malloc( SUPPORTED_COMPRESSION_METHODS * sizeof(CompressionMethod));
+
+/* NULL Compression */
+ (*comp)[0] = COMPRESSION_NULL;
+
+ return SUPPORTED_COMPRESSION_METHODS;
+}
+
+int _gnutls_send_handshake(int cd, GNUTLS_STATE state, void* i_data, uint32 i_datasize, HandshakeType type) {
+ int ret;
+ uint8* data;
+ uint24 length;
+ uint32 datasize;
+ int pos=0;
+
+#ifdef WORDS_BIGENDIAN
+ datasize = i_datasize;
+#else
+ datasize = byteswap32(i_datasize);
+#endif
+
+ length = uint32touint24( datasize);
+
+ i_datasize += 4;
+ data = gnutls_malloc( i_datasize);
+ memmove( &data[pos++], &type, 1);
+ memmove( &data[pos++], &length.pint[0], 1);
+ memmove( &data[pos++], &length.pint[1], 1);
+ memmove( &data[pos++], &length.pint[2], 1);
+
+ if (i_datasize > 0) memmove( &data[pos], i_data, i_datasize-4);
+
+ if (state->gnutls_internals.client_hash==HASH_TRUE) {
+ mhash( state->gnutls_internals.client_td_md5, data ,i_datasize);
+ mhash( state->gnutls_internals.client_td_sha1, data, i_datasize);
+ }
+ if (state->gnutls_internals.server_hash==HASH_TRUE) {
+ mhash( state->gnutls_internals.server_td_md5, data ,i_datasize);
+ mhash( state->gnutls_internals.server_td_sha1, data, i_datasize);
+ }
+
+ ret = gnutls_send_int( cd, state, GNUTLS_HANDSHAKE, data, i_datasize);
+
+ return ret;
+}
+
+int _gnutls_recv_handshake_int( int cd, GNUTLS_STATE state, void* data, uint32 datasize, void* output_data, uint32 output_datasize) {
+ int ret;
+ uint32 length32=0;
+ int pos=0;
+ uint8 *dataptr=data;
+ uint24 num;
+
+
+ num.pint[0] = dataptr[1];
+ num.pint[1] = dataptr[2];
+ num.pint[2] = dataptr[3];
+ length32 = uint24touint32( num);
+
+
+#ifndef WORDS_BIGENDIAN
+ length32 = byteswap32(length32);
+#endif
+
+ if (state->gnutls_internals.client_hash == HASH_TRUE) {
+ mhash( state->gnutls_internals.client_td_md5, dataptr, length32 + 4);
+ mhash( state->gnutls_internals.client_td_sha1, dataptr, length32 + 4);
+ }
+
+ if (state->gnutls_internals.server_hash == HASH_TRUE) {
+ mhash( state->gnutls_internals.server_td_md5, dataptr, length32 + 4);
+ mhash( state->gnutls_internals.server_td_sha1, dataptr, length32 + 4);
+ }
+
+ ret = GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
+ switch(dataptr[0]) {
+ case GNUTLS_CLIENT_HELLO:
+ case GNUTLS_SERVER_HELLO:
+ if (state->gnutls_internals.next_handshake_type == dataptr[0])
+ ret = _gnutls_recv_hello( cd, state, &dataptr[4], length32, NULL, 0);
+ break;
+ case GNUTLS_SERVER_HELLO_DONE:
+ ret = 0;
+ break;
+ case GNUTLS_FINISHED:
+ if (output_datasize > length32) output_datasize=length32;
+ memmove( output_data, &dataptr[4], length32);
+ ret = length32;
+ break;
+ }
+
+ return ret;
+}
+
+int _gnutls_send_hello_request(int cd, GNUTLS_STATE state) {
+ return _gnutls_send_handshake( cd, state, NULL, 0, GNUTLS_HELLO_REQUEST);
+}
+
+
+int _gnutls_send_hello(int cd, GNUTLS_STATE state, opaque* SessionID, uint8 SessionIDLen) {
+ char* rand;
+ char *data=NULL;
+ uint8 session_id_len, z;
+ uint32 cur_time;
+ int pos=0;
+ GNUTLS_CipherSuite* cipher_suites;
+ CompressionMethod* compression_methods;
+ int i, datalen, ret=0;
+ uint16 x;
+
+ session_id_len = SessionIDLen;
+ if (SessionID==NULL) session_id_len=0;
+ rand=gcry_random_bytes( 28, GCRY_STRONG_RANDOM);
+
+ if (state->security_parameters.entity == GNUTLS_CLIENT) {
+
+ datalen = 2 + 4 + (session_id_len+1) + 28 + 3;
+ data = gnutls_malloc ( datalen);
+
+ data[pos++] = GNUTLS_VERSION_MAJOR;
+ data[pos++] = GNUTLS_VERSION_MINOR;
+#ifdef WORDS_BIGENDIAN
+ cur_time = time(NULL);
+#else
+ cur_time = byteswap32(time(NULL));
+#endif
+ memmove( state->security_parameters.client_random, &cur_time, 4);
+ memmove( &state->security_parameters.client_random[4], rand, 28);
+
+ memmove( &data[pos], &cur_time, 4);
+ pos += 4;
+ memmove( &data[pos], rand, 28);
+ pos+=28;
+
+ memmove( &data[pos++], &session_id_len, 1);
+
+ if (session_id_len>0) {
+ memmove( &data[pos], SessionID, session_id_len);
+ }
+ pos+=session_id_len;
+
+ x = _gnutls_supported_ciphersuites( &cipher_suites);
+
+#ifdef WORDS_BIGENDIAN
+ memmove( &data[pos], &x, sizeof(uint16));
+#else
+ x=byteswap16(x);
+ memmove( &data[pos], &x, sizeof(uint16));
+ x=byteswap16(x);
+#endif
+ pos+=2;
+
+ datalen += 2*x;
+ data = gnutls_realloc( data, datalen);
+
+ for (i=0;i<x;i++) {
+ memmove( &data[pos], &cipher_suites[i].CipherSuite, 2);
+ pos+=2;
+ }
+
+ z = _gnutls_supported_compression_methods( &compression_methods);
+ memmove( &data[pos++], &z, sizeof(uint8));
+ datalen += z;
+ data = gnutls_realloc( data, datalen);
+
+ for (i=0;i<z;i++) {
+ memmove( &data[pos], &compression_methods[i], 1);
+ pos++;
+ }
+
+ gcry_free(rand);
+ gnutls_free(cipher_suites);
+ gnutls_free(compression_methods);
+
+ ret = _gnutls_send_handshake( cd, state, data, datalen, GNUTLS_CLIENT_HELLO);
+ gnutls_free(data);
+
+
+ } else { /* SERVER */
+ datalen = 2 + sizeof(uint32) + session_id_len+1 + 28;
+ data = gnutls_malloc ( datalen);
+
+ data[pos++] = GNUTLS_VERSION_MAJOR;
+ data[pos++] = GNUTLS_VERSION_MINOR;
+#ifdef WORDS_BIGENDIAN
+ cur_time = time(NULL);
+#else
+ cur_time = byteswap32(time(NULL));
+#endif
+ memmove( state->security_parameters.server_random, &cur_time, 4);
+ memmove( &state->security_parameters.server_random[4], rand, 28);
+
+ memmove( &data[pos], &cur_time, sizeof(uint32));
+ pos += sizeof(uint32);
+ memmove( &data[pos], rand, 28);
+ pos+=28;
+
+ memmove( &data[pos++], &session_id_len, sizeof(uint8));
+ if (session_id_len>0) {
+ memmove( &data[pos], SessionID, session_id_len);
+ }
+ pos+=session_id_len;
+
+ datalen += 2;
+ data = gnutls_realloc( data, datalen);
+ memmove( &data[pos], &state->gnutls_internals.current_cipher_suite.CipherSuite, 2);
+ pos+=2;
+
+ datalen += 1;
+ data = gnutls_realloc( data, datalen);
+ memmove( &data[pos++], &state->gnutls_internals.compression_method, 1);
+
+ gcry_free(rand);
+ ret = _gnutls_send_handshake( cd, state, data, datalen, GNUTLS_SERVER_HELLO);
+ gnutls_free(data);
+
+ }
+
+ return ret;
+}
+
+
+/* RECEIVE A HELLO MESSAGE. This should be called from gnutls_recv_handshake_int only if a
+ * hello message is expected. It uses the gnutls_internals.current_cipher_suite
+ * and gnutls_internals.compression_method.
+ */
+int _gnutls_recv_hello(int cd, GNUTLS_STATE state, char* data, int datalen, opaque** SessionID, int SessionIDnum) {
+ uint8 session_id_len=0, z;
+ uint32 cur_time;
+ int pos=0;
+ GNUTLS_CipherSuite cipher_suite, *cipher_suites;
+ CompressionMethod compression_method, *compression_methods;
+ int i, ret;
+ uint16 x, sizeOfSuites;
+
+ if (state->security_parameters.entity == GNUTLS_CLIENT) {
+ if (datalen < 38) return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
+
+ if (data[pos++] != GNUTLS_VERSION_MAJOR)
+ return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
+
+ if (data[pos++] != GNUTLS_VERSION_MINOR)
+ return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
+
+ memmove( state->security_parameters.server_random, &data[pos], 32);
+ pos+=32;
+
+ memmove( &session_id_len, &data[pos++], 1);
+
+ if (datalen < 38+session_id_len) return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
+#ifdef DEBUG
+ fprintf(stderr, "SessionID length: %d\n", session_id_len);
+ fprintf(stderr, "SessionID: %s\n", bin2hex(&data[pos], session_id_len));
+#endif
+ pos+=session_id_len;
+
+ /* We should resume an old connection here. This is not
+ * implemented yet.
+ */
+
+ memmove( &cipher_suite.CipherSuite, &data[pos], 2);
+ pos+=2;
+
+ z=1;
+ x = _gnutls_supported_ciphersuites( &cipher_suites);
+ for (i=0;i<x;i++) {
+ if ( memcmp( &cipher_suites[i], cipher_suite.CipherSuite, 2) == 0) {
+ z=0;
+
+ }
+ }
+ if (z!=0) return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
+ memmove( state->gnutls_internals.current_cipher_suite.CipherSuite, cipher_suite.CipherSuite, 2);
+
+ z=1;
+ memmove( &compression_method, &data[pos++], 1);
+ z = _gnutls_supported_compression_methods( &compression_methods);
+ for (i=0;i<z;i++) {
+ if (memcmp( &compression_methods[i], &compression_method, 1)==0) {
+ z=0;
+
+ }
+ }
+ if (z!=0) return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
+ memmove( &state->gnutls_internals.compression_method, &compression_method, 1);
+
+
+ gnutls_free(cipher_suites);
+ gnutls_free(compression_methods);
+
+ } else { /* Server side reading a client hello */
+ if (datalen < 35) return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
+
+ if (data[pos++] != GNUTLS_VERSION_MAJOR)
+ return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
+
+ if (data[pos++] != GNUTLS_VERSION_MINOR)
+ return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
+
+ memmove( state->security_parameters.client_random, &data[pos], 32);
+ pos+=32;
+
+ memmove( &session_id_len, &data[pos++], 1);
+ pos+=session_id_len;
+
+ /* We should resume an old connection here. This is not
+ * implemented yet.
+ */
+
+
+ /* Select a ciphersuite */
+ memmove( &sizeOfSuites, &data[pos], 2);
+ pos+=2;
+#ifndef WORDS_BIGENDIAN
+ sizeOfSuites=byteswap16(sizeOfSuites);
+#endif
+ SelectSuite( state->gnutls_internals.current_cipher_suite.CipherSuite, &data[pos], sizeOfSuites);
+ pos+=sizeOfSuites;
+
+ memmove( &z, &data[pos++], 1);
+ SelectCompMethod( &state->gnutls_internals.compression_method, &data[pos], z);
+
+ }
+
+ return ret;
+}
+
+#define HASH(x) state->gnutls_internals.x=HASH_TRUE
+#define NOT_HASH(x) state->gnutls_internals.x=HASH_FALSE
+
+int gnutls_handshake(int cd, GNUTLS_STATE state) {
+int ret;
+char* session_id;
+uint8 session_id_size;
+
+ state->gnutls_internals.client_td_md5 = mhash_init(MHASH_MD5);
+ state->gnutls_internals.client_td_sha1 = mhash_init(MHASH_SHA1);
+ state->gnutls_internals.server_td_md5 = mhash_init(MHASH_MD5);
+ state->gnutls_internals.server_td_sha1 = mhash_init(MHASH_SHA1);
+
+ if (state->security_parameters.entity == GNUTLS_CLIENT) {
+ HASH(client_hash);
+ HASH(server_hash);
+ ret = _gnutls_send_hello( cd, state, NULL, 0);
+ NOT_HASH(client_hash);
+ NOT_HASH(server_hash);
+ if (ret<0) {
+ ERR("send hello", ret);
+ return ret;
+ }
+
+ /* receive the server hello */
+ HASH(client_hash);
+ HASH(server_hash);
+ ret = _gnutls_recv_handshake( cd, state, NULL, 0, GNUTLS_SERVER_HELLO);
+ NOT_HASH(client_hash);
+ NOT_HASH(server_hash);
+ if (ret<0) {
+ ERR("recv hello", ret);
+ return ret;
+ }
+
+ /* RECV CERTIFICATE + KEYEXCHANGE + CERTIFICATE_REQUEST */
+
+ /* receive the server hello done */
+ HASH(client_hash);
+ HASH(server_hash);
+ ret = _gnutls_recv_handshake( cd, state, NULL, 0, GNUTLS_SERVER_HELLO_DONE);
+ NOT_HASH(client_hash);
+ NOT_HASH(server_hash);
+ if (ret<0) {
+ ERR("recv server hello done", ret);
+ return ret;
+ }
+
+ /* SEND CERTIFICATE + KEYEXCHANGE + CERTIFICATE_VERIFY */
+
+ /* Send the CHANGE CIPHER SPEC PACKET */
+ ret = _gnutls_send_change_cipher_spec( cd, state);
+ if (ret<0) {
+ ERR("send ChangeCipherSpec", ret);
+ return ret;
+ }
+
+
+ state->gnutls_internals.client_md_md5 = mhash_end( state->gnutls_internals.client_td_md5);
+ state->gnutls_internals.client_md_sha1 = mhash_end( state->gnutls_internals.client_td_sha1);
+
+ /* Initialize the connection state (start encryption) */
+ _gnutls_connection_state_init(state);
+
+ /* send the finished message */
+
+ NOT_HASH(client_hash);
+ HASH(server_hash);
+ ret = _gnutls_send_finished( cd, state);
+ NOT_HASH(client_hash);
+ NOT_HASH(server_hash);
+ if (ret<0) {
+ ERR("send Finished", ret);
+ return ret;
+ }
+
+
+ ret = gnutls_recv_int( cd, state, GNUTLS_CHANGE_CIPHER_SPEC, NULL, 0);
+ if (ret<0) {
+ ERR("recv ChangeCipherSpec", ret);
+ return ret;
+ }
+
+ state->gnutls_internals.server_md_md5 = mhash_end( state->gnutls_internals.server_td_md5);
+ state->gnutls_internals.server_md_sha1 = mhash_end( state->gnutls_internals.server_td_sha1);
+
+ NOT_HASH(client_hash);
+ NOT_HASH(server_hash);
+ ret = _gnutls_recv_finished( cd, state);
+ if (ret<0) {
+ ERR("recv finished", ret);
+ return ret;
+ }
+
+ mhash_free( state->gnutls_internals.client_md_md5);
+ mhash_free( state->gnutls_internals.client_md_sha1);
+ mhash_free( state->gnutls_internals.server_md_md5);
+ mhash_free( state->gnutls_internals.server_md_sha1);
+
+ } else { /* SERVER */
+
+ HASH(client_hash);
+ HASH(server_hash);
+ ret = _gnutls_recv_handshake( cd, state, NULL, 0, GNUTLS_CLIENT_HELLO);
+ NOT_HASH(client_hash);
+ NOT_HASH(server_hash);
+ if (ret<0) {
+ ERR("recv hello", ret);
+ return ret;
+ }
+
+ _gnutls_generate_session_id( &session_id, &session_id_size);
+ HASH(client_hash);
+ HASH(server_hash);
+ ret = _gnutls_send_hello( cd, state, session_id, session_id_size);
+ NOT_HASH(client_hash);
+ NOT_HASH(server_hash);
+ if (ret<0) {
+ ERR("send hello", ret);
+ return ret;
+ }
+ gnutls_free(session_id);
+
+ /* SEND CERTIFICATE + KEYEXCHANGE + CERTIFICATE_REQUEST */
+
+ /* send the server hello done */
+ HASH(client_hash);
+ HASH(server_hash);
+ ret = _gnutls_send_handshake( cd, state, NULL, 0, GNUTLS_SERVER_HELLO_DONE);
+ NOT_HASH(client_hash);
+ NOT_HASH(server_hash);
+ if (ret<0) {
+ ERR("send server hello done", ret);
+ return ret;
+ }
+
+ /* RECV CERTIFICATE + KEYEXCHANGE + CERTIFICATE_VERIFY */
+
+
+ /* Initialize the connection state (start encryption) */
+
+
+
+ ret = gnutls_recv_int( cd, state, GNUTLS_CHANGE_CIPHER_SPEC, NULL, 0);
+ if (ret<0) {
+ ERR("recv ChangeCipherSpec", ret);
+ return ret;
+ }
+
+ _gnutls_connection_state_init(state);
+
+ state->gnutls_internals.client_md_md5 = mhash_end( state->gnutls_internals.client_td_md5);
+ state->gnutls_internals.client_md_sha1 = mhash_end( state->gnutls_internals.client_td_sha1);
+
+ NOT_HASH(client_hash);
+ HASH(server_hash);
+ ret = _gnutls_recv_finished( cd, state);
+ NOT_HASH(client_hash);
+ NOT_HASH(server_hash);
+ if (ret<0) {
+ ERR("recv finished", ret);
+ return ret;
+ }
+
+ ret = _gnutls_send_change_cipher_spec( cd, state);
+ if (ret<0) {
+ ERR("send ChangeCipherSpec", ret);
+ return ret;
+ }
+
+ state->gnutls_internals.server_md_md5 = mhash_end( state->gnutls_internals.server_td_md5);
+ state->gnutls_internals.server_md_sha1 = mhash_end( state->gnutls_internals.server_td_sha1);
+
+ NOT_HASH(client_hash);
+ NOT_HASH(server_hash);
+ ret = _gnutls_send_finished( cd, state);
+ if (ret<0) {
+ ERR("recv finished", ret);
+ return ret;
+ }
+
+ mhash_free( state->gnutls_internals.server_md_md5);
+ mhash_free( state->gnutls_internals.server_md_sha1);
+ mhash_free( state->gnutls_internals.client_md_md5);
+ mhash_free( state->gnutls_internals.client_md_sha1);
+
+ }
+
+ return ret;
+
+}
+
+int _gnutls_generate_session_id( char** session_id, uint8* len) {
+char* rand;
+ *session_id=gnutls_malloc(32);
+ rand = gcry_random_bytes(32, GCRY_WEAK_RANDOM);
+
+ memmove( *session_id, rand, 32);
+ gcry_free(rand);
+ *len=32;
+
+#ifdef DEBUG
+ fprintf(stderr, "SessionID: %s\n", bin2hex( *session_id, 32));
+#endif
+ return 0;
+}
+
diff --git a/lib/gnutls_handshake.h b/lib/gnutls_handshake.h
new file mode 100644
index 0000000000..b1fbd1c48b
--- /dev/null
+++ b/lib/gnutls_handshake.h
@@ -0,0 +1,9 @@
+int _gnutls_supported_ciphersuites(GNUTLS_CipherSuite **ciphers);
+int _gnutls_supported_compression_methods(CompressionMethod **comp);
+int _gnutls_send_handshake(int cd, GNUTLS_STATE state, void* i_data, uint32 i_datasize, HandshakeType type);
+int _gnutls_send_hello_request(int cd, GNUTLS_STATE state);
+int _gnutls_send_hello(int cd, GNUTLS_STATE state, opaque* SessionID, uint8 SessionIDLen);
+int _gnutls_recv_hello(int cd, GNUTLS_STATE state, char* data, int datalen, opaque** SessionID, int SessionIDnum);
+int gnutls_handshake(int cd, GNUTLS_STATE state);
+int _gnutls_recv_handshake_int( int cd, GNUTLS_STATE state, void*, uint32, void*, uint32);
+int _gnutls_generate_session_id( char** session_id, uint8* len);
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
new file mode 100644
index 0000000000..1700ad1b56
--- /dev/null
+++ b/lib/gnutls_int.h
@@ -0,0 +1,254 @@
+#define DEBUG
+
+#define svoid void /* for functions that allocate using secure_free */
+#define secure_free free
+#define secure_malloc malloc
+#define secure_realloc realloc
+#define secure_calloc calloc
+#define gnutls_malloc malloc
+#define gnutls_realloc realloc
+#define gnutls_calloc calloc
+#define gnutls_free free
+
+typedef struct {
+ uint8 pint[3];
+} uint24;
+
+#define rotl64(x,n) (((x) << ((uint16)(n))) | ((x) >> (64 - (uint16)(n))))
+#define rotr64(x,n) (((x) >> ((uint16)(n))) | ((x) << (64 - (uint16)(n))))
+#define rotl32(x,n) (((x) << ((uint16)(n))) | ((x) >> (32 - (uint16)(n))))
+#define rotr32(x,n) (((x) >> ((uint16)(n))) | ((x) << (32 - (uint16)(n))))
+#define rotl16(x,n) (((x) << ((uint16)(n))) | ((x) >> (16 - (uint16)(n))))
+#define rotr16(x,n) (((x) >> ((uint16)(n))) | ((x) << (16 - (uint16)(n))))
+
+#define byteswap16(x) ((rotl16(x, 8) & 0x00ff) | (rotr16(x, 8) & 0xff00))
+#define byteswap32(x) ((rotl32(x, 8) & 0x00ff00ff) | (rotr32(x, 8) & 0xff00ff00))
+#define byteswap64(x) ((rotl64(x, 8) & 0x00ff00ff00ff00ff) | (rotr64(x, 8) & 0xff00ff00ff00ff00))
+
+typedef unsigned char opaque;
+
+
+enum ChangeCipherSpecType { GNUTLS_TYPE_CHANGE_CIPHER_SPEC=1 };
+enum AlertLevel { GNUTLS_WARNING, GNUTLS_FATAL };
+enum AlertDescription { GNUTLS_CLOSE_NOTIFY, GNUTLS_UNEXPECTED_MESSAGE=10, GNUTLS_BAD_RECORD_MAC=20,
+ GNUTLS_DECRYPTION_FAILED, GNUTLS_RECORD_OVERFLOW, GNUTLS_DECOMPRESSION_FAILURE=30,
+ GNUTLS_HANDSHAKE_FAILURE=40, GNUTLS_BAD_CERTIFICATE=42, GNUTLS_UNSUPPORTED_CERTIFICATE,
+ GNUTLS_CERTIFICATE_REVOKED, GNUTLS_CERTIFICATE_EXPIRED, GNUTLS_CERTIFICATE_UNKNOWN,
+ GNUTLS_ILLEGAL_PARAMETER, GNUTLS_UNKNOWN_CA, GNUTLS_ACCESS_DENIED, GNUTLS_DECODE_ERROR=50,
+ GNUTLS_DECRYPT_ERROR, GNUTLS_EXPORT_RESTRICTION=60, GNUTLS_PROTOCOL_VERSION=70,
+ GNUTLS_INSUFFICIENT_SECURITY, GNUTLS_INTERNAL_ERROR=80, GNUTLS_USER_CANCELED=90,
+ GNUTLS_NO_RENEGOTIATION=100
+ };
+
+typedef enum AlertDescription AlertDescription;
+typedef enum AlertLevel AlertLevel;
+typedef enum ChangeCipherSpecType ChangeCipherSpecType;
+
+enum HandshakeType { GNUTLS_HELLO_REQUEST, GNUTLS_CLIENT_HELLO, GNUTLS_SERVER_HELLO,
+ GNUTLS_CERTIFICATE=11, GNUTLS_SERVER_KEY_EXCHANGE,
+ GNUTLS_CERTIFICATE_REQUEST, GNUTLS_SERVER_HELLO_DONE,
+ GNUTLS_CERTIFICATE_VERIFY, GNUTLS_CLIENT_KEY_EXCHANGE,
+ GNUTLS_FINISHED=20, GNUTLS_NONE=255 };
+
+typedef enum HandshakeType HandshakeType;
+
+
+typedef struct {
+ ChangeCipherSpecType type;
+} ChangeCipherSpec;
+
+typedef struct {
+ AlertLevel level;
+ AlertDescription description;
+} Alert;
+
+
+/* STATE */
+enum ConnectionEnd { GNUTLS_SERVER, GNUTLS_CLIENT };
+enum BulkCipherAlgorithm { CIPHER_NULL, CIPHER_3DES = 4 };
+enum KX_Algorithm { KX_RSA, KX_DHE_DSS, KX_DHE_RSA, KX_DH_DSS, KX_DH_RSA, KX_ANON_DH };
+enum CipherType { CIPHER_STREAM, CIPHER_BLOCK };
+enum IsExportable { EXPORTABLE_TRUE, EXPORTABLE_FALSE };
+enum MACAlgorithm { MAC_NULL, MAC_MD5, MAC_SHA };
+enum CompressionMethod { COMPRESSION_NULL };
+
+enum ValidSession { VALID_TRUE, VALID_FALSE };
+enum ResumableSession { RESUME_TRUE, RESUME_FALSE };
+
+typedef enum KX_Algorithm KX_Algorithm;
+typedef enum ValidSession ValidSession;
+typedef enum ResumableSession ResumableSession;
+typedef enum ConnectionEnd ConnectionEnd;
+typedef enum BulkCipherAlgorithm BulkCipherAlgorithm;
+typedef enum CipherType CipherType;
+typedef enum IsExportable IsExportable;
+typedef enum MACAlgorithm MACAlgorithm;
+typedef enum CompressionMethod CompressionMethod;
+
+typedef struct {
+ ConnectionEnd entity;
+ BulkCipherAlgorithm bulk_cipher_algorithm;
+ CipherType cipher_type;
+ uint8 IV_size; /* not specified in the protocol, but later it
+ * uses it */
+ uint8 key_size;
+ uint8 key_material_length;
+ IsExportable is_exportable;
+ MACAlgorithm mac_algorithm;
+ uint8 hash_size;
+ CompressionMethod compression_algorithm;
+ opaque master_secret[48];
+ opaque client_random[32];
+ opaque server_random[32];
+} SecurityParameters;
+
+typedef struct {
+ opaque* server_write_mac_secret;
+ opaque* client_write_mac_secret;
+ opaque* server_write_IV;
+ opaque* client_write_IV;
+ opaque* server_write_key;
+ opaque* client_write_key;
+} CipherSpecs;
+
+typedef struct {
+ opaque* read_compression_state;
+ opaque* write_compression_state;
+ GCRY_CIPHER_HD write_cipher_state;
+ GCRY_CIPHER_HD read_cipher_state;
+ opaque* read_mac_secret;
+ opaque* write_mac_secret;
+ uint8 mac_secret_size;
+ uint64 read_sequence_number;
+ uint64 write_sequence_number;
+} ConnectionState;
+
+typedef struct {
+ uint8 CipherSuite[2];
+} GNUTLS_CipherSuite;
+
+
+typedef struct {
+ char* buffer;
+ uint32 bufferSize;
+ ResumableSession resumable;
+ ValidSession valid_connection;
+ AlertDescription last_alert;
+ GNUTLS_CipherSuite current_cipher_suite;
+ CompressionMethod compression_method;
+ /* for the handshake protocol */
+ HandshakeType next_handshake_type;
+ MHASH client_td_md5;
+ MHASH client_td_sha1;
+ void* client_md_md5;
+ void* client_md_sha1;
+ MHASH server_td_md5;
+ MHASH server_td_sha1;
+ void* server_md_md5;
+ void* server_md_sha1;
+ int server_hash;
+ int client_hash;
+} GNUTLS_INTERNALS;
+
+typedef struct {
+ SecurityParameters security_parameters;
+ CipherSpecs cipher_specs;
+ ConnectionState connection_state;
+ GNUTLS_INTERNALS gnutls_internals;
+} GNUTLS_STATE_INT;
+
+typedef GNUTLS_STATE_INT *GNUTLS_STATE;
+
+
+/* Record Protocol */
+enum ContentType { GNUTLS_CHANGE_CIPHER_SPEC=20, GNUTLS_ALERT, GNUTLS_HANDSHAKE,
+ GNUTLS_APPLICATION_DATA };
+typedef enum ContentType ContentType;
+
+#define GNUTLS_VERSION_MAJOR 3
+#define GNUTLS_VERSION_MINOR 1
+
+typedef struct {
+ uint8 major;
+ uint8 minor;
+} ProtocolVersion;
+
+typedef struct {
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length;
+ opaque* fragment;
+} GNUTLSPlaintext;
+
+typedef struct {
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length;
+ opaque* fragment;
+} GNUTLSCompressed;
+
+/* This is used for both block ciphers and stream ciphers. In stream ciphers
+ * the padding is just ignored.
+ */
+typedef struct {
+ opaque* content;
+ opaque* MAC;
+ uint8* padding;
+ uint8 padding_length;
+} GNUTLS_GenericBlockCipher;
+
+typedef struct {
+ opaque* content;
+ opaque* MAC;
+} GNUTLS_GenericStreamCipher;
+
+typedef struct {
+ ContentType type;
+ ProtocolVersion version;
+ uint16 length;
+ void* fragment; /* points GenericStreamCipher
+ * or GenericBlockCipher
+ */
+} GNUTLSCiphertext;
+
+
+/* Handshake protocol */
+
+
+typedef struct {
+ HandshakeType msg_type;
+ uint24 length;
+ void* body;
+} GNUTLS_Handshake;
+
+typedef struct {
+ uint32 gmt_unix_time;
+ opaque random_bytes[28];
+} GNUTLS_random;
+
+
+typedef struct {
+ ProtocolVersion client_version;
+ GNUTLS_random random;
+ opaque* session_id;
+ GNUTLS_CipherSuite* cipher_suites;
+ CompressionMethod* compression_methods;
+} GNUTLS_ClientHello;
+
+typedef struct {
+ ProtocolVersion server_version;
+ GNUTLS_random random;
+ opaque* session_id;
+ GNUTLS_CipherSuite cipher_suite;
+ CompressionMethod compression_method;
+} GNUTLS_ServerHello;
+
+#define GNUTLS_DH_anon_WITH_3DES_EDE_CBC_SHA { 0x00, 0x1B }
+
+/* functions */
+int _gnutls_send_alert( int cd, GNUTLS_STATE state, AlertLevel level, AlertDescription desc);
+int gnutls_close(int cd, GNUTLS_STATE state);
+svoid *gnutls_PRF(opaque * secret, int secret_size, uint8 * label,
+ int label_size, opaque * seed, int seed_size,
+ int total_bytes);
+ \ No newline at end of file
diff --git a/lib/gnutls_num.c b/lib/gnutls_num.c
new file mode 100644
index 0000000000..4374d32ecb
--- /dev/null
+++ b/lib/gnutls_num.c
@@ -0,0 +1,21 @@
+#include <defines.h>
+#include <mhash.h>
+#include <gnutls_int.h>
+
+uint32 uint24touint32( uint24 num) {
+uint32 ret=0;
+
+ ((uint8*)&ret)[1] = num.pint[0];
+ ((uint8*)&ret)[2] = num.pint[1];
+ ((uint8*)&ret)[3] = num.pint[2];
+ return ret;
+}
+uint24 uint32touint24( uint32 num) {
+uint24 ret;
+
+ ret.pint[0] = ((uint8*)&num)[1];
+ ret.pint[1] = ((uint8*)&num)[2];
+ ret.pint[2] = ((uint8*)&num)[3];
+ return ret;
+
+}
diff --git a/lib/gnutls_num.h b/lib/gnutls_num.h
new file mode 100644
index 0000000000..a1d755d3f4
--- /dev/null
+++ b/lib/gnutls_num.h
@@ -0,0 +1,2 @@
+uint32 uint24touint32( uint24 num);
+uint24 uint32touint24( uint32 num);
diff --git a/lib/gnutls_plaintext.c b/lib/gnutls_plaintext.c
new file mode 100644
index 0000000000..b57ad97911
--- /dev/null
+++ b/lib/gnutls_plaintext.c
@@ -0,0 +1,51 @@
+#include <defines.h>
+#include <mhash.h>
+#include "gnutls_int.h"
+#include "gnutls_errors.h"
+
+/* Plaintext Handling */
+int _gnutls_text2TLSPlaintext(ContentType type, GNUTLSPlaintext** plain, char *text, uint16 length)
+{
+ GNUTLSPlaintext *plaintext;
+
+ if (length > 16384)
+ return GNUTLS_E_LARGE_PACKET;
+
+ *plain = gnutls_malloc(sizeof(GNUTLSPlaintext));
+ plaintext = *plain;
+
+ plaintext->fragment = gnutls_malloc(length);
+ memmove(plaintext->fragment, text, length);
+ plaintext->length = length;
+ plaintext->type = type;
+ plaintext->version.major = GNUTLS_VERSION_MAJOR;
+ plaintext->version.minor = GNUTLS_VERSION_MINOR;
+
+ return 0;
+}
+
+int _gnutls_TLSPlaintext2text( char** txt, GNUTLSPlaintext* plaintext)
+{
+ char *text;
+
+ if (plaintext->length > 16384)
+ return GNUTLS_E_LARGE_PACKET;
+
+ *txt = gnutls_malloc(plaintext->length);
+ text = *txt;
+
+ memmove(text, plaintext->fragment, plaintext->length);
+
+ return 0;
+}
+
+int _gnutls_freeTLSPlaintext(GNUTLSPlaintext * plaintext)
+{
+ if (plaintext == NULL)
+ return 0;
+
+ gnutls_free(plaintext->fragment);
+ gnutls_free(plaintext);
+
+ return 0;
+}
diff --git a/lib/gnutls_plaintext.h b/lib/gnutls_plaintext.h
new file mode 100644
index 0000000000..9e3e931de3
--- /dev/null
+++ b/lib/gnutls_plaintext.h
@@ -0,0 +1,3 @@
+int _gnutls_text2TLSPlaintext(ContentType type, GNUTLSPlaintext**, char *text, uint16 length);
+int _gnutls_freeTLSPlaintext(GNUTLSPlaintext* plaintext);
+int _gnutls_TLSPlaintext2text( char**, GNUTLSPlaintext* plaintext);