-
Notifications
You must be signed in to change notification settings - Fork 1
/
HttpsCertificateExtension.h
144 lines (128 loc) · 4.21 KB
/
HttpsCertificateExtension.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#ifndef HTTPS_CERTIFICATE_EXT_H
#define HTTPS_CERTIFICATE_EXT_H
/**
* This file implements extension for client certificates for HTTPS protocol.
* Certificate and key need to be in unencrypted (empty passphrase) DER format.
*
* Example for making keys:
* generate the private key (a 1024 bit key is used in this example)
* > openssl genrsa -out my_private_key.pem 1024
*
* convert the private key into DER format
* > openssl rsa -in ./my_private_key.pem -out ./my_private_key -outform DER
*
* generate the certificate request using the previously generated private key
* > openssl req -new -key my_private_key.pem -out my_cert_req.pem
*
* get the certificate from Certificate Authority
* (see other guides if you are managing your own CA)
*
* convert the certificate into DER format
* > openssl x509 -in my_cert.pem -out my_cert -outform DER
*
* Then you can use SPIFFS or convert the keys to C code header with
* > xxd -i client.crt > MyCertificates.cpp
* > xxd -i client.key >> MyCertificates.cpp
*
* Then you can use these classes to do the job:
* #include "MyCertificates.h"
* HttpsCertificateClient http;
* http.begin(url, fingerprint, client_crt, client_crt_len, client_key, client_key_len);
*/
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#include <WiFiClientSecure.h>
#include <memory>
class TransportTraits
{
public:
virtual ~TransportTraits() { }
virtual std::unique_ptr<WiFiClient> create() {
return std::unique_ptr<WiFiClient>(new WiFiClient());
}
virtual bool verify(WiFiClient& client, const char* host) {
return true;
}
};
class TLSTraits : public TransportTraits
{
public:
TLSTraits(const String& fingerprint) : _fingerprint(fingerprint) {}
protected:
String _fingerprint;
};
class ClientCertificateTLSTraits : public TLSTraits {
public:
ClientCertificateTLSTraits(
const String& fingerprint,
const uint8_t* certificate,
const uint16_t cert_len,
const uint8_t* private_key,
const uint16_t key_len)
: TLSTraits (fingerprint)
, _cert(certificate)
, _certLen(cert_len)
, _key(private_key)
, _keyLen(key_len)
{ };
std::unique_ptr<WiFiClient> create() override
{
auto espClient = new WiFiClientSecure();
espClient->setCertificate(_cert, _certLen);
espClient->setPrivateKey(_key, _keyLen);
return std::unique_ptr<WiFiClient>(espClient);
};
bool verify(WiFiClient& client, const char* host) override
{
auto wcs = reinterpret_cast<WiFiClientSecure&>(client);
return wcs.verify(_fingerprint.c_str(), host);
}
protected:
const uint8_t* _cert;
const uint16_t _certLen;
const uint8_t* _key;
const uint16_t _keyLen;
};
class HttpsCertificateClient : public HTTPClient {
public:
bool begin(String url,
String httpsFingerprint,
const uint8_t* certificate,
const uint16_t cert_len,
const uint8_t* private_key,
const uint16_t key_len)
{
_transportTraits.reset(nullptr);
_port = 443;
if (httpsFingerprint.length() == 0
|| cert_len < 100
|| key_len < 100) {
return false;
}
if (!beginInternal(url, "https")) {
return false;
}
_transportTraits = TransportTraitsPtr(
new ClientCertificateTLSTraits(
httpsFingerprint, certificate, cert_len, private_key, key_len));
//DEBUG_HTTPCLIENT("[HTTP-Client][begin] httpsFingerprint: %s\n", httpsFingerprint.c_str());
return true;
};
};
class ESPCertificateUpdate : ESP8266HTTPUpdate {
public:
t_httpUpdate_return update(
const String& url,
const String& currentVersion,
const String& fingerprint,
const uint8_t* certificate,
const uint16_t cert_len,
const uint8_t* private_key,
const uint16_t key_len) {
HttpsCertificateClient http;
http.begin(url, fingerprint, certificate, cert_len, private_key, key_len);
yield();
return handleUpdate(http, currentVersion);
};
};
#endif