From 8d4396ce78053b8bff6af06aab591eb4f34a9790 Mon Sep 17 00:00:00 2001 From: xicilion Date: Sat, 11 May 2024 02:52:27 +0800 Subject: [PATCH 1/2] Support for setting the cert and key on new PeerConnection. --- include/rtc/configuration.hpp | 4 +++ src/impl/peerconnection.cpp | 10 ++++++- src/impl/peerconnection.hpp | 2 +- test/connectivity.cpp | 52 +++++++++++++++++++++++++++++++++++ test/main.cpp | 9 ++++++ 5 files changed, 75 insertions(+), 2 deletions(-) diff --git a/include/rtc/configuration.hpp b/include/rtc/configuration.hpp index 873061f91..22c3d50d6 100644 --- a/include/rtc/configuration.hpp +++ b/include/rtc/configuration.hpp @@ -87,6 +87,10 @@ struct RTC_CPP_EXPORT Configuration { // Local maximum message size for Data Channels optional maxMessageSize; + + // Certificates and private keys + optional certPem; + optional keyPem; }; #ifdef RTC_ENABLE_WEBSOCKET diff --git a/src/impl/peerconnection.cpp b/src/impl/peerconnection.cpp index 3133fe328..5de05c97e 100644 --- a/src/impl/peerconnection.cpp +++ b/src/impl/peerconnection.cpp @@ -45,9 +45,17 @@ static LogCounter "Number of unknown RTCP packet types over past second"); PeerConnection::PeerConnection(Configuration config_) - : config(std::move(config_)), mCertificate(make_certificate(config.certificateType)) { + : config(std::move(config_)) { PLOG_VERBOSE << "Creating PeerConnection"; + if( config.certPem.has_value() && config.keyPem.has_value() ) { + std::promise cert; + cert.set_value(std::make_shared(Certificate::FromString(config.certPem.value(), config.keyPem.value()))); + mCertificate = cert.get_future(); + } else { + mCertificate = make_certificate(config.certificateType); + } + if (config.portRangeEnd && config.portRangeBegin > config.portRangeEnd) throw std::invalid_argument("Invalid port range"); diff --git a/src/impl/peerconnection.hpp b/src/impl/peerconnection.hpp index ad6f41e28..33dba4408 100644 --- a/src/impl/peerconnection.hpp +++ b/src/impl/peerconnection.hpp @@ -131,7 +131,7 @@ struct PeerConnection : std::enable_shared_from_this { void updateTrackSsrcCache(const Description &description); const init_token mInitToken = Init::Instance().token(); - const future_certificate_ptr mCertificate; + future_certificate_ptr mCertificate; Processor mProcessor; optional mLocalDescription, mRemoteDescription; diff --git a/test/connectivity.cpp b/test/connectivity.cpp index a54783c6f..bf4d9d6f3 100644 --- a/test/connectivity.cpp +++ b/test/connectivity.cpp @@ -263,3 +263,55 @@ void test_connectivity(bool signal_wrong_fingerprint) { cout << "Success" << endl; } + +const char* key_pem = +"-----BEGIN PRIVATE KEY-----\n" +"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg3bbuT2SjSlMZH/J1\n" +"vHwmF0Blb/DBc/v7f1Za9GPUXHmhRANCAATDpmYxZozjVw6xlERNjJJGgfY3bEmj\n" +"xAKFRq3nbxbDHvMEs34u9HntMZWJ0hp3GUC+Ax7JHTv3cYqSaAg2SpR4\n" +"-----END PRIVATE KEY-----\n"; + +const char* cert_pem = +"-----BEGIN CERTIFICATE-----\n" +"MIIBgjCCASigAwIBAgIJAPMXEoZXOaDEMAoGCCqGSM49BAMCMEoxDzANBgNVBAMM\n" +"BmNhLmNvbTELMAkGA1UEBhMCVVMxCzAJBgNVBAcMAkNBMRAwDgYDVQQKDAdleGFt\n" +"cGxlMQswCQYDVQQIDAJDQTAeFw0yNDA1MDUxNjAzMjFaFw0yNDA4MTMxNjAzMjFa\n" +"MDExCzAJBgNVBAYTAkNOMRAwDgYDVQQKDAdiYW96LmNuMRAwDgYDVQQDDAdiYW96\n" +"Lm1lMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEw6ZmMWaM41cOsZRETYySRoH2\n" +"N2xJo8QChUat528Wwx7zBLN+LvR57TGVidIadxlAvgMeyR0793GKkmgINkqUeKMQ\n" +"MA4wDAYDVR0TAQH/BAIwADAKBggqhkjOPQQDAgNIADBFAiAPNldqGJHryfjPFyX3\n" +"zfHHWlO7xSDTzdyoxzroFdwy+gIhAKmZizEVvDlBiIe+3ptCArU3dbp+bzLynTcr\n" +"Ma9ayzQy\n" +"-----END CERTIFICATE-----\n"; + +void test_pem() { + InitLogger(LogLevel::Debug); + + Configuration config1; + + config1.certPem = cert_pem; + config1.keyPem = key_pem; + + PeerConnection pc1(config1); + atomic_bool done; + string f; + + pc1.onLocalDescription([&done, &f](Description sdp) { + f = sdp.fingerprint().value().value; + done = true; + }); + + auto dc1 = pc1.createDataChannel("test"); + + // Wait a bit + int attempts = 10; + while (!done && attempts--) + this_thread::sleep_for(1s); + + cout << "Fingerprint: " << f << endl; + + if (f != "07:E5:6F:2A:1A:0C:2C:32:0E:C1:C3:9C:34:5A:78:4E:A5:8B:32:05:D1:57:D6:F4:E7:02:41:12:E6:01:C6:8F") + throw runtime_error("The fingerprint of the specified certificate do not match"); + + cout << "Success" << endl; +} diff --git a/test/main.cpp b/test/main.cpp index 825652dd7..b7326ad5e 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -16,6 +16,7 @@ using namespace std; using namespace chrono_literals; void test_connectivity(bool signal_wrong_fingerprint); +void test_pem(); void test_negotiated(); void test_reliability(); void test_turn_connectivity(); @@ -56,6 +57,14 @@ int main(int argc, char **argv) { } catch (const exception &) { } + try { + cout << endl << "*** Running pem test..." << endl; + test_pem(); + } catch (const exception &e) { + cerr << "pem test failed: " << e.what() << endl; + return -1; + } + // TODO: Temporarily disabled as the Open Relay TURN server is unreliable /* try { From c30c4e93ba5e3a3572698476b2513788c8044085 Mon Sep 17 00:00:00 2001 From: xicilion Date: Sun, 12 May 2024 15:01:04 +0800 Subject: [PATCH 2/2] Support for setting the cert and key on new PeerConnection. --- include/rtc/configuration.hpp | 5 +++-- src/impl/peerconnection.cpp | 16 +++++++++++++--- test/connectivity.cpp | 4 ++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/include/rtc/configuration.hpp b/include/rtc/configuration.hpp index 22c3d50d6..2d0657f90 100644 --- a/include/rtc/configuration.hpp +++ b/include/rtc/configuration.hpp @@ -89,8 +89,9 @@ struct RTC_CPP_EXPORT Configuration { optional maxMessageSize; // Certificates and private keys - optional certPem; - optional keyPem; + optional certificatePemFile; + optional keyPemFile; + optional keyPemPass; }; #ifdef RTC_ENABLE_WEBSOCKET diff --git a/src/impl/peerconnection.cpp b/src/impl/peerconnection.cpp index 5de05c97e..99a224ccc 100644 --- a/src/impl/peerconnection.cpp +++ b/src/impl/peerconnection.cpp @@ -44,16 +44,26 @@ static LogCounter COUNTER_UNKNOWN_PACKET_TYPE(plog::warning, "Number of unknown RTCP packet types over past second"); +const string PemBeginCertificateTag = "-----BEGIN CERTIFICATE-----"; + PeerConnection::PeerConnection(Configuration config_) : config(std::move(config_)) { PLOG_VERBOSE << "Creating PeerConnection"; - if( config.certPem.has_value() && config.keyPem.has_value() ) { + + if (config.certificatePemFile && config.keyPemFile) { std::promise cert; - cert.set_value(std::make_shared(Certificate::FromString(config.certPem.value(), config.keyPem.value()))); + cert.set_value(std::make_shared( + config.certificatePemFile->find(PemBeginCertificateTag) != string::npos + ? Certificate::FromString(*config.certificatePemFile, *config.keyPemFile) + : Certificate::FromFile(*config.certificatePemFile, *config.keyPemFile, + config.keyPemPass.value_or("")))); mCertificate = cert.get_future(); - } else { + } else if (!config.certificatePemFile && !config.keyPemFile) { mCertificate = make_certificate(config.certificateType); + } else { + throw std::invalid_argument( + "Either none or both certificate and key PEM files must be specified"); } if (config.portRangeEnd && config.portRangeBegin > config.portRangeEnd) diff --git a/test/connectivity.cpp b/test/connectivity.cpp index bf4d9d6f3..df7a75063 100644 --- a/test/connectivity.cpp +++ b/test/connectivity.cpp @@ -289,8 +289,8 @@ void test_pem() { Configuration config1; - config1.certPem = cert_pem; - config1.keyPem = key_pem; + config1.certificatePemFile = cert_pem; + config1.keyPemFile = key_pem; PeerConnection pc1(config1); atomic_bool done;