From f41c8fef99497e357965ef3514bb7b5282a2e938 Mon Sep 17 00:00:00 2001
From: Adrien Beraud <adrien.beraud@savoirfairelinux.com>
Date: Thu, 20 Apr 2017 16:48:55 +0200
Subject: [PATCH] crypto: unify API across GnuTLS versions

Throw an exception if GnuTLS is too old
instead of not providing the API.

Also consistently throw in case of hash error,
and return 0 for an empty hash, for both
PublicKey and Certificate.
---
 include/opendht/crypto.h    |  4 ----
 include/opendht/securedht.h |  3 +--
 src/crypto.cpp              | 40 ++++++++++++++++++++++++++-----------
 3 files changed, 29 insertions(+), 18 deletions(-)

diff --git a/include/opendht/crypto.h b/include/opendht/crypto.h
index ef87b415..8a1f86bd 100644
--- a/include/opendht/crypto.h
+++ b/include/opendht/crypto.h
@@ -83,9 +83,7 @@ struct OPENDHT_PUBLIC PublicKey
     PublicKey& operator=(PublicKey&& o) noexcept;
 
     InfoHash getId() const;
-#if GNUTLS_VERSION_NUMBER >= 0x030401
     PkId getLongId() const;
-#endif
     bool checkSignature(const Blob& data, const Blob& signature) const;
     Blob encrypt(const Blob&) const;
 
@@ -364,9 +362,7 @@ struct OPENDHT_PUBLIC Certificate {
 
     /** Same as getPublicKey().getId() */
     InfoHash getId() const;
-#if GNUTLS_VERSION_NUMBER >= 0x030401
     PkId getLongId() const;
-#endif
 
     /** Read certificate Common Name (CN) */
     std::string getName() const;
diff --git a/include/opendht/securedht.h b/include/opendht/securedht.h
index 7e2004d9..acae729f 100644
--- a/include/opendht/securedht.h
+++ b/include/opendht/securedht.h
@@ -51,11 +51,10 @@ public:
     InfoHash getId() const {
         return key_ ? key_->getPublicKey().getId() : InfoHash();
     }
-#if GNUTLS_VERSION_NUMBER >= 0x030401
     PkId getLongId() const {
         return key_ ? key_->getPublicKey().getLongId() : PkId();
     }
-#endif
+
     ValueType secureType(ValueType&& type);
 
     ValueType secureType(const ValueType& type) {
diff --git a/src/crypto.cpp b/src/crypto.cpp
index 4b35b1ec..ec3ce321 100644
--- a/src/crypto.cpp
+++ b/src/crypto.cpp
@@ -525,24 +525,34 @@ PublicKey::encrypt(const Blob& data) const
 InfoHash
 PublicKey::getId() const
 {
+    if (not pk)
+        return {};
     InfoHash id;
     size_t sz = id.size();
-    if (gnutls_pubkey_get_key_id(pk, 0, id.data(), &sz) != GNUTLS_E_SUCCESS || sz != id.size())
-        return {};
+    if (auto err = gnutls_pubkey_get_key_id(pk, 0, id.data(), &sz))
+        throw CryptoException(std::string("Can't get public key ID: ") + gnutls_strerror(err));
+    if (sz != id.size())
+        throw CryptoException("Can't get public key ID: wrong output length.");
     return id;
 }
 
-#if GNUTLS_VERSION_NUMBER >= 0x030401
 PkId
 PublicKey::getLongId() const
 {
+    if (not pk)
+        return {};
+#if GNUTLS_VERSION_NUMBER < 0x030401
+    throw CryptoException("Can't get 256 bits public key ID: GnuTLS 3.4.1 or higher required.");
+#else
     PkId h;
     size_t sz = h.size();
-    if (gnutls_pubkey_get_key_id(pk, GNUTLS_KEYID_USE_SHA256, h.data(), &sz) != GNUTLS_E_SUCCESS || sz != h.size())
-        return {};
+    if (auto err = gnutls_pubkey_get_key_id(pk, GNUTLS_KEYID_USE_SHA256, h.data(), &sz))
+        throw CryptoException(std::string("Can't get 256 bits public key ID: ") + gnutls_strerror(err));
+    if (sz != h.size())
+        throw CryptoException("Can't get 256 bits public key ID: wrong output length.");
     return h;
-}
 #endif
+}
 
 Certificate::Certificate(const Blob& certData) : cert(nullptr)
 {
@@ -643,24 +653,30 @@ Certificate::getId() const
         return {};
     InfoHash id;
     size_t sz = id.size();
-    if (gnutls_x509_crt_get_key_id(cert, 0, id.data(), &sz) != GNUTLS_E_SUCCESS || sz != id.size())
-        throw CryptoException("Can't get certificate public key ID.");
+    if (auto err = gnutls_x509_crt_get_key_id(cert, 0, id.data(), &sz))
+        throw CryptoException(std::string("Can't get certificate public key ID: ") + gnutls_strerror(err));
+    if (sz != id.size())
+        throw CryptoException("Can't get certificate public key ID: wrong output length.");
     return id;
 }
 
-#if GNUTLS_VERSION_NUMBER >= 0x030401
 PkId
 Certificate::getLongId() const
 {
     if (not cert)
         return {};
+#if GNUTLS_VERSION_NUMBER < 0x030401
+    throw CryptoException("Can't get certificate 256 bits public key ID: GnuTLS 3.4.1 or higher required.");
+#else
     PkId id;
     size_t sz = id.size();
-    if (gnutls_x509_crt_get_key_id(cert, GNUTLS_KEYID_USE_SHA256, id.data(), &sz) != GNUTLS_E_SUCCESS || sz != id.size())
-        throw CryptoException("Can't get certificate public key ID.");
+    if (auto err = gnutls_x509_crt_get_key_id(cert, GNUTLS_KEYID_USE_SHA256, id.data(), &sz))
+        throw CryptoException(std::string("Can't get certificate 256 bits public key ID: ") + gnutls_strerror(err));
+    if (sz != id.size())
+        throw CryptoException("Can't get certificate 256 bits public key ID: wrong output length.");
     return id;
-}
 #endif
+}
 
 static std::string
 getDN(gnutls_x509_crt_t cert, const char* oid, bool issuer = false)
-- 
GitLab