A simple library to support serving https.

Dependents:   oldheating gps motorhome heating

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?

UserRevisionLine numberNew 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 }