A simple library to support serving https.

Dependents:   oldheating gps motorhome heating

tls/tls-request.c

Committer:
andrewboyson
Date:
2019-07-31
Revision:
2:82268409e83f
Child:
4:6a1d887f1cad

File content as of revision 2:82268409e83f:

#include "tls.h"
#include "tls-defs.h"
#include "tls-state.h"
#include "tls-session.h"
#include "tls-log.h"
#include "mstimer.h"
#include "random.h"
#include "log.h"
#include "pri-key.h"

static int handleClientHello(int length, char* pBuffer, struct TlsState* pState) //returns 0 on success; -1 on error
{
    //Check things look ok
    char* p = pBuffer;
    if (length < 100)
    {
        LogF("TLS - %d byte client hello message is not at least 100 bytes long\r\n", length);
        return -1;
    }
    
    //Read in the parameters
    char versionH         = *p++;
    char versionL         = *p++;
    
    char* pRandom = p;
    p += 32;
    
    int sessionIdLength = *p++;
    char* pSessionId = p;
    
    //Handle the parameters
    pState->session = -1;
    if (sessionIdLength == 1) pState->session = *pSessionId;
    struct TlsSession* pSession = TlsSessionGetFromIndex(pState->session);
    if (!pSession || pSession->state != TLS_SESSION_STATE_VALID)
    {
        pSession = TlsSessionGetOldest();
        pSession->state = TLS_SESSION_STATE_STARTED;
    }
    pState->session = TlsSessionGetIndex(pSession);

    pSession->lastUsed = MsTimerCount;
    for (int i = 0; i < 32; i++) pSession->clientRandom[i] = *pRandom++;
    for (int i = 0; i < 32; i++) pSession->serverRandom[i] = RandomGetByte();
    
    //Log the parameters
    if (TlsTrace)
    {
        LogF("- client version HH:LL: %02x:%02x\r\n", versionH, versionL);
        Log ("- client random:\r\n");     LogBytesAsHex(pRandom,                 32); Log("\r\n");
        Log ("- client session id:\r\n"); LogBytesAsHex(pSessionId, sessionIdLength); Log("\r\n");
        LogF("- session index: %d\r\n",  pState->session);
    }
    return 0;
}
static int handleClientKeyExchange(int length, char* pBuffer, struct TlsState* pState) //returns 0 on success; -1 on error
{
    struct TlsSession* pSession = TlsSessionGetFromIndex(pState->session);
    
    if (length != 130)
    {
        LogF("TLS - %d byte client key exchange message is not 130 bytes long\r\n", length);
        return -1;
    }
    int premasterLength = pBuffer[0] << 8 | pBuffer[1]; //Overall length 2 bytes
    if (premasterLength != 128)
    {
        LogF("TLS - %d byte encrypted pre master secret is not 128 bytes long\r\n", length);
        return -1;
    }
    char* pEncryptedPreMasterSecret = pBuffer + 2;
    pSession->slotPriKeyDecryption = PriKeyDecryptStart(pEncryptedPreMasterSecret);
    
    if (TlsTrace)
    {
        LogF("- encrypted pre master\r\n", premasterLength);
        LogBytesAsHex(pEncryptedPreMasterSecret, 128);
        Log("\r\n");
    }
    
    return 0;
}
static void handleHandshake(int length, char* pBuffer, struct TlsState* pState)
{
    char* p = pBuffer;
    while (p < pBuffer + length)
    {
        char handshakeType    = *p++;
        int  handshakeLength  = *p++ << 16;
             handshakeLength |= *p++ <<  8;
             handshakeLength |= *p++      ; //Handshake length 3 bytes
             
        if (TlsTrace)
        {
            Log ("- handshake type: "); TlsLogHandshakeType(handshakeType); Log("\r\n");
            LogF("- handshake length: %d\r\n", handshakeLength);
        }
        
        int r = -1;
        switch (handshakeType)
        {
            case TLS_HANDSHAKE_ClientHello:
                r = handleClientHello(handshakeLength, p, pState);
                pState->toDo = r ? DO_SEND_ALERT_ILLEGAL_PARAMETER : DO_SEND_SERVER_HELLO;
                break;
                
            case TLS_HANDSHAKE_ClientKeyExchange:
                r = handleClientKeyExchange(handshakeLength, p, pState);
                pState->toDo = r ? DO_SEND_ALERT_ILLEGAL_PARAMETER : DO_WAIT_DECRYPT_MASTER_SECRET;
                break;
                
            default:
                LogF("TLS - ignoring untreated %d byte handshake type ", handshakeLength);
                TlsLogHandshakeType(handshakeType);
                Log("\r\n");
                break;
        }
        p += handshakeLength;
    }
}
static void handleAlert(int length, char* pBuffer)
{
    char level       = pBuffer[0];
    char description = pBuffer[1];
    if (TlsTrace)
    {
        Log("- alert level:       "); TlsLogAlertLevel      (level);       Log("\r\n");
        Log("- alert description: "); TlsLogAlertDescription(description); Log("\r\n");
    }
}
static void handleApplication(int length, char* pBuffer)
{
    if (TlsTrace)
    {
        Log("- application data:\r\n");
        LogBytesAsHex(pBuffer, length);
        Log("\r\n");
    }    
}
void TlsRequest(char* pTlsState, char* pWebState, int size, char* pRequestStream, uint32_t positionInRequestStream)
{
    struct TlsState* pState = (struct TlsState*)pTlsState;
    
    if (TlsTrace) LogF("TLS <<< %d (%u)\r\n", size, positionInRequestStream);

    if (size == 0) return;
    //if (positionInRequestStream != 0) return;
    char contentType = pRequestStream[0];
    char versionH    = pRequestStream[1];
    char versionL    = pRequestStream[2];
    int length       = pRequestStream[3] << 8 | pRequestStream[4]; //Length (2 bytes)
    if (TlsTrace)
    {
        Log ("- content type: "); TlsLogContentType(contentType); Log("\r\n");
        LogF("- legacy HH:LL: %02x:%02x\r\n", versionH, versionL);
        LogF("- length      : %d\r\n"       , length);
    }
    switch (contentType)
    {
        case TLS_CONTENT_TYPE_Handshake:
        {
            handleHandshake(length, pRequestStream + 5, pState);
            return;
        }
        case TLS_CONTENT_TYPE_ALERT:
        {
            handleAlert(length, pRequestStream + 5);
            return;
        }
        case TLS_CONTENT_TYPE_Application:
        {
            handleApplication(length, pRequestStream + 5);
            pState->toDo = DO_APPLICATION;
            return;
        }
        
        default:
            Log("TLS - untreated content type "); TlsLogContentType(contentType); Log("\r\n");
            pState->toDo = DO_WAIT_CLIENT_HELLO;
            return;
    }
}