A simple library to support serving https.
Dependents: oldheating gps motorhome heating
tls/tls-request.c@5:ee5489ee1117, 2019-08-28 (annotated)
- 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?
User | Revision | Line number | New 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 | } |