Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: oldheating gps motorhome heating
tcp/tls/tls.c@150:3366e4a0c60e, 2019-06-27 (annotated)
- Committer:
- andrewboyson
- Date:
- Thu Jun 27 21:19:08 2019 +0000
- Revision:
- 150:3366e4a0c60e
- Parent:
- 149:39d1ba392f4b
- Child:
- 151:bde6f7da1755
Added function to read PEM encoded private key
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| andrewboyson | 145:206bf0d073c7 | 1 | #include <stdbool.h> |
| andrewboyson | 145:206bf0d073c7 | 2 | |
| andrewboyson | 147:a6093b52e654 | 3 | #include "http.h" |
| andrewboyson | 145:206bf0d073c7 | 4 | #include "tcpbuf.h" |
| andrewboyson | 145:206bf0d073c7 | 5 | #include "action.h" |
| andrewboyson | 147:a6093b52e654 | 6 | #include "net.h" |
| andrewboyson | 147:a6093b52e654 | 7 | #include "log.h" |
| andrewboyson | 147:a6093b52e654 | 8 | #include "led.h" |
| andrewboyson | 145:206bf0d073c7 | 9 | #include "restart.h" |
| andrewboyson | 145:206bf0d073c7 | 10 | #include "mstimer.h" |
| andrewboyson | 149:39d1ba392f4b | 11 | #include "random.h" |
| andrewboyson | 150:3366e4a0c60e | 12 | #include "pri-key.h" |
| andrewboyson | 145:206bf0d073c7 | 13 | |
| andrewboyson | 145:206bf0d073c7 | 14 | #define TLS_CONTENT_TYPE_ChangeCipher 20 |
| andrewboyson | 145:206bf0d073c7 | 15 | #define TLS_CONTENT_TYPE_Alert 21 |
| andrewboyson | 145:206bf0d073c7 | 16 | #define TLS_CONTENT_TYPE_Handshake 22 |
| andrewboyson | 145:206bf0d073c7 | 17 | #define TLS_CONTENT_TYPE_Application 23 |
| andrewboyson | 145:206bf0d073c7 | 18 | #define TLS_CONTENT_TYPE_Heartbeat 24 |
| andrewboyson | 145:206bf0d073c7 | 19 | |
| andrewboyson | 145:206bf0d073c7 | 20 | #define TLS_HANDSHAKE_HelloRequest 0 |
| andrewboyson | 145:206bf0d073c7 | 21 | #define TLS_HANDSHAKE_ClientHello 1 |
| andrewboyson | 145:206bf0d073c7 | 22 | #define TLS_HANDSHAKE_ServerHello 2 |
| andrewboyson | 145:206bf0d073c7 | 23 | #define TLS_HANDSHAKE_NewSessionTicket 4 |
| andrewboyson | 145:206bf0d073c7 | 24 | #define TLS_HANDSHAKE_EncryptedExtensions 8 |
| andrewboyson | 145:206bf0d073c7 | 25 | #define TLS_HANDSHAKE_Certificate 11 |
| andrewboyson | 145:206bf0d073c7 | 26 | #define TLS_HANDSHAKE_ServerKeyExchange 12 |
| andrewboyson | 145:206bf0d073c7 | 27 | #define TLS_HANDSHAKE_CertificateRequest 13 |
| andrewboyson | 145:206bf0d073c7 | 28 | #define TLS_HANDSHAKE_ServerHelloDone 14 |
| andrewboyson | 145:206bf0d073c7 | 29 | #define TLS_HANDSHAKE_CertificateVerify 15 |
| andrewboyson | 145:206bf0d073c7 | 30 | #define TLS_HANDSHAKE_ClientKeyExchange 16 |
| andrewboyson | 145:206bf0d073c7 | 31 | #define TLS_HANDSHAKE_Finished 20 |
| andrewboyson | 145:206bf0d073c7 | 32 | |
| andrewboyson | 148:5489d36986e5 | 33 | #define DO_WAIT_CLIENT_HELLO 0 |
| andrewboyson | 148:5489d36986e5 | 34 | #define DO_SEND_SERVER_HELLO 1 |
| andrewboyson | 148:5489d36986e5 | 35 | #define DO_WAIT_CLIENT_CHANGE 2 |
| andrewboyson | 148:5489d36986e5 | 36 | #define DO_SEND_SERVER_CHANGE 3 |
| andrewboyson | 148:5489d36986e5 | 37 | #define DO_APPLICATION 4 |
| andrewboyson | 147:a6093b52e654 | 38 | |
| andrewboyson | 147:a6093b52e654 | 39 | bool TlsTrace = true; |
| andrewboyson | 145:206bf0d073c7 | 40 | |
| andrewboyson | 149:39d1ba392f4b | 41 | static const char certificate[] = { |
| andrewboyson | 149:39d1ba392f4b | 42 | #include "certificate.inc" |
| andrewboyson | 149:39d1ba392f4b | 43 | }; |
| andrewboyson | 149:39d1ba392f4b | 44 | |
| andrewboyson | 149:39d1ba392f4b | 45 | void TlsInit() |
| andrewboyson | 149:39d1ba392f4b | 46 | { |
| andrewboyson | 150:3366e4a0c60e | 47 | PriKeyInit(); |
| andrewboyson | 149:39d1ba392f4b | 48 | } |
| andrewboyson | 149:39d1ba392f4b | 49 | |
| andrewboyson | 149:39d1ba392f4b | 50 | |
| andrewboyson | 147:a6093b52e654 | 51 | struct state |
| andrewboyson | 147:a6093b52e654 | 52 | { |
| andrewboyson | 147:a6093b52e654 | 53 | int toDo; |
| andrewboyson | 147:a6093b52e654 | 54 | }; |
| andrewboyson | 147:a6093b52e654 | 55 | static void logContentType(char contentType) |
| andrewboyson | 147:a6093b52e654 | 56 | { |
| andrewboyson | 147:a6093b52e654 | 57 | switch (contentType) |
| andrewboyson | 147:a6093b52e654 | 58 | { |
| andrewboyson | 147:a6093b52e654 | 59 | case TLS_CONTENT_TYPE_ChangeCipher: Log ("Change cipher"); break; |
| andrewboyson | 147:a6093b52e654 | 60 | case TLS_CONTENT_TYPE_Alert: Log ("Alert"); break; |
| andrewboyson | 147:a6093b52e654 | 61 | case TLS_CONTENT_TYPE_Handshake: Log ("Handshake"); break; |
| andrewboyson | 147:a6093b52e654 | 62 | case TLS_CONTENT_TYPE_Application: Log ("Application"); break; |
| andrewboyson | 147:a6093b52e654 | 63 | case TLS_CONTENT_TYPE_Heartbeat: Log ("Heartbeat"); break; |
| andrewboyson | 147:a6093b52e654 | 64 | default: LogF("%02hX", contentType); break; |
| andrewboyson | 147:a6093b52e654 | 65 | } |
| andrewboyson | 147:a6093b52e654 | 66 | } |
| andrewboyson | 147:a6093b52e654 | 67 | static void logHandshakeType(char handshakeType) |
| andrewboyson | 145:206bf0d073c7 | 68 | { |
| andrewboyson | 145:206bf0d073c7 | 69 | switch (handshakeType) |
| andrewboyson | 145:206bf0d073c7 | 70 | { |
| andrewboyson | 145:206bf0d073c7 | 71 | case TLS_HANDSHAKE_HelloRequest: Log ("Hello request"); break; |
| andrewboyson | 145:206bf0d073c7 | 72 | case TLS_HANDSHAKE_ClientHello: Log ("Client hello"); break; |
| andrewboyson | 145:206bf0d073c7 | 73 | case TLS_HANDSHAKE_ServerHello: Log ("Server hello"); break; |
| andrewboyson | 145:206bf0d073c7 | 74 | case TLS_HANDSHAKE_NewSessionTicket: Log ("New session ticket"); break; |
| andrewboyson | 145:206bf0d073c7 | 75 | case TLS_HANDSHAKE_EncryptedExtensions: Log ("Encrypted extensions"); break; |
| andrewboyson | 145:206bf0d073c7 | 76 | case TLS_HANDSHAKE_Certificate: Log ("Certificate"); break; |
| andrewboyson | 145:206bf0d073c7 | 77 | case TLS_HANDSHAKE_ServerKeyExchange: Log ("Server key exchange"); break; |
| andrewboyson | 145:206bf0d073c7 | 78 | case TLS_HANDSHAKE_CertificateRequest: Log ("Certificate request"); break; |
| andrewboyson | 145:206bf0d073c7 | 79 | case TLS_HANDSHAKE_ServerHelloDone: Log ("Server hello done"); break; |
| andrewboyson | 145:206bf0d073c7 | 80 | case TLS_HANDSHAKE_CertificateVerify: Log ("Certificate verify"); break; |
| andrewboyson | 145:206bf0d073c7 | 81 | case TLS_HANDSHAKE_ClientKeyExchange: Log ("Client key exchange"); break; |
| andrewboyson | 145:206bf0d073c7 | 82 | case TLS_HANDSHAKE_Finished: Log ("Finished"); break; |
| andrewboyson | 145:206bf0d073c7 | 83 | default: LogF("%02hX", handshakeType); break; |
| andrewboyson | 145:206bf0d073c7 | 84 | } |
| andrewboyson | 145:206bf0d073c7 | 85 | } |
| andrewboyson | 147:a6093b52e654 | 86 | void TlsRequest(char* pTlsState, char* pWebState, int size, char* pRequestStream, uint32_t positionInRequestStream) |
| andrewboyson | 145:206bf0d073c7 | 87 | { |
| andrewboyson | 147:a6093b52e654 | 88 | struct state* pState = (struct state*)pTlsState; |
| andrewboyson | 147:a6093b52e654 | 89 | |
| andrewboyson | 147:a6093b52e654 | 90 | if (TlsTrace) LogF("TLS <<< %d (%u)\r\n", size, positionInRequestStream); |
| andrewboyson | 145:206bf0d073c7 | 91 | |
| andrewboyson | 145:206bf0d073c7 | 92 | if (size == 0) return; |
| andrewboyson | 145:206bf0d073c7 | 93 | if (positionInRequestStream != 0) return; |
| andrewboyson | 145:206bf0d073c7 | 94 | char contentType = pRequestStream[0]; |
| andrewboyson | 149:39d1ba392f4b | 95 | char versionH = pRequestStream[1]; |
| andrewboyson | 149:39d1ba392f4b | 96 | char versionL = pRequestStream[2]; |
| andrewboyson | 149:39d1ba392f4b | 97 | int length = pRequestStream[3] << 8 | pRequestStream[4]; //Length (2 bytes) |
| andrewboyson | 148:5489d36986e5 | 98 | if (TlsTrace) |
| andrewboyson | 148:5489d36986e5 | 99 | { |
| andrewboyson | 149:39d1ba392f4b | 100 | Log (" content type: "); logContentType(contentType); Log("\r\n"); |
| andrewboyson | 149:39d1ba392f4b | 101 | LogF(" legacy HH:LL: %02x:%02x\r\n", versionH, versionL); |
| andrewboyson | 149:39d1ba392f4b | 102 | LogF(" length : %d\r\n" , length); |
| andrewboyson | 148:5489d36986e5 | 103 | } |
| andrewboyson | 145:206bf0d073c7 | 104 | switch (contentType) |
| andrewboyson | 145:206bf0d073c7 | 105 | { |
| andrewboyson | 145:206bf0d073c7 | 106 | case TLS_CONTENT_TYPE_Handshake: |
| andrewboyson | 148:5489d36986e5 | 107 | { |
| andrewboyson | 148:5489d36986e5 | 108 | char handshakeType = pRequestStream[5]; |
| andrewboyson | 148:5489d36986e5 | 109 | if (TlsTrace) { Log(" handshake type: "); logHandshakeType(handshakeType); Log("\r\n"); } |
| andrewboyson | 148:5489d36986e5 | 110 | pState->toDo = DO_SEND_SERVER_HELLO; |
| andrewboyson | 148:5489d36986e5 | 111 | return; |
| andrewboyson | 148:5489d36986e5 | 112 | } |
| andrewboyson | 147:a6093b52e654 | 113 | case TLS_CONTENT_TYPE_Application: |
| andrewboyson | 148:5489d36986e5 | 114 | { |
| andrewboyson | 148:5489d36986e5 | 115 | pState->toDo = DO_APPLICATION; |
| andrewboyson | 148:5489d36986e5 | 116 | return; |
| andrewboyson | 148:5489d36986e5 | 117 | } |
| andrewboyson | 148:5489d36986e5 | 118 | |
| andrewboyson | 145:206bf0d073c7 | 119 | default: |
| andrewboyson | 147:a6093b52e654 | 120 | Log("TLS - ignoring untreated content type\r\n"); |
| andrewboyson | 148:5489d36986e5 | 121 | pState->toDo = DO_WAIT_CLIENT_HELLO; |
| andrewboyson | 145:206bf0d073c7 | 122 | return; |
| andrewboyson | 145:206bf0d073c7 | 123 | } |
| andrewboyson | 145:206bf0d073c7 | 124 | } |
| andrewboyson | 149:39d1ba392f4b | 125 | char lengthH(int size) { return size >> 8;} |
| andrewboyson | 149:39d1ba392f4b | 126 | char lengthL(int size) { return size & 0xFF; } |
| andrewboyson | 149:39d1ba392f4b | 127 | void addSize(int size) |
| andrewboyson | 149:39d1ba392f4b | 128 | { |
| andrewboyson | 149:39d1ba392f4b | 129 | TcpBufAddChar(size >> 8 ); |
| andrewboyson | 149:39d1ba392f4b | 130 | TcpBufAddChar(size & 0xFF); |
| andrewboyson | 149:39d1ba392f4b | 131 | } |
| andrewboyson | 149:39d1ba392f4b | 132 | |
| andrewboyson | 147:a6093b52e654 | 133 | static void sendServerHello() |
| andrewboyson | 145:206bf0d073c7 | 134 | { |
| andrewboyson | 145:206bf0d073c7 | 135 | Log(" sending server hello\r\n"); |
| andrewboyson | 149:39d1ba392f4b | 136 | TcpBufAddChar(TLS_CONTENT_TYPE_Handshake); //Content is handshakes |
| andrewboyson | 149:39d1ba392f4b | 137 | TcpBufAddChar(0x03); TcpBufAddChar(0x03); //Legacy TLS version |
| andrewboyson | 149:39d1ba392f4b | 138 | addSize((45 + 4) + (sizeof(certificate) + 6 + 4) + (0 + 4)); //Handshakes Length (2 bytes) |
| andrewboyson | 148:5489d36986e5 | 139 | |
| andrewboyson | 149:39d1ba392f4b | 140 | TcpBufAddChar(TLS_HANDSHAKE_ServerHello); TcpBufAddChar(0x00); //Handshake type server hello |
| andrewboyson | 149:39d1ba392f4b | 141 | addSize(45); //Size of this handshake |
| andrewboyson | 149:39d1ba392f4b | 142 | TcpBufAddChar(0x03); TcpBufAddChar(0x03); //TLS version 1.2 |
| andrewboyson | 149:39d1ba392f4b | 143 | for (int i = 0; i < 32; i++) TcpBufAddChar(RandomGetByte()); //32 bit random number |
| andrewboyson | 149:39d1ba392f4b | 144 | TcpBufAddChar(0x00); //SessionId length 0 |
| andrewboyson | 149:39d1ba392f4b | 145 | TcpBufAddChar(0x00); TcpBufAddChar(0x2f); //Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) |
| andrewboyson | 149:39d1ba392f4b | 146 | TcpBufAddChar(0x00); //Compression method none |
| andrewboyson | 149:39d1ba392f4b | 147 | TcpBufAddChar(0x00); TcpBufAddChar(0x05); //Extensions length (2 bytes) 5 bytes |
| andrewboyson | 149:39d1ba392f4b | 148 | TcpBufAddChar(0xff); TcpBufAddChar(0x01); //Extension Renegotiation Info |
| andrewboyson | 149:39d1ba392f4b | 149 | TcpBufAddChar(0x00); TcpBufAddChar(0x01); //1 bytes of "Renegotiation Info" extension data follows |
| andrewboyson | 149:39d1ba392f4b | 150 | TcpBufAddChar(0x00); //length is zero, because this is a new connection |
| andrewboyson | 149:39d1ba392f4b | 151 | |
| andrewboyson | 149:39d1ba392f4b | 152 | TcpBufAddChar(TLS_HANDSHAKE_Certificate); TcpBufAddChar(0x00); //Handshake type certificate |
| andrewboyson | 149:39d1ba392f4b | 153 | addSize(sizeof(certificate) + 6); TcpBufAddChar(0x00); //Size of this handshake |
| andrewboyson | 149:39d1ba392f4b | 154 | addSize(sizeof(certificate) + 3); TcpBufAddChar(0x00); //Size of all certificates |
| andrewboyson | 149:39d1ba392f4b | 155 | addSize(sizeof(certificate) ); //Size of first certificate |
| andrewboyson | 149:39d1ba392f4b | 156 | for (int i = 0; i < sizeof(certificate); i++) TcpBufAddChar(certificate[i]); //Certificate |
| andrewboyson | 149:39d1ba392f4b | 157 | |
| andrewboyson | 149:39d1ba392f4b | 158 | TcpBufAddChar(TLS_HANDSHAKE_ServerHelloDone); TcpBufAddChar(0x00); //Handshake type server hello done |
| andrewboyson | 149:39d1ba392f4b | 159 | addSize(0); //Size of this handshake |
| andrewboyson | 145:206bf0d073c7 | 160 | } |
| andrewboyson | 147:a6093b52e654 | 161 | |
| andrewboyson | 147:a6093b52e654 | 162 | int TlsPoll(char* pTlsState, char* pWebState, bool clientFinished) |
| andrewboyson | 145:206bf0d073c7 | 163 | { |
| andrewboyson | 147:a6093b52e654 | 164 | struct state* pState = (struct state*)pTlsState; |
| andrewboyson | 147:a6093b52e654 | 165 | |
| andrewboyson | 147:a6093b52e654 | 166 | switch (pState->toDo) |
| andrewboyson | 147:a6093b52e654 | 167 | { |
| andrewboyson | 148:5489d36986e5 | 168 | case DO_WAIT_CLIENT_HELLO: |
| andrewboyson | 147:a6093b52e654 | 169 | if (clientFinished) return -1; //The client hasn't made a request and never will so finish |
| andrewboyson | 147:a6093b52e654 | 170 | else return 0; //The client hasn't made a request yet but it could. |
| andrewboyson | 147:a6093b52e654 | 171 | case DO_APPLICATION: return HttpPollFunction(pWebState, clientFinished); //Return whatever HTTP would be |
| andrewboyson | 147:a6093b52e654 | 172 | default: return 1; //The client has made a request so do it |
| andrewboyson | 147:a6093b52e654 | 173 | } |
| andrewboyson | 147:a6093b52e654 | 174 | } |
| andrewboyson | 147:a6093b52e654 | 175 | bool TlsReply(char* pTlsState, char* pWebState) |
| andrewboyson | 147:a6093b52e654 | 176 | { |
| andrewboyson | 147:a6093b52e654 | 177 | struct state* pState = (struct state*)pTlsState; |
| andrewboyson | 147:a6093b52e654 | 178 | |
| andrewboyson | 148:5489d36986e5 | 179 | switch(pState->toDo) |
| andrewboyson | 148:5489d36986e5 | 180 | { |
| andrewboyson | 148:5489d36986e5 | 181 | case DO_SEND_SERVER_HELLO: sendServerHello(); return true; |
| andrewboyson | 148:5489d36986e5 | 182 | default: return true; //Finished |
| andrewboyson | 148:5489d36986e5 | 183 | } |
| andrewboyson | 147:a6093b52e654 | 184 | } |
| andrewboyson | 147:a6093b52e654 | 185 | static char encrypt(char c) |
| andrewboyson | 147:a6093b52e654 | 186 | { |
| andrewboyson | 147:a6093b52e654 | 187 | return c; //Implement encryption |
| andrewboyson | 145:206bf0d073c7 | 188 | } |
| andrewboyson | 145:206bf0d073c7 | 189 | void TlsAddChar(char c) |
| andrewboyson | 145:206bf0d073c7 | 190 | { |
| andrewboyson | 147:a6093b52e654 | 191 | char e = encrypt(c); |
| andrewboyson | 147:a6093b52e654 | 192 | TcpBufAddChar(e); |
| andrewboyson | 145:206bf0d073c7 | 193 | } |