A simple library to support serving https.
Dependents: oldheating gps motorhome heating
Diff: tls/tls-response.c
- Revision:
- 14:03a0b8fd6ddc
- Parent:
- 13:0a80b49a5e78
- Child:
- 15:4ddb73b5fea1
--- a/tls/tls-response.c Fri Sep 27 11:31:18 2019 +0000 +++ b/tls/tls-response.c Wed Oct 02 20:26:04 2019 +0000 @@ -12,90 +12,96 @@ #include "tls-mac.h" #include "http.h" -void addSize(uint8_t** ppCurrent, int size) -{ - uint8_t* p = *ppCurrent; - *p++ = size >> 8; - *p++ = size & 0xFF; - *ppCurrent = p; -} void backfillSize(uint8_t* pCurrent, uint8_t* pStart) { int size = pCurrent - pStart - 2; *(pStart + 0) = size >> 8; *(pStart + 1) = size & 0xFF; } -static void sendServerHello(struct TlsConnection* pConnection, struct TlsSession* pSession, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) +void addSize(uint8_t** pp, int size) +{ + uint8_t* p = *pp; + *p++ = size >> 8; + *p++ = size & 0xFF; + *pp = p; +} +static uint8_t* pHandshakeSize; +static uint8_t* pHandshakePayload; +static void addHandshakeStart(uint8_t** pp) { - //Set up a multiple handshakes content - hello, certificate and done - LogTime(" sending server hello\r\n"); - uint8_t* p = pWindow; - *p++ = TLS_CONTENT_TYPE_HANDSHAKE; //Content is handshakes - *p++ = 0x03; *p++ = 0x03; //Legacy TLS version - uint8_t* pHandshakesLength = p; - p += 2; //Handshakes Length (2 bytes) - uint8_t* handshakesPayloadStart = p; //Record the start of the handshake payload + uint8_t* p = *pp; + + *p++ = TLS_CONTENT_TYPE_HANDSHAKE; + *p++ = 0x03; *p++ = 0x03; + pHandshakeSize = p; //Store the position to backfill the handshake size + p += 2; //Leave room to backfill the handshake size + pHandshakePayload = p; //Record the position of the handshake payload to later calculate the hash - //Server hello handshake - *p++ = TLS_HANDSHAKE_SERVER_HELLO; //Handshake type server hello + *pp = p; +} +static void addHandshakeEnd(uint8_t* p, struct TlsConnection* pConnection) +{ + backfillSize(p, pHandshakeSize); + Sha256Add(&pConnection->handshakeSha, pHandshakePayload, p - pHandshakePayload); //Add the handshake hash + pConnection->serverSequence++; +} +static void addHandshakeServerHello(uint8_t** pp, struct TlsConnection* pConnection) +{ + Log(" sending handshake server hello\r\n"); + uint8_t* p = *pp; + + *p++ = TLS_HANDSHAKE_SERVER_HELLO; *p++ = 0x00; - uint8_t* pHandshakeHelloLength = p; - p += 2; //Size of this handshake - *p++ = 0x03; *p++ = 0x03; //TLS version 1.2 + uint8_t* pSize = p; + p += 2; + *p++ = 0x03; *p++ = 0x03; for (int i = 0; i < 32; i++) { uint8_t r = RandomGetByte(); pConnection->serverRandom[i] = r; - *p++ = r; //32 bit random number + *p++ = r; //32 bit random number } - *p++ = 0x04; //SessionId length 4 - *p++ = pConnection->sessionId >> 24; //Session id - *p++ = pConnection->sessionId >> 16; //Session id - *p++ = pConnection->sessionId >> 8; //Session id - *p++ = pConnection->sessionId >> 0; //Session id - *p++ = 0x00; *p++ = 0x2f; //Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) - *p++ = 0x00; //Compression method none - *p++ = 0x00; *p++ = 0x05; //Extensions length (2 bytes) 5 bytes - *p++ = 0xff; *p++ = 0x01; //Extension Renegotiation Info - *p++ = 0x00; *p++ = 0x01; //1 bytes of "Renegotiation Info" extension data follows - *p++ = 0x00; //length is zero, because this is a new connection - backfillSize(p, pHandshakeHelloLength); + *p++ = 0x04; //SessionId length 4 + *p++ = pConnection->sessionId >> 24; //Session id + *p++ = pConnection->sessionId >> 16; //Session id + *p++ = pConnection->sessionId >> 8; //Session id + *p++ = pConnection->sessionId >> 0; //Session id + *p++ = 0x00; *p++ = 0x2f; //Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) + *p++ = 0x00; //Compression method none + *p++ = 0x00; *p++ = 0x05; //Extensions length (2 bytes) 5 bytes + *p++ = 0xff; *p++ = 0x01; //Extension Renegotiation Info + *p++ = 0x00; *p++ = 0x01; //1 bytes of "Renegotiation Info" extension data follows + *p++ = 0x00; //length is zero, because this is a new connection + backfillSize(p, pSize); - //Certificate handshake - *p++ = TLS_HANDSHAKE_CERTIFICATE; *p++ = 0x00; //Handshake type certificate + *pp = p; +} +static void addHandshakeCertificate(uint8_t** pp) +{ + uint8_t* p = *pp; + + *p++ = TLS_HANDSHAKE_CERTIFICATE; *p++ = 0x00; addSize(&p, SerCerSize + 6); *p++ = 0x00; //Size of this handshake addSize(&p, SerCerSize + 3); *p++ = 0x00; //Size of all certificates addSize(&p, SerCerSize ); //Size of first certificate for (int i = 0; i < SerCerSize; i++) *p++ = SerCerData[i]; //Certificate - //Hello done handshake - *p++ = TLS_HANDSHAKE_SERVER_HELLO_DONE; *p++ = 0x00; //Handshake type server hello done - *p++ = 0; *p++ = 0; //Size of this handshake - backfillSize(p, pHandshakesLength); + *pp = p; +} +static void addHandshakeServerHelloDone(uint8_t** pp) +{ + LogTime(" sending handshake server hello done\r\n"); + uint8_t* p = *pp; - //Finalise the handshake content - int handshakeLength = p - handshakesPayloadStart; - Sha256Add(&pConnection->handshakeSha, handshakesPayloadStart, handshakeLength); //Add the handshake hash - *pWindowSize = p - pWindow; + *p++ = TLS_HANDSHAKE_SERVER_HELLO_DONE; *p++ = 0x00; + addSize(&p, 0); + + *pp = p; } -static void sendServerChange(struct TlsConnection* pConnection, struct TlsSession* pSession, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) +static void addHandshakeFinished(uint8_t** pp, struct TlsConnection* pConnection, struct TlsSession* pSession) { - LogTime(" sending server change\r\n"); - uint8_t* p = pWindow; - *p++ = TLS_CONTENT_TYPE_CHANGE_CIPHER; //Content is change cipher - *p++ = 0x03; *p++ = 0x03; //Legacy TLS version - *p++ = 0x00; *p++ = 0x01; //Change cipher Length (2 bytes) - *p++ = 0x01; //Change cipher message 1 - - //Record that all incoming messages are now encrypted - pConnection->serverEncrypted = true; - pConnection->serverSequence = 0; - - LogTime(" sending server handshake finished\r\n"); - *p++ = TLS_CONTENT_TYPE_HANDSHAKE; //Content is handshakes - *p++ = 0x03; *p++ = 0x03; //Legacy TLS version - uint8_t* pHandshakesLength = p; - p += 2; //Handshakes Length (2 bytes) + LogTime(" sending handshake finished\r\n"); + uint8_t* p = *pp; //Hash over all handshake payloads exchanged so far uint8_t hash[32]; @@ -141,28 +147,99 @@ AES_CBC_encrypt_buffer(&ctx, message, 48); for (int i = 0; i < 16; i++) *p++ = iv[i]; - for (int i = 0; i < 48; i++) *p++ = message[i]; + for (int i = 0; i < 48; i++) *p++ = message[i]; + + *pp = p; +} +static void addChangeCipher(uint8_t** pp, struct TlsConnection* pConnection) +{ + LogTime(" sending change cipher\r\n"); + uint8_t* p = *pp; + + *p++ = TLS_CONTENT_TYPE_CHANGE_CIPHER; //Content is change cipher + *p++ = 0x03; *p++ = 0x03; //Legacy TLS version + *p++ = 0x00; *p++ = 0x01; //Change cipher Length (2 bytes) + *p++ = 0x01; //Change cipher message 1 - //Finalise - backfillSize(p, pHandshakesLength); + //Record that all outgoing messages are now encrypted + pConnection->serverEncrypted = true; + pConnection->serverSequence = 0; + + *pp = p; +} +static void addAlert(uint8_t** pp, struct TlsConnection* pConnection, uint8_t level, uint8_t description) +{ + LogTime(" sending alert\r\n"); + Log (" - "); TlsLogAlertLevel(level); Log(": "); TlsLogAlertDescription(description); Log("\r\n"); + + uint8_t* p = *pp; + + *p++ = TLS_CONTENT_TYPE_ALERT; + *p++ = 0x03; *p++ = 0x03; + addSize(&p, 2); + *p++ = level; + *p++ = description; + pConnection->serverSequence++; + + *pp = p; +} +static void sendServerHelloNew(struct TlsConnection* pConnection, struct TlsSession* pSession, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) +{ + uint8_t* p = pWindow; + + addHandshakeStart (&p); + addHandshakeServerHello (&p, pConnection); + addHandshakeCertificate (&p); + addHandshakeServerHelloDone(&p); + addHandshakeEnd ( p, pConnection); + *pWindowSize = p - pWindow; pConnection->serverPositionInStreamOffset = positionOfWindowInStream + *pWindowSize; } -static void sendFatal(char description, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) +static void sendServerHelloResume(struct TlsConnection* pConnection, struct TlsSession* pSession, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) { - LogTime(" sending fatal alert: "); - TlsLogAlertDescription(description); - Log("\r\n"); uint8_t* p = pWindow; - *p++ = TLS_CONTENT_TYPE_ALERT; //Content is alert - *p++ = 0x03; *p++ = 0x03; //Legacy TLS version - addSize(&p, 2); //Alert Length (2 bytes) + + addHandshakeStart (&p); + addHandshakeServerHello(&p, pConnection); + addHandshakeEnd ( p, pConnection); - *p++ = 2; //Fatal (level = 2) - *p++ = description; //Description + TlsPrfKeys (pSession->masterSecret, pConnection->clientRandom, pConnection->serverRandom, pConnection->clientMacKey, + pConnection->serverMacKey, + pConnection->clientWriteKey, + pConnection->serverWriteKey); + + addChangeCipher (&p, pConnection); + + addHandshakeStart (&p); + addHandshakeFinished (&p, pConnection, pSession); + addHandshakeEnd ( p, pConnection); *pWindowSize = p - pWindow; + pConnection->serverPositionInStreamOffset = positionOfWindowInStream + *pWindowSize; +} +static void sendServerChange(struct TlsConnection* pConnection, struct TlsSession* pSession, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) +{ + uint8_t* p = pWindow; + + addChangeCipher(&p, pConnection); + + addHandshakeStart (&p); + addHandshakeFinished(&p, pConnection, pSession); + addHandshakeEnd ( p, pConnection); + + *pWindowSize = p - pWindow; + pConnection->serverPositionInStreamOffset = positionOfWindowInStream + *pWindowSize; +} +static void sendFatal(uint8_t description, struct TlsConnection* pConnection, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) +{ + uint8_t* p = pWindow; + + addAlert(&p, pConnection, TLS_ALERT_FATAL, description); + + *pWindowSize = p - pWindow; + pConnection->serverPositionInStreamOffset = positionOfWindowInStream + *pWindowSize; } static bool sendContent(struct TlsConnection* pConnection, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) @@ -280,8 +357,13 @@ if (clientFinished) return true; //The client hasn't made a request and never will so finish else return false; //The client hasn't made a request yet but it could. - case DO_SEND_SERVER_HELLO: - sendServerHello(pConnection, pSession, pWindowSize, pWindow, positionOfWindowInStream); + case DO_SEND_SERVER_HELLO_NEW: + sendServerHelloNew(pConnection, pSession, pWindowSize, pWindow, positionOfWindowInStream); + pConnection->toDo = DO_WAIT_CLIENT_CHANGE; + return false; //Not finished + + case DO_SEND_SERVER_HELLO_RESUME: + sendServerHelloResume(pConnection, pSession, pWindowSize, pWindow, positionOfWindowInStream); pConnection->toDo = DO_WAIT_CLIENT_CHANGE; return false; //Not finished @@ -304,18 +386,18 @@ return finished; } case DO_SEND_ALERT_ILLEGAL_PARAMETER: - sendFatal(TLS_ALERT_ILLEGAL_PARAMETER, pWindowSize, pWindow, positionOfWindowInStream); + sendFatal(TLS_ALERT_ILLEGAL_PARAMETER, pConnection, pWindowSize, pWindow, positionOfWindowInStream); pConnection->toDo = DO_WAIT_CLIENT_HELLO; return true; //Finished case DO_SEND_ALERT_INTERNAL_ERROR: - sendFatal(TLS_ALERT_INTERNAL_ERROR, pWindowSize, pWindow, positionOfWindowInStream); + sendFatal(TLS_ALERT_INTERNAL_ERROR, pConnection, pWindowSize, pWindow, positionOfWindowInStream); pConnection->toDo = DO_WAIT_CLIENT_HELLO; return true; //Finished default: LogTimeF("TlsPoll - unspecified TLS state %d\r\n", pConnection->toDo); - sendFatal(TLS_ALERT_INTERNAL_ERROR, pWindowSize, pWindow, positionOfWindowInStream); //Internal error + sendFatal(TLS_ALERT_INTERNAL_ERROR, pConnection, pWindowSize, pWindow, positionOfWindowInStream); //Internal error pConnection->toDo = DO_WAIT_CLIENT_HELLO; return true; //Finished }