Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HeaderVersion() and LibraryVersion() functions #371

Closed
noloader opened this issue Jan 28, 2017 · 2 comments
Closed

Add HeaderVersion() and LibraryVersion() functions #371

noloader opened this issue Jan 28, 2017 · 2 comments

Comments

@noloader
Copy link
Collaborator

noloader commented Jan 28, 2017

We've been following a thread from Ethereum. One of the side/related issues appears to be determining the Crypto++ version.

The problem is, CRYPTOPP_VERSION is a macro in config.h, around line 65, and it can be a bit misleading. Someonecould be runtime linking against a shared object version 5.5, but if library versions are mixed/matched, then they could get 5.6.5 from the header.

I think we need two functions in the CryptoPP namespace:

  • int HeaderVersion()
  • int LibraryVersion()

HeaderVersion would return CRYPTOPP_VERSION from config.h. Its the version of the library the app was built against. The function should be declared in a header, and the definition should be in the header, too.

LibraryVersion would return CRYPTOPP_VERSION used to build the library. The function should be declared in a header, and the definition should be in a source file to ensure it records what a distro builds and distributes the library, and it does not change when an app builds against it.

Both LibraryVersion and HeaderVersion should reside int he CryptoPP namespace. Both LibraryVersion and HeaderVersion should use C linkage (extern "C") so that those who dlsym for it don't have to contend with name mangling.

Later, if users mix and match library versions, then they will be able to detect the condition. For app code, it could be as simple as:

if (LibraryVersion() != HeaderVersion())
{
    cout << "Potential library version mismatch << endl;

    const int bmaj = (LibraryVersion() / 100U) % 10;
    const int bmin = (LibraryVersion() / 10U) % 10;

    const int rmaj = (HeaderVersion() / 100U) % 10;
    const int rmin = (HeaderVersion() / 10U) % 10;

    if(bmaj ^ rmaj)
    {
        cout << "Major version mismatch" << endl;
    }
    else if(bmin ^ rmin )
    {
        cout << "Minor version mismatch" << endl;
    }
}

OpenSSL and other projects have the same problem and similar mechanisms. For example, here is OpenSSL's SSLeay_version man page, which returns build-time version information. And here is the OPENSSL_VERSION_NUMBER macro man page, which provides the app's runtime version.

@noloader
Copy link
Collaborator Author

noloader commented Jan 28, 2017

The following patch works as expected (documentation comments removed for brevity):

$ git diff cryptlib.h cryptlib.cpp > version.diff
$ cat version.diff
diff --git a/cryptlib.cpp b/cryptlib.cpp
index f202f53..d37734b 100644
--- a/cryptlib.cpp
+++ b/cryptlib.cpp
@@ -945,6 +945,16 @@ void AuthenticatedKeyAgreementDomain::GenerateEphemeralKeyPair(RandomNumberGener
        GenerateEphemeralPublicKey(rng, privateKey, publicKey);
 }

+// Allow a distro or user to override the build-time version
+//  https://github.com/weidai11/cryptopp/issues/371
+#ifndef CRYPTOPP_BUILD_VERSION
+# define CRYPTOPP_BUILD_VERSION CRYPTOPP_VERSION
+#endif
+int LibraryVersion()
+{
+       return CRYPTOPP_BUILD_VERSION;
+}
+
 NAMESPACE_END

 #endif
diff --git a/cryptlib.h b/cryptlib.h
index 0e6011b..d903022 100644
--- a/cryptlib.h
+++ b/cryptlib.h
@@ -2914,6 +2914,62 @@ public:
        virtual void BEREncode(BufferedTransformation &bt) const {DEREncode(bt);}
 };

+int LibraryVersion();
+
+inline int HeaderVersion()
+{
+       return CRYPTOPP_VERSION;
+}
+
 NAMESPACE_END

 #if CRYPTOPP_MSC_VERSION

If nothing special is done, then everything operates as expected. LibraryVersion() and HeaderVersion() return the same value.

A failure can be introduced that mimics mixing/matching library versions:

# Build library as usual
make distclean
make -j 4

# Induce failure
$ rm cryptlib.o  && CXXFLAGS="-DNDEBUG -g2 -O2 -DCRYPTOPP_BUILD_VERSION=565" make

Running cryptest.exe with -DCRYPTOPP_BUILD_VERSION=565 results in:

./cryptest.exe v
Using seed: 1485589679

Testing Settings...

passed:  Your machine is little endian.
FAILED:  Library version (library): 565, header version (app): 570
passed:  CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS is not defined...
passed:  sizeof(byte) == 1
passed:  sizeof(word16) == 2
passed:  sizeof(word32) == 4
passed:  sizeof(word64) == 8
passed:  sizeof(word128) == 16
passed:  sizeof(hword) == 4, sizeof(word) == 8, sizeof(dword) == 16
passed:  hasMMX == 1, hasISSE == 1, hasSSE2 == 1, hasSSSE3 == 1, hasSSE4 == 1, hasAESNI == 1, hasCLMUL == 1, hasRDRAND == 1, hasRDSEED == 0, hasSHA == 0, isP4 == 0, cacheLineSize == 64
Some critical setting in config.h is in error.  Please fix it and recompile.

noloader referenced this issue Jan 28, 2017
These function are intended to catch mining and matching of library versions. BuildVersion provides CRYPTOPP_VERSION when the shared object was built. RuntimeVersion provides CRYPTOPP_VERSION the app compiled against, which could be different than the shared object's version
@noloader noloader reopened this Jan 28, 2017
@noloader noloader changed the title Add BuildVersion() and RuntimeVersion() functions Add HeaderVersion() and LibraryVersion() functions Jan 29, 2017
@noloader
Copy link
Collaborator Author

Cleared at Commit 6f7339c81b26985a. Function names updated at Commit 42af35fd2bcf00e9.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant