From e71098a6525c84c37ed1567d6eb8935d39c5c28e Mon Sep 17 00:00:00 2001 From: Derek Pryor Date: Mon, 17 Jul 2006 16:38:20 +0000 Subject: [PATCH] The first packet (ClientHello Handshake) can be constructed and is accepted by SSL servers. Framework.c allows me to test the library against a given https server. --- src/crypto/framework.c | 82 ++++++++++++++++ src/crypto/ssl.c | 133 +++++++++++++++++++++++++ src/crypto/ssl.h | 19 ++++ src/crypto/ssl_constructs.h | 190 +++++++++++++++++++++--------------- 4 files changed, 343 insertions(+), 81 deletions(-) create mode 100644 src/crypto/framework.c create mode 100644 src/crypto/ssl.c create mode 100644 src/crypto/ssl.h diff --git a/src/crypto/framework.c b/src/crypto/framework.c new file mode 100644 index 00000000..1a370f2d --- /dev/null +++ b/src/crypto/framework.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include +#include "ssl.h" + +int main(int argc, char *argv[]) +{ + SSL_t ssl; + int sockfd, portno, rc; + struct sockaddr_in serv_addr; + struct hostent *server; + + portno = 443; + sockfd = socket(AF_INET,SOCK_STREAM,0); + if(sockfd<0){ + fprintf(stderr,"Error creating socket\n"); + exit(sockfd); + } + + server = gethostbyname(argv[1]); + if(server==NULL){ + fprintf(stderr,"Error looking up host %s\n",argv[1]); + exit(1); + } + + /** + *matrixSslOpen() + *matrixSslReadKeys() + **/ + printf("Calling CreateSSLHello()\n"); + rc = CreateSSLHello(&ssl); + printf("Finished calling CreateSSLHello()\n"); + + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + bcopy((char *)server->h_addr,(char *)&serv_addr.sin_addr.s_addr,server->h_length); + serv_addr.sin_port = htons(portno); + if(connect(sockfd,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){ + fprintf(stderr,"ERROR connecting to server\n"); + exit(1); + } + + PrintSSLPacket(&ssl); + + printf("Write ssl.buffer\n"); + write(sockfd,ssl.buffer,ssl.length); + printf("Finished writing\n"); + ssl.length = read(sockfd,ssl.buffer,ssl.max_size); + ReadSSLHello(&ssl); + + /** + *matrixSslNewSession() + *matrixSslSetCetValidator() + *encodeSslHandshake() + + *write handshake buffer + + *readSslResponse() <-+ + | + *read return code |-- similar/same function?? + | + *sslEncode() | + *sslDecode() <-------+ + + *encodeSslCloseAlert() + + *write close alert buffer + **/ + close(sockfd); + + /** + *sslClose() + * -free connection + * -free keys + * -close pki interface + **/ + + return 0; +} diff --git a/src/crypto/ssl.c b/src/crypto/ssl.c new file mode 100644 index 00000000..00651bd4 --- /dev/null +++ b/src/crypto/ssl.c @@ -0,0 +1,133 @@ +#include "ssl.h" +#include "ssl_constructs.h" +#include // for bcopy() +#include // for time() +#include // for rand(), htons?, htonl? +// note net byte order is big-endian +// Need to set error codes + +int CreateSSLHello(SSL_t *ssl) +{ + printf("In CreateSSLHello()\n",ssl); + + // Initalize the structure + bzero(ssl,sizeof(SSL_t)); + //ssl->max_size = sizeof(ssl->buffer); + ssl->max_size = 18456; + + // Declare variables + int i; void *ptr; + + // Set pointers into buffer + SSLPlaintext *record = (SSLPlaintext *)ssl->buffer; + Handshake *handshake = (Handshake *)record->fragment; + // the body starts right after the handshake + printf("sizeof(Handshake) = %d\n",sizeof(Handshake)); + ClientHello *hello = (ClientHello *)(handshake + 1); + + printf("record->%#x, handshake->%#x, hello->%#x\n",record,handshake,hello); + + // Construct ClientHello Message + hello->client_version = version; + i = htonl(time(NULL)); + bcopy(&i,hello->random.gmt_unix_time,4); + for(i=0;i<28;i++){ hello->random.random_bytes[i] = (uint8)rand(); } + hello->session_id_length = 0; + hello->session_id = &hello->session_id_length; + hello->session_id_end = hello->session_id; + hello->cipher_suites_length = (CipherSuiteLength *)(hello->session_id_end + 1); + hello->cipher_suites = (hello->cipher_suites_length + 1); + hello->cipher_suites_end = hello->cipher_suites; + i = htons(2*5); // 2 bytes per Suite * 5 Suites + bcopy(&i,hello->cipher_suites_length,2); + bcopy(SSL_NULL_WITH_NULL_NULL,hello->cipher_suites_end,sizeof(CipherSuite)); + *hello->cipher_suites_end++; + bcopy(SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,hello->cipher_suites_end,sizeof(CipherSuite)); + *hello->cipher_suites_end++; + bcopy(SSL_DH_DSS_WITH_DES_CBC_SHA,hello->cipher_suites_end,sizeof(CipherSuite)); + *hello->cipher_suites_end++; + bcopy(SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,hello->cipher_suites_end,sizeof(CipherSuite)); + *hello->cipher_suites_end++; + bcopy(SSL_DH_anon_WITH_RC4_128_MD5,hello->cipher_suites_end,sizeof(CipherSuite)); + hello->compression_methods_length = (CompressionMethodLength *)(hello->cipher_suites_end + 1); + hello->compression_methods = (hello->compression_methods_length + 1); + hello->compression_methods_end = hello->compression_methods; + *hello->compression_methods_length = 1; + *hello->compression_methods_end = compression_method_null; + + // Construct Handshake Message + handshake->msg_type = handshake_type_client_hello; + i = (void *)(hello->compression_methods_end + 1) - (void *)hello; + printf("Handshake.length = %d\n", i); + handshake->length[0] = (char)*(&i+8); + handshake->length[1] = (char)*(&i+8); + handshake->length[2] = (char)i; + //bcopy((&i+1),handshake->length,3); // +1 so we copy 3 bytes + + // Construct SSL Record + printf("sizeof(ContentType)=%d\n",sizeof(ContentType)); + printf("sizeof(uint8)=%d\n",sizeof(uint8)); + record->type = content_type_handshake; + record->version = version; + i += sizeof(Handshake); + printf("SSLPlaintext.length = %d\n",i); + record->length[0] = (char)*(&i+8); + record->length[1] = (char)i; + //bcopy(&i,record->length,4); // length of handshake + + // Set total size of message + i += sizeof(ContentType) + sizeof(ProtocolVersion) + sizeof(uint16); + ssl->length = i; + printf("End of CreateSSLHello\n"); + return 0; +} + +void PrintSSLPacket(SSL_t *ssl) +{ + printf("Printing packet with length:%d\n", ssl->length); + char *ptr = ssl->buffer; + char *begin = ptr; + char *tmp; + char *end = ssl->buffer + ssl->length; + printf("Record Layer:\n"); + printf("\tContentType: %2hhX\n",(char)*ptr++); + printf("\tVersion: %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++); + printf("\tLength: %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++); + + printf("Handshake:\n"); + printf("\tType: %2hhX\n", (char)*ptr++); + printf("\tLength: %2hhX %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++, (char)*ptr++); + printf("\tVersion: %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++); + printf("\tgmt_unix_time: %2hhX %2hhX %2hhX %2hhX\n", (char)*ptr++, (char)*ptr++, (char)*ptr++, (char)*ptr++); + printf("\trandom: "); + tmp = ptr + 28; + for(;ptrbuffer; + + if(ct->type == content_type_alert){ + // assuming text is still plaintext + Alert *a = (Alert *)&ct->fragment; + if(a->level == alert_level_fatal){ + printf("Fatal Alert %d, connection terminated\n",a->description); + return (1); + }else if(a->level == alert_level_warning){ + printf("Warning Alert %d\n", a->description); + }else{ + printf("Unknown alert level %d\n", a->level); + } + }else{ + printf("SSL type %d\n",ct->type); + } + return (0); +} + diff --git a/src/crypto/ssl.h b/src/crypto/ssl.h new file mode 100644 index 00000000..06d43008 --- /dev/null +++ b/src/crypto/ssl.h @@ -0,0 +1,19 @@ +// At the moment I have hard coded one buffer. The size +// is the max size of SSLCiphertext.length (so, actually it should +// be increased to include the other information in the struct) +// I might need to make a new, or split the current, buffer because +// I have to have space to read in and write out, as well as keep +// any data that has not been translated. +// It works for now. +typedef struct _ssl_t{ + char buffer[18456]; + int length; + int max_size; // can't define const here + // Current CipherSuite + // Client random / Server random ??? + // pointers to different crypto functions +} SSL_t; + +int CreateSSLHello(SSL_t *ssl); +int ReadSSLHello(SSL_t *ssl); +void PrintSSLPacket(SSL_t *ssl); diff --git a/src/crypto/ssl_constructs.h b/src/crypto/ssl_constructs.h index 43c58551..ab3aa703 100644 --- a/src/crypto/ssl_constructs.h +++ b/src/crypto/ssl_constructs.h @@ -1,4 +1,6 @@ // Note: This file still needs some work. +// Note: I had to redefine the enums to a set of const values, +// so that the size of the variable would be correct. // Typedefs // (As defined by the SSL v3.0 RFC Draft) @@ -14,15 +16,13 @@ typedef struct _ProtocolVersion{ uint8 major, minor; } ProtocolVersion; -ProtocolVersion version = { 3, 0 }; +const ProtocolVersion version = { 3, 0 }; -typedef enum _ContentType{ - content_type_change_cipher_spec_type=20, - content_type_alert=21, - content_type_handshake=22, - content_type_application_data=23, - content_type_size=255 // to force size -} ContentType; +typedef uint8 ContentType; +const ContentType content_type_change_cipher_spec_type = 20; +const ContentType content_type_alert = 21; +const ContentType content_type_handshake = 22; +const ContentType content_type_application_data = 23; typedef struct _SSLPlaintext{ ContentType type; @@ -38,6 +38,14 @@ typedef struct _SSLCompressed{ uint8 fragment[17408]; // SSLCompressed.length } SSLCompressed; +typedef struct _SSLCiphertext{ + ContentType type; + ProtocolVersion version; + uint16 length; + uint8 fragment; // so we have a pointer to the data, and don't have to do math + // fragment; type GenericStreamCipher or GenericBlockCipher +} SSLCiphertext; // recast to get fragment + typedef struct _GenericStreamCipher{ uint8 content[17408]; // SSLCompressed.length uint8 MAC[]; // CipherSpec.hash_size @@ -72,27 +80,23 @@ typedef struct _ChangeCipherSpec{ } ChangeCipherSpec; // Alert messages -typedef enum _AlertLevel{ - alert_level_warning=1, - alert_level_fatal=2, - alert_level_size=255 -} AlertLevel; +typedef uint8 AlertLevel; +const AlertLevel alert_level_warning = 1; +const AlertLevel alert_level_fatal=2; -typedef enum _AlertDescription{ - alert_description_close_notify=0, - alert_description_unexpected_message=10, - alert_description_bad_record_mac=20, - alert_description_decompression_failure=30, - alert_description_handshake_failure=40, - alert_description_no_certificate=41, - alert_description_bad_certificate=42, - alert_description_unsupported_certificate=43, - alert_description_certificate_revoked=44, - alert_description_certificate_expired=45, - alert_description_certificate_unknown=46, - alert_description_illegal_parameter=47, - alert_description_size=255 -} AlertDescription; +typedef uint8 AlertDescription; +const AlertDescription alert_description_close_notify = 0; +const AlertDescription alert_description_unexpected_message = 10; +const AlertDescription alert_description_bad_record_mac = 20; +const AlertDescription alert_description_decompression_failure = 30; +const AlertDescription alert_description_handshake_failure = 40; +const AlertDescription alert_description_no_certificate = 41; +const AlertDescription alert_description_bad_certificate = 42; +const AlertDescription alert_description_unsupported_certificate = 43; +const AlertDescription alert_description_certificate_revoked = 44; +const AlertDescription alert_description_certificate_expired = 45; +const AlertDescription alert_description_certificate_unknown = 46; +const AlertDescription alert_description_illegal_parameter = 47; typedef struct _Alert{ AlertLevel level; @@ -101,23 +105,22 @@ typedef struct _Alert{ // Handshake protocol // What is the best way to have a generic pointer to the body struct?? -typedef enum _HandshakeType{ - handshake_type_hello_request=0, - handshake_type_client_hello=1, - handshake_type_server_hello=2, - handshake_type_certificate=11, - handshake_type_server_key_exchange=12, - handshake_type_certificate_request=13, - handshake_type_server_done=14, - handshake_type_certificate_verify=15, - handshake_type_client_key_exchange=16, - handshake_type_finished=20, - handshake_type_size=255 -} HandshakeType; +typedef uint8 HandshakeType; +const HandshakeType handshake_type_hello_request = 0; +const HandshakeType handshake_type_client_hello = 1; +const HandshakeType handshake_type_server_hello = 2; +const HandshakeType handshake_type_certificate = 11; +const HandshakeType handshake_type_server_key_exchange = 12; +const HandshakeType handshake_type_certificate_request = 13; +const HandshakeType handshake_type_server_done = 14; +const HandshakeType handshake_type_certificate_verify = 15; +const HandshakeType handshake_type_client_key_exchange = 16; +const HandshakeType handshake_type_finished = 20; typedef struct _Handshake{ HandshakeType msg_type; uint24 length; + // body; // one of HandshakeType structs } Handshake; // generic Handshake, need to recast to get body // Hello messages @@ -134,21 +137,38 @@ typedef struct _Random{ uint8 random_bytes[28]; } Random; -typedef uint8 SessionID[32]; // <0..32> +//typedef uint8 SessionID[32]; // <0..32> +typedef uint8 SessionIDLength; +typedef uint8 SessionID; + +typedef uint16 CipherSuiteLength; typedef uint8 CipherSuite[2]; -typedef enum _CompressionMethod{ compression_method_null=0, compression_method_size=255 } CompressionMethod; +typedef uint8 CompressionMethodLength; +typedef uint8 CompressionMethod; +const CompressionMethod compression_method_null = 0; + typedef struct _ClientHello{ ProtocolVersion client_version; Random random; - SessionID session_id; - CipherSuite cipher_suites[32768]; // <2..2^16-1> = 65,536 bytes and CipherSuite is 2 bytes - CompressionMethod compression_methods[256]; // <0..2^8-1> = 256 bytes and CompressionMethod is 1 byte + SessionIDLength session_id_length; + SessionID *session_id; + SessionID *session_id_end; + CipherSuiteLength *cipher_suites_length; + CipherSuite *cipher_suites; // min size is one entry + CipherSuite *cipher_suites_end; + //CipherSuite cipher_suites[32768]; // <2..2^16-1> = 65,536 bytes and CipherSuite is 2 bytes + CompressionMethodLength *compression_methods_length; + CompressionMethod *compression_methods; + CompressionMethod *compression_methods_end; + //CompressionMethod *compression_methods; // min size is zero + //CompressionMethod compression_methods[256]; // <0..2^8-1> = 256 bytes and CompressionMethod is 1 byte } ClientHello; typedef struct _ClientHelloHandshake{ - HandshakeType msg_type; + //HandshakeType msg_type; + uint8 msg_type; uint24 length; ClientHello body; } ClientHelloHandshake; @@ -175,11 +195,10 @@ typedef struct _Certificate{ // for some reason the size of certificate_list and ASN1Cert is the same, so only one certificate in the list } Certificate; -typedef enum _KeyExchangeAlgorithm{ - key_exchange_algorithm_rsa, - key_exchange_algorithm_diffie_hellman, - key_exchange_algorithm_fortezza_kea -} KeyExchangeAlgorithm; +typedef uint8 KeyExchangeAlgorithm; +const KeyExchangeAlgorithm key_exchange_algorithm_rsa = 0; +const KeyExchangeAlgorithm key_exchange_algorithm_diffie_hellman = 1; +const KeyExchangeAlgorithm key_exchange_algorithm_fortezza_kea = 2; typedef struct _AnonSignature{ struct {}; @@ -218,22 +237,19 @@ typedef struct _ServerRSAKeyExchange{ Signature signed_params; } ServerRSAKeyExchange; -typedef enum _SignatureAlgorithm{ - signature_algorithm_anonymous, - signature_algorithm_rsa, - signature_algorithm_dsa -} SignatureAlgorithm; +typedef uint8 SignatureAlgorithm; +const SignatureAlgorithm signature_algorithm_anonymous = 0; +const SignatureAlgorithm signature_algorithm_rsa = 1; +const SignatureAlgorithm signature_algorithm_dsa = 2; -typedef enum _CertificateType{ - certificate_type_RSA_sign=1, - certificate_type_DSS_sign=2, - certificate_type_RSA_fixed_DH=3, - certificate_type_DSS_fixed_DH=4, - certificate_type_RSA_ephemeral_DH=5, - certificate_type_DSS_ephemeral_DH=6, - certificate_type_FORTEZZA_MISSI=20, - certificate_type_size=255 -} CertificateType; +typedef uint8 CertificateType; +const CertificateType certificate_type_RSA_sign = 1; +const CertificateType certificate_type_DSS_sign = 2; +const CertificateType certificate_type_RSA_fixed_DH = 3; +const CertificateType certificate_type_DSS_fixed_DH = 4; +const CertificateType certificate_type_RSA_ephemeral_DH = 5; +const CertificateType certificate_type_DSS_ephemeral_DH = 6; +const CertificateType certificate_type_FORTEZZA_MISSI = 20; typedef uint8 DistinguishedName[65536]; // <1..2^16-1> = 65,536 @@ -259,7 +275,9 @@ typedef struct _RSAClientKeyExchange{ EncryptedPreMasterSecret exchange_keys; } RSAClientKeyExchange; -typedef enum _PublicValueEncoding{ public_value_encoding_implicit, public_value_encoding_explicit } PublicValueEncoding; +typedef uint8 PublicValueEncoding; +const PublicValueEncoding public_value_encoding_implicit = 0; +const PublicValueEncoding public_value_encoding_explicit = 1; typedef struct _ClientDiffieHellmanPublic{ // This is a select on PublicValueEncoding, and I chose the larger size @@ -281,25 +299,35 @@ typedef struct _Finished{ } Finished; // The CipherSuite -CipherSuite SSL_NULL_WITH_NULL_NULL = { 0x00, 0x00 }; +CipherSuite SSL_NULL_WITH_NULL_NULL = { 0x00, 0x13 }; CipherSuite SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x0B }; CipherSuite SSL_DH_DSS_WITH_DES_CBC_SHA = { 0x00, 0x0C }; +CipherSuite SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00, 0x11 }; CipherSuite SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 = { 0x00, 0x17 }; CipherSuite SSL_DH_anon_WITH_RC4_128_MD5 = { 0x00, 0x18 }; // The CipherSpec -typedef enum _CipherType{ cipher_type_stream, cipher_type_block } CipherType; -typedef enum _IsExportable{ is_exportable_true, is_exportable_false } IsExportable; -typedef enum _BulkCipherAlgorithm{ - bulk_cipher_algorithm_null, - bulk_cipher_algorithm_rc4, - bulk_cipher_algorithm_rc2, - bulk_cipher_algorithm_des, - bulk_cipher_algorithm_3des, - bulk_cipher_algorithm_des40, - bulk_cipher_algorithm_fortezza -} BulkCipherAlgorithm; -typedef enum _MACAlgorithm{ mac_algorithm_null, mac_algorithm_md5, mac_algorithm_sha } MACAlgorithm; +typedef uint8 CipherType; +const CipherType cipher_type_stream = 0; +const CipherType cipher_type_block = 1; + +typedef uint8 IsExportable; +const IsExportable is_exportable_true = 0; +const IsExportable is_exportable_false = 1; + +typedef uint8 BulkCipherAlgorithm; +const BulkCipherAlgorithm bulk_cipher_algorithm_null = 0; +const BulkCipherAlgorithm bulk_cipher_algorithm_rc4 = 1; +const BulkCipherAlgorithm bulk_cipher_algorithm_rc2 = 2; +const BulkCipherAlgorithm bulk_cipher_algorithm_des = 3; +const BulkCipherAlgorithm bulk_cipher_algorithm_3des = 4; +const BulkCipherAlgorithm bulk_cipher_algorithm_des40 = 5; +const BulkCipherAlgorithm bulk_cipher_algorithm_fortezza = 6; + +typedef uint8 MACAlgorithm; +const MACAlgorithm mac_algorithm_null = 0; +const MACAlgorithm mac_algorithm_md5 = 1; +const MACAlgorithm mac_algorithm_sha = 2; typedef struct _CipherSpec{ BulkCipherAlgorithm bulk_cipher_algorithm;