瀏覽代碼

Support all Certificate Fingerprint Algorithms

Before was hardcoded to sha256

Resolves #1076

Co-authored-by: Paul-Louis Ageneau <[email protected]>
Sean DuBois 1 年之前
父節點
當前提交
42ec0883e3

+ 16 - 4
include/rtc/description.hpp

@@ -28,6 +28,17 @@ const string DEFAULT_OPUS_AUDIO_PROFILE =
 const string DEFAULT_H264_VIDEO_PROFILE =
 const string DEFAULT_H264_VIDEO_PROFILE =
     "profile-level-id=42e01f;packetization-mode=1;level-asymmetry-allowed=1";
     "profile-level-id=42e01f;packetization-mode=1;level-asymmetry-allowed=1";
 
 
+struct CertificateFingerprint {
+	enum class Algorithm { Sha1, Sha224, Sha256, Sha384, Sha512 };
+	static string AlgorithmIdentifier(Algorithm algorithm);
+	static size_t AlgorithmSize(Algorithm algorithm);
+
+	bool isValid() const;
+
+	Algorithm algorithm;
+	string value;
+};
+
 class RTC_CPP_EXPORT Description {
 class RTC_CPP_EXPORT Description {
 public:
 public:
 	enum class Type { Unspec, Offer, Answer, Pranswer, Rollback };
 	enum class Type { Unspec, Offer, Answer, Pranswer, Rollback };
@@ -51,11 +62,11 @@ public:
 	std::vector<string> iceOptions() const;
 	std::vector<string> iceOptions() const;
 	optional<string> iceUfrag() const;
 	optional<string> iceUfrag() const;
 	optional<string> icePwd() const;
 	optional<string> icePwd() const;
-	optional<string> fingerprint() const;
+	optional<CertificateFingerprint> fingerprint() const;
 	bool ended() const;
 	bool ended() const;
 
 
 	void hintType(Type type);
 	void hintType(Type type);
-	void setFingerprint(string fingerprint);
+	void setFingerprint(CertificateFingerprint f);
 	void addIceOption(string option);
 	void addIceOption(string option);
 	void removeIceOption(const string &option);
 	void removeIceOption(const string &option);
 
 
@@ -291,7 +302,7 @@ private:
 	string mSessionId;
 	string mSessionId;
 	std::vector<string> mIceOptions;
 	std::vector<string> mIceOptions;
 	optional<string> mIceUfrag, mIcePwd;
 	optional<string> mIceUfrag, mIcePwd;
-	optional<string> mFingerprint;
+	optional<CertificateFingerprint> mFingerprint;
 	std::vector<string> mAttributes; // other attributes
 	std::vector<string> mAttributes; // other attributes
 
 
 	// Entries
 	// Entries
@@ -308,6 +319,7 @@ private:
 RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, const rtc::Description &description);
 RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, const rtc::Description &description);
 RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::Description::Type type);
 RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::Description::Type type);
 RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::Description::Role role);
 RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, rtc::Description::Role role);
-RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out, const rtc::Description::Direction &direction);
+RTC_CPP_EXPORT std::ostream &operator<<(std::ostream &out,
+                                        const rtc::Description::Direction &direction);
 
 
 #endif
 #endif

+ 95 - 36
src/description.cpp

@@ -33,11 +33,6 @@ inline bool match_prefix(string_view str, string_view prefix) {
 	       std::mismatch(prefix.begin(), prefix.end(), str.begin()).first == prefix.end();
 	       std::mismatch(prefix.begin(), prefix.end(), str.begin()).first == prefix.end();
 }
 }
 
 
-inline void trim_begin(string &str) {
-	str.erase(str.begin(),
-	          std::find_if(str.begin(), str.end(), [](char c) { return !std::isspace(c); }));
-}
-
 inline void trim_end(string &str) {
 inline void trim_end(string &str) {
 	str.erase(
 	str.erase(
 	    std::find_if(str.rbegin(), str.rend(), [](char c) { return !std::isspace(c); }).base(),
 	    std::find_if(str.rbegin(), str.rend(), [](char c) { return !std::isspace(c); }).base(),
@@ -71,22 +66,6 @@ template <typename T> T to_integer(string_view s) {
 	}
 	}
 }
 }
 
 
-inline bool is_sha256_fingerprint(string_view f) {
-	if (f.size() != 32 * 3 - 1)
-		return false;
-
-	for (size_t i = 0; i < f.size(); ++i) {
-		if (i % 3 == 2) {
-			if (f[i] != ':')
-				return false;
-		} else {
-			if (!std::isxdigit(f[i]))
-				return false;
-		}
-	}
-	return true;
-}
-
 } // namespace
 } // namespace
 
 
 namespace rtc {
 namespace rtc {
@@ -131,12 +110,35 @@ Description::Description(const string &sdp, Type type, Role role)
 				// media-level SDP attribute. If it is a session-level attribute, it applies to all
 				// media-level SDP attribute. If it is a session-level attribute, it applies to all
 				// TLS sessions for which no media-level fingerprint attribute is defined.
 				// TLS sessions for which no media-level fingerprint attribute is defined.
 				if (!mFingerprint || index == 0) { // first media overrides session-level
 				if (!mFingerprint || index == 0) { // first media overrides session-level
-					if (match_prefix(value, "sha-256 ") || match_prefix(value, "SHA-256 ")) {
-						string fingerprint{value.substr(8)};
-						trim_begin(fingerprint);
-						setFingerprint(std::move(fingerprint));
-					} else {
+					auto fingerprintExploded = utils::explode(string(value), ' ');
+					if (fingerprintExploded.size() != 2) {
 						PLOG_WARNING << "Unknown SDP fingerprint format: " << value;
 						PLOG_WARNING << "Unknown SDP fingerprint format: " << value;
+						continue;
+					}
+
+					auto first = fingerprintExploded.at(0);
+					std::transform(first.begin(), first.end(), first.begin(),
+					               [](char c) { return char(std::tolower(c)); });
+
+					std::optional<CertificateFingerprint::Algorithm> fingerprintAlgorithm;
+
+					for (auto a : std::array<CertificateFingerprint::Algorithm, 5>{
+					         CertificateFingerprint::Algorithm::Sha1,
+					         CertificateFingerprint::Algorithm::Sha224,
+					         CertificateFingerprint::Algorithm::Sha256,
+					         CertificateFingerprint::Algorithm::Sha384,
+					         CertificateFingerprint::Algorithm::Sha512}) {
+						if (first == CertificateFingerprint::AlgorithmIdentifier(a)) {
+							fingerprintAlgorithm = a;
+							break;
+						}
+					}
+
+					if (fingerprintAlgorithm.has_value()) {
+						setFingerprint(CertificateFingerprint{
+						    fingerprintAlgorithm.value(), std::move(fingerprintExploded.at(1))});
+					} else {
+						PLOG_WARNING << "Unknown certificate fingerprint algorithm: " << first;
 					}
 					}
 				}
 				}
 			} else if (key == "ice-ufrag") {
 			} else if (key == "ice-ufrag") {
@@ -205,7 +207,7 @@ std::vector<string> Description::iceOptions() const { return mIceOptions; }
 
 
 optional<string> Description::icePwd() const { return mIcePwd; }
 optional<string> Description::icePwd() const { return mIcePwd; }
 
 
-optional<string> Description::fingerprint() const { return mFingerprint; }
+optional<CertificateFingerprint> Description::fingerprint() const { return mFingerprint; }
 
 
 bool Description::ended() const { return mEnded; }
 bool Description::ended() const { return mEnded; }
 
 
@@ -214,13 +216,13 @@ void Description::hintType(Type type) {
 		mType = type;
 		mType = type;
 }
 }
 
 
-void Description::setFingerprint(string fingerprint) {
-	if (!is_sha256_fingerprint(fingerprint))
-		throw std::invalid_argument("Invalid SHA256 fingerprint \"" + fingerprint + "\"");
+void Description::setFingerprint(CertificateFingerprint f) {
+	if (!f.isValid())
+		throw std::invalid_argument("Invalid " + CertificateFingerprint::AlgorithmIdentifier(f.algorithm) + " fingerprint \"" + f.value + "\"");
 
 
-	std::transform(fingerprint.begin(), fingerprint.end(), fingerprint.begin(),
+	std::transform(f.value.begin(), f.value.end(), f.value.begin(),
 	               [](char c) { return char(std::toupper(c)); });
 	               [](char c) { return char(std::toupper(c)); });
-	mFingerprint.emplace(std::move(fingerprint));
+	mFingerprint = std::move(f);
 }
 }
 
 
 void Description::addIceOption(string option) {
 void Description::addIceOption(string option) {
@@ -315,7 +317,9 @@ string Description::generateSdp(string_view eol) const {
 	if (!mIceOptions.empty())
 	if (!mIceOptions.empty())
 		sdp << "a=ice-options:" << utils::implode(mIceOptions, ',') << eol;
 		sdp << "a=ice-options:" << utils::implode(mIceOptions, ',') << eol;
 	if (mFingerprint)
 	if (mFingerprint)
-		sdp << "a=fingerprint:sha-256 " << *mFingerprint << eol;
+		sdp << "a=fingerprint:"
+		    << CertificateFingerprint::AlgorithmIdentifier(mFingerprint->algorithm) << " "
+		    << mFingerprint->value << eol;
 
 
 	for (const auto &attr : mAttributes)
 	for (const auto &attr : mAttributes)
 		sdp << "a=" << attr << eol;
 		sdp << "a=" << attr << eol;
@@ -378,7 +382,9 @@ string Description::generateApplicationSdp(string_view eol) const {
 	if (!mIceOptions.empty())
 	if (!mIceOptions.empty())
 		sdp << "a=ice-options:" << utils::implode(mIceOptions, ',') << eol;
 		sdp << "a=ice-options:" << utils::implode(mIceOptions, ',') << eol;
 	if (mFingerprint)
 	if (mFingerprint)
-		sdp << "a=fingerprint:sha-256 " << *mFingerprint << eol;
+		sdp << "a=fingerprint:"
+		    << CertificateFingerprint::AlgorithmIdentifier(mFingerprint->algorithm) << " "
+		    << mFingerprint->value << eol;
 
 
 	for (const auto &attr : mAttributes)
 	for (const auto &attr : mAttributes)
 		sdp << "a=" << attr << eol;
 		sdp << "a=" << attr << eol;
@@ -876,8 +882,7 @@ void Description::Application::parseSdpLine(string_view line) {
 	}
 	}
 }
 }
 
 
-Description::Media::Media(const string &sdp)
-    : Entry(get_first_line(sdp), "", Direction::Unknown) {
+Description::Media::Media(const string &sdp) : Entry(get_first_line(sdp), "", Direction::Unknown) {
 	string line;
 	string line;
 	std::istringstream ss(sdp);
 	std::istringstream ss(sdp);
 	std::getline(ss, line); // discard first line
 	std::getline(ss, line); // discard first line
@@ -1288,6 +1293,60 @@ string Description::typeToString(Type type) {
 	}
 	}
 }
 }
 
 
+size_t
+CertificateFingerprint::AlgorithmSize(CertificateFingerprint::Algorithm fingerprintAlgorithm) {
+	switch (fingerprintAlgorithm) {
+	case CertificateFingerprint::Algorithm::Sha1:
+		return 20;
+	case CertificateFingerprint::Algorithm::Sha224:
+		return 28;
+	case CertificateFingerprint::Algorithm::Sha256:
+		return 32;
+	case CertificateFingerprint::Algorithm::Sha384:
+		return 48;
+	case CertificateFingerprint::Algorithm::Sha512:
+		return 64;
+    default:
+        return 0;
+	}
+}
+
+std::string CertificateFingerprint::AlgorithmIdentifier(
+    CertificateFingerprint::Algorithm fingerprintAlgorithm) {
+	switch (fingerprintAlgorithm) {
+	case CertificateFingerprint::Algorithm::Sha1:
+		return "sha-1";
+	case CertificateFingerprint::Algorithm::Sha224:
+		return "sha-224";
+	case CertificateFingerprint::Algorithm::Sha256:
+		return "sha-256";
+	case CertificateFingerprint::Algorithm::Sha384:
+		return "sha-256";
+	case CertificateFingerprint::Algorithm::Sha512:
+		return "sha-512";
+	default:
+	    return "unknown";
+	}
+}
+
+bool CertificateFingerprint::isValid() const {
+	size_t expectedSize = AlgorithmSize(this->algorithm);
+	if (expectedSize == 0 || this->value.size() != expectedSize * 3 - 1) {
+		return false;
+	}
+
+	for (size_t i = 0; i < this->value.size(); ++i) {
+		if (i % 3 == 2) {
+			if (this->value[i] != ':')
+				return false;
+		} else {
+			if (!std::isxdigit(this->value[i]))
+				return false;
+		}
+	}
+	return true;
+}
+
 } // namespace rtc
 } // namespace rtc
 
 
 std::ostream &operator<<(std::ostream &out, const rtc::Description &description) {
 std::ostream &operator<<(std::ostream &out, const rtc::Description &description) {

+ 100 - 25
src/impl/certificate.cpp

@@ -100,18 +100,20 @@ Certificate Certificate::Generate(CertificateType type, const string &commonName
 
 
 Certificate::Certificate(gnutls_x509_crt_t crt, gnutls_x509_privkey_t privkey)
 Certificate::Certificate(gnutls_x509_crt_t crt, gnutls_x509_privkey_t privkey)
     : mCredentials(gnutls::new_credentials(), gnutls::free_credentials),
     : mCredentials(gnutls::new_credentials(), gnutls::free_credentials),
-      mFingerprint(make_fingerprint(crt)) {
+      mFingerprint(make_fingerprint(crt, CertificateFingerprint::Algorithm::Sha256)) {
 
 
 	gnutls::check(gnutls_certificate_set_x509_key(*mCredentials, &crt, 1, privkey),
 	gnutls::check(gnutls_certificate_set_x509_key(*mCredentials, &crt, 1, privkey),
 	              "Unable to set certificate and key pair in credentials");
 	              "Unable to set certificate and key pair in credentials");
 }
 }
 
 
 Certificate::Certificate(shared_ptr<gnutls_certificate_credentials_t> creds)
 Certificate::Certificate(shared_ptr<gnutls_certificate_credentials_t> creds)
-    : mCredentials(std::move(creds)), mFingerprint(make_fingerprint(*mCredentials)) {}
+    : mCredentials(std::move(creds)),
+      mFingerprint(make_fingerprint(*mCredentials, CertificateFingerprint::Algorithm::Sha256)) {}
 
 
 gnutls_certificate_credentials_t Certificate::credentials() const { return *mCredentials; }
 gnutls_certificate_credentials_t Certificate::credentials() const { return *mCredentials; }
 
 
-string make_fingerprint(gnutls_certificate_credentials_t credentials) {
+string make_fingerprint(gnutls_certificate_credentials_t credentials,
+                        CertificateFingerprint::Algorithm fingerprintAlgorithm) {
 	auto new_crt_list = [credentials]() -> gnutls_x509_crt_t * {
 	auto new_crt_list = [credentials]() -> gnutls_x509_crt_t * {
 		gnutls_x509_crt_t *crt_list = nullptr;
 		gnutls_x509_crt_t *crt_list = nullptr;
 		unsigned int crt_list_size = 0;
 		unsigned int crt_list_size = 0;
@@ -127,14 +129,37 @@ string make_fingerprint(gnutls_certificate_credentials_t credentials) {
 
 
 	unique_ptr<gnutls_x509_crt_t, decltype(free_crt_list)> crt_list(new_crt_list(), free_crt_list);
 	unique_ptr<gnutls_x509_crt_t, decltype(free_crt_list)> crt_list(new_crt_list(), free_crt_list);
 
 
-	return make_fingerprint(*crt_list);
+	return make_fingerprint(*crt_list, fingerprintAlgorithm);
 }
 }
 
 
-string make_fingerprint(gnutls_x509_crt_t crt) {
-	const size_t size = 32;
-	unsigned char buffer[size];
+string make_fingerprint(gnutls_x509_crt_t crt,
+                        CertificateFingerprint::Algorithm fingerprintAlgorithm) {
+	const size_t size = CertificateFingerprint::AlgorithmSize(fingerprintAlgorithm);
+	std::vector<unsigned char> buffer(size);
 	size_t len = size;
 	size_t len = size;
-	gnutls::check(gnutls_x509_crt_get_fingerprint(crt, GNUTLS_DIG_SHA256, buffer, &len),
+
+	gnutls_digest_algorithm_t hashFunc;
+	switch (fingerprintAlgorithm) {
+	case CertificateFingerprint::Algorithm::Sha1:
+		hashFunc = GNUTLS_DIG_SHA1;
+		break;
+	case CertificateFingerprint::Algorithm::Sha224:
+		hashFunc = GNUTLS_DIG_SHA224;
+		break;
+	case CertificateFingerprint::Algorithm::Sha256:
+		hashFunc = GNUTLS_DIG_SHA256;
+		break;
+	case CertificateFingerprint::Algorithm::Sha384:
+		hashFunc = GNUTLS_DIG_SHA384;
+		break;
+	case CertificateFingerprint::Algorithm::Sha512:
+		hashFunc = GNUTLS_DIG_SHA512;
+		break;
+	default:
+		throw std::invalid_argument("Unknown fingerprint algorithm");
+	}
+
+	gnutls::check(gnutls_x509_crt_get_fingerprint(crt, hashFunc, buffer.data(), &len),
 	              "X509 fingerprint error");
 	              "X509 fingerprint error");
 
 
 	std::ostringstream oss;
 	std::ostringstream oss;
@@ -142,23 +167,47 @@ string make_fingerprint(gnutls_x509_crt_t crt) {
 	for (size_t i = 0; i < len; ++i) {
 	for (size_t i = 0; i < len; ++i) {
 		if (i)
 		if (i)
 			oss << std::setw(1) << ':';
 			oss << std::setw(1) << ':';
-		oss << std::setw(2) << unsigned(buffer[i]);
+		oss << std::setw(2) << unsigned(buffer.at(i));
 	}
 	}
 	return oss.str();
 	return oss.str();
 }
 }
 
 
 #elif USE_MBEDTLS
 #elif USE_MBEDTLS
-string make_fingerprint(mbedtls_x509_crt *crt) {
-	const int size = 32;
-	uint8_t buffer[size];
+string make_fingerprint(mbedtls_x509_crt *crt,
+                        CertificateFingerprint::Algorithm fingerprintAlgorithm) {
+	const int size = CertificateFingerprint::AlgorithmSize(fingerprintAlgorithm);
+	std::vector<unsigned char> buffer(size);
 	std::stringstream fingerprint;
 	std::stringstream fingerprint;
 
 
-	mbedtls::check(
-	    mbedtls_sha256(crt->raw.p, crt->raw.len, reinterpret_cast<unsigned char *>(buffer), 0),
-	    "Failed to generate certificate fingerprint");
+	switch (fingerprintAlgorithm) {
+	case CertificateFingerprint::Algorithm::Sha1:
+		mbedtls::check(mbedtls_sha1(crt->raw.p, crt->raw.len, buffer.data()),
+		               "Failed to generate certificate fingerprint");
+		break;
+	case CertificateFingerprint::Algorithm::Sha224:
+		mbedtls::check(mbedtls_sha256(crt->raw.p, crt->raw.len, buffer.data(), 1),
+		               "Failed to generate certificate fingerprint");
+
+		break;
+	case CertificateFingerprint::Algorithm::Sha256:
+		mbedtls::check(mbedtls_sha256(crt->raw.p, crt->raw.len, buffer.data(), 0),
+		               "Failed to generate certificate fingerprint");
+		break;
+	case CertificateFingerprint::Algorithm::Sha384:
+		mbedtls::check(mbedtls_sha512(crt->raw.p, crt->raw.len, buffer.data(), 1),
+		               "Failed to generate certificate fingerprint");
+		break;
+	case CertificateFingerprint::Algorithm::Sha512:
+		mbedtls::check(mbedtls_sha512(crt->raw.p, crt->raw.len, buffer.data(), 0),
+		               "Failed to generate certificate fingerprint");
+		break;
+	default:
+		throw std::invalid_argument("Unknown fingerprint algorithm");
+	}
 
 
 	for (auto i = 0; i < size; i++) {
 	for (auto i = 0; i < size; i++) {
-		fingerprint << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(buffer[i]);
+		fingerprint << std::setfill('0') << std::setw(2) << std::hex
+		            << static_cast<int>(buffer.at(i));
 		if (i != (size - 1)) {
 		if (i != (size - 1)) {
 			fingerprint << ":";
 			fingerprint << ":";
 		}
 		}
@@ -168,7 +217,8 @@ string make_fingerprint(mbedtls_x509_crt *crt) {
 }
 }
 
 
 Certificate::Certificate(shared_ptr<mbedtls_x509_crt> crt, shared_ptr<mbedtls_pk_context> pk)
 Certificate::Certificate(shared_ptr<mbedtls_x509_crt> crt, shared_ptr<mbedtls_pk_context> pk)
-    : mCrt(crt), mPk(pk), mFingerprint(make_fingerprint(crt.get())) {}
+    : mCrt(crt), mPk(pk),
+      mFingerprint(make_fingerprint(crt.get(), CertificateFingerprint::Algorithm::Sha256)) {}
 
 
 Certificate Certificate::FromString(string crt_pem, string key_pem) {
 Certificate Certificate::FromString(string crt_pem, string key_pem) {
 	PLOG_DEBUG << "Importing certificate from PEM string (MbedTLS)";
 	PLOG_DEBUG << "Importing certificate from PEM string (MbedTLS)";
@@ -465,17 +515,40 @@ Certificate Certificate::Generate(CertificateType type, const string &commonName
 }
 }
 
 
 Certificate::Certificate(shared_ptr<X509> x509, shared_ptr<EVP_PKEY> pkey)
 Certificate::Certificate(shared_ptr<X509> x509, shared_ptr<EVP_PKEY> pkey)
-    : mX509(std::move(x509)), mPKey(std::move(pkey)), mFingerprint(make_fingerprint(mX509.get())) {}
+    : mX509(std::move(x509)), mPKey(std::move(pkey)),
+      mFingerprint(make_fingerprint(mX509.get(), CertificateFingerprint::Algorithm::Sha256)) {}
 
 
 std::tuple<X509 *, EVP_PKEY *> Certificate::credentials() const {
 std::tuple<X509 *, EVP_PKEY *> Certificate::credentials() const {
 	return {mX509.get(), mPKey.get()};
 	return {mX509.get(), mPKey.get()};
 }
 }
 
 
-string make_fingerprint(X509 *x509) {
-	const size_t size = 32;
-	unsigned char buffer[size];
-	unsigned int len = size;
-	if (!X509_digest(x509, EVP_sha256(), buffer, &len))
+string make_fingerprint(X509 *x509, CertificateFingerprint::Algorithm fingerprintAlgorithm) {
+	size_t size = CertificateFingerprint::AlgorithmSize(fingerprintAlgorithm);
+	std::vector<unsigned char> buffer(size);
+	auto len = static_cast<unsigned int>(size);
+
+	const EVP_MD *hashFunc;
+	switch (fingerprintAlgorithm) {
+	case CertificateFingerprint::Algorithm::Sha1:
+		hashFunc = EVP_sha1();
+		break;
+	case CertificateFingerprint::Algorithm::Sha224:
+		hashFunc = EVP_sha224();
+		break;
+	case CertificateFingerprint::Algorithm::Sha256:
+		hashFunc = EVP_sha256();
+		break;
+	case CertificateFingerprint::Algorithm::Sha384:
+		hashFunc = EVP_sha384();
+		break;
+	case CertificateFingerprint::Algorithm::Sha512:
+		hashFunc = EVP_sha512();
+		break;
+	default:
+		throw std::invalid_argument("Unknown fingerprint algorithm");
+	}
+
+	if (!X509_digest(x509, hashFunc, buffer.data(), &len))
 		throw std::runtime_error("X509 fingerprint error");
 		throw std::runtime_error("X509 fingerprint error");
 
 
 	std::ostringstream oss;
 	std::ostringstream oss;
@@ -483,7 +556,7 @@ string make_fingerprint(X509 *x509) {
 	for (size_t i = 0; i < len; ++i) {
 	for (size_t i = 0; i < len; ++i) {
 		if (i)
 		if (i)
 			oss << std::setw(1) << ':';
 			oss << std::setw(1) << ':';
-		oss << std::setw(2) << unsigned(buffer[i]);
+		oss << std::setw(2) << unsigned(buffer.at(i));
 	}
 	}
 	return oss.str();
 	return oss.str();
 }
 }
@@ -498,6 +571,8 @@ future_certificate_ptr make_certificate(CertificateType type) {
 	});
 	});
 }
 }
 
 
-string Certificate::fingerprint() const { return mFingerprint; }
+CertificateFingerprint Certificate::fingerprint() const {
+	return CertificateFingerprint{CertificateFingerprint::Algorithm::Sha256, mFingerprint};
+}
 
 
 } // namespace rtc::impl
 } // namespace rtc::impl

+ 6 - 5
src/impl/certificate.hpp

@@ -9,6 +9,7 @@
 #ifndef RTC_IMPL_CERTIFICATE_H
 #ifndef RTC_IMPL_CERTIFICATE_H
 #define RTC_IMPL_CERTIFICATE_H
 #define RTC_IMPL_CERTIFICATE_H
 
 
+#include "description.hpp" // for CertificateFingerprint
 #include "common.hpp"
 #include "common.hpp"
 #include "configuration.hpp" // for CertificateType
 #include "configuration.hpp" // for CertificateType
 #include "init.hpp"
 #include "init.hpp"
@@ -37,7 +38,7 @@ public:
 	std::tuple<X509 *, EVP_PKEY *> credentials() const;
 	std::tuple<X509 *, EVP_PKEY *> credentials() const;
 #endif
 #endif
 
 
-	string fingerprint() const;
+	CertificateFingerprint fingerprint() const;
 
 
 private:
 private:
 	const init_token mInitToken = Init::Instance().token();
 	const init_token mInitToken = Init::Instance().token();
@@ -57,12 +58,12 @@ private:
 };
 };
 
 
 #if USE_GNUTLS
 #if USE_GNUTLS
-string make_fingerprint(gnutls_certificate_credentials_t credentials);
-string make_fingerprint(gnutls_x509_crt_t crt);
+string make_fingerprint(gnutls_certificate_credentials_t credentials, CertificateFingerprint::Algorithm fingerprintAlgorithm);
+string make_fingerprint(gnutls_x509_crt_t crt, CertificateFingerprint::Algorithm fingerprintAlgorithm);
 #elif USE_MBEDTLS
 #elif USE_MBEDTLS
-string make_fingerprint(mbedtls_x509_crt *crt);
+string make_fingerprint(mbedtls_x509_crt *crt, CertificateFingerprint::Algorithm fingerprintAlgorithm);
 #else
 #else
-string make_fingerprint(X509 *x509);
+string make_fingerprint(X509 *x509, CertificateFingerprint::Algorithm fingerprintAlgorithm);
 #endif
 #endif
 
 
 using certificate_ptr = shared_ptr<Certificate>;
 using certificate_ptr = shared_ptr<Certificate>;

+ 2 - 1
src/impl/dtlssrtptransport.cpp

@@ -58,10 +58,11 @@ bool DtlsSrtpTransport::IsGcmSupported() {
 
 
 DtlsSrtpTransport::DtlsSrtpTransport(shared_ptr<IceTransport> lower,
 DtlsSrtpTransport::DtlsSrtpTransport(shared_ptr<IceTransport> lower,
                                      shared_ptr<Certificate> certificate, optional<size_t> mtu,
                                      shared_ptr<Certificate> certificate, optional<size_t> mtu,
+                                     CertificateFingerprint::Algorithm fingerprintAlgorithm,
                                      verifier_callback verifierCallback,
                                      verifier_callback verifierCallback,
                                      message_callback srtpRecvCallback,
                                      message_callback srtpRecvCallback,
                                      state_callback stateChangeCallback)
                                      state_callback stateChangeCallback)
-    : DtlsTransport(lower, certificate, mtu, std::move(verifierCallback),
+    : DtlsTransport(lower, certificate, mtu, fingerprintAlgorithm, std::move(verifierCallback),
                     std::move(stateChangeCallback)),
                     std::move(stateChangeCallback)),
       mSrtpRecvCallback(std::move(srtpRecvCallback)) { // distinct from Transport recv callback
       mSrtpRecvCallback(std::move(srtpRecvCallback)) { // distinct from Transport recv callback
 
 

+ 3 - 2
src/impl/dtlssrtptransport.hpp

@@ -31,8 +31,9 @@ public:
 	static bool IsGcmSupported();
 	static bool IsGcmSupported();
 
 
 	DtlsSrtpTransport(shared_ptr<IceTransport> lower, certificate_ptr certificate,
 	DtlsSrtpTransport(shared_ptr<IceTransport> lower, certificate_ptr certificate,
-	                  optional<size_t> mtu, verifier_callback verifierCallback,
-	                  message_callback srtpRecvCallback, state_callback stateChangeCallback);
+	                  optional<size_t> mtu, CertificateFingerprint::Algorithm fingerprintAlgorithm,
+	                  verifier_callback verifierCallback, message_callback srtpRecvCallback,
+	                  state_callback stateChangeCallback);
 	~DtlsSrtpTransport();
 	~DtlsSrtpTransport();
 
 
 	bool sendMedia(message_ptr message);
 	bool sendMedia(message_ptr message);

+ 15 - 12
src/impl/dtlstransport.cpp

@@ -48,10 +48,11 @@ void DtlsTransport::Init() {
 void DtlsTransport::Cleanup() { gnutls_global_deinit(); }
 void DtlsTransport::Cleanup() { gnutls_global_deinit(); }
 
 
 DtlsTransport::DtlsTransport(shared_ptr<IceTransport> lower, certificate_ptr certificate,
 DtlsTransport::DtlsTransport(shared_ptr<IceTransport> lower, certificate_ptr certificate,
-                             optional<size_t> mtu, verifier_callback verifierCallback,
-                             state_callback stateChangeCallback)
+                             optional<size_t> mtu,
+                             CertificateFingerprint::Algorithm fingerprintAlgorithm,
+                             verifier_callback verifierCallback, state_callback stateChangeCallback)
     : Transport(lower, std::move(stateChangeCallback)), mMtu(mtu), mCertificate(certificate),
     : Transport(lower, std::move(stateChangeCallback)), mMtu(mtu), mCertificate(certificate),
-      mVerifierCallback(std::move(verifierCallback)),
+      mFingerprintAlgorithm(fingerprintAlgorithm), mVerifierCallback(std::move(verifierCallback)),
       mIsClient(lower->role() == Description::Role::Active) {
       mIsClient(lower->role() == Description::Role::Active) {
 
 
 	PLOG_DEBUG << "Initializing DTLS transport (GnuTLS)";
 	PLOG_DEBUG << "Initializing DTLS transport (GnuTLS)";
@@ -295,7 +296,7 @@ int DtlsTransport::CertificateCallback(gnutls_session_t session) {
 			return GNUTLS_E_CERTIFICATE_ERROR;
 			return GNUTLS_E_CERTIFICATE_ERROR;
 		}
 		}
 
 
-		string fingerprint = make_fingerprint(crt);
+		string fingerprint = make_fingerprint(crt, t->mFingerprintAlgorithm);
 		gnutls_x509_crt_deinit(crt);
 		gnutls_x509_crt_deinit(crt);
 
 
 		bool success = t->mVerifierCallback(fingerprint);
 		bool success = t->mVerifierCallback(fingerprint);
@@ -374,10 +375,11 @@ const mbedtls_ssl_srtp_profile srtpSupportedProtectionProfiles[] = {
 };
 };
 
 
 DtlsTransport::DtlsTransport(shared_ptr<IceTransport> lower, certificate_ptr certificate,
 DtlsTransport::DtlsTransport(shared_ptr<IceTransport> lower, certificate_ptr certificate,
-                             optional<size_t> mtu, verifier_callback verifierCallback,
-                             state_callback stateChangeCallback)
+                             optional<size_t> mtu,
+                             CertificateFingerprint::Algorithm fingerprintAlgorithm,
+                             verifier_callback verifierCallback, state_callback stateChangeCallback)
     : Transport(lower, std::move(stateChangeCallback)), mMtu(mtu), mCertificate(certificate),
     : Transport(lower, std::move(stateChangeCallback)), mMtu(mtu), mCertificate(certificate),
-      mVerifierCallback(std::move(verifierCallback)),
+      mFingerprintAlgorithm(fingerprintAlgorithm), mVerifierCallback(std::move(verifierCallback)),
       mIsClient(lower->role() == Description::Role::Active) {
       mIsClient(lower->role() == Description::Role::Active) {
 
 
 	PLOG_DEBUG << "Initializing DTLS transport (MbedTLS)";
 	PLOG_DEBUG << "Initializing DTLS transport (MbedTLS)";
@@ -609,7 +611,7 @@ void DtlsTransport::doRecv() {
 int DtlsTransport::CertificateCallback(void *ctx, mbedtls_x509_crt *crt, int /*depth*/,
 int DtlsTransport::CertificateCallback(void *ctx, mbedtls_x509_crt *crt, int /*depth*/,
                                        uint32_t * /*flags*/) {
                                        uint32_t * /*flags*/) {
 	auto this_ = static_cast<DtlsTransport *>(ctx);
 	auto this_ = static_cast<DtlsTransport *>(ctx);
-	string fingerprint = make_fingerprint(crt);
+	string fingerprint = make_fingerprint(crt, this_->mFingerprintAlgorithm);
 	std::transform(fingerprint.begin(), fingerprint.end(), fingerprint.begin(),
 	std::transform(fingerprint.begin(), fingerprint.end(), fingerprint.begin(),
 	               [](char c) { return char(std::toupper(c)); });
 	               [](char c) { return char(std::toupper(c)); });
 	return this_->mVerifierCallback(fingerprint) ? 0 : 1;
 	return this_->mVerifierCallback(fingerprint) ? 0 : 1;
@@ -725,10 +727,11 @@ void DtlsTransport::Cleanup() {
 }
 }
 
 
 DtlsTransport::DtlsTransport(shared_ptr<IceTransport> lower, certificate_ptr certificate,
 DtlsTransport::DtlsTransport(shared_ptr<IceTransport> lower, certificate_ptr certificate,
-                             optional<size_t> mtu, verifier_callback verifierCallback,
-                             state_callback stateChangeCallback)
+                             optional<size_t> mtu,
+                             CertificateFingerprint::Algorithm fingerprintAlgorithm,
+                             verifier_callback verifierCallback, state_callback stateChangeCallback)
     : Transport(lower, std::move(stateChangeCallback)), mMtu(mtu), mCertificate(certificate),
     : Transport(lower, std::move(stateChangeCallback)), mMtu(mtu), mCertificate(certificate),
-      mVerifierCallback(std::move(verifierCallback)),
+      mFingerprintAlgorithm(fingerprintAlgorithm), mVerifierCallback(std::move(verifierCallback)),
       mIsClient(lower->role() == Description::Role::Active) {
       mIsClient(lower->role() == Description::Role::Active) {
 	PLOG_DEBUG << "Initializing DTLS transport (OpenSSL)";
 	PLOG_DEBUG << "Initializing DTLS transport (OpenSSL)";
 
 
@@ -1034,7 +1037,7 @@ int DtlsTransport::CertificateCallback(int /*preverify_ok*/, X509_STORE_CTX *ctx
 	    static_cast<DtlsTransport *>(SSL_get_ex_data(ssl, DtlsTransport::TransportExIndex));
 	    static_cast<DtlsTransport *>(SSL_get_ex_data(ssl, DtlsTransport::TransportExIndex));
 
 
 	X509 *crt = X509_STORE_CTX_get_current_cert(ctx);
 	X509 *crt = X509_STORE_CTX_get_current_cert(ctx);
-	string fingerprint = make_fingerprint(crt);
+	string fingerprint = make_fingerprint(crt, t->mFingerprintAlgorithm);
 
 
 	return t->mVerifierCallback(fingerprint) ? 1 : 0;
 	return t->mVerifierCallback(fingerprint) ? 1 : 0;
 }
 }

+ 2 - 0
src/impl/dtlstransport.hpp

@@ -32,6 +32,7 @@ public:
 	using verifier_callback = std::function<bool(const std::string &fingerprint)>;
 	using verifier_callback = std::function<bool(const std::string &fingerprint)>;
 
 
 	DtlsTransport(shared_ptr<IceTransport> lower, certificate_ptr certificate, optional<size_t> mtu,
 	DtlsTransport(shared_ptr<IceTransport> lower, certificate_ptr certificate, optional<size_t> mtu,
+	              CertificateFingerprint::Algorithm fingerprintAlgorithm,
 	              verifier_callback verifierCallback, state_callback stateChangeCallback);
 	              verifier_callback verifierCallback, state_callback stateChangeCallback);
 	~DtlsTransport();
 	~DtlsTransport();
 
 
@@ -52,6 +53,7 @@ protected:
 
 
 	const optional<size_t> mMtu;
 	const optional<size_t> mMtu;
 	const certificate_ptr mCertificate;
 	const certificate_ptr mCertificate;
+	CertificateFingerprint::Algorithm mFingerprintAlgorithm;
 	const verifier_callback mVerifierCallback;
 	const verifier_callback mVerifierCallback;
 	const bool mIsClient;
 	const bool mIsClient;
 
 

+ 11 - 6
src/impl/peerconnection.cpp

@@ -211,6 +211,11 @@ shared_ptr<DtlsTransport> PeerConnection::initDtlsTransport() {
 
 
 		PLOG_VERBOSE << "Starting DTLS transport";
 		PLOG_VERBOSE << "Starting DTLS transport";
 
 
+		auto fingerprintAlgorithm = CertificateFingerprint::Algorithm::Sha256;
+		if (auto remote = remoteDescription(); remote && remote->fingerprint()) {
+			fingerprintAlgorithm = remote->fingerprint()->algorithm;
+		}
+
 		auto lower = std::atomic_load(&mIceTransport);
 		auto lower = std::atomic_load(&mIceTransport);
 		if (!lower)
 		if (!lower)
 			throw std::logic_error("No underlying ICE transport for DTLS transport");
 			throw std::logic_error("No underlying ICE transport for DTLS transport");
@@ -254,7 +259,7 @@ shared_ptr<DtlsTransport> PeerConnection::initDtlsTransport() {
 
 
 			// DTLS-SRTP
 			// DTLS-SRTP
 			transport = std::make_shared<DtlsSrtpTransport>(
 			transport = std::make_shared<DtlsSrtpTransport>(
-			    lower, certificate, config.mtu, verifierCallback,
+			    lower, certificate, config.mtu, fingerprintAlgorithm, verifierCallback,
 			    weak_bind(&PeerConnection::forwardMedia, this, _1), dtlsStateChangeCallback);
 			    weak_bind(&PeerConnection::forwardMedia, this, _1), dtlsStateChangeCallback);
 #else
 #else
 			PLOG_WARNING << "Ignoring media support (not compiled with media support)";
 			PLOG_WARNING << "Ignoring media support (not compiled with media support)";
@@ -264,7 +269,8 @@ shared_ptr<DtlsTransport> PeerConnection::initDtlsTransport() {
 		if (!transport) {
 		if (!transport) {
 			// DTLS only
 			// DTLS only
 			transport = std::make_shared<DtlsTransport>(lower, certificate, config.mtu,
 			transport = std::make_shared<DtlsTransport>(lower, certificate, config.mtu,
-			                                            verifierCallback, dtlsStateChangeCallback);
+			                                            fingerprintAlgorithm, verifierCallback,
+			                                            dtlsStateChangeCallback);
 		}
 		}
 
 
 		return emplaceTransport(this, &mDtlsTransport, std::move(transport));
 		return emplaceTransport(this, &mDtlsTransport, std::move(transport));
@@ -417,14 +423,13 @@ void PeerConnection::rollbackLocalDescription() {
 
 
 bool PeerConnection::checkFingerprint(const std::string &fingerprint) const {
 bool PeerConnection::checkFingerprint(const std::string &fingerprint) const {
 	std::lock_guard lock(mRemoteDescriptionMutex);
 	std::lock_guard lock(mRemoteDescriptionMutex);
-	auto expectedFingerprint = mRemoteDescription ? mRemoteDescription->fingerprint() : nullopt;
-	if (expectedFingerprint && *expectedFingerprint == fingerprint) {
+	auto expectedFingerprint = mRemoteDescription && mRemoteDescription->fingerprint() ? mRemoteDescription->fingerprint()->value : "";
+	if (expectedFingerprint == fingerprint) {
 		PLOG_VERBOSE << "Valid fingerprint \"" << fingerprint << "\"";
 		PLOG_VERBOSE << "Valid fingerprint \"" << fingerprint << "\"";
 		return true;
 		return true;
 	}
 	}
 
 
-	PLOG_ERROR << "Invalid fingerprint \"" << fingerprint << "\", expected \""
-	           << expectedFingerprint.value_or("[none]") << "\"";
+	PLOG_ERROR << "Invalid fingerprint \"" << fingerprint << "\", expected \"" << expectedFingerprint << "\"";
 	return false;
 	return false;
 }
 }
 
 

+ 2 - 3
test/connectivity.cpp

@@ -52,10 +52,9 @@ void test_connectivity(bool signal_wrong_fingerprint) {
 		if (signal_wrong_fingerprint) {
 		if (signal_wrong_fingerprint) {
 			auto f = sdp.fingerprint();
 			auto f = sdp.fingerprint();
 			if (f.has_value()) {
 			if (f.has_value()) {
-				auto s = f.value();
-				auto& c = s[0];
+				auto& c = f.value().value[0];
 				if (c == 'F' || c == 'f') c = '0'; else c++;
 				if (c == 'F' || c == 'f') c = '0'; else c++;
-				sdp.setFingerprint(s);
+				sdp.setFingerprint(f.value());
 			}
 			}
 		}
 		}
 		pc2.setRemoteDescription(string(sdp));
 		pc2.setRemoteDescription(string(sdp));