A simple library to support serving https.

Dependents:   oldheating gps motorhome heating

Committer:
andrewboyson
Date:
Wed Aug 28 07:10:59 2019 +0000
Revision:
5:ee5489ee1117
Parent:
4:6a1d887f1cad
Child:
6:819c17738dc2
Added connection status

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 2:82268409e83f 1 #include "tls.h"
andrewboyson 2:82268409e83f 2 #include "tls-defs.h"
andrewboyson 5:ee5489ee1117 3 #include "tls-connection.h"
andrewboyson 2:82268409e83f 4 #include "tls-session.h"
andrewboyson 2:82268409e83f 5 #include "tls-log.h"
andrewboyson 2:82268409e83f 6 #include "mstimer.h"
andrewboyson 2:82268409e83f 7 #include "random.h"
andrewboyson 2:82268409e83f 8 #include "log.h"
andrewboyson 2:82268409e83f 9 #include "pri-key.h"
andrewboyson 2:82268409e83f 10
andrewboyson 5:ee5489ee1117 11 static int handleClientHello(int length, uint8_t* pBuffer, struct TlsConnection* pConnection) //returns 0 on success; -1 on error
andrewboyson 5:ee5489ee1117 12 {
andrewboyson 2:82268409e83f 13 //Check things look ok
andrewboyson 4:6a1d887f1cad 14 uint8_t* p = pBuffer;
andrewboyson 2:82268409e83f 15 if (length < 100)
andrewboyson 2:82268409e83f 16 {
andrewboyson 2:82268409e83f 17 LogF("TLS - %d byte client hello message is not at least 100 bytes long\r\n", length);
andrewboyson 2:82268409e83f 18 return -1;
andrewboyson 2:82268409e83f 19 }
andrewboyson 5:ee5489ee1117 20
andrewboyson 4:6a1d887f1cad 21 //Start and add the handshake hash
andrewboyson 5:ee5489ee1117 22 //Sha256Start(&pConnection->handshakeHash);
andrewboyson 5:ee5489ee1117 23 //Sha256Add (&pConnection->handshakeHash, pBuffer, length);
andrewboyson 4:6a1d887f1cad 24
andrewboyson 2:82268409e83f 25 //Read in the parameters
andrewboyson 4:6a1d887f1cad 26 uint8_t versionH = *p++;
andrewboyson 4:6a1d887f1cad 27 uint8_t versionL = *p++;
andrewboyson 2:82268409e83f 28
andrewboyson 4:6a1d887f1cad 29 uint8_t* pRandom = p;
andrewboyson 2:82268409e83f 30 p += 32;
andrewboyson 2:82268409e83f 31
andrewboyson 2:82268409e83f 32 int sessionIdLength = *p++;
andrewboyson 4:6a1d887f1cad 33 uint8_t* pSessionId = p;
andrewboyson 2:82268409e83f 34
andrewboyson 2:82268409e83f 35 //Handle the parameters
andrewboyson 5:ee5489ee1117 36 pConnection->session = -1;
andrewboyson 5:ee5489ee1117 37 if (sessionIdLength == 1) pConnection->session = *pSessionId;
andrewboyson 5:ee5489ee1117 38 struct TlsSession* pSession = TlsSessionOrNull(pConnection->session);
andrewboyson 2:82268409e83f 39 if (!pSession || pSession->state != TLS_SESSION_STATE_VALID)
andrewboyson 2:82268409e83f 40 {
andrewboyson 2:82268409e83f 41 pSession = TlsSessionGetOldest();
andrewboyson 2:82268409e83f 42 pSession->state = TLS_SESSION_STATE_STARTED;
andrewboyson 2:82268409e83f 43 }
andrewboyson 5:ee5489ee1117 44 pConnection->session = TlsSessionGetIndex(pSession);
andrewboyson 2:82268409e83f 45
andrewboyson 2:82268409e83f 46 pSession->lastUsed = MsTimerCount;
andrewboyson 2:82268409e83f 47 for (int i = 0; i < 32; i++) pSession->clientRandom[i] = *pRandom++;
andrewboyson 2:82268409e83f 48 for (int i = 0; i < 32; i++) pSession->serverRandom[i] = RandomGetByte();
andrewboyson 2:82268409e83f 49
andrewboyson 2:82268409e83f 50 //Log the parameters
andrewboyson 2:82268409e83f 51 if (TlsTrace)
andrewboyson 2:82268409e83f 52 {
andrewboyson 2:82268409e83f 53 LogF("- client version HH:LL: %02x:%02x\r\n", versionH, versionL);
andrewboyson 2:82268409e83f 54 Log ("- client random:\r\n"); LogBytesAsHex(pRandom, 32); Log("\r\n");
andrewboyson 2:82268409e83f 55 Log ("- client session id:\r\n"); LogBytesAsHex(pSessionId, sessionIdLength); Log("\r\n");
andrewboyson 5:ee5489ee1117 56 LogF("- session index: %d\r\n", pConnection->session);
andrewboyson 2:82268409e83f 57 }
andrewboyson 2:82268409e83f 58 return 0;
andrewboyson 2:82268409e83f 59 }
andrewboyson 5:ee5489ee1117 60 static int handleClientKeyExchange(int length, uint8_t* pBuffer, struct TlsConnection* pConnection) //returns 0 on success; -1 on error
andrewboyson 2:82268409e83f 61 {
andrewboyson 5:ee5489ee1117 62 struct TlsSession* pSession = TlsSessionOrNull(pConnection->session);
andrewboyson 5:ee5489ee1117 63 if (!pSession)
andrewboyson 5:ee5489ee1117 64 {
andrewboyson 5:ee5489ee1117 65 LogTimeF("handleClientKeyExchange - invalid session %d\r\n", pConnection->session);
andrewboyson 5:ee5489ee1117 66 return -1;
andrewboyson 5:ee5489ee1117 67 }
andrewboyson 2:82268409e83f 68
andrewboyson 5:ee5489ee1117 69 //Sha256Add (&pConnection->handshakeHash, pBuffer, length);
andrewboyson 4:6a1d887f1cad 70
andrewboyson 2:82268409e83f 71 if (length != 130)
andrewboyson 2:82268409e83f 72 {
andrewboyson 2:82268409e83f 73 LogF("TLS - %d byte client key exchange message is not 130 bytes long\r\n", length);
andrewboyson 2:82268409e83f 74 return -1;
andrewboyson 2:82268409e83f 75 }
andrewboyson 2:82268409e83f 76 int premasterLength = pBuffer[0] << 8 | pBuffer[1]; //Overall length 2 bytes
andrewboyson 2:82268409e83f 77 if (premasterLength != 128)
andrewboyson 2:82268409e83f 78 {
andrewboyson 2:82268409e83f 79 LogF("TLS - %d byte encrypted pre master secret is not 128 bytes long\r\n", length);
andrewboyson 2:82268409e83f 80 return -1;
andrewboyson 2:82268409e83f 81 }
andrewboyson 4:6a1d887f1cad 82 uint8_t* pEncryptedPreMasterSecret = pBuffer + 2;
andrewboyson 2:82268409e83f 83 pSession->slotPriKeyDecryption = PriKeyDecryptStart(pEncryptedPreMasterSecret);
andrewboyson 2:82268409e83f 84
andrewboyson 2:82268409e83f 85 if (TlsTrace)
andrewboyson 2:82268409e83f 86 {
andrewboyson 2:82268409e83f 87 LogF("- encrypted pre master\r\n", premasterLength);
andrewboyson 2:82268409e83f 88 LogBytesAsHex(pEncryptedPreMasterSecret, 128);
andrewboyson 2:82268409e83f 89 Log("\r\n");
andrewboyson 2:82268409e83f 90 }
andrewboyson 2:82268409e83f 91
andrewboyson 2:82268409e83f 92 return 0;
andrewboyson 2:82268409e83f 93 }
andrewboyson 4:6a1d887f1cad 94 static void handleAlert(int length, uint8_t* pBuffer)
andrewboyson 2:82268409e83f 95 {
andrewboyson 4:6a1d887f1cad 96 uint8_t level = pBuffer[0];
andrewboyson 4:6a1d887f1cad 97 uint8_t description = pBuffer[1];
andrewboyson 2:82268409e83f 98 if (TlsTrace)
andrewboyson 2:82268409e83f 99 {
andrewboyson 2:82268409e83f 100 Log("- alert level: "); TlsLogAlertLevel (level); Log("\r\n");
andrewboyson 2:82268409e83f 101 Log("- alert description: "); TlsLogAlertDescription(description); Log("\r\n");
andrewboyson 2:82268409e83f 102 }
andrewboyson 2:82268409e83f 103 }
andrewboyson 4:6a1d887f1cad 104 static void handleApplication(int length, uint8_t* pBuffer)
andrewboyson 2:82268409e83f 105 {
andrewboyson 2:82268409e83f 106 if (TlsTrace)
andrewboyson 2:82268409e83f 107 {
andrewboyson 2:82268409e83f 108 Log("- application data:\r\n");
andrewboyson 2:82268409e83f 109 LogBytesAsHex(pBuffer, length);
andrewboyson 2:82268409e83f 110 Log("\r\n");
andrewboyson 2:82268409e83f 111 }
andrewboyson 2:82268409e83f 112 }
andrewboyson 5:ee5489ee1117 113
andrewboyson 5:ee5489ee1117 114 static void handleHandshake(int length, uint8_t* pBuffer, struct TlsConnection* pConnection)
andrewboyson 2:82268409e83f 115 {
andrewboyson 5:ee5489ee1117 116 uint8_t* p = pBuffer;
andrewboyson 5:ee5489ee1117 117 while (p < pBuffer + length)
andrewboyson 5:ee5489ee1117 118 {
andrewboyson 5:ee5489ee1117 119 uint8_t handshakeType = *p++;
andrewboyson 5:ee5489ee1117 120 int handshakeLength = *p++ << 16;
andrewboyson 5:ee5489ee1117 121 handshakeLength |= *p++ << 8;
andrewboyson 5:ee5489ee1117 122 handshakeLength |= *p++ ; //Handshake length 3 bytes
andrewboyson 5:ee5489ee1117 123
andrewboyson 5:ee5489ee1117 124 if (TlsTrace)
andrewboyson 5:ee5489ee1117 125 {
andrewboyson 5:ee5489ee1117 126 Log ("- handshake type: "); TlsLogHandshakeType(handshakeType); Log("\r\n");
andrewboyson 5:ee5489ee1117 127 LogF("- handshake length: %d\r\n", handshakeLength);
andrewboyson 5:ee5489ee1117 128 }
andrewboyson 5:ee5489ee1117 129
andrewboyson 5:ee5489ee1117 130 int r = -1;
andrewboyson 5:ee5489ee1117 131 switch (handshakeType)
andrewboyson 5:ee5489ee1117 132 {
andrewboyson 5:ee5489ee1117 133 case TLS_HANDSHAKE_ClientHello:
andrewboyson 5:ee5489ee1117 134 r = handleClientHello(handshakeLength, p, pConnection);
andrewboyson 5:ee5489ee1117 135 pConnection->toDo = r ? DO_SEND_ALERT_ILLEGAL_PARAMETER : DO_SEND_SERVER_HELLO;
andrewboyson 5:ee5489ee1117 136 break;
andrewboyson 5:ee5489ee1117 137
andrewboyson 5:ee5489ee1117 138 case TLS_HANDSHAKE_ClientKeyExchange:
andrewboyson 5:ee5489ee1117 139 r = handleClientKeyExchange(handshakeLength, p, pConnection);
andrewboyson 5:ee5489ee1117 140 pConnection->toDo = r ? DO_SEND_ALERT_ILLEGAL_PARAMETER : DO_WAIT_DECRYPT_MASTER_SECRET;
andrewboyson 5:ee5489ee1117 141 break;
andrewboyson 5:ee5489ee1117 142
andrewboyson 5:ee5489ee1117 143 default:
andrewboyson 5:ee5489ee1117 144 LogF("TLS - ignoring handshake type ");
andrewboyson 5:ee5489ee1117 145 TlsLogHandshakeType(handshakeType);
andrewboyson 5:ee5489ee1117 146 LogF(" and skipping %d bytes\r\n", handshakeLength);
andrewboyson 5:ee5489ee1117 147 break;
andrewboyson 5:ee5489ee1117 148 }
andrewboyson 5:ee5489ee1117 149 p += handshakeLength;
andrewboyson 5:ee5489ee1117 150 }
andrewboyson 5:ee5489ee1117 151 }
andrewboyson 5:ee5489ee1117 152 static int handleContent(struct TlsConnection* pConnection, uint8_t* pBuffer)
andrewboyson 5:ee5489ee1117 153 {
andrewboyson 5:ee5489ee1117 154 uint8_t contentType = *pBuffer++;
andrewboyson 5:ee5489ee1117 155 uint8_t versionH = *pBuffer++;
andrewboyson 5:ee5489ee1117 156 uint8_t versionL = *pBuffer++;
andrewboyson 5:ee5489ee1117 157 int length = *pBuffer++ << 8;
andrewboyson 5:ee5489ee1117 158 length |= *pBuffer++;
andrewboyson 5:ee5489ee1117 159 int overallLen = length + 5;
andrewboyson 5:ee5489ee1117 160
andrewboyson 2:82268409e83f 161 if (TlsTrace)
andrewboyson 2:82268409e83f 162 {
andrewboyson 2:82268409e83f 163 Log ("- content type: "); TlsLogContentType(contentType); Log("\r\n");
andrewboyson 2:82268409e83f 164 LogF("- legacy HH:LL: %02x:%02x\r\n", versionH, versionL);
andrewboyson 2:82268409e83f 165 LogF("- length : %d\r\n" , length);
andrewboyson 2:82268409e83f 166 }
andrewboyson 2:82268409e83f 167 switch (contentType)
andrewboyson 2:82268409e83f 168 {
andrewboyson 2:82268409e83f 169 case TLS_CONTENT_TYPE_Handshake:
andrewboyson 5:ee5489ee1117 170 handleHandshake(length, pBuffer, pConnection);
andrewboyson 5:ee5489ee1117 171 break;
andrewboyson 5:ee5489ee1117 172
andrewboyson 5:ee5489ee1117 173 case TLS_CONTENT_TYPE_ALERT:
andrewboyson 5:ee5489ee1117 174 handleAlert(length, pBuffer);
andrewboyson 5:ee5489ee1117 175 break;
andrewboyson 5:ee5489ee1117 176
andrewboyson 5:ee5489ee1117 177 case TLS_CONTENT_TYPE_Application:
andrewboyson 5:ee5489ee1117 178 handleApplication(length, pBuffer);
andrewboyson 5:ee5489ee1117 179 pConnection->toDo = DO_APPLICATION;
andrewboyson 5:ee5489ee1117 180 break;
andrewboyson 5:ee5489ee1117 181
andrewboyson 5:ee5489ee1117 182 default:
andrewboyson 5:ee5489ee1117 183 Log("TLS - ignoring content type ");
andrewboyson 5:ee5489ee1117 184 TlsLogContentType(contentType);
andrewboyson 5:ee5489ee1117 185 LogF(" and skipping %d bytes\r\n", overallLen);
andrewboyson 5:ee5489ee1117 186 pConnection->toDo = DO_WAIT_CLIENT_HELLO;
andrewboyson 5:ee5489ee1117 187 break;
andrewboyson 5:ee5489ee1117 188 }
andrewboyson 5:ee5489ee1117 189 return overallLen;
andrewboyson 5:ee5489ee1117 190 }
andrewboyson 5:ee5489ee1117 191 void TlsRequest(int connectionId, int size, uint8_t* pRequestStream, uint32_t positionInRequestStream)
andrewboyson 5:ee5489ee1117 192 {
andrewboyson 5:ee5489ee1117 193 //Log what we are doing
andrewboyson 5:ee5489ee1117 194 if (TlsTrace) LogF("TLS <<< %d (%u)\r\n", size, positionInRequestStream);
andrewboyson 5:ee5489ee1117 195
andrewboyson 5:ee5489ee1117 196 //Get new or existing connection information
andrewboyson 5:ee5489ee1117 197 struct TlsConnection* pConnection;
andrewboyson 5:ee5489ee1117 198 if (!positionInRequestStream)
andrewboyson 5:ee5489ee1117 199 {
andrewboyson 5:ee5489ee1117 200 //If this is the start of the request then open a new connection
andrewboyson 5:ee5489ee1117 201 pConnection = TlsConnectionNew(connectionId);
andrewboyson 5:ee5489ee1117 202 }
andrewboyson 5:ee5489ee1117 203 else
andrewboyson 5:ee5489ee1117 204 {
andrewboyson 5:ee5489ee1117 205 //If this is in the middle of a request then open an existing connection
andrewboyson 5:ee5489ee1117 206 pConnection = TlsConnectionOrNull(connectionId);
andrewboyson 5:ee5489ee1117 207 if (!pConnection)
andrewboyson 2:82268409e83f 208 {
andrewboyson 5:ee5489ee1117 209 LogTimeF("TlsRequest - no connection corresponds to id %d\r\n", connectionId);
andrewboyson 2:82268409e83f 210 return;
andrewboyson 2:82268409e83f 211 }
andrewboyson 5:ee5489ee1117 212 }
andrewboyson 2:82268409e83f 213
andrewboyson 5:ee5489ee1117 214 //Handle each item of coalesced content
andrewboyson 5:ee5489ee1117 215 uint8_t* pNext = pRequestStream;
andrewboyson 5:ee5489ee1117 216 while (pNext < pRequestStream + size) pNext += handleContent(pConnection, pNext);
andrewboyson 2:82268409e83f 217 }
andrewboyson 5:ee5489ee1117 218 void TlsReset(int connectionId)
andrewboyson 5:ee5489ee1117 219 {
andrewboyson 5:ee5489ee1117 220 TlsConnectionReset(connectionId);
andrewboyson 5:ee5489ee1117 221 }