diff options
author | Jose <jose@zeroc.com> | 2015-04-01 14:49:36 +0200 |
---|---|---|
committer | Jose <jose@zeroc.com> | 2015-04-01 14:49:36 +0200 |
commit | eb5749bee9ea0fc46211d365f1e21a6b460bc30d (patch) | |
tree | a5f44b79782cb2997e89dc6e3aafb0397f554afe | |
parent | SSL fixes (bis) (diff) | |
download | ice-eb5749bee9ea0fc46211d365f1e21a6b460bc30d.tar.bz2 ice-eb5749bee9ea0fc46211d365f1e21a6b460bc30d.tar.xz ice-eb5749bee9ea0fc46211d365f1e21a6b460bc30d.zip |
ICE-6383 - Update crypt password usage
Added new script to create crypt passwords using passlib
scripts/cryptpasswd.py
Remove tests passwords files they are now generated using
cryptpasswd script
Update CryptPermissionsVerifierI to support PBKDF2 password schemes
in Windows and OS X, and MD5/SHA256/SHA512 crypt in Linux, on other
systems fallback to DES_crypt from openssl
28 files changed, 614 insertions, 24 deletions
diff --git a/.gitignore b/.gitignore index 80a1760ed5c..82d36a18eb3 100644 --- a/.gitignore +++ b/.gitignore @@ -86,3 +86,5 @@ cpp/src/Ice/EventLoggerMsg.res # WinRT cpp/SDKs + +passwords diff --git a/cpp/allTests.py b/cpp/allTests.py index 8b01519b97c..860fc464940 100755 --- a/cpp/allTests.py +++ b/cpp/allTests.py @@ -115,6 +115,7 @@ tests = [ ("Glacier2/dynamicFiltering", ["service", "novc100", "nomingw"]), ("Glacier2/staticFiltering", ["service", "noipv6", "novc100", "nomingw", "nomx"]), ("Glacier2/sessionHelper", ["core", "novc100", "nomingw"]), + ("Glacier2/cryptpasswd", ["once", "nomingw", "novalgrind", "noappverifier"]) ] # diff --git a/cpp/config/Make.rules.Darwin b/cpp/config/Make.rules.Darwin index c801d50fa7f..d672de5c8c3 100644 --- a/cpp/config/Make.rules.Darwin +++ b/cpp/config/Make.rules.Darwin @@ -100,8 +100,8 @@ ICONV_LIB = -liconv ICEUTIL_OS_LIBS = ICE_OS_LIBS = -ldl - -SSL_OS_LIBS = -framework Security -framework CoreFoundation +CRYPT_OS_LIBS = -framework Security -framework CoreFoundation +SSL_OS_LIBS = $(CRYPT_OS_LIBS) PLATFORM_HAS_READLINE := yes diff --git a/cpp/config/Make.rules.Linux b/cpp/config/Make.rules.Linux index 006434e9277..5668097a15f 100644 --- a/cpp/config/Make.rules.Linux +++ b/cpp/config/Make.rules.Linux @@ -203,6 +203,7 @@ endif ICESSL_LIBS = $(OPENSSL_RPATH_LINK) -lIceSSL LIBS = $(BZIP2_RPATH_LINK) -lIce $(BASELIBS) +CRYPT_OS_LIBS = -lcrypt ICEUTIL_OS_LIBS = -lrt $(OPENSSL_RPATH_LINK) -lcrypto ICE_OS_LIBS = -ldl diff --git a/cpp/src/Glacier2CryptPermissionsVerifier/CryptPermissionsVerifierI.cpp b/cpp/src/Glacier2CryptPermissionsVerifier/CryptPermissionsVerifierI.cpp index 6c111b7c4a3..53bbb23f97f 100644 --- a/cpp/src/Glacier2CryptPermissionsVerifier/CryptPermissionsVerifierI.cpp +++ b/cpp/src/Glacier2CryptPermissionsVerifier/CryptPermissionsVerifierI.cpp @@ -13,8 +13,18 @@ #include <IceUtil/FileUtil.h> #include <IceUtil/StringUtil.h> - -#ifndef __APPLE__ +#include <IceUtil/InputUtil.h> + +#if defined(__GLIBC__) +# include <crypt.h> +#elif defined(__APPLE__) +# include <CoreFoundation/CoreFoundation.h> +# include <Security/Security.h> +# include <CommonCrypto/CommonCrypto.h> +#elif defined(_WIN32) +# include <Bcrypt.h> +# include <Wincrypt.h> +#else # include <openssl/des.h> #endif @@ -92,6 +102,37 @@ CryptPermissionsVerifierI::CryptPermissionsVerifierI(const map<string, string>& { } +namespace +{ + +#if defined(__APPLE__) || defined(_WIN32) + +const string padBytes0 = ""; +const string padBytes1 = "="; +const string padBytes2 = "=="; + +inline string +paddingBytes(int lenght) +{ + switch(lenght % 4) + { + case 2: + { + return padBytes2; + } + case 3: + { + return padBytes1; + } + default: + { + return padBytes0; + } + } +} +#endif + +} bool CryptPermissionsVerifierI::checkPermissions(const string& userId, const string& password, string&, const Current&) const { @@ -103,6 +144,252 @@ CryptPermissionsVerifierI::checkPermissions(const string& userId, const string& { return false; } +#if defined(__GLIBC__) + size_t i = p->second.rfind('$'); + if(i == string::npos) + { + return false; + } + string salt = p->second.substr(0, i + 1); + if(salt.empty()) + { + return false; + } + struct crypt_data data; + data.initialized = 0; + return p->second == crypt_r(password.c_str(), salt.c_str(), &data); +#elif defined(__APPLE__) || defined(_WIN32) + // + // Pbkdf2 string format: + // + // $pbkdf2-digest$rounds$salt$checksum + // $pbkdf2$rounds$salt$checksum (SHA1 digest) + // + + size_t beg = 0; + size_t end = 0; + + + // + // Determine the digest algorithm + // +# if defined(__APPLE__) + CCPseudoRandomAlgorithm algorithmId = 0; +# else + LPCWSTR algorithmId = 0; +# endif + int checksumLength = 0; + + const string pbkdf2SHA1Token = "$pbkdf2$"; + + if(p->second.find(pbkdf2SHA1Token) == 0) + { +# if defined(__APPLE__) + algorithmId = kCCPRFHmacAlgSHA1; +# else + algorithmId = BCRYPT_SHA1_ALGORITHM; +# endif + checksumLength = 20; + beg = pbkdf2SHA1Token.size(); + } + else + { + // + // Pbkdf2 string format: + // + // $pbkdf2-digest$rounds$salt$checksum + // + const string pbkdf2Token = "$pbkdf2-"; + if(p->second.find(pbkdf2Token) != 0) + { + return false; // PBKDF2 start token not found + } + + beg = pbkdf2Token.size(); + end = p->second.find('$', beg); + if(end == string::npos) + { + return false; // Digest algorithm end token not found + } + + if(p->second.substr(beg, (end - beg)) == "sha256") + { +# if defined(__APPLE__) + algorithmId = kCCPRFHmacAlgSHA256; +# else + algorithmId = BCRYPT_SHA256_ALGORITHM; +# endif + checksumLength = 32; + } + else if(p->second.substr(beg, (end - beg)) == "sha512") + { +# if defined(__APPLE__) + algorithmId = kCCPRFHmacAlgSHA512; +# else + algorithmId = BCRYPT_SHA512_ALGORITHM; +# endif + checksumLength = 64; + } + else + { + return false; // Invalid digest algorithm + } + beg = end + 1; + } + // + // Determine the number of rounds + // + end = p->second.find('$', beg); + if(end == string::npos) + { + return false; // Rounds end token not found + } + + IceUtil::Int64 rounds = 0; + if(!IceUtilInternal::stringToInt64(p->second.substr(beg, (end - beg)), rounds)) + { + return false; // Invalid rounds value + } + + // + // Determine salt and checksum + // + beg = end + 1; + end = p->second.find('$', beg); + if(end == string::npos) + { + return false; // Salt value end token not found + } + + string salt = p->second.substr(beg, (end - beg)); + string checksum = p->second.substr(end + 1); + if(checksum.empty()) + { + return false; + } + + // + // passlib encoding is identical to base64 except that it uses . instead of +, + // and omits trailing padding = and whitepsace. + // + std::replace(salt.begin(), salt.end(), '.', '+'); + salt += paddingBytes(salt.size()); + + std::replace(checksum.begin(), checksum.end(), '.', '+'); + checksum += paddingBytes(checksum.size()); +# if defined(__APPLE__) + CFErrorRef error = 0; + SecTransformRef decoder = SecDecodeTransformCreate(kSecBase64Encoding, &error); + if(error) + { + CFRelease(error); + return false; + } + + CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, + reinterpret_cast<const uint8_t*>(salt.c_str()), + salt.size(), kCFAllocatorNull); + + SecTransformSetAttribute(decoder, kSecTransformInputAttributeName, data, &error); + if(error) + { + CFRelease(error); + CFRelease(decoder); + return false; + } + + CFDataRef saltBuffer = static_cast<CFDataRef>(SecTransformExecute(decoder, &error)); + CFRelease(decoder); + + if(error) + { + CFRelease(error); + return false; + } + + vector<uint8_t> checksumBuffer1(checksumLength); + OSStatus status = CCKeyDerivationPBKDF(kCCPBKDF2, password.c_str(), password.size(), + CFDataGetBytePtr(saltBuffer), CFDataGetLength(saltBuffer), + algorithmId, rounds, &checksumBuffer1[0], checksumLength); + CFRelease(saltBuffer); + if(status != errSecSuccess) + { + return false; + } + + decoder = SecDecodeTransformCreate(kSecBase64Encoding, &error); + if(error) + { + CFRelease(error); + return false; + } + data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, + reinterpret_cast<const uint8_t*>(checksum.c_str()), + checksum.size(), kCFAllocatorNull); + SecTransformSetAttribute(decoder, kSecTransformInputAttributeName, data, &error); + if(error) + { + CFRelease(error); + CFRelease(decoder); + return false; + } + + data = static_cast<CFDataRef>(SecTransformExecute(decoder, &error)); + CFRelease(decoder); + decoder = 0; + + if(error) + { + CFRelease(error); + return false; + } + + vector<uint8_t> checksumBuffer2(CFDataGetBytePtr(data), CFDataGetBytePtr(data) + CFDataGetLength(data)); + CFRelease(data); + + return checksumBuffer1 == checksumBuffer2; +# else + DWORD saltLength = salt.size(); + vector<BYTE> saltBuffer(saltLength); + + if(!CryptStringToBinary(salt.c_str(), salt.size(), CRYPT_STRING_BASE64, &saltBuffer[0], &saltLength, 0, 0)) + { + return false; + } + saltBuffer.resize(saltLength); + + BCRYPT_ALG_HANDLE algorithmHandle = 0; + if(BCryptOpenAlgorithmProvider(&algorithmHandle, algorithmId, 0, BCRYPT_ALG_HANDLE_HMAC_FLAG) != 0) + { + return false; + } + + vector<BYTE> checksumBuffer1(checksumLength); + + vector<BYTE> passwordBuffer(password.begin(), password.end()); + + DWORD status = BCryptDeriveKeyPBKDF2(algorithmHandle, &passwordBuffer[0], passwordBuffer.size(), + &saltBuffer[0], saltLength, rounds, + &checksumBuffer1[0], checksumLength, 0); + + BCryptCloseAlgorithmProvider(algorithmHandle, 0); + + if(status != 0) + { + return false; + } + + DWORD checksumBuffer2Length = checksumLength; + vector<BYTE> checksumBuffer2(checksumLength); + + if(!CryptStringToBinary(checksum.c_str(), checksum.size(), CRYPT_STRING_BASE64, &checksumBuffer2[0], + &checksumBuffer2Length, 0, 0)) + { + return false; + } + return checksumBuffer1 == checksumBuffer2; +# endif +#else if(p->second.size() != 13) // Crypt passwords are 13 characters long. { @@ -111,16 +398,13 @@ CryptPermissionsVerifierI::checkPermissions(const string& userId, const string& char buff[14]; string salt = p->second.substr(0, 2); -#if defined(__APPLE__) - return p->second == crypt(password.c_str(), salt.c_str()); -#else # if OPENSSL_VERSION_NUMBER >= 0x0090700fL DES_fcrypt(password.c_str(), salt.c_str(), buff); # else des_fcrypt(password.c_str(), salt.c_str(), buff); # endif -#endif return p->second == buff; +#endif } diff --git a/cpp/src/Glacier2CryptPermissionsVerifier/Makefile b/cpp/src/Glacier2CryptPermissionsVerifier/Makefile index 90829971149..f3c49c50313 100644 --- a/cpp/src/Glacier2CryptPermissionsVerifier/Makefile +++ b/cpp/src/Glacier2CryptPermissionsVerifier/Makefile @@ -24,7 +24,7 @@ include $(top_srcdir)/config/Make.rules CPPFLAGS := -I.. $(CPPFLAGS) -LINKWITH := $(BZIP2_RPATH_LINK) -lIce -lIceUtil -lGlacier2 $(ICEUTIL_OS_LIBS) $(CXXLIBS) +LINKWITH := $(BZIP2_RPATH_LINK) -lIce -lIceUtil -lGlacier2 $(CRYPT_OS_LIBS) $(CXXLIBS) $(libdir)/$(LIBFILENAME): $(OBJS) @mkdir -p $(dir $@) diff --git a/cpp/src/Glacier2CryptPermissionsVerifier/Makefile.mak b/cpp/src/Glacier2CryptPermissionsVerifier/Makefile.mak index 00ba7d8886b..3828a45771e 100644 --- a/cpp/src/Glacier2CryptPermissionsVerifier/Makefile.mak +++ b/cpp/src/Glacier2CryptPermissionsVerifier/Makefile.mak @@ -20,7 +20,7 @@ OBJS = .\CryptPermissionsVerifierI.obj CPPFLAGS = -I.. $(CPPFLAGS) -DWIN32_LEAN_AND_MEAN -LINKWITH = $(LIBS) libeay32.lib +LINKWITH = $(LIBS) crypt32.lib bcrypt.lib !if "$(GENERATE_PDB)" == "yes" PDBFLAGS = /pdb:$(DLLNAME:.dll=.pdb) diff --git a/cpp/test/Glacier2/attack/passwords b/cpp/test/Glacier2/attack/passwords deleted file mode 100644 index a1527dec2b9..00000000000 --- a/cpp/test/Glacier2/attack/passwords +++ /dev/null @@ -1 +0,0 @@ -userid xxMqsnnDcK8tw
\ No newline at end of file diff --git a/cpp/test/Glacier2/attack/run.py b/cpp/test/Glacier2/attack/run.py index cd3302f5371..36540456af9 100755 --- a/cpp/test/Glacier2/attack/run.py +++ b/cpp/test/Glacier2/attack/run.py @@ -26,6 +26,11 @@ router = TestUtil.getGlacier2Router() if TestUtil.appverifier: TestUtil.setAppVerifierSettings([router]) +# +# Generate the crypt passwords file +# +TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"}) + args = ' --Glacier2.RoutingTable.MaxSize=10' + \ ' --Glacier2.Client.Endpoints="default -p 12347"' + \ ' --Ice.Admin.Endpoints="tcp -h 127.0.0.1 -p 12348"' + \ diff --git a/cpp/test/Glacier2/cryptpasswd/run.py b/cpp/test/Glacier2/cryptpasswd/run.py new file mode 100755 index 00000000000..fe441e07281 --- /dev/null +++ b/cpp/test/Glacier2/cryptpasswd/run.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# ********************************************************************** +# +# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved. +# +# This copy of Ice is licensed to you under the terms described in the +# ICE_LICENSE file included in this distribution. +# +# ********************************************************************** + +import os, sys, passlib.hash, subprocess + +path = [ ".", "..", "../..", "../../..", "../../../.." ] +head = os.path.dirname(sys.argv[0]) +if len(head) > 0: + path = [os.path.join(head, p) for p in path] +path = [os.path.abspath(p) for p in path if os.path.exists(os.path.join(p, "scripts", "TestUtil.py")) ] +if len(path) == 0: + raise RuntimeError("can't find toplevel directory!") +sys.path.append(os.path.join(path[0], "scripts")) +import TestUtil + +cryptpasswd = os.path.join(path[0], "scripts", "cryptpasswd.py") + +def test(b): + if not b: + raise RuntimeError('test assertion failed') + +def cryptPasswords(password, args = ""): + p = subprocess.Popen("%s %s %s" % (sys.executable, cryptpasswd, args), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + stdin=subprocess.PIPE) + p.stdin.write(password.encode('UTF-8')) + p.stdin.write('\r\n'.encode('UTF-8')) + p.stdin.flush() + if(p.wait() != 0): + print("cryptpasswd.py failed:\n" + p.stdout.read().decode('UTF-8').strip()) + sys.exit(1) + hash = p.stdout.readline().decode('UTF-8').strip() + return hash + + +usePBKDF2 = sys.platform == "win32" or sys.platform == "darwin" +useCryptExt = sys.platform.startswith("linux") + +if usePBKDF2: + + sys.stdout.write("Testing PBKDF2 crypt passwords...") + sys.stdout.flush() + + test(passlib.hash.pbkdf2_sha256.verify("abc123", cryptPasswords("abc123"))) + test(not passlib.hash.pbkdf2_sha256.verify("abc123", cryptPasswords("abc"))) + + test(passlib.hash.pbkdf2_sha1.verify("abc123", cryptPasswords("abc123", "-d sha1"))) + test(not passlib.hash.pbkdf2_sha1.verify("abc123", cryptPasswords("abc", "-d sha1"))) + + test(passlib.hash.pbkdf2_sha512.verify("abc123", cryptPasswords("abc123", "-d sha512"))) + test(not passlib.hash.pbkdf2_sha512.verify("abc123", cryptPasswords("abc", "-d sha512"))) + + # + # Now use custom rounds, md5 digest doesn't support + # + hash = cryptPasswords("abc123", "-r 1000") + if hash.find("$pbkdf2-sha256$1000$") == -1: + test(False) + test(passlib.hash.pbkdf2_sha256.verify("abc123", hash)) + + hash = cryptPasswords("abc123", "-r 1000 -d sha1") + if hash.find("$pbkdf2$1000$") == -1: + test(False) + test(passlib.hash.pbkdf2_sha1.verify("abc123", hash)) + + hash = cryptPasswords("abc123", "-r 1000 -d sha512") + if hash.find("$pbkdf2-sha512$1000$") == -1: + test(False) + test(passlib.hash.pbkdf2_sha512.verify("abc123", hash)) + + print("ok") + +elif useCryptExt: + + sys.stdout.write("Testing Linux crypt passwords...") + sys.stdout.flush() + + test(passlib.hash.sha512_crypt.verify("abc123", cryptPasswords("abc123"))) + test(not passlib.hash.sha512_crypt.verify("abc123", cryptPasswords("abc"))) + + test(passlib.hash.sha256_crypt.verify("abc123", cryptPasswords("abc123", "-d sha256"))) + test(not passlib.hash.sha256_crypt.verify("abc123", cryptPasswords("abc", "-d sha256"))) + + test(passlib.hash.md5_crypt.verify("abc123", cryptPasswords("abc123", "-d md5"))) + test(not passlib.hash.md5_crypt.verify("abc123", cryptPasswords("abc", "-d md5"))) + + # + # Now use custom rounds, md5 digest doesn't support + # + hash = cryptPasswords("abc123", "-r 5000") + if hash.find("rounds=") != -1: + test(False) + test(passlib.hash.sha512_crypt.verify("abc123", hash)) + hash = cryptPasswords("abc123", "-d sha256 -r 5000") + if hash.find("rounds=") != -1: + test(False) + test(passlib.hash.sha256_crypt.verify("abc123", hash)) + + hash = cryptPasswords("abc123", "-r 10000") + if hash.find("$rounds=10000$") == -1: + test(False) + test(passlib.hash.sha512_crypt.verify("abc123", hash)) + hash = cryptPasswords("abc123", "-d sha256 -r 10000") + if hash.find("$rounds=10000$") == -1: + test(False) + test(passlib.hash.sha256_crypt.verify("abc123", hash)) + + print("ok") diff --git a/cpp/test/Glacier2/router/passwords b/cpp/test/Glacier2/router/passwords deleted file mode 100644 index 01943218b12..00000000000 --- a/cpp/test/Glacier2/router/passwords +++ /dev/null @@ -1,6 +0,0 @@ -userid xxMqsnnDcK8tw -userid-0 xxMqsnnDcK8tw -userid-1 xxMqsnnDcK8tw -userid-2 xxMqsnnDcK8tw -userid-3 xxMqsnnDcK8tw -userid-4 xxMqsnnDcK8tw diff --git a/cpp/test/Glacier2/router/run.py b/cpp/test/Glacier2/router/run.py index 050eee50d4c..60e5d448164 100755 --- a/cpp/test/Glacier2/router/run.py +++ b/cpp/test/Glacier2/router/run.py @@ -55,6 +55,12 @@ def startRouter(buffered): name = os.path.join("Glacier2", "router") # +# Generate the crypt passwords file +# +TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), + {"userid": "abc123", "userid-0": "abc123", "userid-1": "abc123", + "userid-2": "abc123", "userid-3": "abc123","userid-4": "abc123"}) +# # We first run the test with unbuffered mode. # starterProc = startRouter(False) diff --git a/cpp/test/Glacier2/sessionHelper/passwords b/cpp/test/Glacier2/sessionHelper/passwords deleted file mode 100644 index a1527dec2b9..00000000000 --- a/cpp/test/Glacier2/sessionHelper/passwords +++ /dev/null @@ -1 +0,0 @@ -userid xxMqsnnDcK8tw
\ No newline at end of file diff --git a/cpp/test/Glacier2/sessionHelper/run.py b/cpp/test/Glacier2/sessionHelper/run.py index 3ec7dec5363..14e74172df1 100755 --- a/cpp/test/Glacier2/sessionHelper/run.py +++ b/cpp/test/Glacier2/sessionHelper/run.py @@ -22,6 +22,11 @@ import TestUtil router = os.path.join(TestUtil.getCppBinDir(), "glacier2router") +# +# Generate the crypt passwords file +# +TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"}) + args = ' --Ice.Warn.Dispatch=0' + \ ' --Ice.Warn.Connections=0' + \ ' --Glacier2.SessionTimeout="30"' + \ diff --git a/cpp/test/Glacier2/staticFiltering/passwords b/cpp/test/Glacier2/staticFiltering/passwords deleted file mode 100644 index a1527dec2b9..00000000000 --- a/cpp/test/Glacier2/staticFiltering/passwords +++ /dev/null @@ -1 +0,0 @@ -userid xxMqsnnDcK8tw
\ No newline at end of file diff --git a/cpp/test/Glacier2/staticFiltering/run.py b/cpp/test/Glacier2/staticFiltering/run.py index e379442e327..de52ea47942 100755 --- a/cpp/test/Glacier2/staticFiltering/run.py +++ b/cpp/test/Glacier2/staticFiltering/run.py @@ -29,6 +29,11 @@ router = TestUtil.getGlacier2Router() clientCmd = os.path.join(os.getcwd(), 'client') serverCmd = os.path.join(os.getcwd(), 'server') +# +# Generate the crypt passwords file +# +TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"}) + targets = [] if TestUtil.appverifier: targets = [serverCmd, clientCmd, router] diff --git a/csharp/test/Glacier2/router/passwords b/csharp/test/Glacier2/router/passwords deleted file mode 100644 index a1527dec2b9..00000000000 --- a/csharp/test/Glacier2/router/passwords +++ /dev/null @@ -1 +0,0 @@ -userid xxMqsnnDcK8tw
\ No newline at end of file diff --git a/csharp/test/Glacier2/router/run.py b/csharp/test/Glacier2/router/run.py index 4b88f3f882a..c32b3873c0c 100755 --- a/csharp/test/Glacier2/router/run.py +++ b/csharp/test/Glacier2/router/run.py @@ -22,6 +22,11 @@ import TestUtil router = os.path.join(TestUtil.getCppBinDir(), "glacier2router") +# +# Generate the crypt passwords file +# +TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"}) + args = ' --Ice.Warn.Dispatch=0' + \ ' --Ice.Warn.Connections=0' + \ ' --Glacier2.Filter.Category.Accept="c1 c2"' + \ diff --git a/csharp/test/Glacier2/sessionHelper/passwords b/csharp/test/Glacier2/sessionHelper/passwords deleted file mode 100644 index a1527dec2b9..00000000000 --- a/csharp/test/Glacier2/sessionHelper/passwords +++ /dev/null @@ -1 +0,0 @@ -userid xxMqsnnDcK8tw
\ No newline at end of file diff --git a/csharp/test/Glacier2/sessionHelper/run.py b/csharp/test/Glacier2/sessionHelper/run.py index 1565361b923..4bfc2a41224 100755 --- a/csharp/test/Glacier2/sessionHelper/run.py +++ b/csharp/test/Glacier2/sessionHelper/run.py @@ -20,6 +20,11 @@ if len(path) == 0: sys.path.append(os.path.join(path[0], "scripts")) import TestUtil +# +# Generate the crypt passwords file +# +TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"}) + router = os.path.join(TestUtil.getCppBinDir(), "glacier2router") args = ' --Ice.Warn.Dispatch=0' + \ diff --git a/java/test/src/main/java/test/Glacier2/router/passwords b/java/test/src/main/java/test/Glacier2/router/passwords deleted file mode 100644 index a1527dec2b9..00000000000 --- a/java/test/src/main/java/test/Glacier2/router/passwords +++ /dev/null @@ -1 +0,0 @@ -userid xxMqsnnDcK8tw
\ No newline at end of file diff --git a/java/test/src/main/java/test/Glacier2/router/run.py b/java/test/src/main/java/test/Glacier2/router/run.py index 780ceff6580..7baa3ac3c5c 100755 --- a/java/test/src/main/java/test/Glacier2/router/run.py +++ b/java/test/src/main/java/test/Glacier2/router/run.py @@ -23,6 +23,11 @@ import TestUtil router = os.path.join(TestUtil.getCppBinDir(), "glacier2router") +# +# Generate the crypt passwords file +# +TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"}) + args = ' --Ice.Warn.Dispatch=0' + \ ' --Ice.Warn.Connections=0' + \ ' --Glacier2.Filter.Category.Accept="c1 c2"' + \ diff --git a/java/test/src/main/java/test/Glacier2/sessionHelper/passwords b/java/test/src/main/java/test/Glacier2/sessionHelper/passwords deleted file mode 100644 index a1527dec2b9..00000000000 --- a/java/test/src/main/java/test/Glacier2/sessionHelper/passwords +++ /dev/null @@ -1 +0,0 @@ -userid xxMqsnnDcK8tw
\ No newline at end of file diff --git a/java/test/src/main/java/test/Glacier2/sessionHelper/run.py b/java/test/src/main/java/test/Glacier2/sessionHelper/run.py index 0144d973b85..4146018f313 100755 --- a/java/test/src/main/java/test/Glacier2/sessionHelper/run.py +++ b/java/test/src/main/java/test/Glacier2/sessionHelper/run.py @@ -23,6 +23,11 @@ import TestUtil router = os.path.join(TestUtil.getCppBinDir(), "glacier2router") +# +# Generate the crypt passwords file +# +TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"}) + args = ' --Ice.Warn.Dispatch=0' + \ ' --Ice.Warn.Connections=0' + \ ' --Glacier2.SessionTimeout="30"' + \ diff --git a/js/test/Glacier2/router/passwords b/js/test/Glacier2/router/passwords deleted file mode 100644 index a1527dec2b9..00000000000 --- a/js/test/Glacier2/router/passwords +++ /dev/null @@ -1 +0,0 @@ -userid xxMqsnnDcK8tw
\ No newline at end of file diff --git a/js/test/Glacier2/router/run.py b/js/test/Glacier2/router/run.py index b05757bb98b..e1ba5205563 100755 --- a/js/test/Glacier2/router/run.py +++ b/js/test/Glacier2/router/run.py @@ -22,6 +22,11 @@ import TestUtil router = os.path.join(TestUtil.getCppBinDir(), "glacier2router") +# +# Generate the crypt passwords file +# +TestUtil.cryptPasswords(os.path.join(os.getcwd(), "passwords"), {"userid": "abc123"}) + args = ' --Ice.Warn.Dispatch=0' + \ ' --Ice.Warn.Connections=0' + \ ' --Glacier2.Filter.Category.Accept="c1 c2"' + \ diff --git a/scripts/TestUtil.py b/scripts/TestUtil.py index 2a9f847016d..0ee9a0b73af 100755 --- a/scripts/TestUtil.py +++ b/scripts/TestUtil.py @@ -827,6 +827,27 @@ def getIceExe(name): def getNodeCommand(): return nodeCmd +# +# Create a passwords file that contains the given users/passwords using cryptpasswd.py +# +def cryptPasswords(filePath, entries): + if os.path.exists(filePath): + os.remove(filePath) + passwords = open(filePath, "a") + for user, password in entries.items(): + p = subprocess.Popen( + "%s %s" % (sys.executable, os.path.abspath(os.path.join(os.path.dirname(__file__), "cryptpasswd.py"))), + shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE) + p.stdin.write(password.encode('UTF-8')) + p.stdin.write('\r\n'.encode('UTF-8')) + p.stdin.flush() + if(p.wait() != 0): + print("cryptpasswd.py failed:\n" + p.stdout.read().decode('UTF-8').strip()) + passwords.close() + sys.exit(1) + passwords.write("%s %s\n" % (user, p.stdout.readline().decode('UTF-8').strip())) + passwords.close() + class InvalidSelectorString(Exception): def __init__(self, value): self.value = value diff --git a/scripts/cryptpasswd.py b/scripts/cryptpasswd.py new file mode 100644 index 00000000000..2277e23beef --- /dev/null +++ b/scripts/cryptpasswd.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# ********************************************************************** +# +# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved. +# +# This copy of Ice is licensed to you under the terms described in the +# ICE_LICENSE file included in this distribution. +# +# ********************************************************************** + +import sys, getopt, passlib.hash, getpass + +usePBKDF2 = sys.platform == "win32" or sys.platform == "darwin" +useCryptExt = sys.platform.startswith("linux") + +def usage(): + print("cryptpasswd [options]") + print("") + print("OPTIONS") + print("") + if usePBKDF2: + print("") + print(" -d DIGEST_ALGORITHM, --digest=DIGEST_ALGORITHM") + print(" The digest algorithm to use with PBKDF2, valid values are (sha1, sha256, sha512).") + print("") + print(" -s SALT_SIZE, --salt=SALT_SIZE") + print(" Optional number of bytes to use when generating new salts.") + print("") + elif useCryptExt: + print(" -d DIGEST_ALGORITHM, --digest=DIGEST_ALGORITHM") + print(" The digest algorithm to use with crypt function, valid values are (md5, sha256, sha512).") + print("") + if usePBKDF2 or useCryptExt: + print(" -r ROUNDS, --rounds=ROUNDS") + print(" Optional number of rounds to use.") + print("") + print(" -h, --help" ) + print(" Show this message.") + print("") + +def encrypt(): + + digestAlgorithms = () + shortArgs = "h" + longArgs = ["help"] + if usePBKDF2: + shortArgs += "d:s:r:" + longArgs += ["digest=", "salt=", "rounds="] + digestAlgorithms = ("sha1", "sha256", "sha512") + elif useCryptExt: + shortArgs += "d:r:" + longArgs += ["digest=", "rounds="] + digestAlgorithms = ("md5", "sha256", "sha512") + + try: + opts, args = getopt.getopt(sys.argv[1:], shortArgs, longArgs) + except getopt.GetoptError as err: + print("") + print(str(err)) + usage() + sys.exit(2) + + digest = None + salt = None + rounds = None + + for o, a in opts: + if o in ("-h", "--help"): + usage() + sys.exit(0) + elif o in ("-d", "--digest"): + if a in digestAlgorithms: + digest = a + else: + print("Unknown digest algorithm `" + a + "'") + sys.exit(2) + elif o in ("-s", "--salt"): + try: + salt = int(a) + if salt < 0 or salt > 1024: + print("Invalid salt value it must be an integer between 0 and 1024") + usage() + sys.exit(2) + except ValueError as err: + print("Invalid salt value it must be an integer between 0 and 1024") + usage() + sys.exit(2) + elif o in ("-r", "--rounds"): + try: + rounds = int(a) + if rounds < 1 or rounds > sys.maxsize: + print("Invalid rounds value it must be an integer between 1 and %s" % sys.maxsize) + usage() + sys.exit(2) + except ValueError as err: + print("Invalid rounds value it must be an integer between 1 and %s" % sys.maxsize) + usage() + sys.exit(2) + + encryptfn = None + if usePBKDF2: + encryptfn = passlib.hash.pbkdf2_sha256.encrypt + if digest == "sha1": + encryptfn = passlib.hash.pbkdf2_sha1.encrypt + elif digest == "sha512": + encryptfn = passlib.hash.pbkdf2_sha512.encrypt + elif useCryptExt: + encryptfn = passlib.hash.sha512_crypt.encrypt + if digest == "md5": + if rounds: + print("Custom rounds not allowed with md5 digest") + usage() + sys.exit(2) + encryptfn = passlib.hash.md5_crypt.encrypt + elif digest == "sha256": + encryptfn = passlib.hash.sha256_crypt.encrypt + else: + encryptfn = passlib.hash.des_crypt.encrypt + + args = [] + if sys.stdout.isatty(): + args.append(getpass.getpass("Password: ")) + else: + args.append(sys.stdin.readline().strip()) + + opts = {} + if salt: + opts["salt_size"] = salt + + if rounds: + opts["rounds"] = rounds + + print(encryptfn(*args, **opts)) + +encrypt() |