A simple library to support serving https.
Dependents: oldheating gps motorhome heating
tls/tls-response.c@15:4ddb73b5fea1, 2019-10-04 (annotated)
- Committer:
- andrewboyson
- Date:
- Fri Oct 04 18:25:55 2019 +0000
- Revision:
- 15:4ddb73b5fea1
- Parent:
- 14:03a0b8fd6ddc
- Child:
- 16:7eeb5f6626ad
Tidied up the MAC padding and encryption routines
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
andrewboyson | 10:e269fd7b9500 | 1 | #include "tls-defs.h" |
andrewboyson | 10:e269fd7b9500 | 2 | #include "tls-connection.h" |
andrewboyson | 10:e269fd7b9500 | 3 | #include "tls-session.h" |
andrewboyson | 10:e269fd7b9500 | 4 | #include "tls-log.h" |
andrewboyson | 10:e269fd7b9500 | 5 | #include "tls-prf.h" |
andrewboyson | 10:e269fd7b9500 | 6 | #include "ser-cer.h" |
andrewboyson | 10:e269fd7b9500 | 7 | #include "pri-key.h" |
andrewboyson | 10:e269fd7b9500 | 8 | #include "log.h" |
andrewboyson | 10:e269fd7b9500 | 9 | #include "aes128.h" |
andrewboyson | 10:e269fd7b9500 | 10 | #include "random.h" |
andrewboyson | 10:e269fd7b9500 | 11 | #include "sha1.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 | 15:4ddb73b5fea1 | 28 | |
andrewboyson | 15:4ddb73b5fea1 | 29 | static uint8_t* encryptIvPointer; |
andrewboyson | 15:4ddb73b5fea1 | 30 | static uint8_t* encryptPayloadPointer; |
andrewboyson | 15:4ddb73b5fea1 | 31 | static int encryptPayloadSize; |
andrewboyson | 15:4ddb73b5fea1 | 32 | static void encryptAddIv(uint8_t** pp) |
andrewboyson | 15:4ddb73b5fea1 | 33 | { |
andrewboyson | 15:4ddb73b5fea1 | 34 | uint8_t* p = *pp; |
andrewboyson | 15:4ddb73b5fea1 | 35 | |
andrewboyson | 15:4ddb73b5fea1 | 36 | //Add the IV |
andrewboyson | 15:4ddb73b5fea1 | 37 | encryptIvPointer = p; |
andrewboyson | 15:4ddb73b5fea1 | 38 | for (int i = 0; i < AES_BLOCKLEN; i++) *p++ = RandomGetByte(); |
andrewboyson | 15:4ddb73b5fea1 | 39 | |
andrewboyson | 15:4ddb73b5fea1 | 40 | *pp = p; |
andrewboyson | 15:4ddb73b5fea1 | 41 | } |
andrewboyson | 15:4ddb73b5fea1 | 42 | static void encryptAddMac(uint8_t** pp, struct TlsConnection* pConnection, uint8_t contentType) |
andrewboyson | 15:4ddb73b5fea1 | 43 | { |
andrewboyson | 15:4ddb73b5fea1 | 44 | uint8_t* p = *pp; |
andrewboyson | 15:4ddb73b5fea1 | 45 | |
andrewboyson | 15:4ddb73b5fea1 | 46 | //Add the MAC |
andrewboyson | 15:4ddb73b5fea1 | 47 | TlsMacSha1(TLS_KEY_SIZE_MAC, |
andrewboyson | 15:4ddb73b5fea1 | 48 | pConnection->serverMacKey, |
andrewboyson | 15:4ddb73b5fea1 | 49 | pConnection->serverSequence, |
andrewboyson | 15:4ddb73b5fea1 | 50 | contentType, |
andrewboyson | 15:4ddb73b5fea1 | 51 | 0x03, |
andrewboyson | 15:4ddb73b5fea1 | 52 | 0x03, |
andrewboyson | 15:4ddb73b5fea1 | 53 | encryptPayloadSize, |
andrewboyson | 15:4ddb73b5fea1 | 54 | encryptPayloadPointer, |
andrewboyson | 15:4ddb73b5fea1 | 55 | p); |
andrewboyson | 15:4ddb73b5fea1 | 56 | p += SHA1_HASH_SIZE; |
andrewboyson | 15:4ddb73b5fea1 | 57 | |
andrewboyson | 15:4ddb73b5fea1 | 58 | *pp = p; |
andrewboyson | 15:4ddb73b5fea1 | 59 | } |
andrewboyson | 15:4ddb73b5fea1 | 60 | |
andrewboyson | 15:4ddb73b5fea1 | 61 | static void encryptAddPadding(uint8_t** pp) |
andrewboyson | 15:4ddb73b5fea1 | 62 | { |
andrewboyson | 15:4ddb73b5fea1 | 63 | uint8_t* p = *pp; |
andrewboyson | 15:4ddb73b5fea1 | 64 | |
andrewboyson | 15:4ddb73b5fea1 | 65 | int paddingSize = AES_BLOCKLEN - 1 - (encryptPayloadSize + SHA1_HASH_SIZE + 1 - 1) % AES_BLOCKLEN; |
andrewboyson | 15:4ddb73b5fea1 | 66 | LogF("- padding size %d\r\n", paddingSize); |
andrewboyson | 15:4ddb73b5fea1 | 67 | for (int i = 0; i < paddingSize; i++) *p++ = paddingSize; |
andrewboyson | 15:4ddb73b5fea1 | 68 | |
andrewboyson | 15:4ddb73b5fea1 | 69 | *p++ = paddingSize; |
andrewboyson | 15:4ddb73b5fea1 | 70 | |
andrewboyson | 15:4ddb73b5fea1 | 71 | *pp = p; |
andrewboyson | 15:4ddb73b5fea1 | 72 | } |
andrewboyson | 15:4ddb73b5fea1 | 73 | static void encryptPayload(uint8_t* p, struct TlsConnection* pConnection) |
andrewboyson | 15:4ddb73b5fea1 | 74 | { |
andrewboyson | 15:4ddb73b5fea1 | 75 | //Encrypt payload + mac + padding |
andrewboyson | 15:4ddb73b5fea1 | 76 | struct AES_ctx ctx; |
andrewboyson | 15:4ddb73b5fea1 | 77 | AES_init_ctx_iv(&ctx, pConnection->serverWriteKey, encryptIvPointer); |
andrewboyson | 15:4ddb73b5fea1 | 78 | AES_CBC_encrypt_buffer(&ctx, encryptPayloadPointer, p - encryptPayloadPointer);} |
andrewboyson | 15:4ddb73b5fea1 | 79 | |
andrewboyson | 15:4ddb73b5fea1 | 80 | |
andrewboyson | 14:03a0b8fd6ddc | 81 | static uint8_t* pHandshakeSize; |
andrewboyson | 14:03a0b8fd6ddc | 82 | static uint8_t* pHandshakePayload; |
andrewboyson | 14:03a0b8fd6ddc | 83 | static void addHandshakeStart(uint8_t** pp) |
andrewboyson | 10:e269fd7b9500 | 84 | { |
andrewboyson | 14:03a0b8fd6ddc | 85 | uint8_t* p = *pp; |
andrewboyson | 14:03a0b8fd6ddc | 86 | |
andrewboyson | 14:03a0b8fd6ddc | 87 | *p++ = TLS_CONTENT_TYPE_HANDSHAKE; |
andrewboyson | 14:03a0b8fd6ddc | 88 | *p++ = 0x03; *p++ = 0x03; |
andrewboyson | 14:03a0b8fd6ddc | 89 | pHandshakeSize = p; //Store the position to backfill the handshake size |
andrewboyson | 14:03a0b8fd6ddc | 90 | p += 2; //Leave room to backfill the handshake size |
andrewboyson | 14:03a0b8fd6ddc | 91 | pHandshakePayload = p; //Record the position of the handshake payload to later calculate the hash |
andrewboyson | 10:e269fd7b9500 | 92 | |
andrewboyson | 14:03a0b8fd6ddc | 93 | *pp = p; |
andrewboyson | 14:03a0b8fd6ddc | 94 | } |
andrewboyson | 14:03a0b8fd6ddc | 95 | static void addHandshakeEnd(uint8_t* p, struct TlsConnection* pConnection) |
andrewboyson | 14:03a0b8fd6ddc | 96 | { |
andrewboyson | 14:03a0b8fd6ddc | 97 | backfillSize(p, pHandshakeSize); |
andrewboyson | 14:03a0b8fd6ddc | 98 | Sha256Add(&pConnection->handshakeSha, pHandshakePayload, p - pHandshakePayload); //Add the handshake hash |
andrewboyson | 14:03a0b8fd6ddc | 99 | pConnection->serverSequence++; |
andrewboyson | 14:03a0b8fd6ddc | 100 | } |
andrewboyson | 14:03a0b8fd6ddc | 101 | static void addHandshakeServerHello(uint8_t** pp, struct TlsConnection* pConnection) |
andrewboyson | 14:03a0b8fd6ddc | 102 | { |
andrewboyson | 14:03a0b8fd6ddc | 103 | Log(" sending handshake server hello\r\n"); |
andrewboyson | 14:03a0b8fd6ddc | 104 | uint8_t* p = *pp; |
andrewboyson | 14:03a0b8fd6ddc | 105 | |
andrewboyson | 14:03a0b8fd6ddc | 106 | *p++ = TLS_HANDSHAKE_SERVER_HELLO; |
andrewboyson | 10:e269fd7b9500 | 107 | *p++ = 0x00; |
andrewboyson | 14:03a0b8fd6ddc | 108 | uint8_t* pSize = p; |
andrewboyson | 14:03a0b8fd6ddc | 109 | p += 2; |
andrewboyson | 14:03a0b8fd6ddc | 110 | *p++ = 0x03; *p++ = 0x03; |
andrewboyson | 10:e269fd7b9500 | 111 | for (int i = 0; i < 32; i++) |
andrewboyson | 10:e269fd7b9500 | 112 | { |
andrewboyson | 10:e269fd7b9500 | 113 | uint8_t r = RandomGetByte(); |
andrewboyson | 10:e269fd7b9500 | 114 | pConnection->serverRandom[i] = r; |
andrewboyson | 14:03a0b8fd6ddc | 115 | *p++ = r; //32 bit random number |
andrewboyson | 10:e269fd7b9500 | 116 | } |
andrewboyson | 14:03a0b8fd6ddc | 117 | *p++ = 0x04; //SessionId length 4 |
andrewboyson | 14:03a0b8fd6ddc | 118 | *p++ = pConnection->sessionId >> 24; //Session id |
andrewboyson | 14:03a0b8fd6ddc | 119 | *p++ = pConnection->sessionId >> 16; //Session id |
andrewboyson | 14:03a0b8fd6ddc | 120 | *p++ = pConnection->sessionId >> 8; //Session id |
andrewboyson | 14:03a0b8fd6ddc | 121 | *p++ = pConnection->sessionId >> 0; //Session id |
andrewboyson | 14:03a0b8fd6ddc | 122 | *p++ = 0x00; *p++ = 0x2f; //Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) |
andrewboyson | 14:03a0b8fd6ddc | 123 | *p++ = 0x00; //Compression method none |
andrewboyson | 14:03a0b8fd6ddc | 124 | *p++ = 0x00; *p++ = 0x05; //Extensions length (2 bytes) 5 bytes |
andrewboyson | 14:03a0b8fd6ddc | 125 | *p++ = 0xff; *p++ = 0x01; //Extension Renegotiation Info |
andrewboyson | 14:03a0b8fd6ddc | 126 | *p++ = 0x00; *p++ = 0x01; //1 bytes of "Renegotiation Info" extension data follows |
andrewboyson | 14:03a0b8fd6ddc | 127 | *p++ = 0x00; //length is zero, because this is a new connection |
andrewboyson | 14:03a0b8fd6ddc | 128 | backfillSize(p, pSize); |
andrewboyson | 10:e269fd7b9500 | 129 | |
andrewboyson | 14:03a0b8fd6ddc | 130 | *pp = p; |
andrewboyson | 14:03a0b8fd6ddc | 131 | } |
andrewboyson | 14:03a0b8fd6ddc | 132 | static void addHandshakeCertificate(uint8_t** pp) |
andrewboyson | 14:03a0b8fd6ddc | 133 | { |
andrewboyson | 14:03a0b8fd6ddc | 134 | uint8_t* p = *pp; |
andrewboyson | 14:03a0b8fd6ddc | 135 | |
andrewboyson | 14:03a0b8fd6ddc | 136 | *p++ = TLS_HANDSHAKE_CERTIFICATE; *p++ = 0x00; |
andrewboyson | 13:0a80b49a5e78 | 137 | addSize(&p, SerCerSize + 6); *p++ = 0x00; //Size of this handshake |
andrewboyson | 13:0a80b49a5e78 | 138 | addSize(&p, SerCerSize + 3); *p++ = 0x00; //Size of all certificates |
andrewboyson | 13:0a80b49a5e78 | 139 | addSize(&p, SerCerSize ); //Size of first certificate |
andrewboyson | 10:e269fd7b9500 | 140 | for (int i = 0; i < SerCerSize; i++) *p++ = SerCerData[i]; //Certificate |
andrewboyson | 10:e269fd7b9500 | 141 | |
andrewboyson | 14:03a0b8fd6ddc | 142 | *pp = p; |
andrewboyson | 14:03a0b8fd6ddc | 143 | } |
andrewboyson | 14:03a0b8fd6ddc | 144 | static void addHandshakeServerHelloDone(uint8_t** pp) |
andrewboyson | 14:03a0b8fd6ddc | 145 | { |
andrewboyson | 14:03a0b8fd6ddc | 146 | LogTime(" sending handshake server hello done\r\n"); |
andrewboyson | 14:03a0b8fd6ddc | 147 | uint8_t* p = *pp; |
andrewboyson | 10:e269fd7b9500 | 148 | |
andrewboyson | 14:03a0b8fd6ddc | 149 | *p++ = TLS_HANDSHAKE_SERVER_HELLO_DONE; *p++ = 0x00; |
andrewboyson | 14:03a0b8fd6ddc | 150 | addSize(&p, 0); |
andrewboyson | 14:03a0b8fd6ddc | 151 | |
andrewboyson | 14:03a0b8fd6ddc | 152 | *pp = p; |
andrewboyson | 10:e269fd7b9500 | 153 | } |
andrewboyson | 14:03a0b8fd6ddc | 154 | static void addHandshakeFinished(uint8_t** pp, struct TlsConnection* pConnection, struct TlsSession* pSession) |
andrewboyson | 10:e269fd7b9500 | 155 | { |
andrewboyson | 14:03a0b8fd6ddc | 156 | LogTime(" sending handshake finished\r\n"); |
andrewboyson | 14:03a0b8fd6ddc | 157 | uint8_t* p = *pp; |
andrewboyson | 10:e269fd7b9500 | 158 | |
andrewboyson | 15:4ddb73b5fea1 | 159 | encryptAddIv(&p); |
andrewboyson | 15:4ddb73b5fea1 | 160 | encryptPayloadPointer = p; |
andrewboyson | 15:4ddb73b5fea1 | 161 | encryptPayloadSize = 16; |
andrewboyson | 15:4ddb73b5fea1 | 162 | |
andrewboyson | 15:4ddb73b5fea1 | 163 | //Make the 'finished' handshake which is the payload to be encrypted |
andrewboyson | 15:4ddb73b5fea1 | 164 | *p++ = TLS_HANDSHAKE_FINISHED; |
andrewboyson | 15:4ddb73b5fea1 | 165 | *p++ = 0x00; |
andrewboyson | 15:4ddb73b5fea1 | 166 | *p++ = 0x00; |
andrewboyson | 15:4ddb73b5fea1 | 167 | *p++ = 0x0c; //Length 12 |
andrewboyson | 15:4ddb73b5fea1 | 168 | |
andrewboyson | 10:e269fd7b9500 | 169 | //Hash over all handshake payloads exchanged so far |
andrewboyson | 10:e269fd7b9500 | 170 | uint8_t hash[32]; |
andrewboyson | 10:e269fd7b9500 | 171 | Sha256Finish(&pConnection->handshakeSha, hash); |
andrewboyson | 10:e269fd7b9500 | 172 | |
andrewboyson | 10:e269fd7b9500 | 173 | //Make verify data |
andrewboyson | 15:4ddb73b5fea1 | 174 | TlsPrfServerFinished(pSession->masterSecret, hash, p); //Hash over all handshakes |
andrewboyson | 15:4ddb73b5fea1 | 175 | p += 12; |
andrewboyson | 10:e269fd7b9500 | 176 | |
andrewboyson | 15:4ddb73b5fea1 | 177 | encryptAddMac (&p, pConnection, TLS_CONTENT_TYPE_HANDSHAKE); |
andrewboyson | 15:4ddb73b5fea1 | 178 | encryptAddPadding(&p); |
andrewboyson | 15:4ddb73b5fea1 | 179 | encryptPayload ( p, pConnection); |
andrewboyson | 14:03a0b8fd6ddc | 180 | |
andrewboyson | 14:03a0b8fd6ddc | 181 | *pp = p; |
andrewboyson | 14:03a0b8fd6ddc | 182 | } |
andrewboyson | 14:03a0b8fd6ddc | 183 | static void addChangeCipher(uint8_t** pp, struct TlsConnection* pConnection) |
andrewboyson | 14:03a0b8fd6ddc | 184 | { |
andrewboyson | 14:03a0b8fd6ddc | 185 | LogTime(" sending change cipher\r\n"); |
andrewboyson | 14:03a0b8fd6ddc | 186 | uint8_t* p = *pp; |
andrewboyson | 14:03a0b8fd6ddc | 187 | |
andrewboyson | 14:03a0b8fd6ddc | 188 | *p++ = TLS_CONTENT_TYPE_CHANGE_CIPHER; //Content is change cipher |
andrewboyson | 14:03a0b8fd6ddc | 189 | *p++ = 0x03; *p++ = 0x03; //Legacy TLS version |
andrewboyson | 14:03a0b8fd6ddc | 190 | *p++ = 0x00; *p++ = 0x01; //Change cipher Length (2 bytes) |
andrewboyson | 14:03a0b8fd6ddc | 191 | *p++ = 0x01; //Change cipher message 1 |
andrewboyson | 10:e269fd7b9500 | 192 | |
andrewboyson | 14:03a0b8fd6ddc | 193 | //Record that all outgoing messages are now encrypted |
andrewboyson | 14:03a0b8fd6ddc | 194 | pConnection->serverEncrypted = true; |
andrewboyson | 14:03a0b8fd6ddc | 195 | pConnection->serverSequence = 0; |
andrewboyson | 14:03a0b8fd6ddc | 196 | |
andrewboyson | 14:03a0b8fd6ddc | 197 | *pp = p; |
andrewboyson | 14:03a0b8fd6ddc | 198 | } |
andrewboyson | 14:03a0b8fd6ddc | 199 | static void addAlert(uint8_t** pp, struct TlsConnection* pConnection, uint8_t level, uint8_t description) |
andrewboyson | 14:03a0b8fd6ddc | 200 | { |
andrewboyson | 14:03a0b8fd6ddc | 201 | LogTime(" sending alert\r\n"); |
andrewboyson | 14:03a0b8fd6ddc | 202 | Log (" - "); TlsLogAlertLevel(level); Log(": "); TlsLogAlertDescription(description); Log("\r\n"); |
andrewboyson | 14:03a0b8fd6ddc | 203 | |
andrewboyson | 14:03a0b8fd6ddc | 204 | uint8_t* p = *pp; |
andrewboyson | 14:03a0b8fd6ddc | 205 | |
andrewboyson | 14:03a0b8fd6ddc | 206 | *p++ = TLS_CONTENT_TYPE_ALERT; |
andrewboyson | 14:03a0b8fd6ddc | 207 | *p++ = 0x03; *p++ = 0x03; |
andrewboyson | 14:03a0b8fd6ddc | 208 | addSize(&p, 2); |
andrewboyson | 14:03a0b8fd6ddc | 209 | *p++ = level; |
andrewboyson | 14:03a0b8fd6ddc | 210 | *p++ = description; |
andrewboyson | 14:03a0b8fd6ddc | 211 | |
andrewboyson | 10:e269fd7b9500 | 212 | pConnection->serverSequence++; |
andrewboyson | 14:03a0b8fd6ddc | 213 | |
andrewboyson | 14:03a0b8fd6ddc | 214 | *pp = p; |
andrewboyson | 14:03a0b8fd6ddc | 215 | } |
andrewboyson | 14:03a0b8fd6ddc | 216 | static void sendServerHelloNew(struct TlsConnection* pConnection, struct TlsSession* pSession, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) |
andrewboyson | 14:03a0b8fd6ddc | 217 | { |
andrewboyson | 14:03a0b8fd6ddc | 218 | uint8_t* p = pWindow; |
andrewboyson | 14:03a0b8fd6ddc | 219 | |
andrewboyson | 14:03a0b8fd6ddc | 220 | addHandshakeStart (&p); |
andrewboyson | 14:03a0b8fd6ddc | 221 | addHandshakeServerHello (&p, pConnection); |
andrewboyson | 14:03a0b8fd6ddc | 222 | addHandshakeCertificate (&p); |
andrewboyson | 14:03a0b8fd6ddc | 223 | addHandshakeServerHelloDone(&p); |
andrewboyson | 14:03a0b8fd6ddc | 224 | addHandshakeEnd ( p, pConnection); |
andrewboyson | 14:03a0b8fd6ddc | 225 | |
andrewboyson | 10:e269fd7b9500 | 226 | *pWindowSize = p - pWindow; |
andrewboyson | 10:e269fd7b9500 | 227 | pConnection->serverPositionInStreamOffset = positionOfWindowInStream + *pWindowSize; |
andrewboyson | 10:e269fd7b9500 | 228 | } |
andrewboyson | 14:03a0b8fd6ddc | 229 | static void sendServerHelloResume(struct TlsConnection* pConnection, struct TlsSession* pSession, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) |
andrewboyson | 10:e269fd7b9500 | 230 | { |
andrewboyson | 10:e269fd7b9500 | 231 | uint8_t* p = pWindow; |
andrewboyson | 14:03a0b8fd6ddc | 232 | |
andrewboyson | 14:03a0b8fd6ddc | 233 | addHandshakeStart (&p); |
andrewboyson | 14:03a0b8fd6ddc | 234 | addHandshakeServerHello(&p, pConnection); |
andrewboyson | 14:03a0b8fd6ddc | 235 | addHandshakeEnd ( p, pConnection); |
andrewboyson | 10:e269fd7b9500 | 236 | |
andrewboyson | 14:03a0b8fd6ddc | 237 | TlsPrfKeys (pSession->masterSecret, pConnection->clientRandom, pConnection->serverRandom, pConnection->clientMacKey, |
andrewboyson | 14:03a0b8fd6ddc | 238 | pConnection->serverMacKey, |
andrewboyson | 14:03a0b8fd6ddc | 239 | pConnection->clientWriteKey, |
andrewboyson | 14:03a0b8fd6ddc | 240 | pConnection->serverWriteKey); |
andrewboyson | 14:03a0b8fd6ddc | 241 | |
andrewboyson | 14:03a0b8fd6ddc | 242 | addChangeCipher (&p, pConnection); |
andrewboyson | 14:03a0b8fd6ddc | 243 | |
andrewboyson | 14:03a0b8fd6ddc | 244 | addHandshakeStart (&p); |
andrewboyson | 14:03a0b8fd6ddc | 245 | addHandshakeFinished (&p, pConnection, pSession); |
andrewboyson | 14:03a0b8fd6ddc | 246 | addHandshakeEnd ( p, pConnection); |
andrewboyson | 10:e269fd7b9500 | 247 | |
andrewboyson | 10:e269fd7b9500 | 248 | *pWindowSize = p - pWindow; |
andrewboyson | 14:03a0b8fd6ddc | 249 | pConnection->serverPositionInStreamOffset = positionOfWindowInStream + *pWindowSize; |
andrewboyson | 14:03a0b8fd6ddc | 250 | } |
andrewboyson | 14:03a0b8fd6ddc | 251 | static void sendServerChange(struct TlsConnection* pConnection, struct TlsSession* pSession, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) |
andrewboyson | 14:03a0b8fd6ddc | 252 | { |
andrewboyson | 14:03a0b8fd6ddc | 253 | uint8_t* p = pWindow; |
andrewboyson | 14:03a0b8fd6ddc | 254 | |
andrewboyson | 14:03a0b8fd6ddc | 255 | addChangeCipher(&p, pConnection); |
andrewboyson | 14:03a0b8fd6ddc | 256 | |
andrewboyson | 14:03a0b8fd6ddc | 257 | addHandshakeStart (&p); |
andrewboyson | 14:03a0b8fd6ddc | 258 | addHandshakeFinished(&p, pConnection, pSession); |
andrewboyson | 14:03a0b8fd6ddc | 259 | addHandshakeEnd ( p, pConnection); |
andrewboyson | 14:03a0b8fd6ddc | 260 | |
andrewboyson | 14:03a0b8fd6ddc | 261 | *pWindowSize = p - pWindow; |
andrewboyson | 14:03a0b8fd6ddc | 262 | pConnection->serverPositionInStreamOffset = positionOfWindowInStream + *pWindowSize; |
andrewboyson | 14:03a0b8fd6ddc | 263 | } |
andrewboyson | 14:03a0b8fd6ddc | 264 | static void sendFatal(uint8_t description, struct TlsConnection* pConnection, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) |
andrewboyson | 14:03a0b8fd6ddc | 265 | { |
andrewboyson | 14:03a0b8fd6ddc | 266 | uint8_t* p = pWindow; |
andrewboyson | 14:03a0b8fd6ddc | 267 | |
andrewboyson | 14:03a0b8fd6ddc | 268 | addAlert(&p, pConnection, TLS_ALERT_FATAL, description); |
andrewboyson | 14:03a0b8fd6ddc | 269 | |
andrewboyson | 14:03a0b8fd6ddc | 270 | *pWindowSize = p - pWindow; |
andrewboyson | 14:03a0b8fd6ddc | 271 | pConnection->serverPositionInStreamOffset = positionOfWindowInStream + *pWindowSize; |
andrewboyson | 10:e269fd7b9500 | 272 | } |
andrewboyson | 10:e269fd7b9500 | 273 | static bool sendContent(struct TlsConnection* pConnection, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) |
andrewboyson | 10:e269fd7b9500 | 274 | { |
andrewboyson | 10:e269fd7b9500 | 275 | /* |
andrewboyson | 10:e269fd7b9500 | 276 | content: |
andrewboyson | 10:e269fd7b9500 | 277 | contentType * 1 |
andrewboyson | 10:e269fd7b9500 | 278 | version * 2 |
andrewboyson | 10:e269fd7b9500 | 279 | length * 2 |
andrewboyson | 10:e269fd7b9500 | 280 | iv * AES_BLOCKLEN (16) |
andrewboyson | 10:e269fd7b9500 | 281 | message: |
andrewboyson | 10:e269fd7b9500 | 282 | payload * payloadLength |
andrewboyson | 10:e269fd7b9500 | 283 | mac * SHA1_HASH_SIZE (20) |
andrewboyson | 10:e269fd7b9500 | 284 | padding * 0 to AES_BLOCKLEN - 1 (0 to 15) |
andrewboyson | 10:e269fd7b9500 | 285 | paddingLength * 1 |
andrewboyson | 10:e269fd7b9500 | 286 | */ |
andrewboyson | 10:e269fd7b9500 | 287 | #define CONTENT_MAX_OVERHEAD (5 + AES_BLOCKLEN + SHA1_HASH_SIZE + AES_BLOCKLEN - 1 + 1) |
andrewboyson | 10:e269fd7b9500 | 288 | |
andrewboyson | 10:e269fd7b9500 | 289 | //Start |
andrewboyson | 10:e269fd7b9500 | 290 | LogTime(" adding application content\r\n"); |
andrewboyson | 10:e269fd7b9500 | 291 | LogF("- available window size %d\r\n", *pWindowSize); |
andrewboyson | 10:e269fd7b9500 | 292 | LogF("- position of window in stream %d\r\n", positionOfWindowInStream); |
andrewboyson | 10:e269fd7b9500 | 293 | uint8_t* p = pWindow; |
andrewboyson | 13:0a80b49a5e78 | 294 | *p++ = TLS_CONTENT_TYPE_APPLICATION; |
andrewboyson | 10:e269fd7b9500 | 295 | *p++ = 0x03; *p++ = 0x03; |
andrewboyson | 10:e269fd7b9500 | 296 | |
andrewboyson | 10:e269fd7b9500 | 297 | //Prepare a place to backfill the size |
andrewboyson | 10:e269fd7b9500 | 298 | uint8_t* pBackfillSize = p; |
andrewboyson | 10:e269fd7b9500 | 299 | *p++ = 0; *p++ = 0; |
andrewboyson | 10:e269fd7b9500 | 300 | |
andrewboyson | 15:4ddb73b5fea1 | 301 | encryptAddIv(&p); |
andrewboyson | 10:e269fd7b9500 | 302 | |
andrewboyson | 10:e269fd7b9500 | 303 | //Add the plain payload |
andrewboyson | 15:4ddb73b5fea1 | 304 | encryptPayloadPointer = p; |
andrewboyson | 15:4ddb73b5fea1 | 305 | encryptPayloadSize = *pWindowSize - CONTENT_MAX_OVERHEAD; |
andrewboyson | 15:4ddb73b5fea1 | 306 | LogF("- available payload size %d\r\n", encryptPayloadSize); |
andrewboyson | 10:e269fd7b9500 | 307 | uint32_t positionOfPayloadInStream = positionOfWindowInStream - pConnection->serverPositionInStreamOffset; |
andrewboyson | 10:e269fd7b9500 | 308 | LogF("- position of payload in stream %d\r\n", positionOfPayloadInStream); |
andrewboyson | 15:4ddb73b5fea1 | 309 | bool finished = HttpAdd(pConnection->id, &encryptPayloadSize, (char*)p, positionOfPayloadInStream); //Return whatever HTTP would be |
andrewboyson | 15:4ddb73b5fea1 | 310 | LogF("- resulting payload size %d\r\n", encryptPayloadSize); |
andrewboyson | 15:4ddb73b5fea1 | 311 | p += encryptPayloadSize; |
andrewboyson | 10:e269fd7b9500 | 312 | |
andrewboyson | 15:4ddb73b5fea1 | 313 | encryptAddMac (&p, pConnection, TLS_CONTENT_TYPE_APPLICATION); |
andrewboyson | 15:4ddb73b5fea1 | 314 | encryptAddPadding(&p); |
andrewboyson | 10:e269fd7b9500 | 315 | |
andrewboyson | 10:e269fd7b9500 | 316 | //Backfill the size |
andrewboyson | 10:e269fd7b9500 | 317 | backfillSize(p, pBackfillSize); |
andrewboyson | 10:e269fd7b9500 | 318 | |
andrewboyson | 10:e269fd7b9500 | 319 | //Calculate the resulting window size |
andrewboyson | 10:e269fd7b9500 | 320 | *pWindowSize = p - pWindow; |
andrewboyson | 10:e269fd7b9500 | 321 | LogF("- resulting window size %d\r\n", *pWindowSize); |
andrewboyson | 10:e269fd7b9500 | 322 | |
andrewboyson | 10:e269fd7b9500 | 323 | //Log the plain content |
andrewboyson | 10:e269fd7b9500 | 324 | Log("- plain content\r\n"); LogBytesAsHex(pWindow, *pWindowSize); Log("\r\n"); |
andrewboyson | 10:e269fd7b9500 | 325 | |
andrewboyson | 15:4ddb73b5fea1 | 326 | encryptPayload(p, pConnection); |
andrewboyson | 10:e269fd7b9500 | 327 | |
andrewboyson | 10:e269fd7b9500 | 328 | //Finalise |
andrewboyson | 10:e269fd7b9500 | 329 | pConnection->serverSequence++; |
andrewboyson | 15:4ddb73b5fea1 | 330 | pConnection->serverPositionInStreamOffset += *pWindowSize - encryptPayloadSize; |
andrewboyson | 10:e269fd7b9500 | 331 | |
andrewboyson | 10:e269fd7b9500 | 332 | return finished; |
andrewboyson | 10:e269fd7b9500 | 333 | } |
andrewboyson | 10:e269fd7b9500 | 334 | bool TlsResponse(int connectionId, bool clientFinished, int* pWindowSize, uint8_t* pWindow, uint32_t positionOfWindowInStream) |
andrewboyson | 10:e269fd7b9500 | 335 | { |
andrewboyson | 10:e269fd7b9500 | 336 | struct TlsConnection* pConnection = TlsConnectionOrNull(connectionId); |
andrewboyson | 10:e269fd7b9500 | 337 | if (!pConnection) |
andrewboyson | 10:e269fd7b9500 | 338 | { |
andrewboyson | 10:e269fd7b9500 | 339 | *pWindowSize = 0; |
andrewboyson | 10:e269fd7b9500 | 340 | return false; |
andrewboyson | 10:e269fd7b9500 | 341 | } |
andrewboyson | 10:e269fd7b9500 | 342 | |
andrewboyson | 10:e269fd7b9500 | 343 | if (!pConnection->sessionId) |
andrewboyson | 10:e269fd7b9500 | 344 | { |
andrewboyson | 10:e269fd7b9500 | 345 | *pWindowSize = 0; |
andrewboyson | 10:e269fd7b9500 | 346 | return false; |
andrewboyson | 10:e269fd7b9500 | 347 | } |
andrewboyson | 10:e269fd7b9500 | 348 | |
andrewboyson | 10:e269fd7b9500 | 349 | struct TlsSession* pSession = TlsSessionOrNull(pConnection->sessionId); |
andrewboyson | 10:e269fd7b9500 | 350 | if (!pSession) |
andrewboyson | 10:e269fd7b9500 | 351 | { |
andrewboyson | 10:e269fd7b9500 | 352 | LogTimeF("TlsPoll - invalid session %u\r\n", pConnection->sessionId); |
andrewboyson | 10:e269fd7b9500 | 353 | *pWindowSize = 0; |
andrewboyson | 10:e269fd7b9500 | 354 | return false; |
andrewboyson | 10:e269fd7b9500 | 355 | } |
andrewboyson | 10:e269fd7b9500 | 356 | |
andrewboyson | 10:e269fd7b9500 | 357 | switch (pConnection->toDo) |
andrewboyson | 10:e269fd7b9500 | 358 | { |
andrewboyson | 10:e269fd7b9500 | 359 | case DO_WAIT_CLIENT_HELLO: |
andrewboyson | 10:e269fd7b9500 | 360 | case DO_WAIT_CLIENT_CHANGE: |
andrewboyson | 10:e269fd7b9500 | 361 | case DO_WAIT_DECRYPT_MASTER_SECRET: |
andrewboyson | 10:e269fd7b9500 | 362 | *pWindowSize = 0; |
andrewboyson | 10:e269fd7b9500 | 363 | if (clientFinished) return true; //The client hasn't made a request and never will so finish |
andrewboyson | 10:e269fd7b9500 | 364 | else return false; //The client hasn't made a request yet but it could. |
andrewboyson | 10:e269fd7b9500 | 365 | |
andrewboyson | 14:03a0b8fd6ddc | 366 | case DO_SEND_SERVER_HELLO_NEW: |
andrewboyson | 14:03a0b8fd6ddc | 367 | sendServerHelloNew(pConnection, pSession, pWindowSize, pWindow, positionOfWindowInStream); |
andrewboyson | 14:03a0b8fd6ddc | 368 | pConnection->toDo = DO_WAIT_CLIENT_CHANGE; |
andrewboyson | 14:03a0b8fd6ddc | 369 | return false; //Not finished |
andrewboyson | 14:03a0b8fd6ddc | 370 | |
andrewboyson | 14:03a0b8fd6ddc | 371 | case DO_SEND_SERVER_HELLO_RESUME: |
andrewboyson | 14:03a0b8fd6ddc | 372 | sendServerHelloResume(pConnection, pSession, pWindowSize, pWindow, positionOfWindowInStream); |
andrewboyson | 10:e269fd7b9500 | 373 | pConnection->toDo = DO_WAIT_CLIENT_CHANGE; |
andrewboyson | 10:e269fd7b9500 | 374 | return false; //Not finished |
andrewboyson | 10:e269fd7b9500 | 375 | |
andrewboyson | 10:e269fd7b9500 | 376 | case DO_SEND_SERVER_CHANGE: |
andrewboyson | 10:e269fd7b9500 | 377 | sendServerChange(pConnection, pSession, pWindowSize, pWindow, positionOfWindowInStream); |
andrewboyson | 10:e269fd7b9500 | 378 | pConnection->toDo = DO_APPLICATION; |
andrewboyson | 10:e269fd7b9500 | 379 | return false; |
andrewboyson | 10:e269fd7b9500 | 380 | |
andrewboyson | 10:e269fd7b9500 | 381 | case DO_APPLICATION: |
andrewboyson | 10:e269fd7b9500 | 382 | { |
andrewboyson | 10:e269fd7b9500 | 383 | int status = HttpPoll(connectionId, clientFinished); |
andrewboyson | 10:e269fd7b9500 | 384 | bool finished; |
andrewboyson | 10:e269fd7b9500 | 385 | switch (status) |
andrewboyson | 10:e269fd7b9500 | 386 | { |
andrewboyson | 10:e269fd7b9500 | 387 | case HTTP_WAIT: finished = false; *pWindowSize = 0; break; |
andrewboyson | 10:e269fd7b9500 | 388 | case HTTP_FINISHED: finished = true; *pWindowSize = 0; break; |
andrewboyson | 10:e269fd7b9500 | 389 | case HTTP_HAVE_SOMETHING_TO_SEND: finished = sendContent(pConnection, pWindowSize, pWindow, positionOfWindowInStream); break; |
andrewboyson | 10:e269fd7b9500 | 390 | } |
andrewboyson | 10:e269fd7b9500 | 391 | if (finished) pConnection->toDo = DO_WAIT_CLIENT_HELLO; |
andrewboyson | 10:e269fd7b9500 | 392 | return finished; |
andrewboyson | 10:e269fd7b9500 | 393 | } |
andrewboyson | 10:e269fd7b9500 | 394 | case DO_SEND_ALERT_ILLEGAL_PARAMETER: |
andrewboyson | 14:03a0b8fd6ddc | 395 | sendFatal(TLS_ALERT_ILLEGAL_PARAMETER, pConnection, pWindowSize, pWindow, positionOfWindowInStream); |
andrewboyson | 10:e269fd7b9500 | 396 | pConnection->toDo = DO_WAIT_CLIENT_HELLO; |
andrewboyson | 10:e269fd7b9500 | 397 | return true; //Finished |
andrewboyson | 10:e269fd7b9500 | 398 | |
andrewboyson | 10:e269fd7b9500 | 399 | case DO_SEND_ALERT_INTERNAL_ERROR: |
andrewboyson | 14:03a0b8fd6ddc | 400 | sendFatal(TLS_ALERT_INTERNAL_ERROR, pConnection, pWindowSize, pWindow, positionOfWindowInStream); |
andrewboyson | 10:e269fd7b9500 | 401 | pConnection->toDo = DO_WAIT_CLIENT_HELLO; |
andrewboyson | 10:e269fd7b9500 | 402 | return true; //Finished |
andrewboyson | 10:e269fd7b9500 | 403 | |
andrewboyson | 10:e269fd7b9500 | 404 | default: |
andrewboyson | 10:e269fd7b9500 | 405 | LogTimeF("TlsPoll - unspecified TLS state %d\r\n", pConnection->toDo); |
andrewboyson | 14:03a0b8fd6ddc | 406 | sendFatal(TLS_ALERT_INTERNAL_ERROR, pConnection, pWindowSize, pWindow, positionOfWindowInStream); //Internal error |
andrewboyson | 10:e269fd7b9500 | 407 | pConnection->toDo = DO_WAIT_CLIENT_HELLO; |
andrewboyson | 10:e269fd7b9500 | 408 | return true; //Finished |
andrewboyson | 10:e269fd7b9500 | 409 | } |
andrewboyson | 10:e269fd7b9500 | 410 | } |