Browse Source

HPCC-23082 Crypto Plugin needs key file access control

Add new ECL module to load key files from HPCC LFN
Deprecate ECL module that loads key files from file system
Add new testcases for LFN load of key files

Signed-off-by: Russ Whitehead <william.whitehead@lexisnexisrisk.com>
Russ Whitehead 5 years ago
parent
commit
c77c9b7028

+ 56 - 0
ecllibrary/std/Crypto.ecl

@@ -144,6 +144,62 @@ EXPORT PublicKeyEncryption(VARSTRING pkAlgorithm, VARSTRING publicKeyFile = '',
 END; // PublicKeyEncryption module
 
 
+/**
+ * Encryption module containing all asymmetric encryption/decryption/digital
+ * signing/signature verification functions
+ *
+ * @param   pkAlgorithm    Asymmetric algorithm to use, as returned by SupportedPublicKeyAlgorithms()
+ * @param   publicKeyLFN   LFN specification of PEM formatted public key file
+ * @param   privateKeyLFN  LFN specification of PEM formatted private key file
+ * @param   passphrase     Optional Passphrase to use for encryption/encryption/signing/verifying
+ */
+EXPORT PublicKeyEncryptionFromLFN(VARSTRING pkAlgorithm, VARSTRING publicKeyLFN = '', VARSTRING privateKeyLFN = '', VARSTRING passphrase = '') := MODULE
+    /**
+     * Encrypt the given data, using the specified public key LFN,
+     * passphrase, and algorithm
+     *
+     * @param   inputData    Contents to Encrypt
+     * @return               Encrypted data
+     */
+    EXPORT DATA Encrypt(DATA inputData) := FUNCTION
+        RETURN lib_cryptolib.CryptoLib.EncryptLFN( pkAlgorithm, publicKeyLFN, passphrase, inputData);
+    END;
+
+    /**
+     * Decrypt the given encrypted data, using the specified private key LFN,
+     * passphrase, and algorithm
+     *
+     * @param   encryptedData    Contents to Decrypt
+     * @return                   Decrypted data
+     */
+    EXPORT DATA Decrypt(DATA encryptedData) := FUNCTION
+        RETURN lib_cryptolib.CryptoLib.DecryptLFN( pkAlgorithm, privateKeyLFN, passphrase, encryptedData);
+    END;
+
+    /**
+     * Create a digital signature of the given data, using the
+     * specified private key LFN, passphrase and algorithm
+     *
+     * @param   inputData    Contents to sign
+     * @return               Computed Digital signature
+     */
+    EXPORT DATA Sign( DATA inputData) := FUNCTION
+        RETURN lib_cryptolib.CryptoLib.SignLFN( pkAlgorithm, privateKeyLFN, passphrase, inputData);
+    END;
+
+    /**
+     * Verify the given digital signature of the given data, using
+     * the specified public key LFN, passphrase and algorithm
+     *
+     * @param   signature      Signature to verify
+     * @param   signedData     Data used to create signature
+     * @return                 Boolean TRUE/FALSE
+     */
+    EXPORT BOOLEAN VerifySignature(DATA signature, DATA signedData) := FUNCTION
+        RETURN lib_cryptolib.CryptoLib.VerifySignatureLFN( pkAlgorithm, publicKeyLFN, passphrase, signature, signedData);
+    END;
+END; // PublicKeyEncryptionFromLFN module
+
 
 /**
   * Encryption module containing all asymmetric encryption/decryption/digital

+ 3 - 0
plugins/cryptolib/CMakeLists.txt

@@ -33,7 +33,10 @@ include_directories (
          ${HPCC_SOURCE_DIR}/system/include
          ${HPCC_SOURCE_DIR}/system/jlib
          ${HPCC_SOURCE_DIR}/rtl/include
+         ${HPCC_SOURCE_DIR}/dali/base
+         ${HPCC_SOURCE_DIR}/system/mp
          ${HPCC_SOURCE_DIR}/system/security/cryptohelper
+         ${HPCC_SOURCE_DIR}/system/security/shared
          ${OPENSSL_INCLUDE_DIR}
     )
 

+ 170 - 32
plugins/cryptolib/cryptolib.cpp

@@ -17,15 +17,15 @@
 #include "jexcept.hpp"
 #include "digisign.hpp"
 #include "ske.hpp"
-#include <openssl/pem.h>
-#include <openssl/err.h>
+#include "dadfs.hpp"
+#include "dautils.hpp"
+
 #include <openssl/rand.h>
-#include <string>
 #include <unordered_map>
-#include "jthread.hpp"
 
 #include "cryptolib.hpp"
 
+
 using namespace std;
 
 #define CRYPTOLIB_VERSION "CRYPTOLIB 1.0.00"
@@ -177,20 +177,20 @@ void verifySymmetricAlgorithm(const char * algorithm, size32_t len)
      if (strieq(algorithm, "aes-128-cbc"))
      {
          if (len != 16)
-             throw MakeStringException(-1, "Invalid Key Length %d specified for algorithm %s, try 16", len, algorithm);
+             throw makeStringExceptionV(-1, "Invalid Key Length %d specified for algorithm %s, try 16", len, algorithm);
      }
      else if (strieq(algorithm, "aes-192-cbc"))
      {
          if (len != 24)
-             throw MakeStringException(-1, "Invalid Key Length %d specified for algorithm %s, try 24", len, algorithm);
+             throw makeStringExceptionV(-1, "Invalid Key Length %d specified for algorithm %s, try 24", len, algorithm);
      }
      else if (strieq(algorithm, "aes-256-cbc"))
      {
          if (len != 32)
-             throw MakeStringException(-1, "Invalid Key Length %d specified for algorithm %s, try 32", len, algorithm);
+             throw makeStringExceptionV(-1, "Invalid Key Length %d specified for algorithm %s, try 32", len, algorithm);
      }
      else
-         throw MakeStringException(-1, "Unsupported symmetric algorithm (%s) specified", algorithm);
+         throw makeStringExceptionV(-1, "Unsupported symmetric algorithm (%s) specified", algorithm);
 }
 
 CRYPTOLIB_API void CRYPTOLIB_CALL clSymmetricEncrypt(size32_t & __lenResult, void * & __result,
@@ -262,7 +262,7 @@ void throwHashError(const char * str)
     unsigned long err = ERR_get_error();
     char errStr[1024];
     ERR_error_string_n(err, errStr, sizeof(errStr));
-    throw MakeStringException(-1, "%s : ERROR %ld (0x%lX) : %s", str, err, err, errStr);
+    throw makeStringExceptionV(-1, "%s : ERROR %ld (0x%lX) : %s", str, err, err, errStr);
 }
 
 CRYPTOLIB_API void CRYPTOLIB_CALL clHash(size32_t & __lenResult, void * & __result,
@@ -362,7 +362,7 @@ CRYPTOLIB_API void CRYPTOLIB_CALL clHash(size32_t & __lenResult, void * & __resu
     }
     else
     {
-        throw MakeStringException(-1, "Unsupported hash algorithm '%s' specified", algorithm);
+        throw makeStringExceptionV(-1, "Unsupported hash algorithm '%s' specified", algorithm);
     }
 }
 
@@ -400,17 +400,63 @@ void doPKISign(size32_t & __lenResult, void * & __result,
     }
     else
     {
-        throw MakeStringException(-1, "Unable to create Digital Signature");
+        throw makeStringException(-1, "Unable to create Digital Signature");
     }
 }
 
 void verifyPKIAlgorithm(const char * pkAlgorithm)
 {
     if (!strieq(pkAlgorithm, "RSA"))
-        throw MakeStringException(-1, "Unsupported PKI algorithm (%s) specified", pkAlgorithm);
+        throw makeStringExceptionV(-1, "Unsupported PKI algorithm (%s) specified", pkAlgorithm);
 }
 
 
+//---------------------------------------------------------
+// Helper that reads the given logical file into a string buffer
+// Throws if user does not have read permission or if FNF
+//---------------------------------------------------------
+void loadLFS(const char * lfs, IUserDescriptor * user, StringBuffer &sb)
+{
+    CDfsLogicalFileName lfn;
+    lfn.set(lfs);
+    try
+    {
+        Owned<IDistributedFile> df = queryDistributedFileDirectory().lookup(lfn, user, false, false, false, nullptr, defaultPrivilegedUser);//scope checks
+        if (!df)
+        {
+            throw makeStringExceptionV(-1, "File %s Not Found", lfs);
+        }
+
+        if (df->numParts() == 0)
+        {
+            throw makeStringExceptionV(-1, "File %s is Empty", lfs);
+        }
+
+        IDistributedFilePart &part = df->queryPart(0);
+
+        RemoteFilename rfn;
+        Owned<IFile> file = createIFile(part.getFilename(rfn));
+        if (!file->exists())
+        {
+            throw makeStringExceptionV(-1, "File %s Not Found", lfs);
+        }
+
+        Owned<IFileIO> io = file->open(IFOread);
+        offset_t len = file->size();
+        char * buff = sb.reserveTruncate(len);
+        size32_t read = io->read(0, len, buff);
+        assertex(read == len);
+        //IFileIO dtor closes the file
+    }
+    catch(IException * e)
+    {
+        StringBuffer s;
+        VStringBuffer sb("Error accessing Key file '%s' : %s", lfs, e->errorMessage(s).str());
+        e->Release();
+        throw makeStringException(-1, sb.str());
+    }
+}
+
 //-----------------------------------------------------------------
 //  Simple cache for instances of Digital Signature Managers
 //-----------------------------------------------------------------
@@ -422,7 +468,7 @@ private:
     DSMCache dsmCache;
 
 public:
-    IDigitalSignatureManager * getInstance(const char * algo, const char * pubKeyFS, const char * pubKeyBuff, const char * privKeyFS, const char * privKeyBuff, const char * passphrase)
+    IDigitalSignatureManager * getInstance(const char * algo, const char * pubKeyFS, const char * pubKeyBuff, const char * privKeyFS, const char * privKeyBuff, const char * passphrase, bool isLFN, IUserDescriptor * user)
     {
         VStringBuffer searchKey("%s_%s_%s_%s_%s_%s", algo, isEmptyString(pubKeyFS) ? "" : pubKeyFS, isEmptyString(pubKeyBuff) ? "" : pubKeyBuff,
                                 isEmptyString(privKeyFS) ? "" : privKeyFS, isEmptyString(privKeyBuff) ? "" : privKeyBuff, passphrase);
@@ -436,7 +482,19 @@ public:
         else
         {
             if (!isEmptyString(pubKeyFS) || !isEmptyString(privKeyFS))
-                ret = createDigitalSignatureManagerInstanceFromFiles(pubKeyFS, privKeyFS, passphrase);
+            {
+                bool isPublic = isEmptyString(privKeyFS);
+                const char * fs = isPublic ? pubKeyFS : privKeyFS;;
+
+                if (isLFN)
+                {
+                    StringBuffer sb;
+                    loadLFS(fs, user, sb);//read key file into StringBuffer
+                    ret = createDigitalSignatureManagerInstanceFromKeys(isPublic ? sb.str() : nullptr, isPublic ? nullptr : sb.str(), passphrase);
+                }
+                else
+                    ret = createDigitalSignatureManagerInstanceFromFiles(pubKeyFS, privKeyFS, passphrase);
+            }
             else
                 ret = createDigitalSignatureManagerInstanceFromKeys(pubKeyBuff, privKeyBuff, passphrase);
 
@@ -448,6 +506,7 @@ public:
 static CDSMCache g_DSMCache;
 
 //Sign given data using private key
+
 CRYPTOLIB_API void CRYPTOLIB_CALL clPKISign(size32_t & __lenResult,void * & __result,
                                         const char * pkalgorithm,
                                         const char * privatekeyfile,
@@ -455,14 +514,34 @@ CRYPTOLIB_API void CRYPTOLIB_CALL clPKISign(size32_t & __lenResult,void * & __re
                                         size32_t lenInputdata,const void * inputdata)
 {
     verifyPKIAlgorithm(pkalgorithm);//TODO extend cryptohelper to support more algorithms
-    Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, nullptr, nullptr, privatekeyfile, nullptr, passphrase);
+    Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, nullptr, nullptr, privatekeyfile, nullptr, passphrase, false, nullptr);
     if (pDSM)
     {
         doPKISign(__lenResult, __result, pDSM, lenInputdata, inputdata);
     }
     else
     {
-        throw MakeStringException(-1, "Unable to create Digital Signature Manager");
+        throw makeStringException(-1, "Unable to create Digital Signature Manager");
+    }
+}
+
+CRYPTOLIB_API void CRYPTOLIB_CALL clPKISignLFN(ICodeContext * ctx,
+                                        size32_t & __lenResult,void * & __result,
+                                        const char * pkalgorithm,
+                                        const char * privatekeyLFN,
+                                        const char * passphrase,
+                                        size32_t lenInputdata,const void * inputdata)
+{
+    verifyPKIAlgorithm(pkalgorithm);
+    IUserDescriptor * udesc = ctx->queryUserDescriptor();
+    Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, nullptr, nullptr, privatekeyLFN, nullptr, passphrase, true, udesc);
+    if (pDSM)
+    {
+        doPKISign(__lenResult, __result, pDSM, lenInputdata, inputdata);
+    }
+    else
+    {
+        throw makeStringException(-1, "Unable to create Digital Signature Manager");
     }
 }
 
@@ -473,17 +552,18 @@ CRYPTOLIB_API void CRYPTOLIB_CALL clPKISignBuff(size32_t & __lenResult, void * &
                                             size32_t lenInputdata, const void * inputdata)
 {
     verifyPKIAlgorithm(pkalgorithm);
-    Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, nullptr, nullptr, nullptr, privatekeybuff, passphrase);
+    Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, nullptr, nullptr, nullptr, privatekeybuff, passphrase, false, nullptr);
     if (pDSM)
     {
         doPKISign(__lenResult, __result, pDSM, lenInputdata, inputdata);
     }
     else
     {
-        throw MakeStringException(-1, "Unable to create Digital Signature Manager");
+        throw makeStringException(-1, "Unable to create Digital Signature Manager");
     }
 }
 
+
 CRYPTOLIB_API bool CRYPTOLIB_CALL clPKIVerifySignature(const char * pkalgorithm,
                                                     const char * publickeyfile,
                                                     const char * passphrase,
@@ -491,7 +571,7 @@ CRYPTOLIB_API bool CRYPTOLIB_CALL clPKIVerifySignature(const char * pkalgorithm,
                                                     size32_t lenSigneddata,const void * signeddata)
 {
     verifyPKIAlgorithm(pkalgorithm);
-    Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, publickeyfile, nullptr, nullptr, nullptr, passphrase);
+    Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, publickeyfile, nullptr, nullptr, nullptr, passphrase, false, nullptr);
     if (pDSM)
     {
         StringBuffer sbSig(lenSignature, (const char *)signature);
@@ -500,7 +580,29 @@ CRYPTOLIB_API bool CRYPTOLIB_CALL clPKIVerifySignature(const char * pkalgorithm,
     }
     else
     {
-        throw MakeStringException(-1, "Unable to create Digital Signature Manager");
+        throw makeStringException(-1, "Unable to create Digital Signature Manager");
+    }
+}
+
+CRYPTOLIB_API bool CRYPTOLIB_CALL clPKIVerifySignatureLFN(ICodeContext * ctx,
+                                                    const char * pkalgorithm,
+                                                    const char * publickeyLFN,
+                                                    const char * passphrase,
+                                                    size32_t lenSignature,const void * signature,
+                                                    size32_t lenSigneddata,const void * signeddata)
+{
+    verifyPKIAlgorithm(pkalgorithm);
+    IUserDescriptor * udesc = ctx->queryUserDescriptor();
+    Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, publickeyLFN, nullptr, nullptr, nullptr, passphrase, true, udesc);
+    if (pDSM)
+    {
+        StringBuffer sbSig(lenSignature, (const char *)signature);
+        bool rc = pDSM->digiVerify(sbSig.str(), lenSigneddata, signeddata);
+        return rc;
+    }
+    else
+    {
+        throw makeStringException(-1, "Unable to create Digital Signature Manager");
     }
 }
 
@@ -511,7 +613,7 @@ CRYPTOLIB_API bool CRYPTOLIB_CALL clPKIVerifySignatureBuff(const char * pkalgori
                                                        size32_t lenSigneddata, const void * signeddata)
 {
     verifyPKIAlgorithm(pkalgorithm);
-    Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, nullptr, publicKeyBuff, nullptr, nullptr, passphrase);
+    Owned<IDigitalSignatureManager> pDSM = g_DSMCache.getInstance(pkalgorithm, nullptr, publicKeyBuff, nullptr, nullptr, passphrase, false, nullptr);
     if (pDSM)
     {
         StringBuffer sbSig(lenSignature, (const char *)signature);
@@ -520,7 +622,7 @@ CRYPTOLIB_API bool CRYPTOLIB_CALL clPKIVerifySignatureBuff(const char * pkalgori
     }
     else
     {
-        throw MakeStringException(-1, "Unable to create Digital Signature Manager");
+        throw makeStringException(-1, "Unable to create Digital Signature Manager");
     }
 }
 
@@ -541,7 +643,7 @@ public:
     CLoadedKey * getInstance(bool isPublic, const char * keyFS, const char * keyBuff, const char * passphrase)
     {
         if (isEmptyString(keyFS) && isEmptyString(keyBuff))
-            throw MakeStringException(-1, "Must specify a key filename or provide a key buffer");
+            throw makeStringExceptionV(-1, "Must specify a key filename or provide a key buffer");
         VStringBuffer searchKey("%s_%s_%s", isEmptyString(keyFS) ? "" : keyFS, isEmptyString(keyBuff) ? "" : keyBuff, isEmptyString(passphrase) ? "" : passphrase);
         KeyCache::iterator it = keyCache.find(searchKey.str());
         CLoadedKey * ret = nullptr;
@@ -597,7 +699,7 @@ private:
 
 public:
 
-    CLoadedKey * getInstance(bool isPublic, const char * keyFS, const char * keyBuff, const char * passphrase)
+    CLoadedKey * getInstance(bool isPublic, const char * keyFS, const char * keyBuff, const char * passphrase, bool isLFN, IUserDescriptor * user)
     {
         if (!m_loadedKey ||
             isPublic != m_isPublic ||
@@ -609,8 +711,16 @@ public:
 
             if (!isEmptyString(keyFS))
             {
-                //Create CLoadedKey from filespec
-                if (isPublic)
+                if (isLFN)
+                {
+                    StringBuffer sb;
+                    loadLFS(keyFS, user, sb);//read key file into StringBuffer
+                    if (isPublic)
+                        newKey = loadPublicKeyFromMemory(sb.str(), passphrase);
+                    else
+                        newKey = loadPrivateKeyFromMemory(sb.str(), passphrase);
+                }
+                else if (isPublic)
                     newKey = loadPublicKeyFromFile(keyFS, passphrase);
                 else
                     newKey = loadPrivateKeyFromFile(keyFS, passphrase);
@@ -649,15 +759,16 @@ static bool clearupKeyCache(bool isPooled)
     return false;
 }
 
-static CLoadedKey * getCachedKey(bool isPublic, const char * keyFS, const char * keyBuff, const char * passphrase)
+static CLoadedKey * getCachedKey(bool isPublic, const char * keyFS, const char * keyBuff, const char * passphrase, bool isLFN, IUserDescriptor * udesc)
 {
     if (!pKC)
     {
         pKC = new CKeyCache();
         addThreadTermFunc(clearupKeyCache);
     }
-    return pKC->getInstance(isPublic, keyFS, keyBuff, passphrase);
+    return pKC->getInstance(isPublic, keyFS, keyBuff, passphrase, isLFN, udesc);
 }
+
 //------------------------------------
 //Encryption helper
 //------------------------------------
@@ -693,6 +804,7 @@ static void doPKIDecrypt(size32_t & __lenResult,void * & __result,
 
 
 //encryption functions that take filespecs of key files
+
 CRYPTOLIB_API void CRYPTOLIB_CALL clPKIEncrypt(size32_t & __lenResult,void * & __result,
                                             const char * pkalgorithm,
                                             const char * publickeyfile,
@@ -700,7 +812,7 @@ CRYPTOLIB_API void CRYPTOLIB_CALL clPKIEncrypt(size32_t & __lenResult,void * & _
                                             size32_t lenInputdata,const void * inputdata)
 {
     verifyPKIAlgorithm(pkalgorithm);
-    Owned<CLoadedKey> publicKey = getCachedKey(true, publickeyfile, nullptr, passphrase);
+    Owned<CLoadedKey> publicKey = getCachedKey(true, publickeyfile, nullptr, passphrase, false, nullptr);
     doPKIEncrypt(__lenResult, __result, publicKey, lenInputdata, inputdata);
 }
 
@@ -712,7 +824,33 @@ CRYPTOLIB_API void CRYPTOLIB_CALL clPKIDecrypt(size32_t & __lenResult,void * & _
                                             size32_t lenEncrypteddata,const void * encrypteddata)
 {
     verifyPKIAlgorithm(pkalgorithm);
-    Owned<CLoadedKey> privateKey = getCachedKey(false, privatekeyfile, nullptr, passphrase);
+    Owned<CLoadedKey> privateKey = getCachedKey(false, privatekeyfile, nullptr, passphrase, false, nullptr);
+    doPKIDecrypt(__lenResult, __result, privateKey, lenEncrypteddata, encrypteddata);
+}
+
+CRYPTOLIB_API void CRYPTOLIB_CALL clPKIEncryptLFN(ICodeContext * ctx,
+                                            size32_t & __lenResult,void * & __result,
+                                            const char * pkalgorithm,
+                                            const char * publickeyLFN,
+                                            const char * passphrase,
+                                            size32_t lenInputdata,const void * inputdata)
+{
+    verifyPKIAlgorithm(pkalgorithm);
+    IUserDescriptor * udesc = ctx->queryUserDescriptor();
+    Owned<CLoadedKey> publicKey = getCachedKey(true, publickeyLFN, nullptr, passphrase, true, udesc);
+    doPKIEncrypt(__lenResult, __result, publicKey, lenInputdata, inputdata);
+}
+
+CRYPTOLIB_API void CRYPTOLIB_CALL clPKIDecryptLFN(ICodeContext * ctx,
+                                            size32_t & __lenResult,void * & __result,
+                                            const char * pkalgorithm,
+                                            const char * privatekeyLFN,
+                                            const char * passphrase,
+                                            size32_t lenEncrypteddata,const void * encrypteddata)
+{
+    verifyPKIAlgorithm(pkalgorithm);
+    IUserDescriptor * udesc = ctx->queryUserDescriptor();
+    Owned<CLoadedKey> privateKey = getCachedKey(false, privatekeyLFN, nullptr, passphrase, true, udesc);
     doPKIDecrypt(__lenResult, __result, privateKey, lenEncrypteddata, encrypteddata);
 }
 
@@ -725,7 +863,7 @@ CRYPTOLIB_API void CRYPTOLIB_CALL clPKIEncryptBuff(size32_t & __lenResult,void *
                                                 size32_t lenInputdata,const void * inputdata)
 {
     verifyPKIAlgorithm(pkalgorithm);
-    Owned<CLoadedKey> publicKey = getCachedKey(true, nullptr, publickeybuff, passphrase);
+    Owned<CLoadedKey> publicKey = getCachedKey(true, nullptr, publickeybuff, passphrase, false, nullptr);
     doPKIEncrypt(__lenResult, __result, publicKey, lenInputdata, inputdata);
 }
 
@@ -736,6 +874,6 @@ CRYPTOLIB_API void CRYPTOLIB_CALL clPKIDecryptBuff(size32_t & __lenResult,void *
                                                 size32_t lenEncrypteddata,const void * encrypteddata)
 {
     verifyPKIAlgorithm(pkalgorithm);
-    Owned<CLoadedKey> privateKey = getCachedKey(false, nullptr, privatekeybuff, passphrase);
+    Owned<CLoadedKey> privateKey = getCachedKey(false, nullptr, privatekeybuff, passphrase, false, nullptr);
     doPKIDecrypt(__lenResult, __result, privateKey, lenEncrypteddata, encrypteddata);
 }

+ 9 - 0
plugins/cryptolib/cryptolib.hpp

@@ -57,7 +57,9 @@ CRYPTOLIB_API void CRYPTOLIB_CALL clSymmetricEncrypt(size32_t & __lenResult,void
 CRYPTOLIB_API void CRYPTOLIB_CALL clSymmetricDecrypt(size32_t & __lenResult,void * & __result,const char * algorithm,const char * key,size32_t lenEncrypteddata,const void * encrypteddata);
 
 //Public Key encryption/decryption
+
 //CRYPTOLIB_API void CRYPTOLIB_CALL clInstalledPublicKeyAlgorithms(bool & __isAllResult, size32_t & __lenResult, void * & __result);
+//from file system
 CRYPTOLIB_API void CRYPTOLIB_CALL clSupportedPublicKeyAlgorithms(bool & __isAllResult, size32_t & __lenResult, void * & __result);
 CRYPTOLIB_API void CRYPTOLIB_CALL clPKIEncrypt(size32_t & __lenResult,void * & __result,const char * pkalgorithm,const char * publickeyfile,const char * passphrase,size32_t lenInputdata,const void * inputdata);
 CRYPTOLIB_API void CRYPTOLIB_CALL clPKIDecrypt(size32_t & __lenResult,void * & __result,const char * pkalgorithm,const char * privatekeyfile,const char * passphrase,size32_t lenEncrypteddata,const void * encrypteddata);
@@ -65,7 +67,14 @@ CRYPTOLIB_API void CRYPTOLIB_CALL clPKIDecrypt(size32_t & __lenResult,void * & _
 CRYPTOLIB_API void CRYPTOLIB_CALL clPKISign(size32_t & __lenResult,void * & __result,const char * pkalgorithm,const char * privatekeyfile,const char * passphrase,size32_t lenInputdata,const void * inputdata);
 CRYPTOLIB_API bool CRYPTOLIB_CALL clPKIVerifySignature(const char * pkalgorithm,const char * publickeyfile,const char * passphrase,size32_t lenSignature,const void * signature,size32_t lenSigneddata,const void * signeddata);
 
+//from LFN
+CRYPTOLIB_API void CRYPTOLIB_CALL clPKIEncryptLFN(ICodeContext * ctx, size32_t & __lenResult,void * & __result,const char * pkalgorithm,const char * publickeyLFN,const char * passphrase,size32_t lenInputdata,const void * inputdata);
+CRYPTOLIB_API void CRYPTOLIB_CALL clPKIDecryptLFN(ICodeContext * ctx, size32_t & __lenResult,void * & __result,const char * pkalgorithm,const char * privatekeyLFN,const char * passphrase,size32_t lenEncrypteddata,const void * encrypteddata);
+
+CRYPTOLIB_API void CRYPTOLIB_CALL clPKISignLFN(ICodeContext * ctx, size32_t & __lenResult,void * & __result,const char * pkalgorithm,const char * privatekeyLFN,const char * passphrase,size32_t lenInputdata,const void * inputdata);
+CRYPTOLIB_API bool CRYPTOLIB_CALL clPKIVerifySignatureLFN(ICodeContext * ctx, const char * pkalgorithm,const char * publickeyLFN,const char * passphrase,size32_t lenSignature,const void * signature,size32_t lenSigneddata,const void * signeddata);
 
+//from buffer
 CRYPTOLIB_API void CRYPTOLIB_CALL clPKIEncryptBuff(size32_t & __lenResult,void * & __result,const char * pkalgorithm,const char * publickeybuff,const char * passphrase,size32_t lenInputdata,const void * inputdata);
 CRYPTOLIB_API void CRYPTOLIB_CALL clPKIDecryptBuff(size32_t & __lenResult,void * & __result,const char * pkalgorithm,const char * privatekeybuff,const char * passphrase,size32_t lenEncrypteddata,const void * encrypteddata);
 

+ 10 - 4
plugins/proxies/lib_cryptolib.ecllib

@@ -27,8 +27,8 @@ export CryptoLib := SERVICE : plugin('cryptolib')
   //Symmetric Encryption
       
   SET OF STRING SupportedSymmetricCipherAlgorithms() : c, pure, fold, entrypoint='clSupportedSymmetricCipherAlgorithms';
-  DATA  SymmetricEncrypt(CONST VARSTRING algorithm, CONST VARSTRING passphrase, CONST DATA inputData) : c, pure, entrypoint='clSymmetricEncrypt';
-  DATA SymmetricDecrypt( CONST VARSTRING algorithm, CONST VARSTRING passphrase, CONST DATA encryptedData) : c, pure, entrypoint='clSymmetricDecrypt';
+  DATA SymmetricEncrypt(CONST VARSTRING algorithm, CONST VARSTRING passphrase, CONST DATA inputData) : c, pure, entrypoint='clSymmetricEncrypt';
+  DATA SymmetricDecrypt(CONST VARSTRING algorithm, CONST VARSTRING passphrase, CONST DATA encryptedData) : c, pure, entrypoint='clSymmetricDecrypt';
 
   //Asymmetric Public Key Encryption
   
@@ -39,8 +39,14 @@ export CryptoLib := SERVICE : plugin('cryptolib')
   DATA    Decrypt(CONST VARSTRING pkAlgorithm, CONST VARSTRING privateKeyFile, CONST VARSTRING passphrase, CONST DATA encryptedData) : c, pure, entrypoint='clPKIDecrypt';
   DATA    Sign(CONST VARSTRING pkAlgorithm, CONST VARSTRING privateKeyFile, CONST VARSTRING passphrase, CONST DATA inputData) : c, pure, entrypoint='clPKISign';
   BOOLEAN VerifySignature(CONST VARSTRING pkAlgorithm, CONST VARSTRING publicKeyFile, CONST VARSTRING passphrase, CONST DATA signature, CONST DATA signedData) : c, pure, entrypoint='clPKIVerifySignature';
-  
-  //Accepts key data as memory buffer
+
+  //Accepts key data as Logical File Name
+  DATA    EncryptLFN(CONST VARSTRING pkAlgorithm, CONST VARSTRING publickeyLFN, CONST VARSTRING passphrase, CONST DATA inputData) : c, pure, context, entrypoint='clPKIEncryptLFN';
+  DATA    DecryptLFN(CONST VARSTRING pkAlgorithm, CONST VARSTRING privatekeyLFN, CONST VARSTRING passphrase, CONST DATA encryptedData) : c, pure, context, entrypoint='clPKIDecryptLFN';
+  DATA    SignLFN(CONST VARSTRING pkAlgorithm, CONST VARSTRING privatekeyLFN, CONST VARSTRING passphrase, CONST DATA inputData) : c, pure, context, entrypoint='clPKISignLFN';
+  BOOLEAN VerifySignatureLFN(CONST VARSTRING pkAlgorithm, CONST VARSTRING publickeyLFN, CONST VARSTRING passphrase, CONST DATA signature, CONST DATA signedData) : c, pure, context, entrypoint='clPKIVerifySignatureLFN';
+
+   //Accepts key data as memory buffer
   DATA    EncryptBuff(CONST VARSTRING pkAlgorithm, CONST VARSTRING publicKeyBuff, CONST VARSTRING passphrase, CONST DATA inputData) : c, pure, entrypoint='clPKIEncryptBuff';
   DATA    DecryptBuff(CONST VARSTRING pkAlgorithm, CONST VARSTRING privateKeyBuff, CONST VARSTRING passphrase, CONST DATA encryptedData) : c, pure, entrypoint='clPKIDecryptBuff';
   DATA    SignBuff(CONST VARSTRING pkAlgorithm, CONST VARSTRING privateKeyBuff, CONST VARSTRING passphrase, CONST DATA inputData) : c, pure, entrypoint='clPKISignBuff';

+ 121 - 0
testing/regress/ecl/cryptoplugin_pke_lfn.ecl

@@ -0,0 +1,121 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2020 HPCC Systems®.
+
+    Licensed under the Apache License, Version 2.0 (the 'License');
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an 'AS IS' BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+import Std;
+
+output('PKIEncryption Tests enumerating supported public key algorithms');
+
+output(Std.Crypto.SupportedPublicKeyAlgorithms());
+
+
+/*###############################
+    Create key files for testing
+#################################*/
+PKey :=  RECORD
+  STRING  Key;
+END;
+
+dPubKey :=  DATASET([{
+'-----BEGIN PUBLIC KEY-----' + '\n' +
+'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr64RncTp5pV0KMnWRAof' + '\n' +
+'od+3AUS/IDngT39j3Iovv9aI2N8g4W5ipqhKftRESmzQ6I/TiUQcmi42soUXmCeE' + '\n' +
+'BHqlMDydw9aHOQG17CB30GYsw3Lf8iZo7RC7ocQE3OcRzH0eBkOryW6X3efWnMoy' + '\n' +
+'hIR9MexCldF+3WM/X0IX0ApSs7kuVPVG4Yj202+1FVO/XNwjMukJG5ASuxpYAQvv' + '\n' +
+'/oKj6q7kInEIvhLiGfcm3bpTzWQ66zVz3z/huLbEXEy5oj2fQaC5E3s5mdpk/CW3' + '\n' +
+'J6Tk4NY3NySWzE/2/ZOWxZdR79XC+goNL6v/5gPI8B/a3Z8OeM2PfSZwPMnVuvU0' + '\n' +
+'bwIDAQAB' + '\n' +
+'-----END PUBLIC KEY-----' + '\n'
+}],PKey);
+
+OUTPUT(dPubKey,,'~regress::certificates::pubkey.pem', CSV(SEPARATOR(''), TERMINATOR('')), OVERWRITE);
+
+
+
+PRKey :=  RECORD
+  STRING  Key;
+END;
+
+dPrivKey :=  DATASET([{
+'-----BEGIN RSA PRIVATE KEY-----' + '\n' +
+'MIIEowIBAAKCAQEAr64RncTp5pV0KMnWRAofod+3AUS/IDngT39j3Iovv9aI2N8g' + '\n' +
+'4W5ipqhKftRESmzQ6I/TiUQcmi42soUXmCeEBHqlMDydw9aHOQG17CB30GYsw3Lf' + '\n' +
+'8iZo7RC7ocQE3OcRzH0eBkOryW6X3efWnMoyhIR9MexCldF+3WM/X0IX0ApSs7ku' + '\n' +
+'VPVG4Yj202+1FVO/XNwjMukJG5ASuxpYAQvv/oKj6q7kInEIvhLiGfcm3bpTzWQ6' + '\n' +
+'6zVz3z/huLbEXEy5oj2fQaC5E3s5mdpk/CW3J6Tk4NY3NySWzE/2/ZOWxZdR79XC' + '\n' +
+'+goNL6v/5gPI8B/a3Z8OeM2PfSZwPMnVuvU0bwIDAQABAoIBAQCnGAtNYkOOu8wW' + '\n' +
+'F5Oid3aKwnwPytF211WQh3v2AcFU17qle+SMRi+ykBL6+u5RU5qH+HSc9Jm31AjW' + '\n' +
+'V1yPrdYVZInFjYIJCPzorcXY5zDOmMAuzg5PBVV7VhUA0a5GZck6FC8AilDUcEom' + '\n' +
+'GCK6Ul8mR9XELBFQ6keeTo2yDu0TQ4oBXrPBMN61uMHCxh2tDb2yvl8Zz+EllADG' + '\n' +
+'70pztRWNOrCzrC+ARlmmDfYOUgVFtZin53jq6O6ullPLzhkm3/+QFRGYWsFgQB6J' + '\n' +
+'Z9HJtW5YB47RT5RbLHKXeMc6IJW+d+5HrzgTdK79P7wAZk8JCIDyHe2AaNAUzc/G' + '\n' +
+'sB0cNeURAoGBAOKtaVFa6z2F4Q+koMBXCt4m7dCJnaC+qthF249uEOIBeF3ds9Fq' + '\n' +
+'f0jhhvuV0OcN8lYbR/ZlYRJDUs6mHh/2BYSkdeaLKojXTxKR2bA4xQk5dtJCdoPf' + '\n' +
+'0c15AlTgOYk2oNXP/azDICJYT/cdvIdUL9P4IoZthu1FjwG266GacEnNAoGBAMZn' + '\n' +
+'1wRUXS1dbqemoc+g48wj5r3/qsIG8PsZ2Y8W+oYW7diNA5o6acc8YPEWE2RbJDbX' + '\n' +
+'YEADBnRSdzzOdo0JEj4VbNZEtx6nQhBOOrtYKnnqHVI/XOz3VVu6kedUKdBR87KC' + '\n' +
+'eCzO1VcEeZtsTHuLO4t7NmdHGqNxTV+jLvzBoQsrAoGAI+fOD+nz6znirYSpRe5D' + '\n' +
+'tW67KtYxlr28+CcQoUaQ/Au5kjzE9/4DjXrT09QmVAMciNEnc/sZBjiNzFf525wv' + '\n' +
+'wZP/bPZMVYKtbsaVkdlcNJranHGUrkzswbxSRzmBQ5/YmCWrDAuYcnhEqmMWcuU9' + '\n' +
+'8jiS13JP9hOXlHDyIBYDhV0CgYBV6TznuQgnzp9NpQ/H8ijxilItz3lHTu4mLMlR' + '\n' +
+'9mdAjMkszdLTg5uuE+z+N8rp17VUseoRjb3LvLG4+MXIyDbH/0sDdPm+IjqvCNDR' + '\n' +
+'spmh9MgBh0JbsbWaZK0s9/qrI/FcSLZ04JLsfRmTPU/Y5y8/dHjYO6fDQhp44RZF' + '\n' +
+'iCqNxQKBgHf7KZIOKgV4YNyphk1UYWHNz8YY5o7WtaQ51Q+kIbU8PRd9rqJLZyk2' + '\n' +
+'tKf8e6z+wtKjxi8GKQzE/IdkQqiFmB1yEjjRHQ81WS+K5NnjN1t0IEscJqOAwv9s' + '\n' +
+'iIhG5ueb6xoj/N0LuXa8loUT5aChKWxRHEYdegqU48f+qxUcJj9R' + '\n' +
+'-----END RSA PRIVATE KEY-----' + '\n'
+}],PRKey);
+
+OUTPUT(dPrivKey,,'~regress::certificates::privkey.pem', CSV(SEPARATOR(''), TERMINATOR('')), OVERWRITE);
+
+
+/*###############################
+    Begin tests
+#################################*/
+
+
+encModuleLFN := Std.Crypto.PublicKeyEncryptionFromLFN('RSA', '~regress::certificates::pubkey.pem', '~regress::certificates::privkey.pem', '');
+
+//Digital Signature tests
+output('PKIEncryption Tests for PKI Digital Signatures');
+
+DATA sig1 := encModuleLFN.Sign((DATA)'The quick brown fox jumps over the lazy dog');
+output(encModuleLFN.VerifySignature(sig1, (DATA)'This should fail'));
+output(encModuleLFN.VerifySignature(sig1, (DATA)'The quick brown fox jumps over the lazy dog'));//this should pass
+
+DATA sig2 := encModuleLFN.Sign((DATA)'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTTUVWXYZ`~!@#$%^&*()_-+=|}]{[":;?/>.<,');
+DATA sig3 := encModuleLFN.Sign((DATA)'The most beautiful thing in the world is, of course, the world itself!');
+
+output(encModuleLFN.VerifySignature(sig1, (DATA)'The quick brown fox jumps over the lazy dog'));//this should pass
+output(encModuleLFN.VerifySignature(sig2, (DATA)'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTTUVWXYZ`~!@#$%^&*()_-+=|}]{[":;?/>.<,'));//this should pass
+output(encModuleLFN.VerifySignature(sig3, (DATA)'The most beautiful thing in the world is, of course, the world itself!'));//this should pass
+
+
+
+//Encrypt/Decrypt tests
+output('PKIEncryption Tests for PKI Encrypt/Decrypt');
+
+DATA enc1 := encModuleLFN.Encrypt((DATA)'The quick brown fox jumps over the lazy dog');
+output( (STRING)encModuleLFN.Decrypt(enc1) );
+
+DATA enc2 := encModuleLFN.Encrypt((DATA)'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTTUVWXYZ`~!@#$%^&*()_-+=|}]{[":;?/>.<,');
+DATA enc3 := encModuleLFN.Encrypt((DATA)'The most beautiful thing in the world is, of course, the world itself!');//this should use the cached key file
+output( (STRING)encModuleLFN.Decrypt(enc2) );//this should use the cached key file
+output( (STRING)encModuleLFN.Decrypt(enc3) );//this should use the cached key file
+
+output( (STRING)encModuleLFN.Decrypt(enc3) );//this should use the cached key file
+output( (STRING)encModuleLFN.Decrypt(enc2) );//this should use the cached key file
+output( (STRING)encModuleLFN.Decrypt(enc1) );//this should use the cached key file
+

+ 49 - 0
testing/regress/ecl/key/cryptoplugin_pke_lfn.xml

@@ -0,0 +1,49 @@
+<Dataset name='Result 1'>
+ <Row><Result_1>PKIEncryption Tests enumerating supported public key algorithms</Result_1></Row>
+</Dataset>
+<Dataset name='Result 2'>
+ <Row><Result_2><Item>RSA</Item></Result_2></Row>
+</Dataset>
+<Dataset name='Result 3'>
+</Dataset>
+<Dataset name='Result 4'>
+</Dataset>
+<Dataset name='Result 5'>
+ <Row><Result_5>PKIEncryption Tests for PKI Digital Signatures</Result_5></Row>
+</Dataset>
+<Dataset name='Result 6'>
+ <Row><Result_6>false</Result_6></Row>
+</Dataset>
+<Dataset name='Result 7'>
+ <Row><Result_7>true</Result_7></Row>
+</Dataset>
+<Dataset name='Result 8'>
+ <Row><Result_8>true</Result_8></Row>
+</Dataset>
+<Dataset name='Result 9'>
+ <Row><Result_9>true</Result_9></Row>
+</Dataset>
+<Dataset name='Result 10'>
+ <Row><Result_10>true</Result_10></Row>
+</Dataset>
+<Dataset name='Result 11'>
+ <Row><Result_11>PKIEncryption Tests for PKI Encrypt/Decrypt</Result_11></Row>
+</Dataset>
+<Dataset name='Result 12'>
+ <Row><Result_12>The quick brown fox jumps over the lazy dog</Result_12></Row>
+</Dataset>
+<Dataset name='Result 13'>
+ <Row><Result_13>0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTTUVWXYZ`~!@#$%^&amp;*()_-+=|}]{[&quot;:;?/&gt;.&lt;,</Result_13></Row>
+</Dataset>
+<Dataset name='Result 14'>
+ <Row><Result_14>The most beautiful thing in the world is, of course, the world itself!</Result_14></Row>
+</Dataset>
+<Dataset name='Result 15'>
+ <Row><Result_15>The most beautiful thing in the world is, of course, the world itself!</Result_15></Row>
+</Dataset>
+<Dataset name='Result 16'>
+ <Row><Result_16>0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTTUVWXYZ`~!@#$%^&amp;*()_-+=|}]{[&quot;:;?/&gt;.&lt;,</Result_16></Row>
+</Dataset>
+<Dataset name='Result 17'>
+ <Row><Result_17>The quick brown fox jumps over the lazy dog</Result_17></Row>
+</Dataset>