A simple library to support serving https.
Dependents: oldheating gps motorhome heating
tls/tls-response.c@24:cb43290fc439, 2020-04-01 (annotated)
- Committer:
- andrewboyson
- Date:
- Wed Apr 01 12:48:52 2020 +0000
- Revision:
- 24:cb43290fc439
- Parent:
- 23:e93d5529b7a6
Added check so that if the client closes the TCP connection before the TLS connection is established then respond that we have finished and the TCP connection is to be closed.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
andrewboyson | 21:a6d6e26dd742 | 1 | #include "tls.h" |
andrewboyson | 10:e269fd7b9500 | 2 | #include "tls-defs.h" |
andrewboyson | 10:e269fd7b9500 | 3 | #include "tls-connection.h" |
andrewboyson | 10:e269fd7b9500 | 4 | #include "tls-session.h" |
andrewboyson | 10:e269fd7b9500 | 5 | #include "tls-log.h" |
andrewboyson | 10:e269fd7b9500 | 6 | #include "tls-prf.h" |
andrewboyson | 10:e269fd7b9500 | 7 | #include "ser-cer.h" |
andrewboyson | 10:e269fd7b9500 | 8 | #include "pri-key.h" |
andrewboyson | 10:e269fd7b9500 | 9 | #include "log.h" |
andrewboyson | 18:e3cf22ba2a06 | 10 | #include "tls-aes128cbc-sha.h" |
andrewboyson | 10:e269fd7b9500 | 11 | #include "random.h" |
andrewboyson | 10:e269fd7b9500 | 12 | #include "tls-mac.h" |
andrewboyson | 10:e269fd7b9500 | 13 | #include "http.h" |
andrewboyson | 10:e269fd7b9500 | 14 | |
andrewboyson | 10:e269fd7b9500 | 15 | void backfillSize(uint8_t* pCurrent, uint8_t* pStart) |
andrewboyson | 10:e269fd7b9500 | 16 | { |
andrewboyson | 10:e269fd7b9500 | 17 | int size = pCurrent - pStart - 2; |
andrewboyson | 10:e269fd7b9500 | 18 | *(pStart + 0) = size >> 8; |
andrewboyson | 10:e269fd7b9500 | 19 | *(pStart + 1) = size & 0xFF; |
andrewboyson | 10:e269fd7b9500 | 20 | } |
andrewboyson | 14:03a0b8fd6ddc | 21 | void addSize(uint8_t** pp, int size) |
andrewboyson | 14:03a0b8fd6ddc | 22 | { |
andrewboyson | 14:03a0b8fd6ddc | 23 | uint8_t* p = *pp; |
andrewboyson | 14:03a0b8fd6ddc | 24 | *p++ = size >> 8; |
andrewboyson | 14:03a0b8fd6ddc | 25 | *p++ = size & 0xFF; |
andrewboyson | 14:03a0b8fd6ddc | 26 | *pp = p; |
andrewboyson | 14:03a0b8fd6ddc | 27 | } |
andrewboyson | 14:03a0b8fd6ddc | 28 | static uint8_t* pHandshakeSize; |
andrewboyson | 14:03a0b8fd6ddc | 29 | static uint8_t* pHandshakePayload; |
andrewboyson | 14:03a0b8fd6ddc | 30 | static void addHandshakeStart(uint8_t** pp) |
andrewboyson | 10:e269fd7b9500 | 31 | { |
andrewboyson | 14:03a0b8fd6ddc | 32 | uint8_t* p = *pp; |
andrewboyson | 14:03a0b8fd6ddc | 33 | |
andrewboyson | 14:03a0b8fd6ddc | 34 | *p++ = TLS_CONTENT_TYPE_HANDSHAKE; |
andrewboyson | 14:03a0b8fd6ddc | 35 | *p++ = 0x03; *p++ = 0x03; |
andrewboyson | 14:03a0b8fd6ddc | 36 | pHandshakeSize = p; //Store the position to backfill the handshake size |
andrewboyson | 14:03a0b8fd6ddc | 37 | p += 2; //Leave room to backfill the handshake size |
andrewboyson | 14:03a0b8fd6ddc | 38 | pHandshakePayload = p; //Record the position of the handshake payload to later calculate the hash |
andrewboyson | 10:e269fd7b9500 | 39 | |
andrewboyson | 14:03a0b8fd6ddc | 40 | *pp = p; |
andrewboyson | 14:03a0b8fd6ddc | 41 | } |
andrewboyson | 14:03a0b8fd6ddc | 42 | static void addHandshakeEnd(uint8_t* p, struct TlsConnection* pConnection) |
andrewboyson | 14:03a0b8fd6ddc | 43 | { |
andrewboyson | 14:03a0b8fd6ddc | 44 | backfillSize(p, pHandshakeSize); |
andrewboyson | 14:03a0b8fd6ddc | 45 | Sha256Add(&pConnection->handshakeSha, pHandshakePayload, p - pHandshakePayload); //Add the handshake hash |
andrewboyson | 14:03a0b8fd6ddc | 46 | pConnection->serverSequence++; |
andrewboyson | 14:03a0b8fd6ddc | 47 | } |
andrewboyson | 14:03a0b8fd6ddc | 48 | static void addHandshakeServerHello(uint8_t** pp, struct TlsConnection* pConnection) |
andrewboyson | 14:03a0b8fd6ddc | 49 | { |
andrewboyson | 21:a6d6e26dd742 | 50 | if (TlsTrace) Log(" sending handshake server hello\r\n"); |
andrewboyson | 14:03a0b8fd6ddc | 51 | uint8_t* p = *pp; |
andrewboyson | 14:03a0b8fd6ddc | 52 | |
andrewboyson | 14:03a0b8fd6ddc | 53 | *p++ = TLS_HANDSHAKE_SERVER_HELLO; |
andrewboyson | 10:e269fd7b9500 | 54 | *p++ = 0x00; |
andrewboyson | 14:03a0b8fd6ddc | 55 | uint8_t* pSize = p; |
andrewboyson | 14:03a0b8fd6ddc | 56 | p += 2; |
andrewboyson | 14:03a0b8fd6ddc | 57 | *p++ = 0x03; *p++ = 0x03; |
andrewboyson | 17:93feb2a51d58 | 58 | for (int i = 0; i < TLS_LENGTH_RANDOM; i++) |
andrewboyson | 10:e269fd7b9500 | 59 | { |
andrewboyson | 10:e269fd7b9500 | 60 | uint8_t r = RandomGetByte(); |
andrewboyson | 10:e269fd7b9500 | 61 | pConnection->serverRandom[i] = r; |
andrewboyson | 14:03a0b8fd6ddc | 62 | *p++ = r; //32 bit random number |
andrewboyson | 10:e269fd7b9500 | 63 | } |
andrewboyson | 14:03a0b8fd6ddc | 64 | *p++ = 0x04; //SessionId length 4 |
andrewboyson | 14:03a0b8fd6ddc | 65 | *p++ = pConnection->sessionId >> 24; //Session id |
andrewboyson | 14:03a0b8fd6ddc | 66 | *p++ = pConnection->sessionId >> 16; //Session id |
andrewboyson | 14:03a0b8fd6ddc | 67 | *p++ = pConnection->sessionId >> 8; //Session id |
andrewboyson | 14:03a0b8fd6ddc | 68 | *p++ = pConnection->sessionId >> 0; //Session id |
andrewboyson | 14:03a0b8fd6ddc | 69 | *p++ = 0x00; *p++ = 0x2f; //Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) |
andrewboyson | 14:03a0b8fd6ddc | 70 | *p++ = 0x00; //Compression method none |
andrewboyson | 14:03a0b8fd6ddc | 71 | *p++ = 0x00; *p++ = 0x05; //Extensions length (2 bytes) 5 bytes |
andrewboyson | 14:03a0b8fd6ddc | 72 | *p++ = 0xff; *p++ = 0x01; //Extension Renegotiation Info |
andrewboyson | 14:03a0b8fd6ddc | 73 | *p++ = 0x00; *p++ = 0x01; //1 bytes of "Renegotiation Info" extension data follows |
andrewboyson | 14:03a0b8fd6ddc | 74 | *p++ = 0x00; //length is zero, because this is a new connection |
andrewboyson | 14:03a0b8fd6ddc | 75 | backfillSize(p, pSize); |
andrewboyson | 10:e269fd7b9500 | 76 | |
andrewboyson | 14:03a0b8fd6ddc | 77 | *pp = p; |
andrewboyson | 14:03a0b8fd6ddc | 78 | } |
andrewboyson | 14:03a0b8fd6ddc | 79 | static void addHandshakeCertificate(uint8_t** pp) |
andrewboyson | 14:03a0b8fd6ddc | 80 | { |
andrewboyson | 14:03a0b8fd6ddc | 81 | uint8_t* p = *pp; |
andrewboyson | 14:03a0b8fd6ddc | 82 | |
andrewboyson | 14:03a0b8fd6ddc | 83 | *p++ = TLS_HANDSHAKE_CERTIFICATE; *p++ = 0x00; |
andrewboyson | 13:0a80b49a5e78 | 84 | addSize(&p, SerCerSize + 6); *p++ = 0x00; //Size of this handshake |
andrewboyson | 13:0a80b49a5e78 | 85 | addSize(&p, SerCerSize + 3); *p++ = 0x00; //Size of all certificates |
andrewboyson | 13:0a80b49a5e78 | 86 | addSize(&p, SerCerSize ); //Size of first certificate |
andrewboyson | 10:e269fd7b9500 | 87 | for (int i = 0; i < SerCerSize; i++) *p++ = SerCerData[i]; //Certificate |
andrewboyson | 10:e269fd7b9500 | 88 | |
andrewboyson | 14:03a0b8fd6ddc | 89 | *pp = p; |
andrewboyson | 14:03a0b8fd6ddc | 90 | } |
andrewboyson | 14:03a0b8fd6ddc | 91 | static void addHandshakeServerHelloDone(uint8_t** pp) |
andrewboyson | 14:03a0b8fd6ddc | 92 | { |
andrewboyson | 21:a6d6e26dd742 | 93 | if (TlsTrace) LogTime(" sending handshake server hello done\r\n"); |
andrewboyson | 14:03a0b8fd6ddc | 94 | uint8_t* p = *pp; |
andrewboyson | 10:e269fd7b9500 | 95 | |
andrewboyson | 14:03a0b8fd6ddc | 96 | *p++ = TLS_HANDSHAKE_SERVER_HELLO_DONE; *p++ = 0x00; |
andrewboyson | 14:03a0b8fd6ddc | 97 | addSize(&p, 0); |
andrewboyson | 14:03a0b8fd6ddc | 98 | |
andrewboyson | 14:03a0b8fd6ddc | 99 | *pp = p; |
andrewboyson | 10:e269fd7b9500 | 100 | } |
andrewboyson | 14:03a0b8fd6ddc | 101 | static void addHandshakeFinished(uint8_t** pp, struct TlsConnection* pConnection, struct TlsSession* pSession) |
andrewboyson | 10:e269fd7b9500 | 102 | { |
andrewboyson | 21:a6d6e26dd742 | 103 | if (TlsTrace) LogTime(" sending handshake finished\r\n"); |
andrewboyson | 14:03a0b8fd6ddc | 104 | uint8_t* p = *pp; |
andrewboyson | 10:e269fd7b9500 | 105 | |
andrewboyson | 18:e3cf22ba2a06 | 106 | TlsAes128CbcSha1EncryptStart(&p); |
andrewboyson | 15:4ddb73b5fea1 | 107 | |
andrewboyson | 16:7eeb5f6626ad | 108 | //Make the 'finished' handshake which is part of the payload to be encrypted |
andrewboyson | 15:4ddb73b5fea1 | 109 | *p++ = TLS_HANDSHAKE_FINISHED; |
andrewboyson | 15:4ddb73b5fea1 | 110 | *p++ = 0x00; |
andrewboyson | 15:4ddb73b5fea1 | 111 | *p++ = 0x00; |
andrewboyson | 17:93feb2a51d58 | 112 | *p++ = TLS_LENGTH_VERIFY; //Length 12 |
andrewboyson | 15:4ddb73b5fea1 | 113 | |
andrewboyson | 10:e269fd7b9500 | 114 | //Hash over all handshake payloads exchanged so far |
andrewboyson | 17:93feb2a51d58 | 115 | uint8_t hash[SHA256_HASH_SIZE]; |
andrewboyson | 10:e269fd7b9500 | 116 | Sha256Finish(&pConnection->handshakeSha, hash); |
andrewboyson | 10:e269fd7b9500 | 117 | |
andrewboyson | 10:e269fd7b9500 | 118 | //Make verify data |
andrewboyson | 15:4ddb73b5fea1 | 119 | TlsPrfServerFinished(pSession->masterSecret, hash, p); //Hash over all handshakes |
andrewboyson | 17:93feb2a51d58 | 120 | p += TLS_LENGTH_VERIFY; |
andrewboyson | 10:e269fd7b9500 | 121 | |
andrewboyson | 18:e3cf22ba2a06 | 122 | TlsAes128CbcSha1EncryptEnd(&p, pConnection, TLS_CONTENT_TYPE_HANDSHAKE); |
andrewboyson | 14:03a0b8fd6ddc | 123 | |
andrewboyson | 14:03a0b8fd6ddc | 124 | *pp = p; |
andrewboyson | 14:03a0b8fd6ddc | 125 | } |
andrewboyson | 14:03a0b8fd6ddc | 126 | static void addChangeCipher(uint8_t** pp, struct TlsConnection* pConnection) |
andrewboyson | 14:03a0b8fd6ddc | 127 | { |
andrewboyson | 21:a6d6e26dd742 | 128 | if (TlsTrace) LogTime(" sending change cipher\r\n"); |
andrewboyson | 14:03a0b8fd6ddc | 129 | uint8_t* p = *pp; |
andrewboyson | 14:03a0b8fd6ddc | 130 | |
andrewboyson | 14:03a0b8fd6ddc | 131 | *p++ = TLS_CONTENT_TYPE_CHANGE_CIPHER; //Content is change cipher |
andrewboyson | 14:03a0b8fd6ddc | 132 | *p++ = 0x03; *p++ = 0x03; //Legacy TLS version |
andrewboyson | 14:03a0b8fd6ddc | 133 | *p++ = 0x00; *p++ = 0x01; //Change cipher Length (2 bytes) |
andrewboyson | 14:03a0b8fd6ddc | 134 | *p++ = 0x01; //Change cipher message 1 |
andrewboyson | 10:e269fd7b9500 | 135 | |
andrewboyson | 14:03a0b8fd6ddc | 136 | //Record that all outgoing messages are now encrypted |
andrewboyson | 14:03a0b8fd6ddc | 137 | pConnection->serverEncrypted = true; |
andrewboyson | 14:03a0b8fd6ddc | 138 | pConnection->serverSequence = 0; |
andrewboyson | 14:03a0b8fd6ddc | 139 | |
andrewboyson | 14:03a0b8fd6ddc | 140 | *pp = p; |
andrewboyson | 14:03a0b8fd6ddc | 141 | } |
andrewboyson | 14:03a0b8fd6ddc | 142 | static void addAlert(uint8_t** pp, struct TlsConnection* pConnection, uint8_t level, uint8_t description) |
andrewboyson | 14:03a0b8fd6ddc | 143 | { |
andrewboyson | 21:a6d6e26dd742 | 144 | if (TlsTrace) LogTime(" sending alert\r\n"); |
andrewboyson | 14:03a0b8fd6ddc | 145 | Log (" - "); TlsLogAlertLevel(level); Log(": "); TlsLogAlertDescription(description); Log("\r\n"); |
andrewboyson | 14:03a0b8fd6ddc | 146 | |
andrewboyson | 14:03a0b8fd6ddc | 147 | uint8_t* p = *pp; |
andrewboyson | 14:03a0b8fd6ddc | 148 | |
andrewboyson | 14:03a0b8fd6ddc | 149 | *p++ = TLS_CONTENT_TYPE_ALERT; |
andrewboyson | 14:03a0b8fd6ddc | 150 | *p++ = 0x03; *p++ = 0x03; |
andrewboyson | 14:03a0b8fd6ddc | 151 | addSize(&p, 2); |
andrewboyson | 14:03a0b8fd6ddc | 152 | *p++ = level; |
andrewboyson | 14:03a0b8fd6ddc | 153 | *p++ = description; |
andrewboyson | 14:03a0b8fd6ddc | 154 | |
andrewboyson | 10:e269fd7b9500 | 155 | pConnection->serverSequence++; |
andrewboyson | 14:03a0b8fd6ddc | 156 | |
andrewboyson | 14:03a0b8fd6ddc | 157 | *pp = p; |
andrewboyson | 14:03a0b8fd6ddc | 158 | } |
andrewboyson | 14:03a0b8fd6ddc | 159 | static void sendServerHelloNew(struct TlsConnection* pConnection, struct TlsSession* pSession, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) |
andrewboyson | 14:03a0b8fd6ddc | 160 | { |
andrewboyson | 14:03a0b8fd6ddc | 161 | uint8_t* p = pWindow; |
andrewboyson | 14:03a0b8fd6ddc | 162 | |
andrewboyson | 14:03a0b8fd6ddc | 163 | addHandshakeStart (&p); |
andrewboyson | 14:03a0b8fd6ddc | 164 | addHandshakeServerHello (&p, pConnection); |
andrewboyson | 14:03a0b8fd6ddc | 165 | addHandshakeCertificate (&p); |
andrewboyson | 14:03a0b8fd6ddc | 166 | addHandshakeServerHelloDone(&p); |
andrewboyson | 14:03a0b8fd6ddc | 167 | addHandshakeEnd ( p, pConnection); |
andrewboyson | 14:03a0b8fd6ddc | 168 | |
andrewboyson | 10:e269fd7b9500 | 169 | *pWindowSize = p - pWindow; |
andrewboyson | 10:e269fd7b9500 | 170 | pConnection->serverPositionInStreamOffset = positionOfWindowInStream + *pWindowSize; |
andrewboyson | 10:e269fd7b9500 | 171 | } |
andrewboyson | 14:03a0b8fd6ddc | 172 | static void sendServerHelloResume(struct TlsConnection* pConnection, struct TlsSession* pSession, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) |
andrewboyson | 10:e269fd7b9500 | 173 | { |
andrewboyson | 10:e269fd7b9500 | 174 | uint8_t* p = pWindow; |
andrewboyson | 14:03a0b8fd6ddc | 175 | |
andrewboyson | 14:03a0b8fd6ddc | 176 | addHandshakeStart (&p); |
andrewboyson | 14:03a0b8fd6ddc | 177 | addHandshakeServerHello(&p, pConnection); |
andrewboyson | 14:03a0b8fd6ddc | 178 | addHandshakeEnd ( p, pConnection); |
andrewboyson | 10:e269fd7b9500 | 179 | |
andrewboyson | 19:f22327e8be7b | 180 | TlsPrfKeysAes128Sha1(pSession->masterSecret, pConnection->clientRandom, pConnection->serverRandom, pConnection->clientMacKey, |
andrewboyson | 19:f22327e8be7b | 181 | pConnection->serverMacKey, |
andrewboyson | 19:f22327e8be7b | 182 | pConnection->clientWriteKey, |
andrewboyson | 19:f22327e8be7b | 183 | pConnection->serverWriteKey); |
andrewboyson | 14:03a0b8fd6ddc | 184 | |
andrewboyson | 14:03a0b8fd6ddc | 185 | addChangeCipher (&p, pConnection); |
andrewboyson | 14:03a0b8fd6ddc | 186 | |
andrewboyson | 14:03a0b8fd6ddc | 187 | addHandshakeStart (&p); |
andrewboyson | 14:03a0b8fd6ddc | 188 | addHandshakeFinished (&p, pConnection, pSession); |
andrewboyson | 14:03a0b8fd6ddc | 189 | addHandshakeEnd ( p, pConnection); |
andrewboyson | 10:e269fd7b9500 | 190 | |
andrewboyson | 10:e269fd7b9500 | 191 | *pWindowSize = p - pWindow; |
andrewboyson | 14:03a0b8fd6ddc | 192 | pConnection->serverPositionInStreamOffset = positionOfWindowInStream + *pWindowSize; |
andrewboyson | 14:03a0b8fd6ddc | 193 | } |
andrewboyson | 14:03a0b8fd6ddc | 194 | static void sendServerChange(struct TlsConnection* pConnection, struct TlsSession* pSession, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) |
andrewboyson | 14:03a0b8fd6ddc | 195 | { |
andrewboyson | 14:03a0b8fd6ddc | 196 | uint8_t* p = pWindow; |
andrewboyson | 14:03a0b8fd6ddc | 197 | |
andrewboyson | 14:03a0b8fd6ddc | 198 | addChangeCipher(&p, pConnection); |
andrewboyson | 14:03a0b8fd6ddc | 199 | |
andrewboyson | 14:03a0b8fd6ddc | 200 | addHandshakeStart (&p); |
andrewboyson | 14:03a0b8fd6ddc | 201 | addHandshakeFinished(&p, pConnection, pSession); |
andrewboyson | 14:03a0b8fd6ddc | 202 | addHandshakeEnd ( p, pConnection); |
andrewboyson | 14:03a0b8fd6ddc | 203 | |
andrewboyson | 14:03a0b8fd6ddc | 204 | *pWindowSize = p - pWindow; |
andrewboyson | 14:03a0b8fd6ddc | 205 | pConnection->serverPositionInStreamOffset = positionOfWindowInStream + *pWindowSize; |
andrewboyson | 14:03a0b8fd6ddc | 206 | } |
andrewboyson | 14:03a0b8fd6ddc | 207 | static void sendFatal(uint8_t description, struct TlsConnection* pConnection, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) |
andrewboyson | 14:03a0b8fd6ddc | 208 | { |
andrewboyson | 14:03a0b8fd6ddc | 209 | uint8_t* p = pWindow; |
andrewboyson | 14:03a0b8fd6ddc | 210 | |
andrewboyson | 14:03a0b8fd6ddc | 211 | addAlert(&p, pConnection, TLS_ALERT_FATAL, description); |
andrewboyson | 14:03a0b8fd6ddc | 212 | |
andrewboyson | 14:03a0b8fd6ddc | 213 | *pWindowSize = p - pWindow; |
andrewboyson | 14:03a0b8fd6ddc | 214 | pConnection->serverPositionInStreamOffset = positionOfWindowInStream + *pWindowSize; |
andrewboyson | 10:e269fd7b9500 | 215 | } |
andrewboyson | 10:e269fd7b9500 | 216 | static bool sendContent(struct TlsConnection* pConnection, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) |
andrewboyson | 10:e269fd7b9500 | 217 | { |
andrewboyson | 10:e269fd7b9500 | 218 | //Start |
andrewboyson | 21:a6d6e26dd742 | 219 | if (TlsTrace) |
andrewboyson | 21:a6d6e26dd742 | 220 | { |
andrewboyson | 21:a6d6e26dd742 | 221 | LogTime(" adding application content\r\n"); |
andrewboyson | 21:a6d6e26dd742 | 222 | LogF("- available window size %d\r\n", *pWindowSize); |
andrewboyson | 21:a6d6e26dd742 | 223 | LogF("- position of window in stream %d\r\n", positionOfWindowInStream); |
andrewboyson | 21:a6d6e26dd742 | 224 | } |
andrewboyson | 10:e269fd7b9500 | 225 | uint8_t* p = pWindow; |
andrewboyson | 13:0a80b49a5e78 | 226 | *p++ = TLS_CONTENT_TYPE_APPLICATION; |
andrewboyson | 10:e269fd7b9500 | 227 | *p++ = 0x03; *p++ = 0x03; |
andrewboyson | 10:e269fd7b9500 | 228 | |
andrewboyson | 10:e269fd7b9500 | 229 | //Prepare a place to backfill the size |
andrewboyson | 10:e269fd7b9500 | 230 | uint8_t* pBackfillSize = p; |
andrewboyson | 10:e269fd7b9500 | 231 | *p++ = 0; *p++ = 0; |
andrewboyson | 10:e269fd7b9500 | 232 | |
andrewboyson | 18:e3cf22ba2a06 | 233 | TlsAes128CbcSha1EncryptStart(&p); |
andrewboyson | 10:e269fd7b9500 | 234 | |
andrewboyson | 10:e269fd7b9500 | 235 | //Add the plain payload |
andrewboyson | 18:e3cf22ba2a06 | 236 | int payloadSize = *pWindowSize - 5 - TLS_AES_128_CBC_SHA1_MAX_OVERHEAD; |
andrewboyson | 21:a6d6e26dd742 | 237 | if (TlsTrace) LogF("- available payload size %d\r\n", payloadSize); |
andrewboyson | 10:e269fd7b9500 | 238 | uint32_t positionOfPayloadInStream = positionOfWindowInStream - pConnection->serverPositionInStreamOffset; |
andrewboyson | 21:a6d6e26dd742 | 239 | if (TlsTrace) LogF("- position of payload in stream %d\r\n", positionOfPayloadInStream); |
andrewboyson | 16:7eeb5f6626ad | 240 | bool finished = HttpAdd(pConnection->id, &payloadSize, (char*)p, positionOfPayloadInStream); //Return whatever HTTP would be |
andrewboyson | 21:a6d6e26dd742 | 241 | if (TlsTrace) LogF("- resulting payload size %d\r\n", payloadSize); |
andrewboyson | 16:7eeb5f6626ad | 242 | p += payloadSize; |
andrewboyson | 10:e269fd7b9500 | 243 | |
andrewboyson | 18:e3cf22ba2a06 | 244 | TlsAes128CbcSha1EncryptEnd(&p, pConnection, TLS_CONTENT_TYPE_APPLICATION); |
andrewboyson | 10:e269fd7b9500 | 245 | |
andrewboyson | 10:e269fd7b9500 | 246 | //Backfill the size |
andrewboyson | 10:e269fd7b9500 | 247 | backfillSize(p, pBackfillSize); |
andrewboyson | 10:e269fd7b9500 | 248 | |
andrewboyson | 16:7eeb5f6626ad | 249 | //Finalise |
andrewboyson | 16:7eeb5f6626ad | 250 | pConnection->serverSequence++; |
andrewboyson | 10:e269fd7b9500 | 251 | *pWindowSize = p - pWindow; |
andrewboyson | 21:a6d6e26dd742 | 252 | if (TlsTrace) LogF("- resulting window size %d\r\n", *pWindowSize); |
andrewboyson | 16:7eeb5f6626ad | 253 | pConnection->serverPositionInStreamOffset += *pWindowSize - payloadSize; |
andrewboyson | 10:e269fd7b9500 | 254 | |
andrewboyson | 10:e269fd7b9500 | 255 | return finished; |
andrewboyson | 10:e269fd7b9500 | 256 | } |
andrewboyson | 10:e269fd7b9500 | 257 | bool TlsResponse(int connectionId, bool clientFinished, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) |
andrewboyson | 10:e269fd7b9500 | 258 | { |
andrewboyson | 10:e269fd7b9500 | 259 | struct TlsConnection* pConnection = TlsConnectionOrNull(connectionId); |
andrewboyson | 10:e269fd7b9500 | 260 | if (!pConnection) |
andrewboyson | 10:e269fd7b9500 | 261 | { |
andrewboyson | 10:e269fd7b9500 | 262 | *pWindowSize = 0; |
andrewboyson | 24:cb43290fc439 | 263 | return clientFinished; //Ignore empty connections in poll |
andrewboyson | 10:e269fd7b9500 | 264 | } |
andrewboyson | 10:e269fd7b9500 | 265 | |
andrewboyson | 10:e269fd7b9500 | 266 | if (!pConnection->sessionId) |
andrewboyson | 10:e269fd7b9500 | 267 | { |
andrewboyson | 10:e269fd7b9500 | 268 | *pWindowSize = 0; |
andrewboyson | 24:cb43290fc439 | 269 | return clientFinished; //Ignore empty sessions in poll |
andrewboyson | 10:e269fd7b9500 | 270 | } |
andrewboyson | 10:e269fd7b9500 | 271 | |
andrewboyson | 10:e269fd7b9500 | 272 | struct TlsSession* pSession = TlsSessionOrNull(pConnection->sessionId); |
andrewboyson | 10:e269fd7b9500 | 273 | if (!pSession) |
andrewboyson | 10:e269fd7b9500 | 274 | { |
andrewboyson | 23:e93d5529b7a6 | 275 | pConnection->toDo = DO_SEND_ALERT_INTERNAL_ERROR; //Abort invalid sessions |
andrewboyson | 23:e93d5529b7a6 | 276 | LogTimeF("TlsPoll - invalid session %u - sending internal error\r\n", pConnection->sessionId); |
andrewboyson | 10:e269fd7b9500 | 277 | } |
andrewboyson | 10:e269fd7b9500 | 278 | |
andrewboyson | 10:e269fd7b9500 | 279 | switch (pConnection->toDo) |
andrewboyson | 10:e269fd7b9500 | 280 | { |
andrewboyson | 10:e269fd7b9500 | 281 | case DO_WAIT_CLIENT_HELLO: |
andrewboyson | 10:e269fd7b9500 | 282 | case DO_WAIT_CLIENT_CHANGE: |
andrewboyson | 10:e269fd7b9500 | 283 | case DO_WAIT_DECRYPT_MASTER_SECRET: |
andrewboyson | 10:e269fd7b9500 | 284 | *pWindowSize = 0; |
andrewboyson | 10:e269fd7b9500 | 285 | if (clientFinished) return true; //The client hasn't made a request and never will so finish |
andrewboyson | 10:e269fd7b9500 | 286 | else return false; //The client hasn't made a request yet but it could. |
andrewboyson | 10:e269fd7b9500 | 287 | |
andrewboyson | 14:03a0b8fd6ddc | 288 | case DO_SEND_SERVER_HELLO_NEW: |
andrewboyson | 14:03a0b8fd6ddc | 289 | sendServerHelloNew(pConnection, pSession, pWindowSize, pWindow, positionOfWindowInStream); |
andrewboyson | 14:03a0b8fd6ddc | 290 | pConnection->toDo = DO_WAIT_CLIENT_CHANGE; |
andrewboyson | 14:03a0b8fd6ddc | 291 | return false; //Not finished |
andrewboyson | 14:03a0b8fd6ddc | 292 | |
andrewboyson | 14:03a0b8fd6ddc | 293 | case DO_SEND_SERVER_HELLO_RESUME: |
andrewboyson | 14:03a0b8fd6ddc | 294 | sendServerHelloResume(pConnection, pSession, pWindowSize, pWindow, positionOfWindowInStream); |
andrewboyson | 10:e269fd7b9500 | 295 | pConnection->toDo = DO_WAIT_CLIENT_CHANGE; |
andrewboyson | 10:e269fd7b9500 | 296 | return false; //Not finished |
andrewboyson | 10:e269fd7b9500 | 297 | |
andrewboyson | 10:e269fd7b9500 | 298 | case DO_SEND_SERVER_CHANGE: |
andrewboyson | 10:e269fd7b9500 | 299 | sendServerChange(pConnection, pSession, pWindowSize, pWindow, positionOfWindowInStream); |
andrewboyson | 10:e269fd7b9500 | 300 | pConnection->toDo = DO_APPLICATION; |
andrewboyson | 10:e269fd7b9500 | 301 | return false; |
andrewboyson | 10:e269fd7b9500 | 302 | |
andrewboyson | 10:e269fd7b9500 | 303 | case DO_APPLICATION: |
andrewboyson | 10:e269fd7b9500 | 304 | { |
andrewboyson | 10:e269fd7b9500 | 305 | int status = HttpPoll(connectionId, clientFinished); |
andrewboyson | 10:e269fd7b9500 | 306 | bool finished; |
andrewboyson | 10:e269fd7b9500 | 307 | switch (status) |
andrewboyson | 10:e269fd7b9500 | 308 | { |
andrewboyson | 10:e269fd7b9500 | 309 | case HTTP_WAIT: finished = false; *pWindowSize = 0; break; |
andrewboyson | 10:e269fd7b9500 | 310 | case HTTP_FINISHED: finished = true; *pWindowSize = 0; break; |
andrewboyson | 10:e269fd7b9500 | 311 | case HTTP_HAVE_SOMETHING_TO_SEND: finished = sendContent(pConnection, pWindowSize, pWindow, positionOfWindowInStream); break; |
andrewboyson | 10:e269fd7b9500 | 312 | } |
andrewboyson | 10:e269fd7b9500 | 313 | if (finished) pConnection->toDo = DO_WAIT_CLIENT_HELLO; |
andrewboyson | 10:e269fd7b9500 | 314 | return finished; |
andrewboyson | 10:e269fd7b9500 | 315 | } |
andrewboyson | 10:e269fd7b9500 | 316 | case DO_SEND_ALERT_ILLEGAL_PARAMETER: |
andrewboyson | 14:03a0b8fd6ddc | 317 | sendFatal(TLS_ALERT_ILLEGAL_PARAMETER, pConnection, pWindowSize, pWindow, positionOfWindowInStream); |
andrewboyson | 10:e269fd7b9500 | 318 | pConnection->toDo = DO_WAIT_CLIENT_HELLO; |
andrewboyson | 10:e269fd7b9500 | 319 | return true; //Finished |
andrewboyson | 10:e269fd7b9500 | 320 | |
andrewboyson | 10:e269fd7b9500 | 321 | case DO_SEND_ALERT_INTERNAL_ERROR: |
andrewboyson | 14:03a0b8fd6ddc | 322 | sendFatal(TLS_ALERT_INTERNAL_ERROR, pConnection, pWindowSize, pWindow, positionOfWindowInStream); |
andrewboyson | 10:e269fd7b9500 | 323 | pConnection->toDo = DO_WAIT_CLIENT_HELLO; |
andrewboyson | 10:e269fd7b9500 | 324 | return true; //Finished |
andrewboyson | 10:e269fd7b9500 | 325 | |
andrewboyson | 10:e269fd7b9500 | 326 | default: |
andrewboyson | 10:e269fd7b9500 | 327 | LogTimeF("TlsPoll - unspecified TLS state %d\r\n", pConnection->toDo); |
andrewboyson | 14:03a0b8fd6ddc | 328 | sendFatal(TLS_ALERT_INTERNAL_ERROR, pConnection, pWindowSize, pWindow, positionOfWindowInStream); //Internal error |
andrewboyson | 10:e269fd7b9500 | 329 | pConnection->toDo = DO_WAIT_CLIENT_HELLO; |
andrewboyson | 10:e269fd7b9500 | 330 | return true; //Finished |
andrewboyson | 10:e269fd7b9500 | 331 | } |
andrewboyson | 10:e269fd7b9500 | 332 | } |