位置导航: ESP8266库 / WiFiServerSecure库 / 本页
说明
ESP8266建立的HTTPS服务器可以要求客户端提供证书以验证客户端身份。如果客户端无法提供证明身份的证书信息,ESP8266服务器会拒绝客户端访问。我们可以使用WiFiServerSecure库的setClientTrustAnchor函数来实现这一操作。
语法
server.setClientTrustAnchor(cert)
参数
– cert: CA证书
返回值
无
示例程序
请务必注意:本示例程序所使用的证书和密钥只能用于测试使用。您在自己搭建ESP8266物联网项目时,需要自行建立 证书密钥而不要使用本示例中的证书和密钥。
测试使用本示例程序需要使用wget指令。建议您在测试本示例程序以前先准备好一台Linux系统电脑。
接下来请点击以下链接,将用于客户端身份认证的证书和密钥文件下载并解压缩到您的Linux电脑中。
当您将以下示例程序中的WiFi连接信息修改并且将本示例程序上传ESP8266开发板后,开发板随即会自动连接WiFi。WiFi连接成功后,您将可以从串口监视器获取当前ESP8266开发板的IP地址。此时,ESP8266已经成功建立了支持HTTPS协议的网络服务器。您可以通过ESP8266的IP地址来访问该网络服务器。
假设您的ESP8266开发板IP地址是192.168.0.111。接下来请使用Linux电脑的终端应用输入以下指令:
wget –no-check-certificate –certificate=client1_cer.pem –private-key=client1_key.pem https://192.168.0.111
以上指令中client1_cer.pem和client1_key.pem 分别是您刚下载的客户端证书文件以及客户端私钥文件。这两个文件分别是客户端证书以及客户端私钥。他们的作用是为ESP8266服务器提供身份验证。
以下截屏是该指令的运行结果。我们可以看到,客户端成功的使用了下载的证书文件和私钥文件实现了与ESP8266服务器的网络通讯。
另外,我们从串口监视器可以看到,ESP8266服务器成功的响应了客户端请求。
以下示例程序中我们首先使用语句 BearSSL::X509List *serverTrustedCert = new BearSSL::X509List(ca_cert);建立X509List对象用于处理及储存受信CA证书。接下来我们使用了语句server.setClientTrustAnchor(serverTrustedCert);设置受信CA证书以验证客户端身份。
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 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
/* 项目名称/Project : 零基础入门学用物联网 程序名称/Program name : WiFiServerSecure_setClientTrustAnchor 团队/Team : 太极创客团队 / Taichi-Maker (www.taichi-maker.com) 作者/Author : CYNO朔 日期/Date(YYYYMMDD) : 20200422 程序目的/Purpose : 本示例程序借鉴ESP8266库中BearSSL_ServerClientCert示例程序,该程序作者Earle F. Philhower, III。 ESP8266 建立的HTTPS服务器可以要求客户端提供证书以验证客户端身份。如果客户端无法提供CA签署的证书或者无法 提供自签名证书,ESP8266服务器会拒绝客户端访问。此示例程序即是演示如何使用WiFiServerSecure库的 setClientTrustAnchor函数来实现这一操作。 如需了解如何使用本示例程序,请参考以下网址: http://www.taichi-maker.com/homepage/iot-development/iot-dev-reference/esp8266-c-plus-plus-reference/web-server-secure/setclienttrustanchor/ ----------------------------------------------------------------------- 本示例程序为太极创客团队制作的《零基础入门学用物联网》中示例程序。 该教程为对物联网开发感兴趣的朋友所设计和制作。如需了解更多该教程的信息,请参考以下网页: http://www.taichi-maker.com/homepage/esp8266-nodemcu-iot/ */ #include <ESP8266WiFi.h> #include <time.h> // WiFi连接信息 const char *ssid = "taichimaker";// WiFi名称 const char *pass = "12345678"; // WiFi密码 // 建立WiFiServerSecure对象 BearSSL::WiFiServerSecure server(443); // 建立服务器响应信息 static const char *HTTP_RES = "HTTP/1.0 200 OK\r\n" "Connection: close\r\n" "Content-Length: 59\r\n" "Content-Type: text/html; charset=iso-8859-1\r\n" "\r\n" "<html>\r\n" "<body>\r\n" "<p>Hello my friend!</p>\r\n" "</body>\r\n" "</html>\r\n"; // 受信任的CA证书 const char ca_cert[] PROGMEM = R"EOF( -----BEGIN CERTIFICATE----- MIIC1TCCAb2gAwIBAgIJAMPt1Ms37+hLMA0GCSqGSIb3DQEBCwUAMCExCzAJBgNV BAYTAlVTMRIwEAYDVQQDDAkxMjcuMC4wLjMwHhcNMTgwMzE0MDQyMTU0WhcNMjkw NTMxMDQyMTU0WjAhMQswCQYDVQQGEwJVUzESMBAGA1UEAwwJMTI3LjAuMC4zMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxsa4qU/tlzN4YTcnn/I/ffsi jOPc8QRcwClKzasIZNFEye4uThl+LGZWFIFb8X8Dc+xmmBaWlPJbqtphgFKStpar DdduHSW1ud6Y1FVKxljo3UwCMrYm76Q/jNzXJvGs6Z1MDNsVZzGJaoqit2H2Hkvk y+7kk3YbEDlcyVsLOw0zCKL4cd2DSNDyhIZxWo2a8Qn5IdjWAYtsTnW6MvLk/ya4 abNeRfSZwi+r37rqi9CIs++NpL5ynqkKKEMrbeLactWgHbWrZeaMyLpuUEL2GF+w MRaAwaj7ERwT5gFJRqYwj6bbfIdx5PC7h7ucbyp272MbrDa6WNBCMwQO222t4wID AQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCmXfrC42nW IpL3JDkB8YlB2QUvD9JdMp98xxo33+xE69Gov0e6984F1Gluao0p6sS7KF+q3YLS 4hjnzuGzF9GJMimIB7NMQ20yXKfKpmKJ7YugMaKTDWDhHn5679mKVbLSQxHCUMEe tEnMT93/UaDbWBjV6zu876q5vjPMYgDHODqO295ySaA71UkijaCn6UwKUT49286T V9ZtzgabNGHXfklHgUPWoShyze+G3g29I1BR0qABoJI63zaNu8ua42v5g1RldxsW X8yKI14mFOGxuvcygG8L2xxysW7Zq+9g+O7gW0Pm6RDYnUQmIwY83h1KFCtYCJdS 2PgozwkkUNyP -----END CERTIFICATE----- )EOF"; // 服务器私钥 const char server_private_key[] PROGMEM = R"EOF( -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAsRNVTvqP++YUh8NrbXwE83xVsDqcB3F76xcXNKFDERfVd2P/ LvyDovCcoQtT0UCRgPcxRp894EuPH/Ru6Z2Lu85sV//i7ce27tc2WRFSfuhlRxHP LJWHxTl1CEfXp/owkECQ4MB3pw6Ekc16iTEPiezTG+T+mQ/BkiIwcIK6CMlpR9DI eYUTqv0f9NrUfAjdBrqlEO2gpgFvLFrkDEU2ntAIc4aPOP7yDOym/xzfy6TiG8Wo 7nlh6M97xTZGfbEPCH9rZDjo5istym1HzF5P+COq+OTSPscjFGXoi978o6hZwa7i zxorg4h5a5lGnshRu2Gl+Ybfa14OwnIrv/yCswIDAQABAoIBAHxwgbsHCriTcEoY Yx6F0VTrQ6ydA5mXfuYvS/eIfIE+pp1IgMScYEXZobjrJPQg1CA1l0NyFSHS97oV JPy34sMQxcLx6KABgeVHCMJ/EeJtnv7a3SUP0GIhhsVS95Lsl8RIG4hWub+EzFVK eZqAB9N9wr4Pp3wZPodbz37B38rb1QPyMFmQOLlHjKTOmoxsXhL2ot+R3+aLYSur oPO1kQo7/d0UAZoy8h9OQN4a2EXvawh4O2EvFGbc5X/yXwAdEQ4NPp9VZhkNIRkV +XZ3FcIqEVOploKtRF/tVBTz3g61/lFz21L9PMmV5y8tvSafr2SpJugGVmp2rrVQ VNyGlIECgYEA10JSI5gmeCU3zK6kvOfBp54hY/5dDrSUpjKkMxpmm7WZQ6Il/k7A hMcLeMzHiriT7WhRIXF8AOr2MoEkHkH3DhVNN4ccieVZx2SE5P5mVkItZGLrrpfU dysR/ARAI1HYegGUiKacZtf9SrRavU0m7fOVOiYwbFRhjyX+MyuteYkCgYEA0pbz 4ZosetScP68uZx1sGlTfkcqLl7i15DHk3gnj6jKlfhvC2MjeLMhNDtKeUAuY7rLQ guZ0CCghWAv0Glh5eYdfIiPhgqFfX4P5F3Om4zQHVPYj8xHfHG4ZP7dKQTndrO1Q fLdGDTQLVXabAUSp2YGrijC8J9idSW1pYClvF1sCgYEAjkDn41nzYkbGP1/Swnwu AEWCL4Czoro32jVxScxSrugt5wJLNWp508VukWBTJhugtq3Pn9hNaJXeKbYqVkyl pgrxwpZph7+nuxt0r5hnrO2C7eppcjIoWLB/7BorAKxf8REGReBFT7nBTBMwPBW2 el4U6h6+tXh2GJG1Eb/1nnECgYAydVb0THOx7rWNkNUGggc/++why61M6kYy6j2T cj05BW+f2tkCBoctpcTI83BZb53yO8g4RS2yMqNirGKN2XspwmTqEjzbhv0KLt4F X4GyWOoU0nFksXiLIFpOaQWSwWG7KJWrfGJ9kWXR0Xxsfl5QLoDCuNCsn3t4d43T K7phlwKBgHDzF+50+/Wez3YHCy2a/HgSbHCpLQjkknvgwkOh1z7YitYBUm72HP8Z Ge6b4wEfNuBdlZll/y9BQQOZJLFvJTE5t51X9klrkGrOb+Ftwr7eI/H5xgcadI52 tPYglR5fjuRF/wnt3oX9JlQ2RtSbs+3naXH8JoherHaqNn8UpH0t -----END RSA PRIVATE KEY----- )EOF"; // 服务器证书 const char server_cert[] PROGMEM = R"EOF( -----BEGIN CERTIFICATE----- MIIDTzCCAjcCCQDPXvMRYOpeuDANBgkqhkiG9w0BAQsFADCBpjESMBAGA1UEAwwJ MTI3LjAuMC4xMQswCQYDVQQGEwJVUzElMCMGA1UECgwcTXkgT3duIENlcnRpZmlj YXRlIEF1dGhvcml0eTEUMBIGA1UECAwLQXJkdWlub0xhbmQxFTATBgNVBAcMDEFy ZHVpbm9WaWxsZTEVMBMGA1UECgwMRVNQODI2NlVzZXJzMRgwFgYDVQQLDA9FU1A4 MjY2LUFyZHVpbm8wHhcNMTgwMzE0MDQwMDAwWhcNMjkwMjI0MDQwMDAwWjAsMRYw FAYDVQQKDA1NeSBTZXJ2ZXIgT3JnMRIwEAYDVQQDDAkxMjcuMC4wLjMwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxE1VO+o/75hSHw2ttfATzfFWwOpwH cXvrFxc0oUMRF9V3Y/8u/IOi8JyhC1PRQJGA9zFGnz3gS48f9G7pnYu7zmxX/+Lt x7bu1zZZEVJ+6GVHEc8slYfFOXUIR9en+jCQQJDgwHenDoSRzXqJMQ+J7NMb5P6Z D8GSIjBwgroIyWlH0Mh5hROq/R/02tR8CN0GuqUQ7aCmAW8sWuQMRTae0Ahzho84 /vIM7Kb/HN/LpOIbxajueWHoz3vFNkZ9sQ8If2tkOOjmKy3KbUfMXk/4I6r45NI+ xyMUZeiL3vyjqFnBruLPGiuDiHlrmUaeyFG7YaX5ht9rXg7Cciu//IKzAgMBAAEw DQYJKoZIhvcNAQELBQADggEBAEnG+FNyNCOkBvzHiUpHHpScxZqM2f+XDcewJgeS L6HkYEDIZZDNnd5gduSvkHpdJtWgsvJ7dJZL40w7Ba5sxpZHPIgKJGl9hzMkG+aA z5GMkjys9h2xpQZx9KL3q7G6A+C0bll7ODZlwBtY07CFMykT4Mp2oMRrQKRucMSV AB1mKujLAnMRKJ3NM89RQJH4GYiRps9y/HvM5lh7EIK/J0/nEZeJxY5hJngskPKb oPPdmkR97kaQnll4KNsC3owVlHVU2fMftgYkgQLzyeWgzcNa39AF3B6JlcOzNyQY seoK24dHmt6tWmn/sbxX7Aa6TL/4mVlFoOgcaTJyVaY/BrY= -----END CERTIFICATE----- )EOF"; // 获取网络时间,该时间信息用于证书认证 void setClock() { configTime(8 * 3600, 0, "ntp.ntsc.ac.cn","pool.ntp.org", "time.nist.gov"); Serial.print("Waiting for NTP time sync: "); time_t now = time(nullptr); while (now < 8 * 3600 * 2) { delay(500); Serial.print("."); now = time(nullptr); } Serial.println(""); struct tm timeinfo; gmtime_r(&now, &timeinfo); Serial.print("Current time: "); Serial.print(asctime(&timeinfo)); } void setup() { Serial.begin(9600); Serial.println(); Serial.println(); // 连接 WiFi Serial.print("Connecting to "); Serial.println(ssid); WiFi.mode(WIFI_STA); WiFi.begin(ssid, pass); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); setClock(); // 获取网络时间,该时间信息用于证书认证 // 建立X509List对象用于处理及储存服务器证书 BearSSL::X509List *serverCertList = new BearSSL::X509List(server_cert); // 建立PrivateKey对象用于处理及储存服务器私钥 BearSSL::PrivateKey *serverPrivKey = new BearSSL::PrivateKey(server_private_key); // 设置服务器证书和服务器私钥 server.setRSACert(serverCertList, serverPrivKey); // 建立X509List对象用于处理及储存受信CA证书 BearSSL::X509List *serverTrustedCert = new BearSSL::X509List(ca_cert); // 设置受信CA证书以验证客户端身份 server.setClientTrustAnchor(serverTrustedCert); // 启动服务器 server.begin(); } void loop() { BearSSL::WiFiClientSecure incoming = server.available(); if (!incoming) { return; } Serial.println("Incoming connection...\n"); // 等待客户端发送请求 uint32_t timeout=millis() + 1000; int lcwn = 0; for (;;) { unsigned char x=0; if ((millis() > timeout) || (incoming.available() && incoming.read(&x, 1) < 0)) { incoming.stop(); Serial.printf("Connection error, closed\n"); return; } else if (!x) { yield(); continue; } else if (x == 0x0D) { continue; } else if (x == 0x0A) { if (lcwn) { break; } lcwn = 1; } else lcwn = 0; } // 发送响应信息 incoming.write((uint8_t*)HTTP_RES, strlen(HTTP_RES)); incoming.flush(); incoming.stop(); Serial.printf("Connection closed.\n"); } |
位置导航: ESP8266库 / WiFiServerSecure库 / 本页