work on Proprietary Certificate

This commit is contained in:
Jay Sorg 2011-09-05 11:02:52 -07:00
parent bc1e264eb5
commit afc9ac89ae
10 changed files with 226 additions and 21 deletions

View File

@ -227,15 +227,88 @@ void certificate_free_x509_certificate_chain(rdpX509CertChain* x509_cert_chain)
xfree(x509_cert_chain);
}
static boolean certificate_process_server_public_key(rdpCertificate* certificate, STREAM* s, uint32 length)
{
uint8 magic[4];
uint32 keylen;
uint32 bitlen;
uint32 datalen;
uint32 modlen;
memcpy(magic, s->p, 4);
if (memcmp(magic, "RSA1", 4) != 0)
{
printf("gcc_process_server_public_key: magic error\n");
return False;
}
stream_seek(s, 4);
stream_read_uint32(s, keylen);
stream_read_uint32(s, bitlen);
stream_read_uint32(s, datalen);
memcpy(certificate->cert_info.exponent, s->p, 4);
stream_seek(s, 4);
modlen = keylen - 8;
freerdp_blob_alloc(&(certificate->cert_info.modulus), modlen);
memcpy(certificate->cert_info.modulus.data, s->p, modlen);
stream_seek(s, keylen);
return True;
}
static boolean certificate_process_server_public_signature(rdpCertificate* certificate, STREAM* s, uint32 length)
{
stream_seek(s, length);
return True;
}
/**
* Read a Server Proprietary Certificate.\n
* @param certificate certificate module
* @param s stream
*/
void certificate_read_server_proprietary_certificate(rdpCertificate* certificate, STREAM* s)
boolean certificate_read_server_proprietary_certificate(rdpCertificate* certificate, STREAM* s)
{
uint32 dwSigAlgId;
uint32 dwKeyAlgId;
uint32 wPublicKeyBlobType;
uint32 wPublicKeyBlobLen;
uint32 wSignatureBlobType;
uint32 wSignatureBlobLen;
printf("Server Proprietary Certificate\n");
stream_read_uint32(s, dwSigAlgId);
stream_read_uint32(s, dwKeyAlgId);
if (!(dwSigAlgId == 1 && dwKeyAlgId == 1))
{
printf("certificate_read_server_proprietary_certificate: parse error 1\n");
return False;
}
stream_read_uint16(s, wPublicKeyBlobType);
if (wPublicKeyBlobType != BB_RSA_KEY_BLOB)
{
printf("certificate_read_server_proprietary_certificate: parse error 2\n");
return False;
}
stream_read_uint16(s, wPublicKeyBlobLen);
if (!certificate_process_server_public_key(certificate, s, wPublicKeyBlobLen))
{
printf("certificate_read_server_proprietary_certificate: parse error 3\n");
return False;
}
stream_read_uint16(s, wSignatureBlobType);
if (wSignatureBlobType != BB_RSA_SIGNATURE_BLOB)
{
printf("certificate_read_server_proprietary_certificate: parse error 4\n");
return False;
}
stream_read_uint16(s, wSignatureBlobLen);
if (!certificate_process_server_public_signature(certificate, s, wSignatureBlobLen))
{
printf("certificate_read_server_proprietary_certificate: parse error 5\n");
return False;
}
return True;
}
/**
@ -244,7 +317,7 @@ void certificate_read_server_proprietary_certificate(rdpCertificate* certificate
* @param s stream
*/
void certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, STREAM* s)
boolean certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, STREAM* s)
{
int i;
uint32 certLength;
@ -280,6 +353,7 @@ void certificate_read_server_x509_certificate_chain(rdpCertificate* certificate,
DEBUG_CERTIFICATE("modulus length:%d", certificate->cert_info.modulus.length);
}
}
return True;
}
/**
@ -289,7 +363,7 @@ void certificate_read_server_x509_certificate_chain(rdpCertificate* certificate,
* @param length certificate length
*/
void certificate_read_server_certificate(rdpCertificate* certificate, uint8* server_cert, int length)
boolean certificate_read_server_certificate(rdpCertificate* certificate, uint8* server_cert, int length)
{
STREAM* s;
uint32 dwVersion;
@ -300,7 +374,7 @@ void certificate_read_server_certificate(rdpCertificate* certificate, uint8* ser
if (length < 1)
{
printf("null server certificate\n");
return;
return False;
}
stream_read_uint32(s, dwVersion); /* dwVersion (4 bytes) */
@ -319,6 +393,9 @@ void certificate_read_server_certificate(rdpCertificate* certificate, uint8* ser
printf("invalid certificate chain version:%d\n", dwVersion & CERT_CHAIN_VERSION_MASK);
break;
}
xfree(s);
return True;
}
/**
@ -327,7 +404,7 @@ void certificate_read_server_certificate(rdpCertificate* certificate, uint8* ser
* @return new certificate module
*/
rdpCertificate* certificate_new(rdpRdp* rdp)
rdpCertificate* certificate_new(void)
{
rdpCertificate* certificate;
@ -335,7 +412,6 @@ rdpCertificate* certificate_new(rdpRdp* rdp)
if (certificate != NULL)
{
certificate->rdp = rdp;
certificate->x509_cert_chain = NULL;
}

View File

@ -37,6 +37,9 @@ typedef struct rdp_certificate rdpCertificate;
#define CERT_PERMANENTLY_ISSUED 0x00000000
#define CERT_TEMPORARILY_ISSUED 0x80000000
#define BB_RSA_KEY_BLOB 6
#define BB_RSA_SIGNATURE_BLOB 8
struct rdp_CertBlob
{
uint32 length;
@ -60,7 +63,6 @@ typedef struct rdp_CertInfo rdpCertInfo;
struct rdp_certificate
{
struct rdp_rdp* rdp;
rdpCertInfo cert_info;
rdpX509CertChain* x509_cert_chain;
};
@ -70,11 +72,11 @@ void certificate_read_x509_certificate(rdpCertBlob* cert, rdpCertInfo* info);
rdpX509CertChain* certificate_new_x509_certificate_chain(uint32 count);
void certificate_free_x509_certificate_chain(rdpX509CertChain* x509_cert_chain);
void certificate_read_server_proprietary_certificate(rdpCertificate* certificate, STREAM* s);
void certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, STREAM* s);
void certificate_read_server_certificate(rdpCertificate* certificate, uint8* server_cert, int length);
boolean certificate_read_server_proprietary_certificate(rdpCertificate* certificate, STREAM* s);
boolean certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, STREAM* s);
boolean certificate_read_server_certificate(rdpCertificate* certificate, uint8* server_cert, int length);
rdpCertificate* certificate_new(rdpRdp* rdp);
rdpCertificate* certificate_new(void);
void certificate_free(rdpCertificate* certificate);
#ifdef WITH_DEBUG_CERTIFICATE

View File

@ -104,11 +104,38 @@ boolean rdp_client_connect(rdpRdp* rdp)
return True;
}
static boolean rdp_establish_keys(rdpRdp* rdp)
{
uint8 client_random[32];
uint8 crypt_client_random[256];
uint32 key_len;
uint8* mod;
uint8* exp;
printf("rdp_establish_keys:\n");
if (rdp->settings->encryption == False)
{
/* no RDP encryption */
return True;
}
memset(client_random, 0x5e, 32); /* TODO: get real random */
crypto_nonce(client_random, 32);
key_len = rdp->settings->server_cert->cert_info.modulus.length;
mod = rdp->settings->server_cert->cert_info.modulus.data;
exp = rdp->settings->server_cert->cert_info.exponent;
crypto_rsa_encrypt(client_random, 32, key_len, mod, exp, crypt_client_random);
return True;
}
boolean rdp_client_connect_mcs_connect_response(rdpRdp* rdp, STREAM* s)
{
if (!mcs_recv_connect_response(rdp->mcs, s))
{
printf("rdp_client_connect_mcs_connect_response: mcs_recv_connect_response failed\n");
return False;
}
if (!mcs_send_erect_domain_request(rdp->mcs))
return False;
if (!mcs_send_attach_user_request(rdp->mcs))
@ -188,6 +215,8 @@ boolean rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, STREAM* s)
if (rdp->mcs->user_channel_joined && rdp->mcs->global_channel_joined && all_joined)
{
if (!rdp_establish_keys(rdp))
return False;
if (!rdp_send_client_info(rdp))
return False;
rdp->state = CONNECTION_STATE_LICENSE;

View File

@ -18,6 +18,7 @@
*/
#include "gcc.h"
#include "certificate.h"
/**
* T.124 GCC is defined in:
@ -250,12 +251,16 @@ boolean gcc_read_conference_create_response(STREAM* s, rdpSettings* settings)
per_read_choice(s, &choice);
/* h221NonStandard */
per_read_octet_string(s, h221_sc_key, 4, 4); /* h221NonStandard, server-to-client H.221 key, "McDn" */
if (!per_read_octet_string(s, h221_sc_key, 4, 4)) /* h221NonStandard, server-to-client H.221 key, "McDn" */
return False;
/* userData (OCTET_STRING) */
per_read_length(s, &length);
if (!gcc_read_server_data_blocks(s, settings, length))
{
printf("gcc_read_conference_create_response: gcc_read_server_data_blocks failed\n");
return False;
}
return True;
}
@ -357,34 +362,49 @@ boolean gcc_read_server_data_blocks(STREAM* s, rdpSettings *settings, int length
uint16 type;
uint16 offset = 0;
uint16 blockLength;
uint8* holdp;
while (offset < length)
{
holdp = s->p;
if (!gcc_read_user_data_header(s, &type, &blockLength))
{
printf("gcc_read_server_data_blocks: gcc_read_user_data_header failed\n");
return False;
}
switch (type)
{
case SC_CORE:
if (!gcc_read_server_core_data(s, settings))
{
printf("gcc_read_server_data_blocks: gcc_read_server_core_data failed\n");
return False;
}
break;
case SC_SECURITY:
if (!gcc_read_server_security_data(s, settings))
{
printf("gcc_read_server_data_blocks: gcc_read_server_security_data failed\n");
return False;
}
break;
case SC_NET:
if (!gcc_read_server_network_data(s, settings))
{
printf("gcc_read_server_data_blocks: gcc_read_server_network_data failed\n");
return False;
}
break;
default:
break;
}
offset += blockLength;
s->p = holdp + blockLength;
}
return True;
@ -729,7 +749,11 @@ void gcc_write_client_security_data(STREAM* s, rdpSettings *settings)
{
gcc_write_user_data_header(s, CS_SECURITY, 12);
if (settings->encryption > 0)
printf("settings->encryption %d\n", settings->encryption);
printf("settings->encryption_method %d\n", settings->encryption_method);
printf("settings->encryption_level %d\n", settings->encryption_level);
if (settings->encryption)
{
stream_write_uint32(s, settings->encryption_method); /* encryptionMethods */
stream_write_uint32(s, 0); /* extEncryptionMethods */
@ -744,23 +768,30 @@ void gcc_write_client_security_data(STREAM* s, rdpSettings *settings)
boolean gcc_read_server_security_data(STREAM* s, rdpSettings *settings)
{
uint32 encryptionMethod;
uint32 encryptionLevel;
uint32 serverRandomLen;
uint32 serverCertLen;
uint8* data;
uint32 len;
stream_read_uint32(s, encryptionMethod); /* encryptionMethod */
stream_read_uint32(s, encryptionLevel); /* encryptionLevel */
stream_read_uint32(s, settings->encryption_method); /* encryptionMethod */
stream_read_uint32(s, settings->encryption_level); /* encryptionLevel */
if (encryptionMethod == 0 && encryptionLevel == 0)
printf("gcc_read_server_security_data: encryption_method %d encryption_level %d\n", settings->encryption_method, settings->encryption_level);
if (settings->encryption_method == 0 && settings->encryption_level == 0)
{
/* serverRandom and serverRandom must not be present */
settings->encryption = False;
settings->encryption_method = ENCRYPTION_METHOD_NONE;
settings->encryption_level = ENCRYPTION_LEVEL_NONE;
return True;
}
stream_read_uint32(s, serverRandomLen); /* serverRandomLen */
stream_read_uint32(s, serverCertLen); /* serverCertLen */
printf("gcc_read_server_security_data: serverRandomLen %d serverCertLen %d\n", serverRandomLen, serverCertLen);
if (serverRandomLen > 0)
{
/* serverRandom */
@ -768,6 +799,10 @@ boolean gcc_read_server_security_data(STREAM* s, rdpSettings *settings)
memcpy(settings->server_random.data, s->p, serverRandomLen);
stream_seek(s, serverRandomLen);
}
else
{
return False;
}
if (serverCertLen > 0)
{
@ -775,6 +810,18 @@ boolean gcc_read_server_security_data(STREAM* s, rdpSettings *settings)
freerdp_blob_alloc(&settings->server_certificate, serverCertLen);
memcpy(settings->server_certificate.data, s->p, serverCertLen);
stream_seek(s, serverCertLen);
certificate_free(settings->server_cert);
settings->server_cert = certificate_new();
data = settings->server_certificate.data;
len = settings->server_certificate.length;
if (!certificate_read_server_certificate(settings->server_cert, data, len))
{
return False;
}
}
else
{
return False;
}
return True;

View File

@ -864,7 +864,8 @@ rdpLicense* license_new(rdpRdp* rdp)
{
license->rdp = rdp;
license->state = LICENSE_STATE_AWAIT;
license->certificate = certificate_new(rdp);
//license->certificate = certificate_new(rdp);
license->certificate = certificate_new();
license->product_info = license_new_product_info();
license->error_info = license_new_binary_blob(BB_ERROR_BLOB);
license->key_exchange_list = license_new_binary_blob(BB_KEY_EXCHG_ALG_BLOB);

View File

@ -517,7 +517,10 @@ boolean mcs_recv_connect_response(rdpMcs* mcs, STREAM* s)
ber_read_octet_string(s, &length);
if (!gcc_read_conference_create_response(s, mcs->transport->settings))
{
printf("mcs_recv_connect_response: gcc_read_conference_create_response failed\n");
return False;
}
return True;
}

View File

@ -397,6 +397,20 @@ void rdp_recv_data_pdu(rdpRdp* rdp, STREAM* s)
}
}
/**
* Decrypt an RDP packet.\n
* @param rdp RDP module
* @param s stream
* @param length int
*/
static boolean rdp_decrypt(rdpRdp* rdp, STREAM* s, int length)
{
printf("rdp_decrypt:\n");
stream_seek(s, 8); /* signature */
return True;
}
/**
* Process an RDP packet.\n
* @param rdp RDP module
@ -409,6 +423,7 @@ static boolean rdp_recv_tpkt_pdu(rdpRdp* rdp, STREAM* s)
uint16 pduType;
uint16 pduLength;
uint16 channelId;
uint32 securityHeader;
if (!rdp_read_header(rdp, s, &length, &channelId))
{
@ -416,6 +431,24 @@ static boolean rdp_recv_tpkt_pdu(rdpRdp* rdp, STREAM* s)
return False;
}
if (rdp->settings->encryption)
{
stream_read_uint32(s, securityHeader);
if (securityHeader & SEC_SECURE_CHECKSUM)
{
printf("Error: TODO\n");
return False;
}
if (securityHeader & SEC_ENCRYPT)
{
if (!rdp_decrypt(rdp, s, length))
{
printf("rdp_decrypt failed\n");
return False;
}
}
}
if (channelId != MCS_GLOBAL_CHANNEL_ID)
{
vchan_process(rdp->vchan, s, channelId);
@ -492,6 +525,7 @@ static int rdp_recv_callback(rdpTransport* transport, STREAM* s, void* extra)
{
rdpRdp* rdp = (rdpRdp*) extra;
printf("state %d\n", rdp->state);
switch (rdp->state)
{
case CONNECTION_STATE_NEGO:

View File

@ -167,6 +167,8 @@ void settings_free(rdpSettings* settings)
xfree(settings->client_dir);
xfree(settings->cert_file);
xfree(settings->privatekey_file);
freerdp_blob_free(&(settings->server_certificate));
certificate_free(settings->server_cert);
xfree(settings);
}
}

View File

@ -165,6 +165,11 @@ int tcp_read(rdpTcp* tcp, uint8* data, int length)
perror("recv");
return -1;
}
else
{
printf("tcp_read: length %d\n", status);
freerdp_hexdump(data, status);
}
return status;
}
@ -175,6 +180,9 @@ int tcp_write(rdpTcp* tcp, uint8* data, int length)
status = send(tcp->sockfd, data, length, MSG_NOSIGNAL);
printf("tcp_write: length %d\n", status);
freerdp_hexdump(data, status);
if (status < 0)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)

View File

@ -283,6 +283,9 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
settings->rdp_security = True;
settings->tls_security = False;
settings->nla_security = False;
settings->encryption = True;
settings->encryption_method = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT;
settings->encryption_level = ENCRYPTION_LEVEL_HIGH;
}
else if (strncmp("tls", argv[index], 1) == 0) /* TLS */
{