summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/tests/unit/tlsserver/cmd/EncryptedClientHelloServer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'security/manager/ssl/tests/unit/tlsserver/cmd/EncryptedClientHelloServer.cpp')
-rw-r--r--security/manager/ssl/tests/unit/tlsserver/cmd/EncryptedClientHelloServer.cpp178
1 files changed, 178 insertions, 0 deletions
diff --git a/security/manager/ssl/tests/unit/tlsserver/cmd/EncryptedClientHelloServer.cpp b/security/manager/ssl/tests/unit/tlsserver/cmd/EncryptedClientHelloServer.cpp
new file mode 100644
index 0000000000..fd284874b3
--- /dev/null
+++ b/security/manager/ssl/tests/unit/tlsserver/cmd/EncryptedClientHelloServer.cpp
@@ -0,0 +1,178 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// This is a standalone server that offers TLS 1.3 Encrypted
+// Client Hello support.
+
+#include <stdio.h>
+
+#include "nspr.h"
+#include "ScopedNSSTypes.h"
+#include "ssl.h"
+#include "sslexp.h"
+#include "TLSServer.h"
+#include <pk11pub.h>
+#include <vector>
+
+using namespace mozilla;
+using namespace mozilla::test;
+
+struct EchHost {
+ const char* mHostName;
+ const char* mCertName;
+};
+
+const std::vector<uint32_t> kSuiteChaCha = {
+ (static_cast<uint32_t>(HpkeKdfHkdfSha256) << 16) |
+ HpkeAeadChaCha20Poly1305};
+
+// Hostname, cert nickname pairs.
+const EchHost sEchHosts[] = {{"ech-public.example.com", "default-ee"},
+ {"ech-private.example.com", "private-ee"},
+ {"selfsigned.example.com", "selfsigned"},
+ {nullptr, nullptr}};
+
+int32_t DoSNISocketConfigBySubjectCN(PRFileDesc* aFd,
+ const SECItem* aSrvNameArr,
+ uint32_t aSrvNameArrSize) {
+ for (uint32_t i = 0; i < aSrvNameArrSize; i++) {
+ UniquePORTString name(
+ static_cast<char*>(PORT_ZAlloc(aSrvNameArr[i].len + 1)));
+ if (name) {
+ PORT_Memcpy(name.get(), aSrvNameArr[i].data, aSrvNameArr[i].len);
+ if (ConfigSecureServerWithNamedCert(aFd, name.get(), nullptr, nullptr,
+ nullptr) == SECSuccess) {
+ return 0;
+ }
+ }
+ }
+
+ return SSL_SNI_SEND_ALERT;
+}
+
+int32_t DoSNISocketConfig(PRFileDesc* aFd, const SECItem* aSrvNameArr,
+ uint32_t aSrvNameArrSize, void* aArg) {
+ const EchHost* host = GetHostForSNI(aSrvNameArr, aSrvNameArrSize, sEchHosts);
+ if (!host) {
+ PrintPRError("No cert found for hostname");
+ return SSL_SNI_SEND_ALERT;
+ }
+
+ if (gDebugLevel >= DEBUG_VERBOSE) {
+ fprintf(stderr, "found pre-defined host '%s'\n", host->mHostName);
+ }
+
+ UniqueCERTCertificate cert;
+ SSLKEAType certKEA;
+ if (SECSuccess != ConfigSecureServerWithNamedCert(aFd, host->mCertName, &cert,
+ &certKEA, nullptr)) {
+ return SSL_SNI_SEND_ALERT;
+ }
+
+ return 0;
+}
+
+int32_t SetAlpnOptions(PRFileDesc* aFd, uint8_t flags) {
+ const std::vector<uint8_t> http1 = {0x08, 0x68, 0x74, 0x74, 0x70,
+ 0x2f, 0x31, 0x2e, 0x31};
+ const std::vector<uint8_t> http2 = {0x02, 0x68, 0x32};
+ const std::vector<uint8_t> http3 = {0x02, 0x68, 0x33};
+ std::vector<uint8_t> alpnVec = {};
+ if (flags & 0b001) {
+ alpnVec.insert(alpnVec.end(), http1.begin(), http1.end());
+ }
+ if (flags & 0b010) {
+ alpnVec.insert(alpnVec.end(), http2.begin(), http2.end());
+ }
+ if (flags & 0b100) {
+ alpnVec.insert(alpnVec.end(), http3.begin(), http3.end());
+ }
+ fprintf(stderr, "ALPN Flags: %u\n", flags);
+ fprintf(stderr, "ALPN length: %zu\n", alpnVec.size());
+ if (SSL_SetNextProtoNego(aFd, alpnVec.data(), alpnVec.size()) != SECSuccess) {
+ fprintf(stderr, "Setting ALPN failed!\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+SECStatus ConfigureServer(PRFileDesc* aFd) {
+ const char* alpnFlag = PR_GetEnv("MOZ_TLS_ECH_ALPN_FLAG");
+ if (alpnFlag) {
+ uint8_t flag = atoi(alpnFlag);
+ SetAlpnOptions(aFd, flag);
+ }
+
+ UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
+ if (!slot) {
+ PrintPRError("PK11_GetInternalKeySlot failed");
+ return SECFailure;
+ }
+
+ UniqueSECKEYPublicKey pubKey;
+ UniqueSECKEYPrivateKey privKey;
+ SECKEYPublicKey* tmpPubKey = nullptr;
+ SECKEYPrivateKey* tmpPrivKey = nullptr;
+
+ static const std::vector<uint8_t> pkcs8{
+ 0x30, 0x67, 0x02, 0x01, 0x00, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48,
+ 0xce, 0x3d, 0x02, 0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda,
+ 0x47, 0x0f, 0x01, 0x04, 0x4c, 0x30, 0x4a, 0x02, 0x01, 0x01, 0x04, 0x20,
+ 0x8c, 0x49, 0x0e, 0x5b, 0x0c, 0x7d, 0xbe, 0x0c, 0x6d, 0x21, 0x92, 0x48,
+ 0x4d, 0x2b, 0x7a, 0x04, 0x23, 0xb3, 0xb4, 0x54, 0x4f, 0x24, 0x81, 0x09,
+ 0x5a, 0x99, 0xdb, 0xf2, 0x38, 0xfb, 0x35, 0x0f, 0xa1, 0x23, 0x03, 0x21,
+ 0x00, 0x8a, 0x07, 0x56, 0x39, 0x49, 0xfa, 0xc6, 0x23, 0x29, 0x36, 0xed,
+ 0x6f, 0x36, 0xc4, 0xfa, 0x73, 0x59, 0x30, 0xec, 0xde, 0xae, 0xf6, 0x73,
+ 0x4e, 0x31, 0x4a, 0xea, 0xc3, 0x5a, 0x56, 0xfd, 0x0a};
+
+ SECItem pkcs8Item = {siBuffer, const_cast<uint8_t*>(pkcs8.data()),
+ static_cast<unsigned int>(pkcs8.size())};
+ SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
+ slot.get(), &pkcs8Item, nullptr, nullptr, false, false, KU_ALL,
+ &tmpPrivKey, nullptr);
+
+ if (rv != SECSuccess) {
+ PrintPRError("PK11_ImportDERPrivateKeyInfoAndReturnKey failed");
+ return SECFailure;
+ }
+ privKey.reset(tmpPrivKey);
+ tmpPubKey = SECKEY_ConvertToPublicKey(privKey.get());
+ pubKey.reset(tmpPubKey);
+
+ if (!privKey || !pubKey) {
+ PrintPRError("ECH/HPKE Public or Private key is null!");
+ return SECFailure;
+ }
+
+ std::vector<uint8_t> echConfig(1000, 0);
+ unsigned int len = 0;
+ const PRUint8 configId = 77;
+ const HpkeSymmetricSuite echCipherSuite = {HpkeKdfHkdfSha256,
+ HpkeAeadChaCha20Poly1305};
+ rv = SSL_EncodeEchConfigId(configId, "ech-public.example.com", 100,
+ HpkeDhKemX25519Sha256, pubKey.get(),
+ &echCipherSuite, 1, echConfig.data(), &len,
+ echConfig.size());
+ if (rv != SECSuccess) {
+ PrintPRError("SSL_EncodeEchConfig failed");
+ return rv;
+ }
+
+ rv = SSL_SetServerEchConfigs(aFd, pubKey.get(), privKey.get(),
+ echConfig.data(), len);
+ if (rv != SECSuccess) {
+ PrintPRError("SSL_SetServerEchConfigs failed");
+ return rv;
+ }
+
+ return SECSuccess;
+}
+
+int main(int argc, char* argv[]) {
+ int rv = StartServer(argc, argv, DoSNISocketConfig, nullptr, ConfigureServer);
+ if (rv < 0) {
+ return rv;
+ }
+}