Skip to content

Commit caa46dd

Browse files
committed
Release v0.2.20
1 parent c55f802 commit caa46dd

7 files changed

Lines changed: 189 additions & 99 deletions

File tree

RELEASING.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,34 @@ For the future update-check task, the recommended flow is:
157157
3. choose the correct OTA entry for the current hardware profile
158158
4. verify the matching SHA-256 before applying the update
159159

160+
## HTTPS Certificate Bundle
161+
162+
GitHub OTA now uses an Espressif X.509 certificate bundle via `setCACertBundle(...)` instead of a hand-maintained PEM string.
163+
164+
Relevant files:
165+
166+
- `src/TrustedCerts.h`
167+
- `src/TrustedCertsBundle.h`
168+
169+
If GitHub or the OTA HTTPS chain changes in the future, regenerate the bundle with the tool shipped in the Arduino-ESP32 package:
170+
171+
```bash
172+
python3 ~/.platformio/packages/framework-arduinoespressif32/tools/gen_crt_bundle.py --input /path/to/cert/folder
173+
xxd -i x509_crt_bundle > /tmp/sp7_ca_bundle.inc
174+
```
175+
176+
Current bundle contents:
177+
178+
- `ISRG Root X1`
179+
- `USERTrust ECC Certification Authority`
180+
181+
After regenerating:
182+
183+
1. Replace the byte array in `src/TrustedCertsBundle.h`
184+
2. Build `pio run -e soundpanel7_usb`
185+
3. Validate `POST /api/release/check`
186+
4. Validate a real GitHub OTA install from device
187+
160188
## Suggested first release notes
161189

162190
Example:

custom_components/soundpanel7/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"iot_class": "local_polling",
99
"issue_tracker": "https://github.com/jjtronics/SoundPanel7/issues",
1010
"requirements": [],
11-
"version": "0.2.19",
11+
"version": "0.2.20",
1212
"zeroconf": [
1313
{
1414
"type": "_soundpanel7._tcp.local."

include/AppConfig.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#pragma once
33
#include <stdint.h>
44

5-
#define SOUNDPANEL7_VERSION "0.2.19"
5+
#define SOUNDPANEL7_VERSION "0.2.20"
66
#define SOUNDPANEL7_BUILD_DATE __DATE__ " " __TIME__
77

88
#ifndef SOUNDPANEL7_BUILD_ENV

src/ReleaseUpdateManager.cpp

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ void ReleaseUpdateManager::setError(const String& error) {
150150

151151
void ReleaseUpdateManager::clearInstallState() {
152152
cleanupInstallTransport();
153+
_installDownloadUrl = "";
153154
_installInProgress = false;
154155
_installFinished = false;
155156
_installSucceeded = false;
@@ -351,6 +352,17 @@ void ReleaseUpdateManager::processInstall() {
351352
updateInstallUi(true);
352353
WiFi.setSleep(false);
353354

355+
if (_installDownloadUrl.isEmpty()) {
356+
int resolvedCode = 0;
357+
String resolvedError;
358+
String resolvedUrl;
359+
if (resolveGithubAssetUrl(String(_otaUrl), resolvedUrl, resolvedCode, resolvedError) && !resolvedUrl.isEmpty()) {
360+
_installDownloadUrl = resolvedUrl;
361+
} else {
362+
_installDownloadUrl = String(_otaUrl);
363+
}
364+
}
365+
354366
_installClient = new WiFiClientSecure();
355367
_installHttp = new HTTPClient();
356368
if (!_installClient || !_installHttp) {
@@ -368,7 +380,7 @@ void ReleaseUpdateManager::processInstall() {
368380
_installHttp->setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
369381
_installHttp->setReuse(false);
370382
_installHttp->setUserAgent(String("SoundPanel7/") + SOUNDPANEL7_VERSION);
371-
if (!_installHttp->begin(*_installClient, _otaUrl)) {
383+
if (!_installHttp->begin(*_installClient, _installDownloadUrl)) {
372384
cleanupInstallTransport();
373385
finishInstall(false, "ota request init failed");
374386
return;
@@ -573,6 +585,63 @@ bool ReleaseUpdateManager::fetchUrl(const String& url, String& payload, int& htt
573585
return true;
574586
}
575587

588+
bool ReleaseUpdateManager::resolveGithubAssetUrl(const String& url, String& resolvedUrl, int& httpCode, String& error) {
589+
resolvedUrl = url;
590+
httpCode = 0;
591+
error = "";
592+
593+
if (!url.startsWith("https://github.com/")) {
594+
return true;
595+
}
596+
597+
WiFi.setSleep(false);
598+
WiFiClientSecure client;
599+
configureSecureClient(client);
600+
client.setTimeout(kHttpTimeoutMs);
601+
602+
HTTPClient http;
603+
http.setConnectTimeout(kHttpConnectTimeoutMs);
604+
http.setTimeout(kHttpTimeoutMs);
605+
http.setFollowRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS);
606+
http.setReuse(false);
607+
http.setUserAgent(String("SoundPanel7/") + SOUNDPANEL7_VERSION);
608+
609+
const char* headerKeys[] = {"Location"};
610+
http.collectHeaders(headerKeys, 1);
611+
612+
if (!http.begin(client, url)) {
613+
error = "resolve init failed";
614+
return false;
615+
}
616+
617+
httpCode = http.sendRequest("HEAD");
618+
if (httpCode == HTTP_CODE_FOUND || httpCode == HTTP_CODE_MOVED_PERMANENTLY ||
619+
httpCode == HTTP_CODE_TEMPORARY_REDIRECT || httpCode == HTTP_CODE_PERMANENT_REDIRECT) {
620+
const String location = http.header("Location");
621+
http.end();
622+
if (location.isEmpty()) {
623+
error = "redirect missing location";
624+
return false;
625+
}
626+
resolvedUrl = location;
627+
return true;
628+
}
629+
630+
if (httpCode == HTTP_CODE_OK) {
631+
http.end();
632+
return true;
633+
}
634+
635+
error = "resolve http ";
636+
error += String(httpCode);
637+
if (httpCode < 0) {
638+
error += " ";
639+
error += http.errorToString(httpCode);
640+
}
641+
http.end();
642+
return false;
643+
}
644+
576645
bool ReleaseUpdateManager::parseLatestReleaseApiPayload(const String& payload) {
577646
const String tag = sp7json::parseString(payload, "tag_name", "", false);
578647
const String version = stripLeadingVersionPrefix(tag);

src/ReleaseUpdateManager.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class ReleaseUpdateManager {
7777

7878
bool fetchManifest(String& payload);
7979
bool fetchUrl(const String& url, String& payload, int& httpCode, String& error);
80+
bool resolveGithubAssetUrl(const String& url, String& resolvedUrl, int& httpCode, String& error);
8081
bool parseLatestReleaseApiPayload(const String& payload);
8182
bool fetchManifestViaLatestReleaseApi(String& payload, int& httpCode, String& error);
8283
bool parseManifest(const String& payload);
@@ -102,6 +103,7 @@ class ReleaseUpdateManager {
102103
mbedtls_sha256_context _installSha = {};
103104
bool _installShaActive = false;
104105
uint8_t _installBuffer[kInstallChunkSize] = {};
106+
String _installDownloadUrl;
105107
Preferences _prefs;
106108
bool _prefsReady = false;
107109
uint8_t _lastInstallUiProgressPct = 255;

src/TrustedCerts.h

Lines changed: 3 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,9 @@
11
#pragma once
22

3-
// Let's Encrypt ISRG Root X1 (expires 2035)
4-
// Covers GitHub release assets and other modern services.
5-
static const char* const ISRG_ROOT_X1_CA = R"EOF(-----BEGIN CERTIFICATE-----
6-
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
7-
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
8-
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
9-
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
10-
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
11-
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
12-
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
13-
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
14-
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
15-
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
16-
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
17-
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
18-
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
19-
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
20-
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
21-
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hvc1sXoaxgktohCYZAU
22-
wGRpAAgyLQVJOgERSaGnZzhku0ByHU+lQNh3xaSnpDEn20RCIBmM+gGF3dYNXOTx
23-
Kg1gGyRv3FsSGCu3qJHx3UJgFCbFMQXbN5K0zFGJCe9GJMKsUn5hBfkGLwFRqJ0i
24-
x4zWN7JdxNtNYVgKIuXrFrJGhEhKqJwH1RxLTDmGQmFhYx1ZnUTqFy7Iw8JCxLqU
25-
MaXeJnUQeFxLJqMTi8qJkJqU0PzRc0C2MwDCHLVBN7/lROBQlk9j7VxGHqU9N8Qe
26-
7KfBvCUBdWXdBwARA8e3AoIBAQCfBpQ5l5Lm3Z1uYm0qD7pXdKj3k6NjTPl+3+VK
27-
5E03F5SY3EoGN3qQZ7KHMh3Dxfm2CtxHHxTNdCQvfaKsVrL3q3wFLT6yVtI1zE9j
28-
AH3eLQlK0wP3thPHZrqpqQi3PQbg5HCRlNtSDmDYnVfhvWWXr9yQCYGLyQr7VBfM
29-
ECxpGwSwdBCVhEfLBJKNZfJXbCTTBkMRqhMxXEZQqGQ3bLJKPR5fHYDHKT5t8qEV
30-
8dXjxqT7Kg1FqF0VlON8ZpN5w4FW6PxRvhNrHJ0BcKs8IkYLvBwUZwGkYt0mA0X0
31-
MFQfwNfXXDCAT0xKQ0ULmqLLLGv1K7xW0N+mQfCKIuHJjQRE
32-
-----END CERTIFICATE-----
33-
)EOF";
3+
#include <WiFiClientSecure.h>
344

35-
// Sectigo Public Server Authentication Root E46 (expires 2046)
36-
// GitHub API and release pages currently chain to Sectigo, so OTA checks need it.
37-
static const char* const SECTIGO_PUBLIC_SERVER_AUTH_ROOT_E46_CA = R"EOF(-----BEGIN CERTIFICATE-----
38-
MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw
39-
CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T
40-
ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN
41-
MjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYG
42-
A1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT
43-
ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA
44-
IgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccC
45-
WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+
46-
6xnOQ6OjQjBAMB0GA1UdDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8B
47-
Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa
48-
qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q
49-
4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw==
50-
-----END CERTIFICATE-----
51-
)EOF";
5+
#include "TrustedCertsBundle.h"
526

53-
static const char* const SOUNDPANEL7_TRUSTED_CA_BUNDLE = R"EOF(
54-
)EOF"
55-
R"EOF(-----BEGIN CERTIFICATE-----
56-
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
57-
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
58-
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
59-
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
60-
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
61-
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
62-
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
63-
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
64-
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
65-
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
66-
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
67-
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
68-
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
69-
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
70-
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
71-
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hvc1sXoaxgktohCYZAU
72-
wGRpAAgyLQVJOgERSaGnZzhku0ByHU+lQNh3xaSnpDEn20RCIBmM+gGF3dYNXOTx
73-
Kg1gGyRv3FsSGCu3qJHx3UJgFCbFMQXbN5K0zFGJCe9GJMKsUn5hBfkGLwFRqJ0i
74-
x4zWN7JdxNtNYVgKIuXrFrJGhEhKqJwH1RxLTDmGQmFhYx1ZnUTqFy7Iw8JCxLqU
75-
MaXeJnUQeFxLJqMTi8qJkJqU0PzRc0C2MwDCHLVBN7/lROBQlk9j7VxGHqU9N8Qe
76-
7KfBvCUBdWXdBwARA8e3AoIBAQCfBpQ5l5Lm3Z1uYm0qD7pXdKj3k6NjTPl+3+VK
77-
5E03F5SY3EoGN3qQZ7KHMh3Dxfm2CtxHHxTNdCQvfaKsVrL3q3wFLT6yVtI1zE9j
78-
AH3eLQlK0wP3thPHZrqpqQi3PQbg5HCRlNtSDmDYnVfhvWWXr9yQCYGLyQr7VBfM
79-
ECxpGwSwdBCVhEfLBJKNZfJXbCTTBkMRqhMxXEZQqGQ3bLJKPR5fHYDHKT5t8qEV
80-
8dXjxqT7Kg1FqF0VlON8ZpN5w4FW6PxRvhNrHJ0BcKs8IkYLvBwUZwGkYt0mA0X0
81-
MFQfwNfXXDCAT0xKQ0ULmqLLLGv1K7xW0N+mQfCKIuHJjQRE
82-
-----END CERTIFICATE-----
83-
-----BEGIN CERTIFICATE-----
84-
MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw
85-
CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T
86-
ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN
87-
MjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYG
88-
A1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT
89-
ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA
90-
IgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccC
91-
WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+
92-
6xnOQ6OjQjBAMB0GA1UdDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8B
93-
Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa
94-
qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q
95-
4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw==
96-
-----END CERTIFICATE-----
97-
)EOF";
98-
99-
// Helper function to configure WiFiClientSecure with certificate validation.
1007
inline void configureSecureClient(WiFiClientSecure& client) {
101-
client.setCACert(SOUNDPANEL7_TRUSTED_CA_BUNDLE);
8+
client.setCACertBundle(kSoundPanel7TrustedCaBundle, kSoundPanel7TrustedCaBundleLen);
1029
}

src/TrustedCertsBundle.h

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#pragma once
2+
3+
// Generated with Espressif's gen_crt_bundle.py from:
4+
// - ISRG Root X1 (Let's Encrypt)
5+
// - USERTrust ECC Certification Authority
6+
static const unsigned char kSoundPanel7TrustedCaBundle[] = {
7+
0x00, 0x02, 0x00, 0x51, 0x02, 0x26, 0x30, 0x4f, 0x31, 0x0b, 0x30, 0x09,
8+
0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x29, 0x30,
9+
0x27, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x20, 0x49, 0x6e, 0x74, 0x65,
10+
0x72, 0x6e, 0x65, 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
11+
0x79, 0x20, 0x52, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, 0x47,
12+
0x72, 0x6f, 0x75, 0x70, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04,
13+
0x03, 0x13, 0x0c, 0x49, 0x53, 0x52, 0x47, 0x20, 0x52, 0x6f, 0x6f, 0x74,
14+
0x20, 0x58, 0x31, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
15+
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
16+
0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00,
17+
0xad, 0xe8, 0x24, 0x73, 0xf4, 0x14, 0x37, 0xf3, 0x9b, 0x9e, 0x2b, 0x57,
18+
0x28, 0x1c, 0x87, 0xbe, 0xdc, 0xb7, 0xdf, 0x38, 0x90, 0x8c, 0x6e, 0x3c,
19+
0xe6, 0x57, 0xa0, 0x78, 0xf7, 0x75, 0xc2, 0xa2, 0xfe, 0xf5, 0x6a, 0x6e,
20+
0xf6, 0x00, 0x4f, 0x28, 0xdb, 0xde, 0x68, 0x86, 0x6c, 0x44, 0x93, 0xb6,
21+
0xb1, 0x63, 0xfd, 0x14, 0x12, 0x6b, 0xbf, 0x1f, 0xd2, 0xea, 0x31, 0x9b,
22+
0x21, 0x7e, 0xd1, 0x33, 0x3c, 0xba, 0x48, 0xf5, 0xdd, 0x79, 0xdf, 0xb3,
23+
0xb8, 0xff, 0x12, 0xf1, 0x21, 0x9a, 0x4b, 0xc1, 0x8a, 0x86, 0x71, 0x69,
24+
0x4a, 0x66, 0x66, 0x6c, 0x8f, 0x7e, 0x3c, 0x70, 0xbf, 0xad, 0x29, 0x22,
25+
0x06, 0xf3, 0xe4, 0xc0, 0xe6, 0x80, 0xae, 0xe2, 0x4b, 0x8f, 0xb7, 0x99,
26+
0x7e, 0x94, 0x03, 0x9f, 0xd3, 0x47, 0x97, 0x7c, 0x99, 0x48, 0x23, 0x53,
27+
0xe8, 0x38, 0xae, 0x4f, 0x0a, 0x6f, 0x83, 0x2e, 0xd1, 0x49, 0x57, 0x8c,
28+
0x80, 0x74, 0xb6, 0xda, 0x2f, 0xd0, 0x38, 0x8d, 0x7b, 0x03, 0x70, 0x21,
29+
0x1b, 0x75, 0xf2, 0x30, 0x3c, 0xfa, 0x8f, 0xae, 0xdd, 0xda, 0x63, 0xab,
30+
0xeb, 0x16, 0x4f, 0xc2, 0x8e, 0x11, 0x4b, 0x7e, 0xcf, 0x0b, 0xe8, 0xff,
31+
0xb5, 0x77, 0x2e, 0xf4, 0xb2, 0x7b, 0x4a, 0xe0, 0x4c, 0x12, 0x25, 0x0c,
32+
0x70, 0x8d, 0x03, 0x29, 0xa0, 0xe1, 0x53, 0x24, 0xec, 0x13, 0xd9, 0xee,
33+
0x19, 0xbf, 0x10, 0xb3, 0x4a, 0x8c, 0x3f, 0x89, 0xa3, 0x61, 0x51, 0xde,
34+
0xac, 0x87, 0x07, 0x94, 0xf4, 0x63, 0x71, 0xec, 0x2e, 0xe2, 0x6f, 0x5b,
35+
0x98, 0x81, 0xe1, 0x89, 0x5c, 0x34, 0x79, 0x6c, 0x76, 0xef, 0x3b, 0x90,
36+
0x62, 0x79, 0xe6, 0xdb, 0xa4, 0x9a, 0x2f, 0x26, 0xc5, 0xd0, 0x10, 0xe1,
37+
0x0e, 0xde, 0xd9, 0x10, 0x8e, 0x16, 0xfb, 0xb7, 0xf7, 0xa8, 0xf7, 0xc7,
38+
0xe5, 0x02, 0x07, 0x98, 0x8f, 0x36, 0x08, 0x95, 0xe7, 0xe2, 0x37, 0x96,
39+
0x0d, 0x36, 0x75, 0x9e, 0xfb, 0x0e, 0x72, 0xb1, 0x1d, 0x9b, 0xbc, 0x03,
40+
0xf9, 0x49, 0x05, 0xd8, 0x81, 0xdd, 0x05, 0xb4, 0x2a, 0xd6, 0x41, 0xe9,
41+
0xac, 0x01, 0x76, 0x95, 0x0a, 0x0f, 0xd8, 0xdf, 0xd5, 0xbd, 0x12, 0x1f,
42+
0x35, 0x2f, 0x28, 0x17, 0x6c, 0xd2, 0x98, 0xc1, 0xa8, 0x09, 0x64, 0x77,
43+
0x6e, 0x47, 0x37, 0xba, 0xce, 0xac, 0x59, 0x5e, 0x68, 0x9d, 0x7f, 0x72,
44+
0xd6, 0x89, 0xc5, 0x06, 0x41, 0x29, 0x3e, 0x59, 0x3e, 0xdd, 0x26, 0xf5,
45+
0x24, 0xc9, 0x11, 0xa7, 0x5a, 0xa3, 0x4c, 0x40, 0x1f, 0x46, 0xa1, 0x99,
46+
0xb5, 0xa7, 0x3a, 0x51, 0x6e, 0x86, 0x3b, 0x9e, 0x7d, 0x72, 0xa7, 0x12,
47+
0x05, 0x78, 0x59, 0xed, 0x3e, 0x51, 0x78, 0x15, 0x0b, 0x03, 0x8f, 0x8d,
48+
0xd0, 0x2f, 0x05, 0xb2, 0x3e, 0x7b, 0x4a, 0x1c, 0x4b, 0x73, 0x05, 0x12,
49+
0xfc, 0xc6, 0xea, 0xe0, 0x50, 0x13, 0x7c, 0x43, 0x93, 0x74, 0xb3, 0xca,
50+
0x74, 0xe7, 0x8e, 0x1f, 0x01, 0x08, 0xd0, 0x30, 0xd4, 0x5b, 0x71, 0x36,
51+
0xb4, 0x07, 0xba, 0xc1, 0x30, 0x30, 0x5c, 0x48, 0xb7, 0x82, 0x3b, 0x98,
52+
0xa6, 0x7d, 0x60, 0x8a, 0xa2, 0xa3, 0x29, 0x82, 0xcc, 0xba, 0xbd, 0x83,
53+
0x04, 0x1b, 0xa2, 0x83, 0x03, 0x41, 0xa1, 0xd6, 0x05, 0xf1, 0x1b, 0xc2,
54+
0xb6, 0xf0, 0xa8, 0x7c, 0x86, 0x3b, 0x46, 0xa8, 0x48, 0x2a, 0x88, 0xdc,
55+
0x76, 0x9a, 0x76, 0xbf, 0x1f, 0x6a, 0xa5, 0x3d, 0x19, 0x8f, 0xeb, 0x38,
56+
0xf3, 0x64, 0xde, 0xc8, 0x2b, 0x0d, 0x0a, 0x28, 0xff, 0xf7, 0xdb, 0xe2,
57+
0x15, 0x42, 0xd4, 0x22, 0xd0, 0x27, 0x5d, 0xe1, 0x79, 0xfe, 0x18, 0xe7,
58+
0x70, 0x88, 0xad, 0x4e, 0xe6, 0xd9, 0x8b, 0x3a, 0xc6, 0xdd, 0x27, 0x51,
59+
0x6e, 0xff, 0xbc, 0x64, 0xf5, 0x33, 0x43, 0x4f, 0x02, 0x03, 0x01, 0x00,
60+
0x01, 0x00, 0x8b, 0x00, 0x78, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09,
61+
0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30,
62+
0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x4e, 0x65, 0x77, 0x20,
63+
0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03,
64+
0x55, 0x04, 0x07, 0x13, 0x0b, 0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x20,
65+
0x43, 0x69, 0x74, 0x79, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04,
66+
0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54,
67+
0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
68+
0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x25, 0x55,
69+
0x53, 0x45, 0x52, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, 0x43, 0x43,
70+
0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
71+
0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
72+
0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
73+
0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04,
74+
0x1a, 0xac, 0x54, 0x5a, 0xa9, 0xf9, 0x68, 0x23, 0xe7, 0x7a, 0xd5, 0x24,
75+
0x6f, 0x53, 0xc6, 0x5a, 0xd8, 0x4b, 0xab, 0xc6, 0xd5, 0xb6, 0xd1, 0xe6,
76+
0x73, 0x71, 0xae, 0xdd, 0x9c, 0xd6, 0x0c, 0x61, 0xfd, 0xdb, 0xa0, 0x89,
77+
0x03, 0xb8, 0x05, 0x14, 0xec, 0x57, 0xce, 0xee, 0x5d, 0x3f, 0xe2, 0x21,
78+
0xb3, 0xce, 0xf7, 0xd4, 0x8a, 0x79, 0xe0, 0xa3, 0x83, 0x7e, 0x2d, 0x97,
79+
0xd0, 0x61, 0xc4, 0xf1, 0x99, 0xdc, 0x25, 0x91, 0x63, 0xab, 0x7f, 0x30,
80+
0xa3, 0xb4, 0x70, 0xe2, 0xc7, 0xa1, 0x33, 0x9c, 0xf3, 0xbf, 0x2e, 0x5c,
81+
0x53, 0xb1, 0x5f, 0xb3, 0x7d, 0x32, 0x7f, 0x8a, 0x34, 0xe3, 0x79, 0x79
82+
};
83+
84+
static const unsigned int kSoundPanel7TrustedCaBundleLen = 900;

0 commit comments

Comments
 (0)