diff --git a/examples/copy-paste-capi/CMakeLists.txt b/examples/copy-paste-capi/CMakeLists.txt index fd593800f..d97686739 100644 --- a/examples/copy-paste-capi/CMakeLists.txt +++ b/examples/copy-paste-capi/CMakeLists.txt @@ -30,7 +30,7 @@ else() endif() set_target_properties(datachannel-copy-paste-capi-offerer PROPERTIES - OUTPUT_NAME offerer) + OUTPUT_NAME offerer-capi) set_target_properties(datachannel-copy-paste-capi-offerer PROPERTIES XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER com.github.paullouisageneau.libdatachannel.examples.copypaste.capi.offerer) @@ -44,7 +44,7 @@ else() endif() set_target_properties(datachannel-copy-paste-capi-answerer PROPERTIES - OUTPUT_NAME answerer) + OUTPUT_NAME answerer-capi) set_target_properties(datachannel-copy-paste-capi-answerer PROPERTIES XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER com.github.paullouisageneau.libdatachannel.examples.copypaste.capi.answerer) diff --git a/src/description.cpp b/src/description.cpp index c6aafb2f8..77d0d8033 100644 --- a/src/description.cpp +++ b/src/description.cpp @@ -310,12 +310,6 @@ string Description::generateSdp(string_view eol) const { // Session-level attributes sdp << "a=msid-semantic:WMS *" << eol; - sdp << "a=setup:" << mRole << eol; - - if (mIceUfrag) - sdp << "a=ice-ufrag:" << *mIceUfrag << eol; - if (mIcePwd) - sdp << "a=ice-pwd:" << *mIcePwd << eol; if (!mIceOptions.empty()) sdp << "a=ice-options:" << utils::implode(mIceOptions, ',') << eol; if (mFingerprint) @@ -339,6 +333,14 @@ string Description::generateSdp(string_view eol) const { for (const auto &entry : mEntries) { sdp << entry->generateSdp(eol, addr, port); + // RFC 8829: Attributes that SDP permits to be at either the session level or the media level + // SHOULD generally be at the media level even if they are identical. + sdp << "a=setup:" << mRole << eol; + if (mIceUfrag) + sdp << "a=ice-ufrag:" << *mIceUfrag << eol; + if (mIcePwd) + sdp << "a=ice-pwd:" << *mIcePwd << eol; + if (!entry->isRemoved() && std::exchange(first, false)) { // Candidates for (const auto &candidate : mCandidates) @@ -369,28 +371,29 @@ string Description::generateApplicationSdp(string_view eol) const { const uint16_t port = cand && cand->isResolved() ? *cand->port() : 9; // Port 9 is the discard protocol + // Session-level attributes + sdp << "a=msid-semantic:WMS *" << eol; + if (!mIceOptions.empty()) + sdp << "a=ice-options:" << utils::implode(mIceOptions, ',') << eol; + + for (const auto &attr : mAttributes) + sdp << "a=" << attr << eol; + // Application auto app = mApplication ? mApplication : std::make_shared(); sdp << app->generateSdp(eol, addr, port); - // Session-level attributes - sdp << "a=msid-semantic:WMS *" << eol; + // Media-level attributes sdp << "a=setup:" << mRole << eol; - if (mIceUfrag) sdp << "a=ice-ufrag:" << *mIceUfrag << eol; if (mIcePwd) sdp << "a=ice-pwd:" << *mIcePwd << eol; - if (!mIceOptions.empty()) - sdp << "a=ice-options:" << utils::implode(mIceOptions, ',') << eol; if (mFingerprint) sdp << "a=fingerprint:" << CertificateFingerprint::AlgorithmIdentifier(mFingerprint->algorithm) << " " << mFingerprint->value << eol; - for (const auto &attr : mAttributes) - sdp << "a=" << attr << eol; - // Candidates for (const auto &candidate : mCandidates) sdp << string(candidate) << eol; diff --git a/src/impl/certificate.cpp b/src/impl/certificate.cpp index fed8cef1e..1194bed74 100644 --- a/src/impl/certificate.cpp +++ b/src/impl/certificate.cpp @@ -9,6 +9,7 @@ #include "certificate.hpp" #include "threadpool.hpp" +#include #include #include #include @@ -384,9 +385,16 @@ Certificate Certificate::FromString(string crt_pem, string key_pem) { BIO *bio = BIO_new(BIO_s_mem()); BIO_write(bio, crt_pem.data(), int(crt_pem.size())); auto x509 = shared_ptr(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free); - BIO_free(bio); - if (!x509) + if (!x509) { + BIO_free(bio); throw std::invalid_argument("Unable to import PEM certificate"); + } + std::vector> chain; + while (auto extra = + shared_ptr(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free)) { + chain.push_back(std::move(extra)); + } + BIO_free(bio); bio = BIO_new(BIO_s_mem()); BIO_write(bio, key_pem.data(), int(key_pem.size())); @@ -396,7 +404,7 @@ Certificate Certificate::FromString(string crt_pem, string key_pem) { if (!pkey) throw std::invalid_argument("Unable to import PEM key"); - return Certificate(x509, pkey); + return Certificate(x509, pkey, std::move(chain)); } Certificate Certificate::FromFile(const string &crt_pem_file, const string &key_pem_file, @@ -408,9 +416,16 @@ Certificate Certificate::FromFile(const string &crt_pem_file, const string &key_ throw std::invalid_argument("Unable to open PEM certificate file"); auto x509 = shared_ptr(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free); - BIO_free(bio); - if (!x509) + if (!x509) { + BIO_free(bio); throw std::invalid_argument("Unable to import PEM certificate from file"); + } + std::vector> chain; + while (auto extra = + shared_ptr(PEM_read_bio_X509(bio, nullptr, nullptr, nullptr), X509_free)) { + chain.push_back(std::move(extra)); + } + BIO_free(bio); bio = openssl::BIO_new_from_file(key_pem_file); if (!bio) @@ -423,7 +438,7 @@ Certificate Certificate::FromFile(const string &crt_pem_file, const string &key_ if (!pkey) throw std::invalid_argument("Unable to import PEM key from file"); - return Certificate(x509, pkey); + return Certificate(x509, pkey, std::move(chain)); } Certificate Certificate::Generate(CertificateType type, const string &commonName) { @@ -514,14 +529,23 @@ Certificate Certificate::Generate(CertificateType type, const string &commonName return Certificate(x509, pkey); } -Certificate::Certificate(shared_ptr x509, shared_ptr pkey) - : mX509(std::move(x509)), mPKey(std::move(pkey)), +Certificate::Certificate(shared_ptr x509, shared_ptr pkey, + std::vector> chain) + : mX509(std::move(x509)), mPKey(std::move(pkey)), mChain(std::move(chain)), mFingerprint(make_fingerprint(mX509.get(), CertificateFingerprint::Algorithm::Sha256)) {} std::tuple Certificate::credentials() const { return {mX509.get(), mPKey.get()}; } +std::vector Certificate::chain() const { + std::vector v; + v.reserve(mChain.size()); + std::transform(mChain.begin(), mChain.end(), std::back_inserter(v), + [](const auto &c) { return c.get(); }); + return v; +} + string make_fingerprint(X509 *x509, CertificateFingerprint::Algorithm fingerprintAlgorithm) { size_t size = CertificateFingerprint::AlgorithmSize(fingerprintAlgorithm); std::vector buffer(size); diff --git a/src/impl/certificate.hpp b/src/impl/certificate.hpp index 66111ccb4..0617ba173 100644 --- a/src/impl/certificate.hpp +++ b/src/impl/certificate.hpp @@ -34,8 +34,9 @@ class Certificate { Certificate(shared_ptr crt, shared_ptr pk); std::tuple, shared_ptr> credentials() const; #else // OPENSSL - Certificate(shared_ptr x509, shared_ptr pkey); + Certificate(shared_ptr x509, shared_ptr pkey, std::vector> chain = {}); std::tuple credentials() const; + std::vector chain() const; #endif CertificateFingerprint fingerprint() const; @@ -52,6 +53,7 @@ class Certificate { #else const shared_ptr mX509; const shared_ptr mPKey; + const std::vector> mChain; #endif const string mFingerprint; diff --git a/src/impl/peerconnection.cpp b/src/impl/peerconnection.cpp index ab6208e22..1d3611b2b 100644 --- a/src/impl/peerconnection.cpp +++ b/src/impl/peerconnection.cpp @@ -879,11 +879,6 @@ void PeerConnection::validateRemoteDescription(const Description &description) { if (activeMediaCount == 0) throw std::invalid_argument("Remote description has no active media"); - if (auto local = localDescription(); local && local->iceUfrag() && local->icePwd()) - if (*description.iceUfrag() == *local->iceUfrag() && - *description.icePwd() == *local->icePwd()) - throw std::logic_error("Got the local description as remote description"); - PLOG_VERBOSE << "Remote description looks valid"; } diff --git a/src/impl/tlstransport.cpp b/src/impl/tlstransport.cpp index 8f66d200f..0f5e9e967 100644 --- a/src/impl/tlstransport.cpp +++ b/src/impl/tlstransport.cpp @@ -603,6 +603,9 @@ TlsTransport::TlsTransport(variant, shared_ptrcredentials(); SSL_CTX_use_certificate(mCtx, x509); SSL_CTX_use_PrivateKey(mCtx, pkey); + + for (auto c : certificate->chain()) + SSL_CTX_add1_chain_cert(mCtx, c); // add1 increments reference count } SSL_CTX_set_options(mCtx, SSL_OP_NO_SSLv3 | SSL_OP_NO_RENEGOTIATION);