A simple library to support serving https.
Dependents: oldheating gps motorhome heating
tls/tls.c@1:9c66a551a67e, 2019-07-26 (annotated)
- Committer:
- andrewboyson
- Date:
- Fri Jul 26 13:49:52 2019 +0000
- Revision:
- 1:9c66a551a67e
- Child:
- 2:82268409e83f
Moved TLS module from net library to crypto library
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
andrewboyson | 1:9c66a551a67e | 1 | #include <stdbool.h> |
andrewboyson | 1:9c66a551a67e | 2 | |
andrewboyson | 1:9c66a551a67e | 3 | #include "http.h" |
andrewboyson | 1:9c66a551a67e | 4 | #include "tcpbuf.h" |
andrewboyson | 1:9c66a551a67e | 5 | #include "action.h" |
andrewboyson | 1:9c66a551a67e | 6 | #include "net.h" |
andrewboyson | 1:9c66a551a67e | 7 | #include "log.h" |
andrewboyson | 1:9c66a551a67e | 8 | #include "led.h" |
andrewboyson | 1:9c66a551a67e | 9 | #include "restart.h" |
andrewboyson | 1:9c66a551a67e | 10 | #include "mstimer.h" |
andrewboyson | 1:9c66a551a67e | 11 | #include "random.h" |
andrewboyson | 1:9c66a551a67e | 12 | #include "pri-key.h" |
andrewboyson | 1:9c66a551a67e | 13 | #include "ser-cer.h" |
andrewboyson | 1:9c66a551a67e | 14 | #include "tls-prf.h" |
andrewboyson | 1:9c66a551a67e | 15 | |
andrewboyson | 1:9c66a551a67e | 16 | #define TLS_CONTENT_TYPE_ChangeCipher 20 |
andrewboyson | 1:9c66a551a67e | 17 | #define TLS_CONTENT_TYPE_Alert 21 |
andrewboyson | 1:9c66a551a67e | 18 | #define TLS_CONTENT_TYPE_Handshake 22 |
andrewboyson | 1:9c66a551a67e | 19 | #define TLS_CONTENT_TYPE_Application 23 |
andrewboyson | 1:9c66a551a67e | 20 | #define TLS_CONTENT_TYPE_Heartbeat 24 |
andrewboyson | 1:9c66a551a67e | 21 | |
andrewboyson | 1:9c66a551a67e | 22 | #define TLS_HANDSHAKE_HelloRequest 0 |
andrewboyson | 1:9c66a551a67e | 23 | #define TLS_HANDSHAKE_ClientHello 1 |
andrewboyson | 1:9c66a551a67e | 24 | #define TLS_HANDSHAKE_ServerHello 2 |
andrewboyson | 1:9c66a551a67e | 25 | #define TLS_HANDSHAKE_NewSessionTicket 4 |
andrewboyson | 1:9c66a551a67e | 26 | #define TLS_HANDSHAKE_EncryptedExtensions 8 |
andrewboyson | 1:9c66a551a67e | 27 | #define TLS_HANDSHAKE_Certificate 11 |
andrewboyson | 1:9c66a551a67e | 28 | #define TLS_HANDSHAKE_ServerKeyExchange 12 |
andrewboyson | 1:9c66a551a67e | 29 | #define TLS_HANDSHAKE_CertificateRequest 13 |
andrewboyson | 1:9c66a551a67e | 30 | #define TLS_HANDSHAKE_ServerHelloDone 14 |
andrewboyson | 1:9c66a551a67e | 31 | #define TLS_HANDSHAKE_CertificateVerify 15 |
andrewboyson | 1:9c66a551a67e | 32 | #define TLS_HANDSHAKE_ClientKeyExchange 16 |
andrewboyson | 1:9c66a551a67e | 33 | #define TLS_HANDSHAKE_Finished 20 |
andrewboyson | 1:9c66a551a67e | 34 | |
andrewboyson | 1:9c66a551a67e | 35 | #define DO_WAIT_CLIENT_HELLO 0 |
andrewboyson | 1:9c66a551a67e | 36 | #define DO_SEND_SERVER_HELLO 1 |
andrewboyson | 1:9c66a551a67e | 37 | #define DO_WAIT_CLIENT_CHANGE 2 |
andrewboyson | 1:9c66a551a67e | 38 | #define DO_WAIT_DECRYPT_MASTER_SECRET 3 |
andrewboyson | 1:9c66a551a67e | 39 | #define DO_SEND_SERVER_CHANGE 4 |
andrewboyson | 1:9c66a551a67e | 40 | #define DO_APPLICATION 5 |
andrewboyson | 1:9c66a551a67e | 41 | #define DO_SEND_ALERT_ILLEGAL_PARAMETER 6 |
andrewboyson | 1:9c66a551a67e | 42 | #define DO_SEND_ALERT_INTERNAL_ERROR 7 |
andrewboyson | 1:9c66a551a67e | 43 | |
andrewboyson | 1:9c66a551a67e | 44 | bool TlsTrace = true; |
andrewboyson | 1:9c66a551a67e | 45 | |
andrewboyson | 1:9c66a551a67e | 46 | char paddedMasterSecret[128]; |
andrewboyson | 1:9c66a551a67e | 47 | char clientHelloRandom[32]; |
andrewboyson | 1:9c66a551a67e | 48 | |
andrewboyson | 1:9c66a551a67e | 49 | void TlsInit() |
andrewboyson | 1:9c66a551a67e | 50 | { |
andrewboyson | 1:9c66a551a67e | 51 | SerCerInit(); |
andrewboyson | 1:9c66a551a67e | 52 | PriKeyInit(); |
andrewboyson | 1:9c66a551a67e | 53 | TlsPrfTest(); |
andrewboyson | 1:9c66a551a67e | 54 | } |
andrewboyson | 1:9c66a551a67e | 55 | |
andrewboyson | 1:9c66a551a67e | 56 | struct state |
andrewboyson | 1:9c66a551a67e | 57 | { |
andrewboyson | 1:9c66a551a67e | 58 | int toDo; |
andrewboyson | 1:9c66a551a67e | 59 | }; |
andrewboyson | 1:9c66a551a67e | 60 | static void logContentType(char contentType) |
andrewboyson | 1:9c66a551a67e | 61 | { |
andrewboyson | 1:9c66a551a67e | 62 | switch (contentType) |
andrewboyson | 1:9c66a551a67e | 63 | { |
andrewboyson | 1:9c66a551a67e | 64 | case TLS_CONTENT_TYPE_ChangeCipher: Log ("Change cipher" ); break; |
andrewboyson | 1:9c66a551a67e | 65 | case TLS_CONTENT_TYPE_Alert: Log ("Alert" ); break; |
andrewboyson | 1:9c66a551a67e | 66 | case TLS_CONTENT_TYPE_Handshake: Log ("Handshake" ); break; |
andrewboyson | 1:9c66a551a67e | 67 | case TLS_CONTENT_TYPE_Application: Log ("Application" ); break; |
andrewboyson | 1:9c66a551a67e | 68 | case TLS_CONTENT_TYPE_Heartbeat: Log ("Heartbeat" ); break; |
andrewboyson | 1:9c66a551a67e | 69 | default: LogF("%02hX", contentType); break; |
andrewboyson | 1:9c66a551a67e | 70 | } |
andrewboyson | 1:9c66a551a67e | 71 | } |
andrewboyson | 1:9c66a551a67e | 72 | static void logHandshakeType(char handshakeType) |
andrewboyson | 1:9c66a551a67e | 73 | { |
andrewboyson | 1:9c66a551a67e | 74 | switch (handshakeType) |
andrewboyson | 1:9c66a551a67e | 75 | { |
andrewboyson | 1:9c66a551a67e | 76 | case TLS_HANDSHAKE_HelloRequest: Log ("Hello request" ); break; |
andrewboyson | 1:9c66a551a67e | 77 | case TLS_HANDSHAKE_ClientHello: Log ("Client hello" ); break; |
andrewboyson | 1:9c66a551a67e | 78 | case TLS_HANDSHAKE_ServerHello: Log ("Server hello" ); break; |
andrewboyson | 1:9c66a551a67e | 79 | case TLS_HANDSHAKE_NewSessionTicket: Log ("New session ticket" ); break; |
andrewboyson | 1:9c66a551a67e | 80 | case TLS_HANDSHAKE_EncryptedExtensions: Log ("Encrypted extensions"); break; |
andrewboyson | 1:9c66a551a67e | 81 | case TLS_HANDSHAKE_Certificate: Log ("Certificate" ); break; |
andrewboyson | 1:9c66a551a67e | 82 | case TLS_HANDSHAKE_ServerKeyExchange: Log ("Server key exchange" ); break; |
andrewboyson | 1:9c66a551a67e | 83 | case TLS_HANDSHAKE_CertificateRequest: Log ("Certificate request" ); break; |
andrewboyson | 1:9c66a551a67e | 84 | case TLS_HANDSHAKE_ServerHelloDone: Log ("Server hello done" ); break; |
andrewboyson | 1:9c66a551a67e | 85 | case TLS_HANDSHAKE_CertificateVerify: Log ("Certificate verify" ); break; |
andrewboyson | 1:9c66a551a67e | 86 | case TLS_HANDSHAKE_ClientKeyExchange: Log ("Client key exchange" ); break; |
andrewboyson | 1:9c66a551a67e | 87 | case TLS_HANDSHAKE_Finished: Log ("Finished" ); break; |
andrewboyson | 1:9c66a551a67e | 88 | default: LogF("%02hX", handshakeType); break; |
andrewboyson | 1:9c66a551a67e | 89 | } |
andrewboyson | 1:9c66a551a67e | 90 | } |
andrewboyson | 1:9c66a551a67e | 91 | static void logAlertLevel(char level) |
andrewboyson | 1:9c66a551a67e | 92 | { |
andrewboyson | 1:9c66a551a67e | 93 | switch (level) |
andrewboyson | 1:9c66a551a67e | 94 | { |
andrewboyson | 1:9c66a551a67e | 95 | case 1: Log ("Warning" ); break; |
andrewboyson | 1:9c66a551a67e | 96 | case 2: Log ("Fatal" ); break; |
andrewboyson | 1:9c66a551a67e | 97 | default: LogF("%d", level); break; |
andrewboyson | 1:9c66a551a67e | 98 | } |
andrewboyson | 1:9c66a551a67e | 99 | } |
andrewboyson | 1:9c66a551a67e | 100 | static void logAlertDescription(char description) |
andrewboyson | 1:9c66a551a67e | 101 | { |
andrewboyson | 1:9c66a551a67e | 102 | switch (description) |
andrewboyson | 1:9c66a551a67e | 103 | { |
andrewboyson | 1:9c66a551a67e | 104 | case 0: Log("Close notify" ); break; |
andrewboyson | 1:9c66a551a67e | 105 | case 10: Log("Unexpected message" ); break; |
andrewboyson | 1:9c66a551a67e | 106 | case 20: Log("Bad record MAC" ); break; |
andrewboyson | 1:9c66a551a67e | 107 | case 21: Log("Decryption failed" ); break; |
andrewboyson | 1:9c66a551a67e | 108 | case 22: Log("Record overflow" ); break; |
andrewboyson | 1:9c66a551a67e | 109 | case 30: Log("Decompression failure" ); break; |
andrewboyson | 1:9c66a551a67e | 110 | case 40: Log("Handshake failure" ); break; |
andrewboyson | 1:9c66a551a67e | 111 | case 41: Log("No certificate" ); break; |
andrewboyson | 1:9c66a551a67e | 112 | case 42: Log("Bad certificate" ); break; |
andrewboyson | 1:9c66a551a67e | 113 | case 43: Log("Unsupported certificate" ); break; |
andrewboyson | 1:9c66a551a67e | 114 | case 44: Log("Certificate revoked" ); break; |
andrewboyson | 1:9c66a551a67e | 115 | case 45: Log("Certificate expired" ); break; |
andrewboyson | 1:9c66a551a67e | 116 | case 46: Log("Certificate unknown" ); break; |
andrewboyson | 1:9c66a551a67e | 117 | case 47: Log("Illegal parameter" ); break; |
andrewboyson | 1:9c66a551a67e | 118 | case 48: Log("Unknown CA" ); break; |
andrewboyson | 1:9c66a551a67e | 119 | case 49: Log("Access denied" ); break; |
andrewboyson | 1:9c66a551a67e | 120 | case 50: Log("Decode error" ); break; |
andrewboyson | 1:9c66a551a67e | 121 | case 51: Log("Decrypt error" ); break; |
andrewboyson | 1:9c66a551a67e | 122 | case 60: Log("Export restriction" ); break; |
andrewboyson | 1:9c66a551a67e | 123 | case 70: Log("Protocol version" ); break; |
andrewboyson | 1:9c66a551a67e | 124 | case 71: Log("Insufficient security" ); break; |
andrewboyson | 1:9c66a551a67e | 125 | case 80: Log("Internal error" ); break; |
andrewboyson | 1:9c66a551a67e | 126 | case 86: Log("Inappropriate Fallback" ); break; |
andrewboyson | 1:9c66a551a67e | 127 | case 90: Log("User cancelled" ); break; |
andrewboyson | 1:9c66a551a67e | 128 | case 100: Log("No renegotiation" ); break; |
andrewboyson | 1:9c66a551a67e | 129 | case 110: Log("Unsupported extension" ); break; |
andrewboyson | 1:9c66a551a67e | 130 | case 111: Log("Certificate unobtainable" ); break; |
andrewboyson | 1:9c66a551a67e | 131 | case 112: Log("Unrecognized name" ); break; |
andrewboyson | 1:9c66a551a67e | 132 | case 113: Log("Bad certificate status response"); break; |
andrewboyson | 1:9c66a551a67e | 133 | case 114: Log("Bad certificate hash value" ); break; |
andrewboyson | 1:9c66a551a67e | 134 | case 115: Log("Unknown PSK identity" ); break; |
andrewboyson | 1:9c66a551a67e | 135 | case 120: Log("No Application Protocol" ); break; |
andrewboyson | 1:9c66a551a67e | 136 | default: LogF("%d", description ); break; |
andrewboyson | 1:9c66a551a67e | 137 | } |
andrewboyson | 1:9c66a551a67e | 138 | } |
andrewboyson | 1:9c66a551a67e | 139 | static int handleClientHello(int length, char* pBuffer) //returns 0 on success; -1 on error |
andrewboyson | 1:9c66a551a67e | 140 | { |
andrewboyson | 1:9c66a551a67e | 141 | if (length != 32) |
andrewboyson | 1:9c66a551a67e | 142 | { |
andrewboyson | 1:9c66a551a67e | 143 | LogF("TLS - %d byte client hello message is not 32 bytes long\r\n", length); |
andrewboyson | 1:9c66a551a67e | 144 | return -1; |
andrewboyson | 1:9c66a551a67e | 145 | } |
andrewboyson | 1:9c66a551a67e | 146 | for (int i = 0; i < 32; i++) clientHelloRandom[i] = pBuffer[i]; |
andrewboyson | 1:9c66a551a67e | 147 | if (TlsTrace) |
andrewboyson | 1:9c66a551a67e | 148 | { |
andrewboyson | 1:9c66a551a67e | 149 | Log("- random:\r\n"); |
andrewboyson | 1:9c66a551a67e | 150 | LogBytesAsHex(clientHelloRandom, 32); |
andrewboyson | 1:9c66a551a67e | 151 | Log("\r\n"); |
andrewboyson | 1:9c66a551a67e | 152 | } |
andrewboyson | 1:9c66a551a67e | 153 | return 0; |
andrewboyson | 1:9c66a551a67e | 154 | } |
andrewboyson | 1:9c66a551a67e | 155 | static int handleClientKeyExchange(int length, char* pBuffer) //returns 0 on success; -1 on error |
andrewboyson | 1:9c66a551a67e | 156 | { |
andrewboyson | 1:9c66a551a67e | 157 | if (length != 130) |
andrewboyson | 1:9c66a551a67e | 158 | { |
andrewboyson | 1:9c66a551a67e | 159 | LogF("TLS - %d byte client key exchange message is not 130 bytes long\r\n", length); |
andrewboyson | 1:9c66a551a67e | 160 | return -1; |
andrewboyson | 1:9c66a551a67e | 161 | } |
andrewboyson | 1:9c66a551a67e | 162 | int premasterLength = pBuffer[0] << 8 | pBuffer[1]; //Overall length 2 bytes |
andrewboyson | 1:9c66a551a67e | 163 | if (premasterLength != 128) |
andrewboyson | 1:9c66a551a67e | 164 | { |
andrewboyson | 1:9c66a551a67e | 165 | LogF("TLS - %d byte encrypted pre master secret is not 128 bytes long\r\n", length); |
andrewboyson | 1:9c66a551a67e | 166 | return -1; |
andrewboyson | 1:9c66a551a67e | 167 | } |
andrewboyson | 1:9c66a551a67e | 168 | char* pEncryptedPreMasterSecret = pBuffer + 2; |
andrewboyson | 1:9c66a551a67e | 169 | PriKeyDecryptStart(pEncryptedPreMasterSecret, paddedMasterSecret); |
andrewboyson | 1:9c66a551a67e | 170 | |
andrewboyson | 1:9c66a551a67e | 171 | if (TlsTrace) |
andrewboyson | 1:9c66a551a67e | 172 | { |
andrewboyson | 1:9c66a551a67e | 173 | LogF("- encrypted premaster (%d bytes little endian)\r\n", premasterLength); |
andrewboyson | 1:9c66a551a67e | 174 | LogBytesAsHex(pEncryptedPreMasterSecret, 128); |
andrewboyson | 1:9c66a551a67e | 175 | Log("\r\n"); |
andrewboyson | 1:9c66a551a67e | 176 | } |
andrewboyson | 1:9c66a551a67e | 177 | |
andrewboyson | 1:9c66a551a67e | 178 | return 0; |
andrewboyson | 1:9c66a551a67e | 179 | } |
andrewboyson | 1:9c66a551a67e | 180 | static void handleHandshake(int length, char* pBuffer, int* pToDo) |
andrewboyson | 1:9c66a551a67e | 181 | { |
andrewboyson | 1:9c66a551a67e | 182 | char* p = pBuffer; |
andrewboyson | 1:9c66a551a67e | 183 | while (p < pBuffer + length) |
andrewboyson | 1:9c66a551a67e | 184 | { |
andrewboyson | 1:9c66a551a67e | 185 | char handshakeType = *p++; |
andrewboyson | 1:9c66a551a67e | 186 | int handshakeLength = *p++ << 16 | *p++ << 8 | *p++; //Handshake length 3 bytes |
andrewboyson | 1:9c66a551a67e | 187 | if (TlsTrace) |
andrewboyson | 1:9c66a551a67e | 188 | { |
andrewboyson | 1:9c66a551a67e | 189 | Log ("- handshake type: "); logHandshakeType(handshakeType); Log("\r\n"); |
andrewboyson | 1:9c66a551a67e | 190 | LogF("- handshake length: %d\r\n", handshakeLength); |
andrewboyson | 1:9c66a551a67e | 191 | } |
andrewboyson | 1:9c66a551a67e | 192 | int r = -1; |
andrewboyson | 1:9c66a551a67e | 193 | switch (handshakeType) |
andrewboyson | 1:9c66a551a67e | 194 | { |
andrewboyson | 1:9c66a551a67e | 195 | case TLS_HANDSHAKE_ClientHello: |
andrewboyson | 1:9c66a551a67e | 196 | r = handleClientHello(handshakeLength, p); |
andrewboyson | 1:9c66a551a67e | 197 | *pToDo = r ? DO_SEND_ALERT_ILLEGAL_PARAMETER : DO_SEND_SERVER_HELLO; |
andrewboyson | 1:9c66a551a67e | 198 | break; |
andrewboyson | 1:9c66a551a67e | 199 | |
andrewboyson | 1:9c66a551a67e | 200 | case TLS_HANDSHAKE_ClientKeyExchange: |
andrewboyson | 1:9c66a551a67e | 201 | r = handleClientKeyExchange(handshakeLength, p); |
andrewboyson | 1:9c66a551a67e | 202 | *pToDo = r ? DO_SEND_ALERT_ILLEGAL_PARAMETER : DO_WAIT_DECRYPT_MASTER_SECRET; |
andrewboyson | 1:9c66a551a67e | 203 | break; |
andrewboyson | 1:9c66a551a67e | 204 | |
andrewboyson | 1:9c66a551a67e | 205 | default: |
andrewboyson | 1:9c66a551a67e | 206 | LogF("TLS - ignoring untreated %d byte handshake type ", handshakeLength); |
andrewboyson | 1:9c66a551a67e | 207 | logHandshakeType(handshakeType); |
andrewboyson | 1:9c66a551a67e | 208 | Log("\r\n"); |
andrewboyson | 1:9c66a551a67e | 209 | break; |
andrewboyson | 1:9c66a551a67e | 210 | } |
andrewboyson | 1:9c66a551a67e | 211 | p += handshakeLength; |
andrewboyson | 1:9c66a551a67e | 212 | } |
andrewboyson | 1:9c66a551a67e | 213 | } |
andrewboyson | 1:9c66a551a67e | 214 | static void handleAlert(int length, char* pBuffer) |
andrewboyson | 1:9c66a551a67e | 215 | { |
andrewboyson | 1:9c66a551a67e | 216 | char level = pBuffer[0]; |
andrewboyson | 1:9c66a551a67e | 217 | char description = pBuffer[1]; |
andrewboyson | 1:9c66a551a67e | 218 | if (TlsTrace) |
andrewboyson | 1:9c66a551a67e | 219 | { |
andrewboyson | 1:9c66a551a67e | 220 | Log("- alert level: "); logAlertLevel (level); Log("\r\n"); |
andrewboyson | 1:9c66a551a67e | 221 | Log("- alert description: "); logAlertDescription(description); Log("\r\n"); |
andrewboyson | 1:9c66a551a67e | 222 | } |
andrewboyson | 1:9c66a551a67e | 223 | } |
andrewboyson | 1:9c66a551a67e | 224 | static void handleApplication(int length, char* pBuffer) |
andrewboyson | 1:9c66a551a67e | 225 | { |
andrewboyson | 1:9c66a551a67e | 226 | if (TlsTrace) |
andrewboyson | 1:9c66a551a67e | 227 | { |
andrewboyson | 1:9c66a551a67e | 228 | Log("- application data:\r\n"); |
andrewboyson | 1:9c66a551a67e | 229 | LogBytesAsHex(pBuffer, length); |
andrewboyson | 1:9c66a551a67e | 230 | Log("\r\n"); |
andrewboyson | 1:9c66a551a67e | 231 | } |
andrewboyson | 1:9c66a551a67e | 232 | } |
andrewboyson | 1:9c66a551a67e | 233 | void TlsRequest(char* pTlsState, char* pWebState, int size, char* pRequestStream, uint32_t positionInRequestStream) |
andrewboyson | 1:9c66a551a67e | 234 | { |
andrewboyson | 1:9c66a551a67e | 235 | struct state* pState = (struct state*)pTlsState; |
andrewboyson | 1:9c66a551a67e | 236 | |
andrewboyson | 1:9c66a551a67e | 237 | if (TlsTrace) LogF("TLS <<< %d (%u)\r\n", size, positionInRequestStream); |
andrewboyson | 1:9c66a551a67e | 238 | |
andrewboyson | 1:9c66a551a67e | 239 | if (size == 0) return; |
andrewboyson | 1:9c66a551a67e | 240 | //if (positionInRequestStream != 0) return; |
andrewboyson | 1:9c66a551a67e | 241 | char contentType = pRequestStream[0]; |
andrewboyson | 1:9c66a551a67e | 242 | char versionH = pRequestStream[1]; |
andrewboyson | 1:9c66a551a67e | 243 | char versionL = pRequestStream[2]; |
andrewboyson | 1:9c66a551a67e | 244 | int length = pRequestStream[3] << 8 | pRequestStream[4]; //Length (2 bytes) |
andrewboyson | 1:9c66a551a67e | 245 | if (TlsTrace) |
andrewboyson | 1:9c66a551a67e | 246 | { |
andrewboyson | 1:9c66a551a67e | 247 | Log ("- content type: "); logContentType(contentType); Log("\r\n"); |
andrewboyson | 1:9c66a551a67e | 248 | LogF("- legacy HH:LL: %02x:%02x\r\n", versionH, versionL); |
andrewboyson | 1:9c66a551a67e | 249 | LogF("- length : %d\r\n" , length); |
andrewboyson | 1:9c66a551a67e | 250 | } |
andrewboyson | 1:9c66a551a67e | 251 | switch (contentType) |
andrewboyson | 1:9c66a551a67e | 252 | { |
andrewboyson | 1:9c66a551a67e | 253 | case TLS_CONTENT_TYPE_Handshake: |
andrewboyson | 1:9c66a551a67e | 254 | { |
andrewboyson | 1:9c66a551a67e | 255 | handleHandshake(length, pRequestStream + 5, &pState->toDo); |
andrewboyson | 1:9c66a551a67e | 256 | return; |
andrewboyson | 1:9c66a551a67e | 257 | } |
andrewboyson | 1:9c66a551a67e | 258 | case TLS_CONTENT_TYPE_Alert: |
andrewboyson | 1:9c66a551a67e | 259 | { |
andrewboyson | 1:9c66a551a67e | 260 | handleAlert(length, pRequestStream + 5); |
andrewboyson | 1:9c66a551a67e | 261 | return; |
andrewboyson | 1:9c66a551a67e | 262 | } |
andrewboyson | 1:9c66a551a67e | 263 | case TLS_CONTENT_TYPE_Application: |
andrewboyson | 1:9c66a551a67e | 264 | { |
andrewboyson | 1:9c66a551a67e | 265 | handleApplication(length, pRequestStream + 5); |
andrewboyson | 1:9c66a551a67e | 266 | pState->toDo = DO_APPLICATION; |
andrewboyson | 1:9c66a551a67e | 267 | return; |
andrewboyson | 1:9c66a551a67e | 268 | } |
andrewboyson | 1:9c66a551a67e | 269 | |
andrewboyson | 1:9c66a551a67e | 270 | default: |
andrewboyson | 1:9c66a551a67e | 271 | Log("TLS - untreated content type "); logContentType(contentType); Log("\r\n"); |
andrewboyson | 1:9c66a551a67e | 272 | pState->toDo = DO_WAIT_CLIENT_HELLO; |
andrewboyson | 1:9c66a551a67e | 273 | return; |
andrewboyson | 1:9c66a551a67e | 274 | } |
andrewboyson | 1:9c66a551a67e | 275 | } |
andrewboyson | 1:9c66a551a67e | 276 | char lengthH(int size) { return size >> 8;} |
andrewboyson | 1:9c66a551a67e | 277 | char lengthL(int size) { return size & 0xFF; } |
andrewboyson | 1:9c66a551a67e | 278 | void addSize(int size) |
andrewboyson | 1:9c66a551a67e | 279 | { |
andrewboyson | 1:9c66a551a67e | 280 | TcpBufAddChar(size >> 8 ); |
andrewboyson | 1:9c66a551a67e | 281 | TcpBufAddChar(size & 0xFF); |
andrewboyson | 1:9c66a551a67e | 282 | } |
andrewboyson | 1:9c66a551a67e | 283 | |
andrewboyson | 1:9c66a551a67e | 284 | static void sendServerHello() |
andrewboyson | 1:9c66a551a67e | 285 | { |
andrewboyson | 1:9c66a551a67e | 286 | Log(" sending server hello\r\n"); |
andrewboyson | 1:9c66a551a67e | 287 | TcpBufAddChar(TLS_CONTENT_TYPE_Handshake); //Content is handshakes |
andrewboyson | 1:9c66a551a67e | 288 | TcpBufAddChar(0x03); TcpBufAddChar(0x03); //Legacy TLS version |
andrewboyson | 1:9c66a551a67e | 289 | addSize((45 + 4) + (SerCerSize + 6 + 4) + (0 + 4)); //Handshakes Length (2 bytes) |
andrewboyson | 1:9c66a551a67e | 290 | |
andrewboyson | 1:9c66a551a67e | 291 | TcpBufAddChar(TLS_HANDSHAKE_ServerHello); TcpBufAddChar(0x00); //Handshake type server hello |
andrewboyson | 1:9c66a551a67e | 292 | addSize(45); //Size of this handshake |
andrewboyson | 1:9c66a551a67e | 293 | TcpBufAddChar(0x03); TcpBufAddChar(0x03); //TLS version 1.2 |
andrewboyson | 1:9c66a551a67e | 294 | for (int i = 0; i < 32; i++) TcpBufAddChar(RandomGetByte()); //32 bit random number |
andrewboyson | 1:9c66a551a67e | 295 | TcpBufAddChar(0x00); //SessionId length 0 |
andrewboyson | 1:9c66a551a67e | 296 | TcpBufAddChar(0x00); TcpBufAddChar(0x2f); //Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) |
andrewboyson | 1:9c66a551a67e | 297 | TcpBufAddChar(0x00); //Compression method none |
andrewboyson | 1:9c66a551a67e | 298 | TcpBufAddChar(0x00); TcpBufAddChar(0x05); //Extensions length (2 bytes) 5 bytes |
andrewboyson | 1:9c66a551a67e | 299 | TcpBufAddChar(0xff); TcpBufAddChar(0x01); //Extension Renegotiation Info |
andrewboyson | 1:9c66a551a67e | 300 | TcpBufAddChar(0x00); TcpBufAddChar(0x01); //1 bytes of "Renegotiation Info" extension data follows |
andrewboyson | 1:9c66a551a67e | 301 | TcpBufAddChar(0x00); //length is zero, because this is a new connection |
andrewboyson | 1:9c66a551a67e | 302 | |
andrewboyson | 1:9c66a551a67e | 303 | TcpBufAddChar(TLS_HANDSHAKE_Certificate); TcpBufAddChar(0x00); //Handshake type certificate |
andrewboyson | 1:9c66a551a67e | 304 | addSize(SerCerSize + 6); TcpBufAddChar(0x00); //Size of this handshake |
andrewboyson | 1:9c66a551a67e | 305 | addSize(SerCerSize + 3); TcpBufAddChar(0x00); //Size of all certificates |
andrewboyson | 1:9c66a551a67e | 306 | addSize(SerCerSize ); //Size of first certificate |
andrewboyson | 1:9c66a551a67e | 307 | for (int i = 0; i < SerCerSize; i++) TcpBufAddChar(SerCerData[i]); //Certificate |
andrewboyson | 1:9c66a551a67e | 308 | |
andrewboyson | 1:9c66a551a67e | 309 | TcpBufAddChar(TLS_HANDSHAKE_ServerHelloDone); TcpBufAddChar(0x00); //Handshake type server hello done |
andrewboyson | 1:9c66a551a67e | 310 | addSize(0); //Size of this handshake |
andrewboyson | 1:9c66a551a67e | 311 | } |
andrewboyson | 1:9c66a551a67e | 312 | static void sendServerChange() |
andrewboyson | 1:9c66a551a67e | 313 | { |
andrewboyson | 1:9c66a551a67e | 314 | Log(" sending server change\r\n"); |
andrewboyson | 1:9c66a551a67e | 315 | } |
andrewboyson | 1:9c66a551a67e | 316 | static void sendFatal(char description) |
andrewboyson | 1:9c66a551a67e | 317 | { |
andrewboyson | 1:9c66a551a67e | 318 | Log(" sending fatal alert: "); |
andrewboyson | 1:9c66a551a67e | 319 | logAlertDescription(description); |
andrewboyson | 1:9c66a551a67e | 320 | Log("\r\n"); |
andrewboyson | 1:9c66a551a67e | 321 | TcpBufAddChar(TLS_CONTENT_TYPE_Alert); //Content is alert |
andrewboyson | 1:9c66a551a67e | 322 | TcpBufAddChar(0x03); TcpBufAddChar(0x03); //Legacy TLS version |
andrewboyson | 1:9c66a551a67e | 323 | addSize(2); //Alert Length (2 bytes) |
andrewboyson | 1:9c66a551a67e | 324 | |
andrewboyson | 1:9c66a551a67e | 325 | TcpBufAddChar(2); //Fatal (level = 2) |
andrewboyson | 1:9c66a551a67e | 326 | TcpBufAddChar(description); //Description |
andrewboyson | 1:9c66a551a67e | 327 | |
andrewboyson | 1:9c66a551a67e | 328 | } |
andrewboyson | 1:9c66a551a67e | 329 | int TlsPoll(char* pTlsState, char* pWebState, bool clientFinished) |
andrewboyson | 1:9c66a551a67e | 330 | { |
andrewboyson | 1:9c66a551a67e | 331 | struct state* pState = (struct state*)pTlsState; |
andrewboyson | 1:9c66a551a67e | 332 | |
andrewboyson | 1:9c66a551a67e | 333 | switch (pState->toDo) |
andrewboyson | 1:9c66a551a67e | 334 | { |
andrewboyson | 1:9c66a551a67e | 335 | case DO_WAIT_CLIENT_HELLO: |
andrewboyson | 1:9c66a551a67e | 336 | case DO_WAIT_CLIENT_CHANGE: |
andrewboyson | 1:9c66a551a67e | 337 | if (clientFinished) return -1; //The client hasn't made a request and never will so finish |
andrewboyson | 1:9c66a551a67e | 338 | else return 0; //The client hasn't made a request yet but it could. |
andrewboyson | 1:9c66a551a67e | 339 | |
andrewboyson | 1:9c66a551a67e | 340 | case DO_WAIT_DECRYPT_MASTER_SECRET: |
andrewboyson | 1:9c66a551a67e | 341 | if (PriKeyDecryptFinished()) |
andrewboyson | 1:9c66a551a67e | 342 | { |
andrewboyson | 1:9c66a551a67e | 343 | Log("Master secret\r\n"); |
andrewboyson | 1:9c66a551a67e | 344 | LogBytesAsHex(paddedMasterSecret, sizeof(paddedMasterSecret)); |
andrewboyson | 1:9c66a551a67e | 345 | Log("\r\n"); |
andrewboyson | 1:9c66a551a67e | 346 | pState->toDo = DO_SEND_SERVER_CHANGE; |
andrewboyson | 1:9c66a551a67e | 347 | return 1; //Call TlsReply to do the send |
andrewboyson | 1:9c66a551a67e | 348 | } |
andrewboyson | 1:9c66a551a67e | 349 | else |
andrewboyson | 1:9c66a551a67e | 350 | { |
andrewboyson | 1:9c66a551a67e | 351 | if (clientFinished) return -1; //The client hasn't made a request and never will so finish |
andrewboyson | 1:9c66a551a67e | 352 | else return 0; //The client hasn't made a request yet but it could. |
andrewboyson | 1:9c66a551a67e | 353 | } |
andrewboyson | 1:9c66a551a67e | 354 | |
andrewboyson | 1:9c66a551a67e | 355 | case DO_APPLICATION: |
andrewboyson | 1:9c66a551a67e | 356 | return HttpPollFunction(pWebState, clientFinished); //Return whatever HTTP would be |
andrewboyson | 1:9c66a551a67e | 357 | |
andrewboyson | 1:9c66a551a67e | 358 | case DO_SEND_SERVER_HELLO: |
andrewboyson | 1:9c66a551a67e | 359 | case DO_SEND_ALERT_ILLEGAL_PARAMETER: |
andrewboyson | 1:9c66a551a67e | 360 | case DO_SEND_ALERT_INTERNAL_ERROR: |
andrewboyson | 1:9c66a551a67e | 361 | return 1; |
andrewboyson | 1:9c66a551a67e | 362 | |
andrewboyson | 1:9c66a551a67e | 363 | default: |
andrewboyson | 1:9c66a551a67e | 364 | LogTimeF("TlsPoll - unspecified TLS state %d\r\n", pState->toDo); |
andrewboyson | 1:9c66a551a67e | 365 | return -1; //Finish |
andrewboyson | 1:9c66a551a67e | 366 | } |
andrewboyson | 1:9c66a551a67e | 367 | } |
andrewboyson | 1:9c66a551a67e | 368 | bool TlsReply(char* pTlsState, char* pWebState) |
andrewboyson | 1:9c66a551a67e | 369 | { |
andrewboyson | 1:9c66a551a67e | 370 | struct state* pState = (struct state*)pTlsState; |
andrewboyson | 1:9c66a551a67e | 371 | |
andrewboyson | 1:9c66a551a67e | 372 | switch(pState->toDo) |
andrewboyson | 1:9c66a551a67e | 373 | { |
andrewboyson | 1:9c66a551a67e | 374 | case DO_SEND_SERVER_HELLO: |
andrewboyson | 1:9c66a551a67e | 375 | sendServerHello(); |
andrewboyson | 1:9c66a551a67e | 376 | pState->toDo = DO_WAIT_CLIENT_CHANGE; |
andrewboyson | 1:9c66a551a67e | 377 | return false; //Not finished |
andrewboyson | 1:9c66a551a67e | 378 | |
andrewboyson | 1:9c66a551a67e | 379 | case DO_SEND_SERVER_CHANGE: |
andrewboyson | 1:9c66a551a67e | 380 | sendServerChange(); |
andrewboyson | 1:9c66a551a67e | 381 | pState->toDo = DO_APPLICATION; |
andrewboyson | 1:9c66a551a67e | 382 | return false; //Not finished |
andrewboyson | 1:9c66a551a67e | 383 | |
andrewboyson | 1:9c66a551a67e | 384 | case DO_APPLICATION: |
andrewboyson | 1:9c66a551a67e | 385 | return HttpReplyFunction(pWebState); //Return whatever HTTP would be |
andrewboyson | 1:9c66a551a67e | 386 | |
andrewboyson | 1:9c66a551a67e | 387 | case DO_SEND_ALERT_ILLEGAL_PARAMETER: |
andrewboyson | 1:9c66a551a67e | 388 | sendFatal(47); |
andrewboyson | 1:9c66a551a67e | 389 | pState->toDo = DO_WAIT_CLIENT_HELLO; |
andrewboyson | 1:9c66a551a67e | 390 | return true; //Finished |
andrewboyson | 1:9c66a551a67e | 391 | |
andrewboyson | 1:9c66a551a67e | 392 | case DO_SEND_ALERT_INTERNAL_ERROR: |
andrewboyson | 1:9c66a551a67e | 393 | sendFatal(80); |
andrewboyson | 1:9c66a551a67e | 394 | pState->toDo = DO_WAIT_CLIENT_HELLO; |
andrewboyson | 1:9c66a551a67e | 395 | return true; //Finished |
andrewboyson | 1:9c66a551a67e | 396 | |
andrewboyson | 1:9c66a551a67e | 397 | default: |
andrewboyson | 1:9c66a551a67e | 398 | LogTimeF("TlsReply - unspecified TLS state %d\r\n", pState->toDo); |
andrewboyson | 1:9c66a551a67e | 399 | return true; //Finished |
andrewboyson | 1:9c66a551a67e | 400 | } |
andrewboyson | 1:9c66a551a67e | 401 | } |
andrewboyson | 1:9c66a551a67e | 402 | static char encrypt(char c) |
andrewboyson | 1:9c66a551a67e | 403 | { |
andrewboyson | 1:9c66a551a67e | 404 | return c; //Implement encryption |
andrewboyson | 1:9c66a551a67e | 405 | } |
andrewboyson | 1:9c66a551a67e | 406 | void TlsAddChar(char c) |
andrewboyson | 1:9c66a551a67e | 407 | { |
andrewboyson | 1:9c66a551a67e | 408 | char e = encrypt(c); |
andrewboyson | 1:9c66a551a67e | 409 | TcpBufAddChar(e); |
andrewboyson | 1:9c66a551a67e | 410 | } |