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 /cpp/src | |
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
Diffstat (limited to 'cpp/src')
3 files changed, 292 insertions, 8 deletions
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) |