diff --git a/Makefile.in b/Makefile.in index 16bf551..a904c51 100644 --- a/Makefile.in +++ b/Makefile.in @@ -27,7 +27,7 @@ VNCLINK = @VNCLINK@ SOUNDOBJ = @SOUNDOBJ@ SCARDOBJ = @SCARDOBJ@ -RDPOBJ = tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o rdp5.o channels.o rdpdr.o serial.o printer.o disk.o parallel.o printercache.o mppc.o pstcache.o lspci.o seamless.o +RDPOBJ = tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o rdp5.o channels.o rdpdr.o serial.o printer.o disk.o parallel.o printercache.o mppc.o pstcache.o lspci.o seamless.o ssl.o X11OBJ = rdesktop.o xwin.o xkeymap.o ewmhints.o xclip.o cliprdr.o VNCOBJ = vnc/rdp2vnc.o vnc/vnc.o vnc/xkeymap.o vnc/x11stubs.o diff --git a/licence.c b/licence.c index 8cd26f4..c5d57c1 100644 --- a/licence.c +++ b/licence.c @@ -19,7 +19,7 @@ */ #include "rdesktop.h" -#include +#include "ssl.h" extern char g_username[64]; extern char g_hostname[16]; @@ -143,7 +143,7 @@ licence_process_demand(STREAM s) uint8 hwid[LICENCE_HWID_SIZE]; uint8 *licence_data; int licence_size; - RC4_KEY crypt_key; + SSL_RC4 crypt_key; /* Retrieve the server random from the incoming packet */ in_uint8p(s, server_random, SEC_RANDOM_SIZE); @@ -161,8 +161,8 @@ licence_process_demand(STREAM s) sec_sign(signature, 16, g_licence_sign_key, 16, hwid, sizeof(hwid)); /* Now encrypt the HWID */ - RC4_set_key(&crypt_key, 16, g_licence_key); - RC4(&crypt_key, sizeof(hwid), hwid, hwid); + ssl_rc4_set_key(&crypt_key, g_licence_key, 16); + ssl_rc4_crypt(&crypt_key, hwid, hwid, sizeof(hwid)); licence_present(null_data, null_data, licence_data, licence_size, hwid, signature); xfree(licence_data); @@ -230,15 +230,15 @@ licence_process_authreq(STREAM s) uint8 hwid[LICENCE_HWID_SIZE], crypt_hwid[LICENCE_HWID_SIZE]; uint8 sealed_buffer[LICENCE_TOKEN_SIZE + LICENCE_HWID_SIZE]; uint8 out_sig[LICENCE_SIGNATURE_SIZE]; - RC4_KEY crypt_key; + SSL_RC4 crypt_key; /* Parse incoming packet and save the encrypted token */ licence_parse_authreq(s, &in_token, &in_sig); memcpy(out_token, in_token, LICENCE_TOKEN_SIZE); /* Decrypt the token. It should read TEST in Unicode. */ - RC4_set_key(&crypt_key, 16, g_licence_key); - RC4(&crypt_key, LICENCE_TOKEN_SIZE, in_token, decrypt_token); + ssl_rc4_set_key(&crypt_key, g_licence_key, 16); + ssl_rc4_crypt(&crypt_key, in_token, decrypt_token, LICENCE_TOKEN_SIZE); /* Generate a signature for a buffer of token and HWID */ licence_generate_hwid(hwid); @@ -247,8 +247,8 @@ licence_process_authreq(STREAM s) sec_sign(out_sig, 16, g_licence_sign_key, 16, sealed_buffer, sizeof(sealed_buffer)); /* Now encrypt the HWID */ - RC4_set_key(&crypt_key, 16, g_licence_key); - RC4(&crypt_key, LICENCE_HWID_SIZE, hwid, crypt_hwid); + ssl_rc4_set_key(&crypt_key, g_licence_key, 16); + ssl_rc4_crypt(&crypt_key, hwid, crypt_hwid, LICENCE_HWID_SIZE); licence_send_authresp(out_token, crypt_hwid, out_sig); } @@ -257,7 +257,7 @@ licence_process_authreq(STREAM s) static void licence_process_issue(STREAM s) { - RC4_KEY crypt_key; + SSL_RC4 crypt_key; uint32 length; uint16 check; int i; @@ -267,8 +267,8 @@ licence_process_issue(STREAM s) if (!s_check_rem(s, length)) return; - RC4_set_key(&crypt_key, 16, g_licence_key); - RC4(&crypt_key, length, s->p, s->p); + ssl_rc4_set_key(&crypt_key, g_licence_key, 16); + ssl_rc4_crypt(&crypt_key, s->p, s->p, length); in_uint16(s, check); if (check != 0) diff --git a/rdesktop.c b/rdesktop.c index fdb0826..34b5c48 100644 --- a/rdesktop.c +++ b/rdesktop.c @@ -45,7 +45,7 @@ #include /* sockaddr_un */ #endif -#include +#include "ssl.h" char g_title[64] = ""; char g_username[64]; @@ -1052,7 +1052,7 @@ generate_random(uint8 * random) { struct stat st; struct tms tmsbuf; - MD5_CTX md5; + SSL_MD5 md5; uint32 *r; int fd, n; @@ -1084,11 +1084,11 @@ generate_random(uint8 * random) r[7] = st.st_ctime; /* Hash both halves with MD5 to obscure possible patterns */ - MD5_Init(&md5); - MD5_Update(&md5, random, 16); - MD5_Final(random, &md5); - MD5_Update(&md5, random + 16, 16); - MD5_Final(random + 16, &md5); + ssl_md5_init(&md5); + ssl_md5_update(&md5, random, 16); + ssl_md5_final(&md5, random); + ssl_md5_update(&md5, random + 16, 16); + ssl_md5_final(&md5, random + 16); } /* malloc; exit if out of memory */ diff --git a/secure.c b/secure.c index 715f471..cacfa49 100644 --- a/secure.c +++ b/secure.c @@ -19,18 +19,7 @@ */ #include "rdesktop.h" - -#include -#include -#include -#include -#include - -#if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x0090800f) -#define D2I_X509_CONST const -#else -#define D2I_X509_CONST -#endif +#include "ssl.h" extern char g_hostname[16]; extern int g_width; @@ -49,9 +38,8 @@ extern VCHANNEL g_channels[]; extern unsigned int g_num_channels; static int rc4_key_len; -static RC4_KEY rc4_decrypt_key; -static RC4_KEY rc4_encrypt_key; -static RSA *server_public_key; +static SSL_RC4 rc4_decrypt_key; +static SSL_RC4 rc4_encrypt_key; static uint32 server_public_key_len; static uint8 sec_sign_key[16]; @@ -86,25 +74,25 @@ sec_hash_48(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2, uint8 salt) { uint8 shasig[20]; uint8 pad[4]; - SHA_CTX sha; - MD5_CTX md5; + SSL_SHA1 sha1; + SSL_MD5 md5; int i; for (i = 0; i < 3; i++) { memset(pad, salt + i, i + 1); - SHA1_Init(&sha); - SHA1_Update(&sha, pad, i + 1); - SHA1_Update(&sha, in, 48); - SHA1_Update(&sha, salt1, 32); - SHA1_Update(&sha, salt2, 32); - SHA1_Final(shasig, &sha); + ssl_sha1_init(&sha1); + ssl_sha1_update(&sha1, pad, i + 1); + ssl_sha1_update(&sha1, in, 48); + ssl_sha1_update(&sha1, salt1, 32); + ssl_sha1_update(&sha1, salt2, 32); + ssl_sha1_final(&sha1, shasig); - MD5_Init(&md5); - MD5_Update(&md5, in, 48); - MD5_Update(&md5, shasig, 20); - MD5_Final(&out[i * 16], &md5); + ssl_md5_init(&md5); + ssl_md5_update(&md5, in, 48); + ssl_md5_update(&md5, shasig, 20); + ssl_md5_final(&md5, &out[i * 16]); } } @@ -114,13 +102,13 @@ sec_hash_48(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2, uint8 salt) void sec_hash_16(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2) { - MD5_CTX md5; + SSL_MD5 md5; - MD5_Init(&md5); - MD5_Update(&md5, in, 16); - MD5_Update(&md5, salt1, 32); - MD5_Update(&md5, salt2, 32); - MD5_Final(out, &md5); + ssl_md5_init(&md5); + ssl_md5_update(&md5, in, 16); + ssl_md5_update(&md5, salt1, 32); + ssl_md5_update(&md5, salt2, 32); + ssl_md5_final(&md5, out); } /* Reduce key entropy from 64 to 40 bits */ @@ -209,23 +197,23 @@ sec_sign(uint8 * signature, int siglen, uint8 * session_key, int keylen, uint8 * uint8 shasig[20]; uint8 md5sig[16]; uint8 lenhdr[4]; - SHA_CTX sha; - MD5_CTX md5; + SSL_SHA1 sha1; + SSL_MD5 md5; buf_out_uint32(lenhdr, datalen); - SHA1_Init(&sha); - SHA1_Update(&sha, session_key, keylen); - SHA1_Update(&sha, pad_54, 40); - SHA1_Update(&sha, lenhdr, 4); - SHA1_Update(&sha, data, datalen); - SHA1_Final(shasig, &sha); + ssl_sha1_init(&sha1); + ssl_sha1_update(&sha1, session_key, keylen); + ssl_sha1_update(&sha1, pad_54, 40); + ssl_sha1_update(&sha1, lenhdr, 4); + ssl_sha1_update(&sha1, data, datalen); + ssl_sha1_final(&sha1, shasig); - MD5_Init(&md5); - MD5_Update(&md5, session_key, keylen); - MD5_Update(&md5, pad_92, 48); - MD5_Update(&md5, shasig, 20); - MD5_Final(md5sig, &md5); + ssl_md5_init(&md5); + ssl_md5_update(&md5, session_key, keylen); + ssl_md5_update(&md5, pad_92, 48); + ssl_md5_update(&md5, shasig, 20); + ssl_md5_final(&md5, md5sig); memcpy(signature, md5sig, siglen); } @@ -235,24 +223,24 @@ static void sec_update(uint8 * key, uint8 * update_key) { uint8 shasig[20]; - SHA_CTX sha; - MD5_CTX md5; - RC4_KEY update; + SSL_SHA1 sha1; + SSL_MD5 md5; + SSL_RC4 update; - SHA1_Init(&sha); - SHA1_Update(&sha, update_key, rc4_key_len); - SHA1_Update(&sha, pad_54, 40); - SHA1_Update(&sha, key, rc4_key_len); - SHA1_Final(shasig, &sha); + ssl_sha1_init(&sha1); + ssl_sha1_update(&sha1, update_key, rc4_key_len); + ssl_sha1_update(&sha1, pad_54, 40); + ssl_sha1_update(&sha1, key, rc4_key_len); + ssl_sha1_final(&sha1, shasig); - MD5_Init(&md5); - MD5_Update(&md5, update_key, rc4_key_len); - MD5_Update(&md5, pad_92, 48); - MD5_Update(&md5, shasig, 20); - MD5_Final(key, &md5); + ssl_md5_init(&md5); + ssl_md5_update(&md5, update_key, rc4_key_len); + ssl_md5_update(&md5, pad_92, 48); + ssl_md5_update(&md5, shasig, 20); + ssl_md5_final(&md5, key); - RC4_set_key(&update, rc4_key_len, key); - RC4(&update, rc4_key_len, key, key); + ssl_rc4_set_key(&update, key, rc4_key_len); + ssl_rc4_crypt(&update, key, key, rc4_key_len); if (rc4_key_len == 8) sec_make_40bit(key); @@ -265,11 +253,11 @@ sec_encrypt(uint8 * data, int length) if (sec_encrypt_use_count == 4096) { sec_update(sec_encrypt_key, sec_encrypt_update_key); - RC4_set_key(&rc4_encrypt_key, rc4_key_len, sec_encrypt_key); + ssl_rc4_set_key(&rc4_encrypt_key, sec_encrypt_key, rc4_key_len); sec_encrypt_use_count = 0; } - RC4(&rc4_encrypt_key, length, data, data); + ssl_rc4_crypt(&rc4_encrypt_key, data, data, length); sec_encrypt_use_count++; } @@ -280,63 +268,20 @@ sec_decrypt(uint8 * data, int length) if (sec_decrypt_use_count == 4096) { sec_update(sec_decrypt_key, sec_decrypt_update_key); - RC4_set_key(&rc4_decrypt_key, rc4_key_len, sec_decrypt_key); + ssl_rc4_set_key(&rc4_decrypt_key, sec_decrypt_key, rc4_key_len); sec_decrypt_use_count = 0; } - RC4(&rc4_decrypt_key, length, data, data); + ssl_rc4_crypt(&rc4_decrypt_key, data, data, length); sec_decrypt_use_count++; } -static void -reverse(uint8 * p, int len) -{ - int i, j; - uint8 temp; - - for (i = 0, j = len - 1; i < j; i++, j--) - { - temp = p[i]; - p[i] = p[j]; - p[j] = temp; - } -} - /* Perform an RSA public key encryption operation */ static void sec_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus, uint8 * exponent) { - BN_CTX *ctx; - BIGNUM mod, exp, x, y; - uint8 inr[SEC_MAX_MODULUS_SIZE]; - int outlen; - - reverse(modulus, modulus_size); - reverse(exponent, SEC_EXPONENT_SIZE); - memcpy(inr, in, len); - reverse(inr, len); - - ctx = BN_CTX_new(); - BN_init(&mod); - BN_init(&exp); - BN_init(&x); - BN_init(&y); - - BN_bin2bn(modulus, modulus_size, &mod); - BN_bin2bn(exponent, SEC_EXPONENT_SIZE, &exp); - BN_bin2bn(inr, len, &x); - BN_mod_exp(&y, &x, &exp, &mod, ctx); - outlen = BN_bn2bin(&y, out); - reverse(out, outlen); - if (outlen < modulus_size) - memset(out + outlen, 0, modulus_size - outlen); - - BN_free(&y); - BN_clear_free(&x); - BN_free(&exp); - BN_free(&mod); - BN_CTX_free(ctx); + ssl_rsa_encrypt(out, in, len, modulus_size, modulus, exponent); } /* Initialise secure transport packet */ @@ -511,7 +456,7 @@ sec_out_mcs_data(STREAM s) /* Parse a public key structure */ static RD_BOOL -sec_parse_public_key(STREAM s, uint8 ** modulus, uint8 ** exponent) +sec_parse_public_key(STREAM s, uint8 * modulus, uint8 * exponent) { uint32 magic, modulus_len; @@ -524,65 +469,48 @@ sec_parse_public_key(STREAM s, uint8 ** modulus, uint8 ** exponent) in_uint32_le(s, modulus_len); modulus_len -= SEC_PADDING_SIZE; - if ((modulus_len < 64) || (modulus_len > SEC_MAX_MODULUS_SIZE)) + if ((modulus_len < SEC_MODULUS_SIZE) || (modulus_len > SEC_MAX_MODULUS_SIZE)) { error("Bad server public key size (%u bits)\n", modulus_len * 8); return False; } in_uint8s(s, 8); /* modulus_bits, unknown */ - in_uint8p(s, *exponent, SEC_EXPONENT_SIZE); - in_uint8p(s, *modulus, modulus_len); + in_uint8a(s, exponent, SEC_EXPONENT_SIZE); + in_uint8a(s, modulus, modulus_len); in_uint8s(s, SEC_PADDING_SIZE); server_public_key_len = modulus_len; return s_check(s); } +/* Parse a public signature structure */ static RD_BOOL -sec_parse_x509_key(X509 * cert) +sec_parse_public_sig(STREAM s, uint32 len, uint8 * modulus, uint8 * exponent) { - EVP_PKEY *epk = NULL; - /* By some reason, Microsoft sets the OID of the Public RSA key to - the oid for "MD5 with RSA Encryption" instead of "RSA Encryption" + uint8 signature[SEC_MAX_MODULUS_SIZE]; + uint32 sig_len; - Kudos to Richard Levitte for the following (. intiutive .) - lines of code that resets the OID and let's us extract the key. */ - if (OBJ_obj2nid(cert->cert_info->key->algor->algorithm) == NID_md5WithRSAEncryption) + if (len != 72) { - DEBUG_RDP5(("Re-setting algorithm type to RSA in server certificate\n")); - ASN1_OBJECT_free(cert->cert_info->key->algor->algorithm); - cert->cert_info->key->algor->algorithm = OBJ_nid2obj(NID_rsaEncryption); + return True; } - epk = X509_get_pubkey(cert); - if (NULL == epk) - { - error("Failed to extract public key from certificate\n"); - return False; - } - - server_public_key = RSAPublicKey_dup((RSA *) epk->pkey.ptr); - EVP_PKEY_free(epk); - - server_public_key_len = RSA_size(server_public_key); - if ((server_public_key_len < 64) || (server_public_key_len > SEC_MAX_MODULUS_SIZE)) - { - error("Bad server public key size (%u bits)\n", server_public_key_len * 8); - return False; - } - - return True; + memset(signature, 0, sizeof(signature)); + sig_len = len - 8; + in_uint8a(s, signature, sig_len); + return ssl_sig_ok(exponent, SEC_EXPONENT_SIZE, modulus, server_public_key_len, + signature, sig_len); } - /* Parse a crypto information structure */ static RD_BOOL sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size, - uint8 ** server_random, uint8 ** modulus, uint8 ** exponent) + uint8 ** server_random, uint8 * modulus, uint8 * exponent) { uint32 crypt_level, random_len, rsa_info_len; uint32 cacert_len, cert_len, flags; - X509 *cacert, *server_cert; + SSL_CERT *cacert, *server_cert; + SSL_RKEY *server_public_key; uint16 tag, length; uint8 *next_tag, *end; @@ -629,10 +557,8 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size, break; case SEC_TAG_KEYSIG: - /* Is this a Microsoft key that we just got? */ - /* Care factor: zero! */ - /* Actually, it would probably be a good idea to check if the public key is signed with this key, and then store this - key as a known key of the hostname. This would prevent some MITM-attacks. */ + if (!sec_parse_public_sig(s, length, modulus, exponent)) + return False; break; default: @@ -648,26 +574,21 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size, DEBUG_RDP5(("We're going for the RDP5-style encryption\n")); in_uint32_le(s, certcount); /* Number of certificates */ - if (certcount < 2) { error("Server didn't send enough X509 certificates\n"); return False; } - for (; certcount > 2; certcount--) { /* ignore all the certificates between the root and the signing CA */ uint32 ignorelen; - X509 *ignorecert; + SSL_CERT *ignorecert; DEBUG_RDP5(("Ignored certs left: %d\n", certcount)); - in_uint32_le(s, ignorelen); DEBUG_RDP5(("Ignored Certificate length is %d\n", ignorelen)); - ignorecert = - d2i_X509(NULL, (D2I_X509_CONST unsigned char **) &(s->p), - ignorelen); - + ignorecert = ssl_cert_read(s->p, ignorelen); + in_uint8s(s, ignorelen); if (ignorecert == NULL) { /* XXX: error out? */ DEBUG_RDP5(("got a bad cert: this will probably screw up the rest of the communication\n")); @@ -675,11 +596,10 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size, #ifdef WITH_DEBUG_RDP5 DEBUG_RDP5(("cert #%d (ignored):\n", certcount)); - X509_print_fp(stdout, ignorecert); + ssl_cert_print_fp(stdout, ignorecert); #endif } - - /* Do da funky X.509 stuffy + /* Do da funky X.509 stuffy "How did I find out about this? I looked up and saw a bright light and when I came to I had a scar on my forehead @@ -687,52 +607,57 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size, - Peter Gutman in a early version of http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt */ - in_uint32_le(s, cacert_len); DEBUG_RDP5(("CA Certificate length is %d\n", cacert_len)); - cacert = d2i_X509(NULL, (D2I_X509_CONST unsigned char **) &(s->p), cacert_len); - /* Note: We don't need to move s->p here - d2i_X509 is - "kind" enough to do it for us */ + cacert = ssl_cert_read(s->p, cacert_len); + in_uint8s(s, cacert_len); if (NULL == cacert) { error("Couldn't load CA Certificate from server\n"); return False; } - - /* Currently, we don't use the CA Certificate. - FIXME: - *) Verify the server certificate (server_cert) with the - CA certificate. - *) Store the CA Certificate with the hostname of the - server we are connecting to as key, and compare it - when we connect the next time, in order to prevent - MITM-attacks. - */ - - X509_free(cacert); - in_uint32_le(s, cert_len); DEBUG_RDP5(("Certificate length is %d\n", cert_len)); - server_cert = d2i_X509(NULL, (D2I_X509_CONST unsigned char **) &(s->p), cert_len); + server_cert = ssl_cert_read(s->p, cert_len); + in_uint8s(s, cert_len); if (NULL == server_cert) { + ssl_cert_free(cacert); error("Couldn't load Certificate from server\n"); return False; } - - in_uint8s(s, 16); /* Padding */ - - /* Note: Verifying the server certificate must be done here, - before sec_parse_public_key since we'll have to apply - serious violence to the key after this */ - - if (!sec_parse_x509_key(server_cert)) + if (!ssl_certs_ok(server_cert, cacert)) { - DEBUG_RDP5(("Didn't parse X509 correctly\n")); - X509_free(server_cert); + ssl_cert_free(server_cert); + ssl_cert_free(cacert); + error("Security error CA Certificate invalid\n"); return False; } - X509_free(server_cert); + ssl_cert_free(cacert); + in_uint8s(s, 16); /* Padding */ + server_public_key = ssl_cert_to_rkey(server_cert, &server_public_key_len); + if (NULL == server_public_key) + { + DEBUG_RDP5(("Didn't parse X509 correctly\n")); + ssl_cert_free(server_cert); + return False; + } + ssl_cert_free(server_cert); + if ((server_public_key_len < SEC_MODULUS_SIZE) || + (server_public_key_len > SEC_MAX_MODULUS_SIZE)) + { + error("Bad server public key size (%u bits)\n", server_public_key_len * 8); + ssl_rkey_free(server_public_key); + return False; + } + if (ssl_rkey_get_exp_mod(server_public_key, exponent, SEC_EXPONENT_SIZE, + modulus, SEC_MAX_MODULUS_SIZE) != 0) + { + error("Problem extracting RSA exponent, modulus"); + ssl_rkey_free(server_public_key); + return False; + } + ssl_rkey_free(server_public_key); return True; /* There's some garbage here we don't care about */ } return s_check_end(s); @@ -742,51 +667,23 @@ sec_parse_crypt_info(STREAM s, uint32 * rc4_key_size, static void sec_process_crypt_info(STREAM s) { - uint8 *server_random = NULL, *modulus = NULL, *exponent = NULL; + uint8 *server_random = NULL; uint8 client_random[SEC_RANDOM_SIZE]; + uint8 modulus[SEC_MAX_MODULUS_SIZE]; + uint8 exponent[SEC_EXPONENT_SIZE]; uint32 rc4_key_size; - if (!sec_parse_crypt_info(s, &rc4_key_size, &server_random, &modulus, &exponent)) + memset(modulus, 0, sizeof(modulus)); + memset(exponent, 0, sizeof(exponent)); + if (!sec_parse_crypt_info(s, &rc4_key_size, &server_random, modulus, exponent)) { DEBUG(("Failed to parse crypt info\n")); return; } - DEBUG(("Generating client random\n")); generate_random(client_random); - - if (NULL != server_public_key) - { /* Which means we should use - RDP5-style encryption */ - uint8 inr[SEC_MAX_MODULUS_SIZE]; - uint32 padding_len = server_public_key_len - SEC_RANDOM_SIZE; - - /* This is what the MS client do: */ - memset(inr, 0, padding_len); - /* *ARIGL!* Plaintext attack, anyone? - I tried doing: - generate_random(inr); - ..but that generates connection errors now and then (yes, - "now and then". Something like 0 to 3 attempts needed before a - successful connection. Nice. Not! - */ - memcpy(inr + padding_len, client_random, SEC_RANDOM_SIZE); - reverse(inr + padding_len, SEC_RANDOM_SIZE); - - RSA_public_encrypt(server_public_key_len, - inr, sec_crypted_random, server_public_key, RSA_NO_PADDING); - - reverse(sec_crypted_random, server_public_key_len); - - RSA_free(server_public_key); - server_public_key = NULL; - } - else - { /* RDP4-style encryption */ - sec_rsa_encrypt(sec_crypted_random, - client_random, SEC_RANDOM_SIZE, server_public_key_len, modulus, - exponent); - } + sec_rsa_encrypt(sec_crypted_random, client_random, SEC_RANDOM_SIZE, + server_public_key_len, modulus, exponent); sec_generate_keys(client_random, server_random, rc4_key_size); } diff --git a/ssl.c b/ssl.c new file mode 100644 index 0000000..a619a84 --- /dev/null +++ b/ssl.c @@ -0,0 +1,222 @@ +/* -*- c-basic-offset: 8 -*- + rdesktop: A Remote Desktop Protocol client. + Secure sockets abstraction layer + Copyright (C) Matthew Chapman 1999-2007 + Copyright (C) Jay Sorg 2006-2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "rdesktop.h" +#include "ssl.h" + +void +ssl_sha1_init(SSL_SHA1 * sha1) +{ + SHA1_Init(sha1); +} + +void +ssl_sha1_update(SSL_SHA1 * sha1, uint8 * data, uint32 len) +{ + SHA1_Update(sha1, data, len); +} + +void +ssl_sha1_final(SSL_SHA1 * sha1, uint8 * out_data) +{ + SHA1_Final(out_data, sha1); +} + +void +ssl_md5_init(SSL_MD5 * md5) +{ + MD5_Init(md5); +} + +void +ssl_md5_update(SSL_MD5 * md5, uint8 * data, uint32 len) +{ + MD5_Update(md5, data, len); +} + +void +ssl_md5_final(SSL_MD5 * md5, uint8 * out_data) +{ + MD5_Final(out_data, md5); +} + +void +ssl_rc4_set_key(SSL_RC4 * rc4, uint8 * key, uint32 len) +{ + RC4_set_key(rc4, len, key); +} + +void +ssl_rc4_crypt(SSL_RC4 * rc4, uint8 * in_data, uint8 * out_data, uint32 len) +{ + RC4(rc4, len, in_data, out_data); +} + +static void +reverse(uint8 * p, int len) +{ + int i, j; + uint8 temp; + + for (i = 0, j = len - 1; i < j; i++, j--) + { + temp = p[i]; + p[i] = p[j]; + p[j] = temp; + } +} + +void +ssl_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus, + uint8 * exponent) +{ + BN_CTX * ctx; + BIGNUM mod, exp, x, y; + uint8 inr[SEC_MAX_MODULUS_SIZE]; + int outlen; + + reverse(modulus, modulus_size); + reverse(exponent, SEC_EXPONENT_SIZE); + memcpy(inr, in, len); + reverse(inr, len); + + ctx = BN_CTX_new(); + BN_init(&mod); + BN_init(&exp); + BN_init(&x); + BN_init(&y); + + BN_bin2bn(modulus, modulus_size, &mod); + BN_bin2bn(exponent, SEC_EXPONENT_SIZE, &exp); + BN_bin2bn(inr, len, &x); + BN_mod_exp(&y, &x, &exp, &mod, ctx); + outlen = BN_bn2bin(&y, out); + reverse(out, outlen); + if (outlen < modulus_size) + memset(out + outlen, 0, modulus_size - outlen); + + BN_free(&y); + BN_clear_free(&x); + BN_free(&exp); + BN_free(&mod); + BN_CTX_free(ctx); +} + +/* returns newly allocated SSL_CERT or NULL */ +SSL_CERT * +ssl_cert_read(uint8 * data, uint32 len) +{ + /* this will move the data pointer but we don't care, we don't use it again */ + return d2i_X509(NULL, (D2I_X509_CONST unsigned char **) &data, len); +} + +void +ssl_cert_free(SSL_CERT * cert) +{ + X509_free(cert); +} + +/* returns newly allocated SSL_RKEY or NULL */ +SSL_RKEY * +ssl_cert_to_rkey(SSL_CERT * cert, uint32 * key_len) +{ + EVP_PKEY * epk = NULL; + SSL_RKEY * lkey; + /* By some reason, Microsoft sets the OID of the Public RSA key to + the oid for "MD5 with RSA Encryption" instead of "RSA Encryption" + + Kudos to Richard Levitte for the following (. intiutive .) + lines of code that resets the OID and let's us extract the key. */ + if (OBJ_obj2nid(cert->cert_info->key->algor->algorithm) == NID_md5WithRSAEncryption) + { + DEBUG_RDP5(("Re-setting algorithm type to RSA in server certificate\n")); + ASN1_OBJECT_free(cert->cert_info->key->algor->algorithm); + cert->cert_info->key->algor->algorithm = OBJ_nid2obj(NID_rsaEncryption); + } + epk = X509_get_pubkey(cert); + if (NULL == epk) + { + error("Failed to extract public key from certificate\n"); + return NULL; + } + + lkey = RSAPublicKey_dup((RSA *) epk->pkey.ptr); + EVP_PKEY_free(epk); + *key_len = RSA_size(lkey); + return lkey; +} + +/* returns boolean */ +RD_BOOL +ssl_certs_ok(SSL_CERT * server_cert, SSL_CERT * cacert) +{ + /* Currently, we don't use the CA Certificate. + FIXME: + *) Verify the server certificate (server_cert) with the + CA certificate. + *) Store the CA Certificate with the hostname of the + server we are connecting to as key, and compare it + when we connect the next time, in order to prevent + MITM-attacks. + */ + return True; +} + +int +ssl_cert_print_fp(FILE * fp, SSL_CERT * cert) +{ + return X509_print_fp(fp, cert); +} + +void +ssl_rkey_free(SSL_RKEY * rkey) +{ + RSA_free(rkey); +} + +/* returns error */ +int +ssl_rkey_get_exp_mod(SSL_RKEY * rkey, uint8 * exponent, uint32 max_exp_len, uint8 * modulus, + uint32 max_mod_len) +{ + uint32 len; + + if ((BN_num_bytes(rkey->e) > max_exp_len) || (BN_num_bytes(rkey->n) > max_mod_len)) + { + return 1; + } + len = BN_bn2bin(rkey->e, exponent); + reverse(exponent, len); + len = BN_bn2bin(rkey->n, modulus); + reverse(modulus, len); + return 0; +} + +/* returns boolean */ +RD_BOOL +ssl_sig_ok(uint8 * exponent, uint32 exp_len, uint8 * modulus, uint32 mod_len, + uint8 * signature, uint32 sig_len) +{ + /* Currently, we don't check the signature + FIXME: + */ + return True; +} diff --git a/ssl.h b/ssl.h new file mode 100644 index 0000000..969c825 --- /dev/null +++ b/ssl.h @@ -0,0 +1,81 @@ +/* -*- c-basic-offset: 8 -*- + rdesktop: A Remote Desktop Protocol client. + Secure sockets abstraction layer + Copyright (C) Matthew Chapman 1999-2007 + Copyright (C) Jay Sorg 2006-2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _SSL_H +#define _SSL_H + +#include +#include +#include +#include +#include + +#if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x0090800f) +#define D2I_X509_CONST const +#else +#define D2I_X509_CONST +#endif + +#define SSL_RC4 RC4_KEY +#define SSL_SHA1 SHA_CTX +#define SSL_MD5 MD5_CTX +#define SSL_CERT X509 +#define SSL_RKEY RSA + +void +ssl_sha1_init(SSL_SHA1 * sha1); +void +ssl_sha1_update(SSL_SHA1 * sha1, uint8 * data, uint32 len); +void +ssl_sha1_final(SSL_SHA1 * sha1, uint8 * out_data); +void +ssl_md5_init(SSL_MD5 * md5); +void +ssl_md5_update(SSL_MD5 * md5, uint8 * data, uint32 len); +void +ssl_md5_final(SSL_MD5 * md5, uint8 * out_data); +void +ssl_rc4_set_key(SSL_RC4 * rc4, uint8 * key, uint32 len); +void +ssl_rc4_crypt(SSL_RC4 * rc4, uint8 * in_data, uint8 * out_data, uint32 len); +void +ssl_rsa_encrypt(uint8 * out, uint8 * in, int len, uint32 modulus_size, uint8 * modulus, + uint8 * exponent); +SSL_CERT * +ssl_cert_read(uint8 * data, uint32 len); +void +ssl_cert_free(SSL_CERT * cert); +SSL_RKEY * +ssl_cert_to_rkey(SSL_CERT * cert, uint32 * key_len); +RD_BOOL +ssl_certs_ok(SSL_CERT * server_cert, SSL_CERT * cacert); +int +ssl_cert_print_fp(FILE * fp, SSL_CERT * cert); +void +ssl_rkey_free(SSL_RKEY * rkey); +int +ssl_rkey_get_exp_mod(SSL_RKEY * rkey, uint8 * exponent, uint32 max_exp_len, uint8 * modulus, + uint32 max_mod_len); +RD_BOOL +ssl_sig_ok(uint8 * exponent, uint32 exp_len, uint8 * modulus, uint32 mod_len, + uint8 * signature, uint32 sig_len); + +#endif