HTTPS sobre TLS

Objetivo


O propósito deste trabalho é implementar o lado cliente do protocolo HTTPS sobre o protocolo TLS no sistema operacional LINUX. Isto é, partindo do pressuposto que até a camada TCP/IP esteja desenvolvida, iremos implementar os dois protocolos que vêm logo acima (TLS + HTTPS). Lembramos que não vamos modificar a concepção original de tais protocolos por motivos didáticos, com ênfase na compreensão de protocolos de comunicação , nem unificá-los com o intuito de fazer com que eles tenham menor complexidade no sistema operacional voltado a sistemas embarcados. Porém, implementaremos o TLS da maneira mais básica, isto é, sempre que possível, optaremos pela utilização de itens mais simples, como: algortimos de criptografia menos complexos (AES), suporte restrito a apenas um tipo de certificado, entre outros aspectos que percebermos mais viáveis ao longo do desenvolvimento.

Nosso objetivo final é conseguir acessar um website seguro a partir da classe criada.



Conceitos Básicos

 

Hypertext Transfer Protocol Secure (HTTPS)


Hypertext Transfer Protocol Secure (HTTPS), é a combinação de HTTP com o protocolo TLS/SSL. E este tem sido utilizado ao longo dos anos para transações financeiras, e-mail e sistemas corporativos na Internet, mas ultimamente sua aplicação também está sendo estendida para a autenticação em todos os tipos de websites, na segurança de contas e comunicação de usuários, por exemplo.

A própria RFC 2818 define HTTP sobre TLS como muito simples, pois consiste em utilizar HTTP sobre TLS como se utilizaria sobre TCP, com algumas particularidades:

  • O cliente HTTP atua também como cliente TLS e, após o handshaking, passa a enviar os dados como TLS, seguindo o comportamento normal do HTTP;

  • As URLs iniciam com https:// e uma prática comum é utilizar uma porta diferente para rodar HTTP/TLS, a porta 443 no caso de uma conexão TCP/IP;

  • O servidor deve possuir um certificado digital reconhecido por uma autoridade certificadora confiável.


Transport Layer Security (TLS)


Transport Layer Security (TLS) é um protocolo criptográfico, sucessor do Secure Sockets Layer (SSL), que busca prover comunicação segura aos serviços da Internet, como HTTP, SMTP e FTP. A versão atual (1.2) é definida pela RFC 5246, e em seu abstract consta ”O protocolo permite a comunicação de aplicações cliente/servidor em uma maneira projetada para prevenir espionagem, adulteração ou falsificação de mensagens”.

Na camada de protocolos, TLS fica acima de um protocolo de transporte confiável, como TCP, e abaixo da aplicação. Ele é composto de duas camadas: o protocolo de registro (TLS Record Protocol), e os protocolos de handshaking (TLS Handshaking Protocols).




Figura 1 - Posição do TLS perante as demais camadas

O protocolo prevê privacidade e integridade dos dados via Internet, pois as partes são autenticadas e os dados cifrados. Resumidamente, a figura abaixo demonstra de forma sintetizada o processo inicial entre o cliente e o servidor para que se estabeleça uma conexão segura.

Figura 2 - HandshakeTLS  entre cliente e servidor 

De maneira mais detalhada, a figura supracitada pode ser detalhada da seguinte forma:

PassoAção
1O Cliente envia a mensagem ClientHello propondo uma conexão segura com as opções TLS. (Version, Random Number, Session Id,  CipherSuites, Compression Methods)
2O servidor responde com uma mensagem ServerHello.
3O servidor envia seu certificado de chave pública (certificado X.509) na mensagem Certificate.
4O servidor conclui essa parte da negociação com a mensagem ServerHelloDone
5O cliente envia a chave de sessão (encriptado com a chave pública do servidor) na mensagemClientKeyExchange
6O Cliente envia a mensagem ChangeCipherSpec para ativar as opções previamente negociadas para as próximas mensagens enviadas
7O Cliente envia a mensagem Finished para que o servidor verifique as opções recentemente ativadas
8O servidor envia a mensagem ChangeCipherSpec para ativar as opções previamente negociadas para as próximas mensagens enviadas
9O Servidor envia a mensagem Finished ao cliente com as opções recentemente ativadas
Fim do Handsake

Após esse procedimento de handshaking, e se nenhum passo falhou, a conexão segura é iniciada utilizando as chaves geradas no último passo até o seu fechamento. Esse protocolo ajuda a prevenir que intermediários entre as duas pontas da comunicação tenham acesso indevido ou falsifiquem os dados transmitidos.

 

Para re-utilizar uma conexão existente:
* 1. Cliente envia ClientHello com session ID (já utilizado).
* 2. Cliente recebe ServerHello com o mesmo session ID.
* 3. Cliente recebe ChangeCipherSpec.
* 4. Cliente recebe Finished.
* 5. Cliente envia ChangeCipherSpec.
* 6. Cliente envia Finished.

Solução

===========================
PROJETO  ANTERIOR
===========================
- Objetivo: comunicar duas máquinas utilizando EPOS (TLS Client + TLS Server)

===========================
PROJETO 2012.1
===========================
- Vamos utilizar a SessionID para "aproveitar" o canal de comunicação seguro já criado.
- Obter a chave pública do servidor através de seu certificado.
- Ler o certificado X-509 do servidor.
- Objetivo: Utilizar nossa classe para obter um recurso de um host qualquer com suporte a TLS 1.0. Como por exemplo, um "wget" em https://host_qualquer.com.br/recurso

Limitações:


- Utilizaremos somente os algoritmos: AES 128bits, SHA. Ou seja, no momento de enviar a o ClientHello ao servidor, diremos que nossa lista de CypherSuites é composta apenas de um elemento (TLS_RSA_WITH_AES_128_CBC_SHA)
- TLS apenas versão 1.0. 
- Não damos suporte ao canal de comunicação que necessite do cliente enviar um certificado para se identificar.



Diagrama de Estados



Diagrama de Classes:





Diagrama de Sequência:


 

Implementação

 

Primeiro estágio:

Ao buscar subsídios e referências para nosso projeto, encontramos 5 implementações abertas do TLS:

No entanto, tais projetos utilizam suas próprias estruturas nos algoritmos criptográficos, impedindo o  reuso desses. Buscamos, então, estruturas mais enxutas e portáveis.

Já encontramos e testamos, com sucesso, os seguintes algoritmos:

VANTAGEM: Todas as estruturas acima fazem uso apenas de estruturas e bibliotecas básicas da linguagem, exceto SHA-256, que utiliza string.h.
 
Segundo Estágio:

 

Implementação do Projeto: existe a classe HTTPS responsável em prover uma conexão segura para o usuário requisitar um recurso. A classe HTTPS por sua vez, monta o cabeçalho HTTP e utiliza a classe TLS para enviar a mensagem. Já a classe TLS, antes de enviar aquela mensagem ao HOST, realiza todo o processo de Handshake. Para deixar o projeto mais genérico, isolamos as classes com socket para o projeto ser facilmente migrado para qualquer outro SO. Também fizemos com que classe utilize métodos para "simular" os estados da máquina de estados. Além disso, foi mais do que necessário usar sub-classes para modelar as mensagens, a título de de exemplo, demonstraremos a implementação da mensagem ClientHello:

 Como a mensagem Clientehello é encapsulada pela camada HandShake, e esta é encapsulada pela camada RecordLayer; utilizamos o conceito de herança para modelar as classes, como pode ser visto na figura abaixo:

 

 E como fazer para enviar? Realizando a chamada de cada método montarMsg(), isto é, "classeAvô", classePai e classeFilha e agrupando-as.

Após isto, a varíavel "streamByte_final" é enviada à classe TCP.

Será enviado o seguinte seguinte fluxo de bytes:

>16030100 2D010000 2903014F FA2A106C< ....-...)..O.*.l 0x00000000 => 0x13EF7350
>0921C127 AF9ADC60 7B5C4A71 9DA5100C< .!.'...`{\Jq.... 0x00000010 => 0x13EF7360
>0C524413 C6A46C03 AB917A00 0002002F< .RD...l...z..../ 0x00000020 => 0x13EF7370
>0100< .. 0x00000030 => 0x13EF7380

Tal fluxo corresponde à seguinte estrura:

Datagrama ClientHello

------------ Record Layer ----------------

0x16 = 22

0x0301 = versão TLS 1.0 

0x002D = 45 bytes encapsulados

-----------------------------------------------

------------ HandShake Protocol ----------------

0x01 = Client Hello

0x000029 = 41 bytes restantes

0x0301 = versão TLS 1.0

-----------------------------------------------

------------ Client ----------------

0x4F FA2A106C...AB917A = Random 32 bytes (4bytes gmt_unix_time + 28bytes random) -> 4FFA2A10 -> 352297633 = GMT: Mon, 09 Jul 2012 00:47:12 GMT

0x00 = Session Id Length

0x0002 = CipherSuites Length

0x002f = CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA   (sempre uma cypher suite  ocupa 2 bytes)

0x01 = MethodCompression Length

0x00 = Method NULL

-----------------------------------------------

Ou para ter uma visão mais clara, segue um screenshot do Wireshark.

  

Exemplo de Utilzação

 

Classe do Usuário

Classe HTTPS

A classe TLS vai primeiramente realizar todo o processo de handshake, antes de começar a enviar o que a camada acima (HTTPS, FTP, SMT, etc.) solicitou que fosse enviado. Exemplo de DEBUG do método TLS::send_receive():

Teste HTTPS:

IP: 150.162.1.162

A camada acima (HTTP/SMTP/FTP) quer enviar a seguinte mensagem:

‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖

>47455420 2F696E64 65782E68 746D6C20< GET /index.html 0x00000000 => 0x132251B0
>48545450 2F312E31 0A0D486F 73743A6D< HTTP/1.1..Host:m 0x00000010 => 0x132251C0
>6F6F646C 652E7566 73632E62 720A0D0A< oodle.ufsc.br... 0x00000020 => 0x132251D0
>0D< . 0x00000030 => 0x132251E0


‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ ‖‖ ‖ 

Evolução e dificuldades encontradas

Subestimamos a complexidade do protocolo. As mensagens de Hello foram superadas com algum esforço, no entanto, a partir do recebimento dos primeiros dados do servidor e da mensagem ClientKeyExchange, a dificuldade cresceu exponencialmente.

Alguns dos obstáculos enfrentados:

- Dificuldade de depuração. O servidor simplesmente ignorou várias mensagens que tentamos montar;

- Falta de exemplos reais. Quando tentávamos analisar o fluxo através de uma utilização real, os navegadores escolhiam métodos diferentes do metódo pretendido de handshake;

- Muito tempo gasto para converter a classe em array de bytes, especialmente quando precisávamos converter um inteiro para um inteiro de 3 bytes, cuidando do "endianness";

- Dificuldade também na volta dos dados.

Expectativa: Precisaríamos de mais tempo para fazer funcionar. O escopo/tempo mal dimensionado.

Bibliografia

HTTP over TLS, RFC 2818

Transport Layer Security (TLS) Renegotiation Indication Extension, RFC5746
http://tools.ietf.org/html/rfc5746

 

The TLS Protocol - Version 1.0
http://www.ietf.org/rfc/rfc2246.txt

The Transport Layer Security (TLS) Protocol Version 1.2, RFC 5246
http://tools.ietf.org/html/rfc5246

 The Transport Layer Security (TLS) Protocol - Version 1.1
http://tools.ietf.org/html/rfc4346


HTTP Made Really Easy. A Practical Guide to Writing Clients and Servers
http://www.jmarshall.com/easy/http/
/>


Writing endian-independent code in C
http://www.ibm.com/developerworks/aix/library/au-endianc/index.html?ca=drs-
/>
The Open Group Base Specifications Issue 6 - <stdint.h> IEEE Std 1003.1, 2004 Edition
http://pubs.opengroup.org/onlinepubs/007904975/basedefs/stdint.h.html

Wikipedia - Transport Layer Security
http://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_1.1


Convert Unix timestamp to Readable Date/time
http://www.onlineconversion.com/unix_time.htm

SSL Report:  Analyze Servers SSL/TLS - moodle.ufsc.br
https://www.ssllabs.com/ssltest/analyze.html?d=www.moodle.ufsc.br
/>

A quick look over some browsers and their SSL/TLS implementations
http://www.carbonwind.net/blog/post/A-quick-look-over-some-browsers-and-their-SSLTLS-implementations.aspx

Tags:

Código

so2.tar.gz