summaryrefslogtreecommitdiff
path: root/cpp/src
diff options
context:
space:
mode:
authorJose <jose@zeroc.com>2015-04-01 14:49:36 +0200
committerJose <jose@zeroc.com>2015-04-01 14:49:36 +0200
commiteb5749bee9ea0fc46211d365f1e21a6b460bc30d (patch)
treea5f44b79782cb2997e89dc6e3aafb0397f554afe /cpp/src
parentSSL fixes (bis) (diff)
downloadice-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')
-rw-r--r--cpp/src/Glacier2CryptPermissionsVerifier/CryptPermissionsVerifierI.cpp296
-rw-r--r--cpp/src/Glacier2CryptPermissionsVerifier/Makefile2
-rw-r--r--cpp/src/Glacier2CryptPermissionsVerifier/Makefile.mak2
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)