From 6e21c06bed91ffa703a264238eb68efde4a64860 Mon Sep 17 00:00:00 2001 From: Jack Del Vecchio Date: Thu, 5 Dec 2024 10:20:32 -0500 Subject: [PATCH 1/8] HPCC-33018 Expose chosen OpenSSL cryptography capabilities via a plugin Signed-off-by: Jack Del Vecchio --- ecllibrary/std/CMakeLists.txt | 1 + ecllibrary/std/OpenSSL.ecl | 329 ++++++++ ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl | 223 +++++ plugins/CMakeLists.txt | 1 + plugins/openssl/CMakeLists.txt | 62 ++ plugins/openssl/openssl.cpp | 915 +++++++++++++++++++++ plugins/openssl/openssl.hpp | 62 ++ plugins/proxies/CMakeLists.txt | 1 + plugins/proxies/lib_openssl.ecllib | 39 + testing/regress/ecl/teststdlibrary.ecl | 1 + 10 files changed, 1634 insertions(+) create mode 100644 ecllibrary/std/OpenSSL.ecl create mode 100644 ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl create mode 100644 plugins/openssl/CMakeLists.txt create mode 100644 plugins/openssl/openssl.cpp create mode 100644 plugins/openssl/openssl.hpp create mode 100644 plugins/proxies/lib_openssl.ecllib diff --git a/ecllibrary/std/CMakeLists.txt b/ecllibrary/std/CMakeLists.txt index 2293005ee76..7c5959d5962 100644 --- a/ecllibrary/std/CMakeLists.txt +++ b/ecllibrary/std/CMakeLists.txt @@ -28,6 +28,7 @@ set( Math.ecl Metaphone3.ecl Metaphone.ecl + OpenSSL.ecl Str.ecl Uni.ecl ) diff --git a/ecllibrary/std/OpenSSL.ecl b/ecllibrary/std/OpenSSL.ecl new file mode 100644 index 00000000000..8c351dab67e --- /dev/null +++ b/ecllibrary/std/OpenSSL.ecl @@ -0,0 +1,329 @@ +/*############################################################################## + + HPCC SYSTEMS software Copyright (C) 2025 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. +############################################################################## */ + +EXPORT OpenSSL := MODULE + +IMPORT lib_openssl; + +EXPORT Digest := MODULE + + /** + * Returns a list of the names of the available hash digest algorithms. + * + * @return A dataset containing the hash algorithm names. + * + * @see Hash() + */ + EXPORT DATASET({STRING name}) AvailableAlgorithms() := lib_openssl.OpenSSL.digestAvailableAlgorithms(); + + /** + * Compute the hash of given data according to the named + * hash algorithm. + * + * @param indata The data to hash; REQUIRED + * @param hash_name The name of the hash algorithm to use; + * must be one of the values returned from + * the AvailableAlgorithms() function in + * this module; cannot be empty; REQUIRED + * + * @return A DATA value representing the hash value of indata. + * + * @see AvailableAlgorithms() + */ + EXPORT DATA Hash(DATA _indata, VARSTRING _hash_name) := lib_openssl.OpenSSL.digesthash(_indata, _hash_name); + +END; // Digest + +EXPORT Ciphers := MODULE + + /** + * Returns a list of the names of the available symmetric + * cipher algorithms. + * + * @return A dataset containing the symmetric cipher algorithm names. + * + * @see IVSize() + * SaltSize() + * Encrypt() + * Decrypt() + */ + EXPORT DATASET({STRING name}) AvailableAlgorithms() := lib_openssl.OpenSSL.cipherAvailableAlgorithms(); + + /** + * Return the size of the IV used for the given symmetric + * cipher algorithm. + * + * This is primarily an introspection/discovery function. Once + * you determine the proper value for the algorithm you want to + * use, you should hardcode it. + * + * @param algorithm The name of the symmetric cipher to examine; + * must be one of the values returned from + * the AvailableAlgorithms() function in + * this module; cannot be empty; REQUIRED + * + * @return The size of the IV used by the given algorithm, in bytes. + * + * @see AvailableAlgorithms() + */ + EXPORT UNSIGNED2 IVSize(VARSTRING algorithm) := lib_openssl.OpenSSL.cipherIVSize(algorithm); + + /** + * Return the size of the salt used for the given symmetric + * cipher algorithm. + * + * This is primarily an introspection/discovery function. Once + * you determine the proper value for the algorithm you want to + * use, you should hardcode it. + * + * @param algorithm The name of the symmetric cipher to examine; + * must be one of the values returned from + * the AvailableAlgorithms() function in + * this module; cannot be empty; REQUIRED + * + * @return The size of the salt used by the given algorithm, in bytes. + * + * @see AvailableAlgorithms() + */ + EXPORT UNSIGNED2 SaltSize(VARSTRING algorithm) := 8; + + /** + * Encrypt some plaintext with the given symmetric cipher and a + * passphrase. Optionally, you can specify static IV and salt values. + * The encrypted ciphertext is returned as a DATA value. + * + * If IV or salt values are explicitly provided during encryption then + * those same values must be provided during decryption. + * + * @param plaintext The data to encrypt; REQUIRED + * @param algorithm The name of the symmetric cipher to use; + * must be one of the values returned from + * the AvailableAlgorithms() function in + * this module; cannot be empty; REQUIRED + * @param iv The IV to use during encryption; if not set + * then a random value will be generated; if set, + * it must be of the expected size for the given + * algorithm; OPTIONAL, defaults to creating a + * random value + * @param salt TCURRENT_OPENSSL_VERSIONencryption; if not set + * then a random value will be generated; if set, + * it must be of the expected size for the given + * algorithm; OPTIONAL, defaults to creating a + * random value + * + * @return The ciphertext as a DATA type. + * + * @see AvailableAlgorithms() + * IVSize() + * SaltSize() + * Decrypt() + */ + EXPORT DATA Encrypt(DATA plaintext, VARSTRING algorithm, DATA passphrase, DATA iv = (DATA)'', DATA salt = (DATA)'') := lib_openssl.OpenSSL.cipherEncrypt(plaintext, algorithm, passphrase, iv, salt); + + + /** + * Decrypt some ciphertext with the given symmetric cipher and a + * passphrase. Optionally, you can specify static IV and salt values. + * The decrypted plaintext is returned as a DATA value. + * + * @param ciphertext The data to decrypt; REQUIRED + * @param algorithm The name of the symmetric cipher to use; + * must be one of the values returned from + * the AvailableAlgorithms() function in + * this module; cannot be empty; REQUIRED + * @param iv The IV to use during decryption; if not set + * then a random value will be used; if set, + * it must be of the expected size for the given + * algorithm; OPTIONAL, defaults to creating a + * random value + * @param salt The salt to use during decryption; if not set + * then a random value will be used; if set, + * it must be of the expected size for the given + * algorithm; OPTIONAL, defaults to creating a + * random value + * + * @return The plaintext as a DATA type. + * + * @see AvailableAlgorithms() + * IVSize() + * SaltSize() + * Encrypt() + */ + EXPORT DATA Decrypt(DATA ciphertext, VARSTRING algorithm, DATA passphrase, DATA iv = (DATA)'', DATA salt = (DATA)'') := lib_openssl.OpenSSL.cipherDecrypt(ciphertext, algorithm, passphrase, iv, salt); +END; // Ciphers + +EXPORT RSA := MODULE + + /** + * Perform a hybrid encryption using one or more RSA public keys. + * + * Because asymmetric encryption is computationally expensive, large + * payloads are actually encrypted with a symmetric cipher and a + * randomly-generated passphrase. The passphrase, which is much shorter, + * is then encrypted with the public key. The whole package is then bundled + * together into an "envelope" and "sealed". + * + * The function uses RSA public keys and they must be in PEM format. To + * generate such keys on the command line: + * + * ssh-keygen -b 4096 -t rsa -m pem -f sample2 + * ssh-keygen -f sample2 -e -m pem > sample2.pub + * + * The resulting files, sample2 and sample2.pub, are the private and public + * keys, respectively. Their contents may be passed to this function. + * + * @param plaintext The data to encrypt; REQUIRED + * @param pem_public_keys One or more RSA public keys, in PEM format; + * note that this is a SET -- you can pass + * more than one public key here, and the resulting + * ciphertext can be decrypted by any one of the + * corresponding private keys; REQUIRED + * @param symmetric_algorithm The name of the symmetric algorithm to use + * to encrypt the payload; must be one of those + * returned by Ciphers.AvailableAlgorithms(); + * OPTIONAL, defaults to aes-256-cbc + * + * @return The encrypted ciphertext. + * + * @see Unseal() + * Ciphers.AvailableAlgorithms() + */ + EXPORT DATA Seal(DATA plaintext, SET OF STRING pem_public_keys, VARSTRING symmetric_algorithm = 'aes-256-cbc') := lib_openssl.OpenSSL.rsaSeal(plaintext, pem_public_keys, symmetric_algorithm); + + /** + * Decrypts ciphertext previously generated by the Seal() function. + * + * Because asymmetric encryption is computationally expensive, large + * payloads are actually encrypted with a symmetric cipher and a + * randomly-generated passphrase. The passphrase, which is much shorter, + * is then encrypted with the public key. The whole package is then bundled + * together into an "envelope" and "sealed". Given the private key that + * corresponds to one of the public keys used to create the ciphertext, + * this function unpacks everything and decrypts the payload. + * + * The function uses RSA public keys and they must be in PEM format. To + * generate such keys on the command line: + * + * ssh-keygen -b 4096 -t rsa -m pem -f sample2 + * ssh-keygen -f sample2 -e -m pem > sample2.pub + * + * The resulting files, sample2 and sample2.pub, are the private and public + * keys, respectively. Their contents may be passed to this function. + * + * @param ciphertext The data to decrypt; REQUIRED + * @param pem_private_key An RSA public key in PEM format; REQUIRED + * @param symmetric_algorithm The name of the symmetric algorithm to use + * to decrypt the payload; must be one of those + * returned by Ciphers.AvailableAlgorithms() and + * it must match the algorithm used to create the + * ciphertext; OPTIONAL, defaults to aes-256-cbc + * + * @return The decrypted plaintext. + * + * @see Seal() + * Ciphers.AvailableAlgorithms() + */ + EXPORT DATA Unseal(DATA ciphertext, STRING pem_private_key, VARSTRING symmetric_algorithm = 'aes-256-cbc') := lib_openssl.OpenSSL.rsaUnseal(ciphertext, pem_private_key, symmetric_algorithm); + + /** + * This function performs asymmetric encryption. It should be used to + * encrypt only small plaintext (e.g. less than 100 bytes) because it is + * computationally expensive. + * + * @param plaintext The data to encrypt; REQUIRED + * @param pem_public_key The public key to use for encryption, in + * PEM format; REQUIRED + * + * @return The encrypted ciphertext. + * + * @see Decrypt() + */ + EXPORT DATA Encrypt(DATA plaintext, STRING pem_public_key) := lib_openssl.OpenSSL.rsaEncrypt(plaintext, pem_public_key); + + /** + * This function performs asymmetric decryption. It should be used to + * decrypt only small plaintext (e.g. less than 100 bytes) because it is + * computationally expensive. + * + * @param ciphertext The data to decrypt; REUIRED + * @param pem_private_key The private key to use for decryption, in + * PEM format; REQUIRED + * + * @return The decrypted plaintext. + * + * @see Encrypt() + */ + EXPORT DATA Decrypt(DATA ciphertext, STRING pem_private_key) := lib_openssl.OpenSSL.rsaDecrypt(ciphertext, pem_private_key); + + /** + * Create a digital signature of the given data, using the + * specified private key, passphrase and algorithm. + * + * The function uses an RSA private key and it must be in PEM format. To + * generate such keys on the command line: + * + * ssh-keygen -b 4096 -t rsa -m pem -f sample2 + * ssh-keygen -f sample2 -e -m pem > sample2.pub + * + * The resulting files, sample2 and sample2.pub, are the private and public + * keys, respectively. Their contents may be passed to this function + * + * @param plaintext Contents to sign; REQUIRED + * @param passphrase Passphrase to use for private key; REQUIRED + * @param pem_private_key Private key to use for signing; REQUIRED + * @param hash_name The name of the hash algorithm to use; + * must be one of the values returned from + * the AvailableAlgorithms() function in + * the Digest module; cannot be empty; REQUIRED + * @return Computed Digital signature + * + * @see Digest.AvailableAlgorithms() + * VerifySignature() + */ + EXPORT DATA Sign(DATA plaintext, DATA passphrase, STRING pem_private_key, VARSTRING hash_name) := lib_openssl.OpenSSL.rsaSign(plaintext, passphrase, pem_private_key, hash_name); + + /** + * Verify the given digital signature of the given data, using + * the specified public key, passphrase and algorithm. + * + * The function uses an RSA public key and it must be in PEM format. To + * generate such keys on the command line: + * + * ssh-keygen -b 4096 -t rsa -m pem -f sample2 + * ssh-keygen -f sample2 -e -m pem > sample2.pub + * + * The resulting files, sample2 and sample2.pub, are the private and public + * keys, respectively. Their contents may be passed to this function + * + * @param signature Signature to verify; REQUIRED + * @param signedData Data used to create signature; REQUIRED + * @param passphrase Passphrase to use for private key; REQUIRED + * @param pem_public_key Public key to use for verification; REQUIRED + * @param hash_name The name of the hash algorithm to use; + * must be one of the values returned from + * the AvailableAlgorithms() function in + * the Digest module; cannot be empty; REQUIRED + * @return Boolean TRUE/FALSE + * + * @see Digest.AvailableAlgorithms() + * Sign() + */ + EXPORT BOOLEAN VerifySignature(DATA signature, DATA signedData, DATA passphrase, STRING pem_public_key, VARSTRING hash_name) := lib_openssl.OpenSSL.rsaVerifySignature(signature, signedData, passphrase, pem_public_key, hash_name); + +END; // RSA + +END; diff --git a/ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl b/ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl new file mode 100644 index 00000000000..82d32147318 --- /dev/null +++ b/ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl @@ -0,0 +1,223 @@ +/*############################################################################## + + HPCC SYSTEMS software Copyright (C) 2025 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; + +EXPORT TestOpenSSL := MODULE + + EXPORT STRING PLAINTEXT := 'Colorless green ideas sleep furiously.'; + EXPORT STRING CIPHERS_CIPHER := 'aes-256-cbc'; + EXPORT STRING PASSPHRASE := 'mypassphrase'; + + EXPORT STRING RSA_PUBLIC_1 := + '-----BEGIN RSA PUBLIC KEY-----' + '\n' + + 'MIICCgKCAgEAuLYYTmPMzp13999s7bUAaJZVON+9k/2PDBF5AfHtQ40FmxwRdG3d' + '\n' + + 'CeUcbhb8Nuw3YizS7WgdZBtjyi7hZ146aHBDXVXhJlInR3y44hAnYB/sOccxQYWQ' + '\n' + + '6xOZ6VpZ7MnJl4j2OFmoc62QAwQuqizXhfFOtd2KfTubKsMPR1tWrWRC6zlDBkYV' + '\n' + + 'D677MqQyhAuZvCjYO5E5dPmoVVxZaBxjsTjElEqtjkRdROG1D0PJY+8XkWP/76ns' + '\n' + + 'ieNsTb9R0umN4x4+lzsHSB4tcGICx+S7cW+FmJzyGlf6J4YWEq4VqoIQ7MI8O8Hj' + '\n' + + 'fuR3jdZwubZQrFzKtvWv3i3Dm16+JxmtK6qjhJhGzlXchBk+j8eOUaWOV0sBMLPo' + '\n' + + 'sVEapY+SmISxj0sn8yLSfbUs5ivHaEMNaZq6BM1Db5y7MEOANv2FplvT9oW7UECg' + '\n' + + '7D7PUZnrBZf16FiNxwXnxK/Sn049y/2nFnHPxACWZVVtXN9N64GZPEP1/vYyYFCN' + '\n' + + 'yt0mdYjJLtf6z87YYLM4kHMNqnbPJKOQahvRC4fW4/QfQYFjLwHFNppUo9D/bx2t' + '\n' + + 'sCmDEWc7cGQE081tQep34rpTel0wkePhxajmSlRNyVtv3ZXph1Hl1XoOj17QLdyw' + '\n' + + 'WjCAqcMKrVHnOkyKo2lTNhY3bsu6PfEe4dTTia3/WlPJe0nGa0SUuvkCAwEAAQ==' + '\n' + + '-----END RSA PUBLIC KEY-----'; + EXPORT STRING RSA_PRIVATE_1 := + '-----BEGIN RSA PRIVATE KEY-----' + '\n' + + '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' + '\n' + + '-----END RSA PRIVATE KEY-----'; + + EXPORT STRING RSA_PUBLIC_2 := + '-----BEGIN RSA PUBLIC KEY-----' + '\n' + + 'MIICCgKCAgEAtHYNEH8DswZUtx3Xk90cPCLtf3vl7awjZvI4V/yJkOb5U/sQRgsw' + '\n' + + '60F84i8Okg3yBxGIEDiZ/cWKBYfQGsycbm+zljIHh0tt8S7hH9iwFiZB41urPZ4Q' + '\n' + + 'zSs84h05SZA9nCVPQOpFYi0I8n6QrGf9eokJf/jO/dZcvsIDYqtiLfTYWMLKibrY' + '\n' + + 'HgP9lIKxJieSmbrX4spYBEf+B9cSQqHBwThAP1mvkIzD2eGuYlQV6hXZb2dSXn8l' + '\n' + + 'Lakgq06mvkCxYglv6GEHKPrEd6KCZKgBLKZsEabvd5+eWXL4VcaAdXjQgRIa5aV2' + '\n' + + 'AJCk5V1ClMraJuw1aw62+2GTi7bTum4t+GJQdTfDSYreTBIZLUzHwlRnlbMrsthd' + '\n' + + 'aVWct3KId2BT/ntqmalBTcu+nK7H3XOEQGrFdQo2tQ459guchYqxk8QFZCVTkNzw' + '\n' + + 'Ky7SyJV9dqDDUhQQSTvwv42CbwpwbqSynE682h1IQThgk1LuDX/IIQRupIgbyJKo' + '\n' + + 'WrFYoNalhyoeXCgQT7gH2y5YdeoGf3oN7dn4HUDFdW2FOYPzpsSMLVr1MUhxelJc' + '\n' + + 'Ru1RUsJDwfkXBUOZM7ChgwGfQYWGjFcEOPK6AbUlSTER2vP3t5R/QPzN6uzih10y' + '\n' + + 'LFFeUxMuvLnmgpKSU9bVsXbN2D4hmInZW8vDRKugNeTrtaV6KkUus5sCAwEAAQ==' + '\n' + + '-----END RSA PUBLIC KEY-----'; + EXPORT STRING RSA_PRIVATE_2 := + '-----BEGIN RSA PRIVATE KEY-----' + '\n' + + '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' + '\n' + + '-----END RSA PRIVATE KEY-----'; + + EXPORT UNSIGNED8 staticSalt := 123456789; + EXPORT DATA staticIV := (DATA)'0123456789012345'; + + EXPORT hash_sha256 := Std.OpenSSL.Digest.Hash((DATA)PLAINTEXT, 'sha256'); + EXPORT hash_sha512 := Std.OpenSSL.Digest.Hash((DATA)PLAINTEXT, 'sha512'); + EXPORT encrypt_my_iv_my_salt := Std.OpenSSL.Ciphers.Encrypt((DATA)PLAINTEXT, CIPHERS_CIPHER, (DATA)PASSPHRASE, salt := (>DATA<)staticSalt, iv := staticIV); + EXPORT encrypt_default_iv_my_salt := Std.OpenSSL.Ciphers.Encrypt((DATA)PLAINTEXT, CIPHERS_CIPHER, (DATA)PASSPHRASE, salt := (>DATA<)staticSalt); + EXPORT encrypt_my_iv_default_salt := Std.OpenSSL.Ciphers.Encrypt((DATA)PLAINTEXT, CIPHERS_CIPHER, (DATA)PASSPHRASE, iv := staticIV); + EXPORT encrypt_default_iv_default_salt := Std.OpenSSL.Ciphers.Encrypt((DATA)PLAINTEXT, CIPHERS_CIPHER, (DATA)PASSPHRASE); + EXPORT encrypt_rsa := Std.OpenSSL.RSA.Encrypt((DATA)PLAINTEXT, RSA_PUBLIC_1); + EXPORT seal_rsa := Std.OpenSSL.RSA.Seal((DATA)PLAINTEXT, [RSA_PUBLIC_1, RSA_PUBLIC_2]); + EXPORT signed_rsa_sha256 := Std.OpenSSL.RSA.Sign((DATA)PLAINTEXT, (DATA)PASSPHRASE, RSA_PRIVATE_1, 'sha256'); + + EXPORT TestDigests := [ + ASSERT(COUNT(Std.OpenSSL.Digest.AvailableAlgorithms()) > 0, 'No digest algorithms available'); + + ASSERT(Std.Str.ToHexPairs(hash_sha256) = '0F6BE6CC79C301CEA386173C0919FEE806E78075618656D24F733AA5052EBF6D'); + ASSERT(LENGTH(hash_sha256) = 32); + ASSERT(Std.Str.ToHexPairs(hash_sha512) = '9E309515371114774EE9E3C216888AFA89CC6616AF2E583601BA6E84750943B246E2CA5A518B44096A3A5929A1A50BF842117676DAFA5435CDF981DCA1344F8F'); + ASSERT(LENGTH(hash_sha512) = 64); + + ASSERT(TRUE) + ]; + + EXPORT TestCiphers := [ + ASSERT(COUNT(Std.OpenSSL.Ciphers.AvailableAlgorithms()) > 0, 'No cipher algorithms available'); + + ASSERT(Std.OpenSSL.Ciphers.IVSize(CIPHERS_CIPHER) = 16); + ASSERT(Std.OpenSSL.Ciphers.SaltSize(CIPHERS_CIPHER) = 8); + + ASSERT(Std.Str.ToHexPairs(encrypt_my_iv_my_salt) = '7D99A971120AF361404F93F27CABB44BEDC9333BF84C3DFDBC803F3CEE7A4BA1A5BE0C2FD98A507E718988A140F2B29D'); + ASSERT(LENGTH(encrypt_my_iv_my_salt) = 48); + ASSERT((STRING)Std.OpenSSL.Ciphers.Decrypt(encrypt_my_iv_my_salt, CIPHERS_CIPHER, (DATA)PASSPHRASE, salt := (>DATA<)staticSalt, iv := staticIV) = PLAINTEXT); + ASSERT(LENGTH(encrypt_default_iv_my_salt) = 48); + ASSERT((STRING)Std.OpenSSL.Ciphers.Decrypt(encrypt_default_iv_my_salt, CIPHERS_CIPHER, (DATA)PASSPHRASE, salt := (>DATA<)staticSalt) = PLAINTEXT); + ASSERT(LENGTH(encrypt_my_iv_default_salt) = 48); + ASSERT((STRING)Std.OpenSSL.Ciphers.Decrypt(encrypt_my_iv_default_salt, CIPHERS_CIPHER, (DATA)PASSPHRASE, iv := staticIV) = PLAINTEXT); + ASSERT(LENGTH(encrypt_default_iv_default_salt) = 48); + ASSERT((STRING)Std.OpenSSL.Ciphers.Decrypt(encrypt_default_iv_default_salt, CIPHERS_CIPHER, (DATA)PASSPHRASE) = PLAINTEXT); + + ASSERT(TRUE) + ]; + + EXPORT TestRSA := [ + ASSERT(LENGTH(encrypt_rsa) = 512); + ASSERT((STRING)Std.OpenSSL.RSA.Decrypt((DATA)encrypt_rsa, RSA_PRIVATE_1) = PLAINTEXT); + ASSERT(LENGTH(seal_rsa) = 1112); + ASSERT((STRING)Std.OpenSSL.RSA.Unseal((DATA)seal_rsa, RSA_PRIVATE_1) = PLAINTEXT); + ASSERT((STRING)Std.OpenSSL.RSA.Unseal((DATA)seal_rsa, RSA_PRIVATE_2) = PLAINTEXT); + + ASSERT(Std.Str.ToHexPairs(signed_rsa_sha256) = '399F5FCB9B1A3C02D734BF3F1C9CB480681126B0F7505697E045ECF22E11A47FADCF7E2BA73761AD6345F6702AAD230957AFA1B0B3C8C29FC537AACA68' + + '13B79DE0CDEF82B4BB6183D0637583D0E2AA78892EE190D7AB9CB20F9AC36D91DB2994A07F0C17A0CFB5AF0385EA4ABA9723FC72FB08081AE4C6C83E659AEBA1C103FB6F4E831EFDAA4CE037A3874D59664B1DE90' + + '313B474897E2BF7D48CF09E19EC706A83B3E86B9F8A5F15BE01BA6A7E0BDC78877D8C60870E4713CCB87EC93A6C47E8EBF522E35BAEC85A1FC0209397CE0C62564B79104514D042F435FF0DF4B4500C8CE0F3AD76' + + '4C26FDAFD14C493D303860C6A9AE7D539F42855C077EE682F6BD234CE035AAFADA5B5E90021D6D82D9030E687234D71E95CA701FDD6E097764443FEC237744FC3530E0AB3715F28B510766F73B6F56DDE7219AA2A' + + 'A77A41AF1D34200CC63F3D35E89398536F4BAA3A5D66E3C9BDF0C3AFFE9AE618413C3EAC2A980DF6B363D6F6F93BCB2D02D5BB4CCFF912CEDEE66FCF916F289C34CA2D45DFD14E545AA8D6CE591F455D993A7E6E4' + + 'C573C9EBE9FE472131A39D60ED53624745A79A29B31D07DE38D1FA64D3DB32EF447F62B64F8A07C012E55C06551F5C60509797A4521DC4E7CB33F9C0759E6B46DA6B758C86E26507CA9D79933532BE923FC449842' + + '17A203F97B97606E18E9F4949DC5E6C21705A89844B316093EFD8C0CC'); + ASSERT(LENGTH(signed_rsa_sha256) = 512); + ASSERT(Std.OpenSSL.RSA.VerifySignature((DATA)signed_rsa_sha256, (DATA)PLAINTEXT, (DATA)PASSPHRASE, RSA_PUBLIC_1, 'sha256') = TRUE); + ASSERT(Std.OpenSSL.RSA.VerifySignature((DATA)((UNSIGNED)signed_rsa_sha256 + 1), (DATA)PLAINTEXT, (DATA)PASSPHRASE, RSA_PUBLIC_1, 'sha256') = FALSE); + + ASSERT(TRUE) + ]; +END; diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 63de3d1cc68..42be5b1e56b 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -44,6 +44,7 @@ add_subdirectory (couchbase) add_subdirectory (sqs) add_subdirectory (mongodb) add_subdirectory (parquet) +add_subdirectory (openssl) IF ( INCLUDE_EE_PLUGINS ) add_subdirectory (eeproxies) ENDIF() diff --git a/plugins/openssl/CMakeLists.txt b/plugins/openssl/CMakeLists.txt new file mode 100644 index 00000000000..6d56cfa6447 --- /dev/null +++ b/plugins/openssl/CMakeLists.txt @@ -0,0 +1,62 @@ +############################################################################## +# HPCC SYSTEMS software Copyright (C) 2025 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. +############################################################################## + +# Component: openssl + +############################################################# +# Description: +# ----------- +# Cmake Input File for openssl +############################################################# + +project(openssl) + +find_package(OpenSSL REQUIRED) + +set( + SRCS + openssl.hpp + openssl.cpp +) + +include_directories( + ${HPCC_SOURCE_DIR}/system/include + ${HPCC_SOURCE_DIR}/rtl/eclrtl + ${HPCC_SOURCE_DIR}/rtl/include + ${HPCC_SOURCE_DIR}/common/deftype + ${HPCC_SOURCE_DIR}/system/jlib +) + +add_definitions(-D_USRDLL -DECL_OPENSSL_EXPORTS) +HPCC_ADD_LIBRARY(openssl SHARED ${SRCS}) + +install( + TARGETS openssl + DESTINATION plugins CALC_DEPS +) +install( + FILES ${OPENSSL_LIBRARIES} + DESTINATION ${LIB_DIR} + COMPONENT Runtime +) + +target_link_libraries( + openssl + eclrtl + jlib + OpenSSL::SSL + OpenSSL::Crypto +) diff --git a/plugins/openssl/openssl.cpp b/plugins/openssl/openssl.cpp new file mode 100644 index 00000000000..a39c66fd867 --- /dev/null +++ b/plugins/openssl/openssl.cpp @@ -0,0 +1,915 @@ +/*############################################################################## + + HPCC SYSTEMS software Copyright (C) 2025 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. +############################################################################## */ + +#include "openssl.hpp" + +#include "openssl/err.h" +#include "openssl/evp.h" +#include "openssl/pem.h" + +#include "jlog.hpp" + +#include +#include + +#define CURRENT_OPENSSL_VERSION "openssl plugin 1.0.0" + +static const char* opensslCompatibleVersions[] = { + CURRENT_OPENSSL_VERSION, + NULL }; + +OPENSSL_API bool OPENSSL_CALL getECLPluginDefinition(ECLPluginDefinitionBlock* pb) +{ + if (pb->size == sizeof(ECLPluginDefinitionBlockEx)) + { + ECLPluginDefinitionBlockEx* pbx = static_cast(pb); + pbx->compatibleVersions = opensslCompatibleVersions; + } + else if (pb->size != sizeof(ECLPluginDefinitionBlock)) + { + return false; + } + + pb->magicVersion = PLUGIN_VERSION; + pb->version = CURRENT_OPENSSL_VERSION; + pb->moduleName = "openssl"; + pb->ECL = NULL; + pb->flags = PLUGIN_IMPLICIT_MODULE; + pb->description = "ECL plugin library for the C++ API in OpenSSL"; + + return true; +} + +namespace nsOpenSSL +{ + +void failOpenSSLError(const std::string& context) +{ + unsigned long errCode = 0; + char buffer[120]; + + ERR_error_string_n(ERR_get_error(), buffer, sizeof(buffer)); + + std::string desc = "Error within "; + desc += context; + desc += ": "; + desc += buffer; + + rtlFail(-1, desc.c_str()); +} + +static constexpr int OPENSSL_MAX_CACHE_SIZE = 10; +static constexpr bool PRINT_STATS = false; +template +class OpenSSLCache +{ +public: + const T * checkCache(const char * algorithm) + { + for (auto& c : cache) + { + if (std::get<0>(c) == algorithm) + { + hits++; + return std::get<1>(c); + } + } + misses++; + const T * newObj = getObjectByName(algorithm); + if (newObj) + { + cache.emplace_front(algorithm, newObj); + if (cache.size() > OPENSSL_MAX_CACHE_SIZE) + cache.pop_back(); + } + else + failOpenSSLError("adding new object to cache"); + + return newObj; + }; + + void printStatistics() {DBGLOG("OPENSSL %s CACHE STATS: HITS = %d, MISSES = %d", cacheName.c_str(), hits, misses);}; + + void init() + { + setCacheName(); + hits = 0; + misses = 0; + }; + +private: + int hits; + int misses; + std::string cacheName; + std::list> cache; + + void setCacheName(); + const T * getObjectByName(const char * name); +}; + +template <> +void OpenSSLCache::setCacheName() { cacheName = "CIPHER"; } + +template <> +void OpenSSLCache::setCacheName() { cacheName = "DIGEST"; } + +template <> +const EVP_CIPHER * OpenSSLCache::getObjectByName(const char * name) { return EVP_get_cipherbyname(name); } + +template <> +const EVP_MD * OpenSSLCache::getObjectByName(const char * name) { return EVP_get_digestbyname(name); } + +// PEM Public/Private keys require parsing from a string +// Store the hash of the original string and parsed key +class PKeyCache +{ +public: + void init() + { + hits = 0; + misses = 0; + }; + + EVP_PKEY * checkCache(size32_t keyLen, const char * key) + { + for (auto& c : cache) + { + if (strncmp(std::get<0>(c).c_str(), key, keyLen) == 0) + { + hits++; + return std::get<1>(c); + } + } + + misses++; + + BIO * bio = BIO_new_mem_buf(key, keyLen); + if (!bio) + failOpenSSLError("creating buffer for EVP_PKEY"); + + EVP_PKEY * pkey; + if (startsWith(key, "-----BEGIN RSA PUBLIC KEY-----")) + pkey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); + else + pkey = PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr); + + BIO_free(bio); + if (pkey) + { + cache.emplace_front(std::string(key, keyLen), pkey); + if (cache.size() > OPENSSL_MAX_CACHE_SIZE) + { + EVP_PKEY_free(std::get<1>(cache.back())); + cache.pop_back(); + } + } + else + failOpenSSLError("loading a pkey"); + + return pkey; + }; + + void clear() + { + for (auto& c : cache) + EVP_PKEY_free(std::get<1>(c)); + cache.clear(); + }; + + void printStatistics() {DBGLOG("OPENSSL PKEY CACHE STATS: HITS = %d, MISSES = %d", hits, misses);}; + +private: + int hits; + int misses; + std::list> cache; +}; + + +static thread_local PKeyCache pkeyCache; + +static thread_local OpenSSLCache cipherCache; +static thread_local OpenSSLCache digestCache; +} // nsOpenSSL + +using namespace nsOpenSSL; + +//-------------------------------------------------------------------------- +// Advertised Entry Point Functions +//-------------------------------------------------------------------------- + +OPENSSL_API void OPENSSL_CALL digestAvailableAlgorithms(ICodeContext *ctx, size32_t & __lenResult, void * & __result) +{ + // Get all the hash (digest) names + OpenSSL_add_all_digests(); + std::vector digestNames; + EVP_MD_do_all([](const EVP_MD * md, const char * name, const char * description, void * arg) { + std::vector * digestNames = static_cast*>(arg); + digestNames->push_back(name); + }, &digestNames); + EVP_cleanup(); + + __lenResult = 0; + __result = nullptr; + + // Determine final size of returned dataset + for (auto& name : digestNames) + __lenResult += (sizeof(size32_t) + name.size()); + + // Allocate and populate result block + if (__lenResult > 0) + { + MemoryBuffer resultBuffer(__lenResult); + size32_t stringSize = 0; + for (auto& name : digestNames) + { + stringSize = name.size(); + resultBuffer.append(stringSize); + resultBuffer.append(stringSize, name.data()); + } + + __result = resultBuffer.detachOwn(); + } +} + +OPENSSL_API void OPENSSL_CALL digestHash(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_indata, const void * _indata, const char * _hash_name) +{ + if (strlen(_hash_name) == 0) + rtlFail(-1, "No hash digest name provided"); + + const EVP_MD * md = digestCache.checkCache(_hash_name); + + EVP_MD_CTX * mdContext = EVP_MD_CTX_new(); + if (!mdContext) + failOpenSSLError("creating a hash digest context"); + + try + { + if (EVP_DigestInit_ex(mdContext, md, nullptr) != 1) + failOpenSSLError("EVP_DigestInit_ex"); + + if (EVP_DigestUpdate(mdContext, _indata, len_indata) != 1) + failOpenSSLError("EVP_DigestUpdate"); + + __lenResult = EVP_MD_CTX_get_size(mdContext); + MemoryBuffer resultBuffer(__lenResult); + + if (EVP_DigestFinal_ex(mdContext, static_cast(resultBuffer.bufferBase()), nullptr) != 1) + failOpenSSLError("EVP_DigestFinal_ex"); + + __result = resultBuffer.detachOwn(); + } + catch (...) + { + EVP_MD_CTX_free(mdContext); + throw; + } + + EVP_MD_CTX_free(mdContext); +} + +// Symmetric ciphers + +OPENSSL_API void OPENSSL_CALL cipherAvailableAlgorithms(ICodeContext *ctx, size32_t & __lenResult, void * & __result) +{ + // Get all the cipher names + OpenSSL_add_all_ciphers(); + std::vector cipherNames; + EVP_CIPHER_do_all([](const EVP_CIPHER * cipher, const char * from, const char * to, void * x) { + auto cipherNames = static_cast *>(x); + cipherNames->push_back(from); + }, &cipherNames); + EVP_cleanup(); + + __lenResult = 0; + __result = nullptr; + + // Determine final size of returned dataset + for (auto& name : cipherNames) + __lenResult += (sizeof(uint32_t) + name.size()); + + // Allocate and populate result block + if (__lenResult > 0) + { + MemoryBuffer resultBuffer(__lenResult); + size32_t stringSize = 0; + for (auto& name : cipherNames) + { + stringSize = name.size(); + resultBuffer.append(stringSize); + resultBuffer.append(stringSize, name.data()); + } + + __result = resultBuffer.detachOwn(); + } +} + +OPENSSL_API uint16_t OPENSSL_CALL cipherIVSize(ICodeContext *ctx, const char * algorithm) +{ + if (strlen(algorithm) == 0) + rtlFail(-1, "No algorithm name provided"); + + // Load the cipher + const EVP_CIPHER * cipher = cipherCache.checkCache(algorithm); + + return static_cast(EVP_CIPHER_iv_length(cipher)); +} + +OPENSSL_API void OPENSSL_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, const char * _algorithm, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt) +{ + __result = nullptr; + __lenResult = 0; + + bool hasIV = (len_iv > 0); + bool hasSalt = (len_salt > 0); + + // Initial sanity check of our arguments + if (strlen(_algorithm) == 0) + rtlFail(-1, "No algorithm name provided"); + if (len_passphrase == 0) + rtlFail(-1, "No passphrase provided"); + if (hasSalt && len_salt != 8) + rtlFail(-1, "Salt value must be exactly 8 bytes in size"); + + if (len_plaintext > 0) + { + // Load the cipher + const EVP_CIPHER * cipher = cipherCache.checkCache(_algorithm); + + int cipherIVSize = EVP_CIPHER_iv_length(cipher); + if (hasIV && len_iv != static_cast(cipherIVSize)) + rtlFail(-1, "Supplied IV is an incorrect size"); + + // Generate a key and an IV (if one was not provided) + MemoryBuffer key(EVP_MAX_KEY_LENGTH); + MemoryBuffer iv(cipherIVSize); + if (!EVP_BytesToKey(cipher, EVP_sha256(), (hasSalt ? static_cast(_salt) : nullptr), static_cast(_passphrase), len_passphrase, 1, static_cast(key.bufferBase()), static_cast(iv.bufferBase()))) + failOpenSSLError("generating an encryption key from the passphrase"); + + // If an IV was supplied, copy it over the one that was generated + if (hasIV) + iv.append(cipherIVSize, _iv); + + // Initialize the context + EVP_CIPHER_CTX * encryptCtx = EVP_CIPHER_CTX_new(); + if (!encryptCtx) + failOpenSSLError("EVP_CIPHER_CTX_new"); + + // Reserve buffers + __lenResult = len_plaintext + EVP_CIPHER_block_size(cipher); // max size, may be changed later + MemoryBuffer resultBuffer(__lenResult); + + try + { + int len = 0; + int ciphertextLen = 0; + + if (EVP_EncryptInit_ex(encryptCtx, cipher, nullptr, static_cast(key.bufferBase()),static_cast(iv.bufferBase())) != 1) + failOpenSSLError("EVP_EncryptInit_ex"); + + if (EVP_EncryptUpdate(encryptCtx, static_cast(resultBuffer.bufferBase()), &len, static_cast(_plaintext), len_plaintext) != 1) + failOpenSSLError("EVP_EncryptUpdate"); + ciphertextLen = len; + + if (EVP_EncryptFinal_ex(encryptCtx, static_cast(resultBuffer.bufferBase()) + len, &len) != 1) + failOpenSSLError("EVP_EncryptFinal_ex"); + ciphertextLen += len; + __lenResult = ciphertextLen; + __result = resultBuffer.detachOwn(); + } + catch (...) + { + EVP_CIPHER_CTX_free(encryptCtx); + __lenResult = 0; + rtlFree(__result); + __result = nullptr; + throw; + } + + EVP_CIPHER_CTX_free(encryptCtx); + } +} + +OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, const char * _algorithm, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt) +{ + __result = nullptr; + __lenResult = 0; + + bool hasIV = (len_iv > 0); + bool hasSalt = (len_salt > 0); + + // Initial sanity check of our arguments + if (strlen(_algorithm) == 0) + rtlFail(-1, "No algorithm name provided"); + if (len_passphrase == 0) + rtlFail(-1, "No passphrase provided"); + if (hasSalt && len_salt != 8) + rtlFail(-1, "Salt value must be exactly 8 bytes in size"); + + if (len_ciphertext > 0) + { + // Load the cipher + const EVP_CIPHER * cipher = cipherCache.checkCache(_algorithm); + + int cipherIVSize = EVP_CIPHER_iv_length(cipher); + if (hasIV && len_iv != static_cast(cipherIVSize)) + rtlFail(-1, "Supplied IV is an incorrect size"); + + // Generate a key and an IV (if one was not provided) + MemoryBuffer key(EVP_MAX_KEY_LENGTH); + MemoryBuffer iv(cipherIVSize); + if (!EVP_BytesToKey(cipher, EVP_sha256(), (hasSalt ? static_cast(_salt) : nullptr), static_cast(_passphrase), len_passphrase, 1, static_cast(key.bufferBase()), static_cast(iv.bufferBase()))) + failOpenSSLError("generating an encryption key from the passphrase"); + + // If an IV was supplied, copy it over the one that was generated + if (hasIV) + iv.append(cipherIVSize, _iv); + + // Initialize the context + EVP_CIPHER_CTX * decryptCtx = EVP_CIPHER_CTX_new(); + if (!decryptCtx) + failOpenSSLError("EVP_CIPHER_CTX_new"); + + // Reserve buffers + __lenResult = len_ciphertext; // max size, may be changed later + MemoryBuffer resultBuffer(__lenResult); + + try + { + int len = 0; + int plaintextLen = 0; + + if (EVP_DecryptInit_ex(decryptCtx, cipher, nullptr, static_cast(key.bufferBase()), static_cast(iv.bufferBase())) != 1) + failOpenSSLError("EVP_DecryptInit_ex"); + + if (EVP_DecryptUpdate(decryptCtx, static_cast(resultBuffer.bufferBase()), &len, static_cast(_ciphertext), len_ciphertext) != 1) + failOpenSSLError("EVP_DecryptUpdate"); + plaintextLen = len; + + if (EVP_DecryptFinal_ex(decryptCtx, static_cast(resultBuffer.bufferBase()) + len, &len) != 1) + failOpenSSLError("EVP_DecryptFinal_ex"); + plaintextLen += len; + __lenResult = plaintextLen; + __result = resultBuffer.detachOwn(); + } + catch (...) + { + EVP_CIPHER_CTX_free(decryptCtx); + __lenResult = 0; + rtlFree(__result); + __result = nullptr; + throw; + } + + EVP_CIPHER_CTX_free(decryptCtx); + } +} + +// RSA functions + +OPENSSL_API void OPENSSL_CALL rsaSeal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, bool isAll_pem_public_keys, size32_t len_pem_public_keys, const void * _pem_public_keys, const char * _symmetric_algorithm) +{ + // Initial sanity check of our arguments + if (len_pem_public_keys == 0) + rtlFail(-1, "No public keys provided"); + + if (!isAll_pem_public_keys && len_plaintext > 0) + { + std::vector publicKeys; + EVP_CIPHER_CTX * encryptCtx = nullptr; + byte ** encryptedKeys = nullptr; + MemoryBuffer iv; + MemoryBuffer ciphertext; + + try + { + // Parse public keys and stuff them into a vector + const char * pubKeyPtr = static_cast(_pem_public_keys); + const char * endPtr = pubKeyPtr + len_pem_public_keys; + while (pubKeyPtr < endPtr) + { + const size32_t keySize = *(reinterpret_cast(pubKeyPtr)); + pubKeyPtr += sizeof(keySize); + publicKeys.push_back(pkeyCache.checkCache(keySize, pubKeyPtr)); + pubKeyPtr += keySize; + } + + // Load the cipher + const EVP_CIPHER * cipher = cipherCache.checkCache(_symmetric_algorithm); + + // Allocate memory for encrypted keys + size_t keyCount = publicKeys.size(); + encryptedKeys = static_cast(rtlMalloc(sizeof(byte *) * keyCount)); + for (size_t x = 0; x < keyCount; x++) + encryptedKeys[x] = static_cast(rtlMalloc(EVP_PKEY_size(publicKeys[x]))); + + // Allocate memory for the IV + int ivLen = EVP_CIPHER_iv_length(cipher); + iv.ensureCapacity(ivLen); + + // Allocate buffer for ciphertext + int ciphertextLen = len_plaintext + EVP_CIPHER_block_size(cipher); + ciphertext.ensureCapacity(ciphertextLen); + + // Create and initialize the context + encryptCtx = EVP_CIPHER_CTX_new(); + if (!encryptCtx) + failOpenSSLError("creating cipher context"); + + // Initialize the envelope + std::vector keyLens(keyCount); + if (EVP_SealInit(encryptCtx, cipher, encryptedKeys, keyLens.data(), static_cast(iv.bufferBase()), publicKeys.data(), keyCount) != static_cast(keyCount)) + failOpenSSLError("EVP_SealInit"); + + // Update the envelope (encrypt the plaintext) + int len = 0; + if (EVP_SealUpdate(encryptCtx, static_cast(ciphertext.bufferBase()), &len, reinterpret_cast(_plaintext), len_plaintext) != 1) + failOpenSSLError("EVP_SealUpdate"); + ciphertextLen = len; + + // Finalize the envelope's ciphertext + if (EVP_SealFinal(encryptCtx, static_cast(ciphertext.bufferBase()) + len, &len) != 1) + failOpenSSLError("EVP_SealFinal"); + ciphertextLen += len; + + int totalKeyLen = 0; + for (int i = 0; i < keyCount; i++) + totalKeyLen += keyLens[i]; + + // We need to prepend the ciphertext with metadata so the blob can be decrypted; + // this is potentially nonstandard + MemoryBuffer outBuffer; + outBuffer.ensureCapacity(ivLen + (sizeof(size_t)*(keyCount+1)) + totalKeyLen + ciphertextLen); + // IV comes first; its length can be derived from the cipher + outBuffer.append(ivLen, static_cast(iv.bufferBase())); + // Number of keys (size_t) + outBuffer.append(sizeof(keyCount), reinterpret_cast(&keyCount)); + // Keys; each is (size_t) + + for (size_t x = 0; x < keyCount; x++) + { + size_t keyLen = keyLens[x]; + outBuffer.append(sizeof(keyLen), reinterpret_cast(&keyLen)); + outBuffer.append(keyLen, encryptedKeys[x]); + } + // And finally the ciphertext + outBuffer.append(ciphertextLen, static_cast(ciphertext.bufferBase())); + + // Copy to the ECL result buffer + __lenResult = outBuffer.length(); + __result = outBuffer.detachOwn(); + + // Cleanup + EVP_CIPHER_CTX_free(encryptCtx); + for (size_t x = 0; x < publicKeys.size(); x++) + rtlFree(encryptedKeys[x]); + rtlFree(encryptedKeys); + } + catch (...) + { + if (encryptCtx) + EVP_CIPHER_CTX_free(encryptCtx); + if (encryptedKeys) + { + for (size_t x = 0; x < publicKeys.size(); x++) + { + if (encryptedKeys[x]) + rtlFree(encryptedKeys[x]); + } + rtlFree(encryptedKeys); + } + __lenResult = 0; + rtlFree(__result); + __result = nullptr; + throw; + } + } +} + +OPENSSL_API void OPENSSL_CALL rsaUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_pem_private_key, const char * _pem_private_key, const char * _symmetric_algorithm) +{ + // Initial sanity check of our arguments + if (len_pem_private_key == 0) + rtlFail(-1, "No private key provided"); + + if (len_ciphertext > 0) + { + EVP_CIPHER_CTX * decryptCtx = nullptr; + MemoryBuffer symmetricKey; + MemoryBuffer iv; + MemoryBuffer plaintext; + + try + { + // Load the private key + EVP_PKEY * privateKey = pkeyCache.checkCache(len_pem_private_key, _pem_private_key); + + // Load the cipher + const EVP_CIPHER * cipher = cipherCache.checkCache(_symmetric_algorithm); + + // Allocate memory for the symmetric key and IV + int keyLen = EVP_PKEY_size(privateKey); + symmetricKey.ensureCapacity(keyLen); + int ivLen = EVP_CIPHER_iv_length(cipher); + iv.ensureCapacity(ivLen); + + // Unpack the structured ciphertext to extract the metadata + const byte * inPtr = static_cast(_ciphertext); + // IV comes first, length determined by the cipher + iv.append(ivLen, inPtr); + inPtr += ivLen; + // Number of keys embedded in the metadata (size_t) + size_t keyCount = 0; + memcpy(&keyCount, inPtr, sizeof(keyCount)); + inPtr += sizeof(keyCount); + // The keys; each has a length (size_t) then contents + std::vector encryptedKeys; + for (size_t x = 0; x < keyCount; x++) + { + size_t keySize = 0; + memcpy(&keySize, inPtr, sizeof(keySize)); + inPtr += sizeof(keySize); + encryptedKeys.emplace_back(reinterpret_cast(inPtr), keySize); + inPtr += keySize; + } + + const byte * newCipherText = inPtr; + size_t newCipherTextLen = (len_ciphertext - (reinterpret_cast(inPtr) - static_cast(_ciphertext))); + + // Initialize the context for decryption + decryptCtx = EVP_CIPHER_CTX_new(); + if (!decryptCtx) + failOpenSSLError("creating cipher context"); + + // Find an encrypted key that we can decrypt + bool found = false; + for (auto& encryptedKey : encryptedKeys) + { + if (EVP_OpenInit(decryptCtx, cipher, reinterpret_cast(encryptedKey.data()), encryptedKey.size(), static_cast(iv.bufferBase()), privateKey) == 1) + { + found = true; + break; + } + } + if (!found) + failOpenSSLError("EVP_OpenInit"); + + // Allocate memory for the plaintext + int plaintextLen = newCipherTextLen; + plaintext.ensureCapacity(plaintextLen); + + int len = 0; + if (EVP_OpenUpdate(decryptCtx, static_cast(plaintext.bufferBase()), &len, newCipherText, newCipherTextLen) != 1) + failOpenSSLError("EVP_OpenUpdate"); + plaintextLen = len; + + if (EVP_OpenFinal(decryptCtx, static_cast(plaintext.bufferBase()) + len, &len) != 1) + failOpenSSLError("EVP_OpenFinal"); + plaintextLen += len; + + // Copy to the ECL result buffer + __lenResult = plaintextLen; + MemoryBuffer resultBuffer(__lenResult); + resultBuffer.append(__lenResult, plaintext.bufferBase()); + __result = resultBuffer.detachOwn(); + + // Cleanup + EVP_CIPHER_CTX_free(decryptCtx); + } + catch (...) + { + if (decryptCtx) + EVP_CIPHER_CTX_free(decryptCtx); + __lenResult = 0; + rtlFree(__result); + __result = nullptr; + throw; + } + } +} + +OPENSSL_API void OPENSSL_CALL rsaEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_pem_public_key, const char * _pem_public_key) +{ + __result = nullptr; + __lenResult = 0; + + // Initial sanity check of our arguments + if (len_pem_public_key == 0) + rtlFail(-1, "No public key provided"); + + EVP_PKEY_CTX * encryptCtx = nullptr; + + if (len_plaintext > 0) + { + try + { + // Load key from buffer + EVP_PKEY * publicKey = pkeyCache.checkCache(len_pem_public_key, _pem_public_key); + + // Create encryption context + encryptCtx = EVP_PKEY_CTX_new(publicKey, nullptr); + if (!encryptCtx) + failOpenSSLError("publicKey"); + if (EVP_PKEY_encrypt_init(encryptCtx) <= 0) + failOpenSSLError("EVP_PKEY_encrypt_init"); + + // Determine max size of output + size_t outLen = 0; + if (EVP_PKEY_encrypt(encryptCtx, nullptr, &outLen, reinterpret_cast(_plaintext), len_plaintext) <= 0) + failOpenSSLError("EVP_PKEY_encrypt"); + + // Set actual size of output + MemoryBuffer resultBuffer(outLen); + + if (EVP_PKEY_encrypt(encryptCtx, static_cast(resultBuffer.bufferBase()), &outLen, reinterpret_cast(_plaintext), len_plaintext) <= 0) + failOpenSSLError("EVP_PKEY_encrypt"); + + __lenResult = outLen; + __result = resultBuffer.detachOwn(); + + EVP_PKEY_CTX_free(encryptCtx); + } + catch (...) + { + if (encryptCtx) + EVP_PKEY_CTX_free(encryptCtx); + rtlFree(__result); + __lenResult = 0; + throw; + } + } +} + +OPENSSL_API void OPENSSL_CALL rsaDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_pem_private_key, const char * _pem_private_key) +{ + __result = nullptr; + __lenResult = 0; + + // Initial sanity check of our arguments + if (len_pem_private_key == 0) + rtlFail(-1, "No private key provided"); + + EVP_PKEY_CTX * decryptCtx = nullptr; + + if (len_ciphertext > 0) + { + try + { + // Load key from buffer + EVP_PKEY * privateKey = pkeyCache.checkCache(len_pem_private_key, _pem_private_key); + + // Create decryption context + decryptCtx = EVP_PKEY_CTX_new(privateKey, nullptr); + if (!decryptCtx) + failOpenSSLError("EVP_PKEY_CTX_new"); + if (EVP_PKEY_decrypt_init(decryptCtx) <= 0) + failOpenSSLError("EVP_PKEY_decrypt_init"); + + // Determine max size of output + size_t outLen = 0; + if (EVP_PKEY_decrypt(decryptCtx, nullptr, &outLen, reinterpret_cast(_ciphertext), len_ciphertext) <= 0) + failOpenSSLError("EVP_PKEY_decrypt"); + + // Set actual size of output + MemoryBuffer resultBuffer(outLen); + + if (EVP_PKEY_decrypt(decryptCtx, static_cast(resultBuffer.bufferBase()), &outLen, reinterpret_cast(_ciphertext), len_ciphertext) <= 0) + failOpenSSLError("EVP_PKEY_decrypt"); + + __lenResult = outLen; + __result = resultBuffer.detachOwn(); + + EVP_PKEY_CTX_free(decryptCtx); + } + catch (...) + { + if (decryptCtx) + EVP_PKEY_CTX_free(decryptCtx); + rtlFree(__result); + __lenResult = 0; + throw; + } + } +} + +OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _hash_name) +{ + EVP_MD_CTX *mdCtx = nullptr; + + try + { + // Load the private key from the PEM string + EVP_PKEY * privateKey = pkeyCache.checkCache(len_pem_private_key, _pem_private_key); + + // Create and initialize the message digest context + mdCtx = EVP_MD_CTX_new(); + if (!mdCtx) + failOpenSSLError("EVP_MD_CTX_new (rsaSign)"); + + const EVP_MD *md = digestCache.checkCache(_hash_name); + + if (EVP_DigestSignInit(mdCtx, nullptr, md, nullptr, privateKey) <= 0) + failOpenSSLError("EVP_DigestSignInit (rsaSign)"); + + // Add plaintext to context + if (EVP_DigestSignUpdate(mdCtx, _plaintext, len_plaintext) <= 0) + failOpenSSLError("EVP_DigestSignUpdate (rsaSign)"); + + // Determine the buffer length for the signature + size_t signatureLen = 0; + if (EVP_DigestSignFinal(mdCtx, nullptr, &signatureLen) <= 0) + failOpenSSLError("determining result length (rsaSign)"); + + // Allocate memory for the signature + MemoryBuffer signatureBuffer(signatureLen); + + // Perform the actual signing + if (EVP_DigestSignFinal(mdCtx, static_cast(signatureBuffer.bufferBase()), &signatureLen) <= 0) + failOpenSSLError("signing (rsaSign)"); + + // Set the result + __lenResult = signatureLen; + __result = signatureBuffer.detachOwn(); + + // Clean up + EVP_MD_CTX_free(mdCtx); + } + catch (...) + { + if (mdCtx) + EVP_MD_CTX_free(mdCtx); + rtlFree(__result); + __lenResult = 0; + throw; + } +} + +OPENSSL_API bool OPENSSL_CALL rsaVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_passphrase, const void * passphrase, size32_t len_pem_public_key, const char * _pem_public_key, const char * _hash_name) +{ + EVP_MD_CTX *mdCtx = nullptr; + + try + { + // Load the public key from the PEM string + EVP_PKEY * publicKey = pkeyCache.checkCache(len_pem_public_key, _pem_public_key); + + // Create and initialize the message digest context + mdCtx = EVP_MD_CTX_new(); + if (!mdCtx) + failOpenSSLError("EVP_MD_CTX_new"); + + const EVP_MD *md = digestCache.checkCache(_hash_name); + + if (EVP_DigestVerifyInit(mdCtx, nullptr, md, nullptr, publicKey) <= 0) + failOpenSSLError("EVP_DigestVerifyInit (rsaVerifySignature)"); + + if (EVP_DigestVerifyUpdate(mdCtx, _signedData, len_signedData) <= 0) + failOpenSSLError("EVP_DigestVerifyUpdate (rsaVerifySignature)"); + + // Perform the actual verification + int res = EVP_DigestVerifyFinal(mdCtx, reinterpret_cast(_signature), len_signature); + + // Clean up + EVP_MD_CTX_free(mdCtx); + return res == 1; + } + catch (...) + { + if (mdCtx) + EVP_MD_CTX_free(mdCtx); + throw; + } +} + +MODULE_INIT(INIT_PRIORITY_STANDARD) +{ + pkeyCache.init(); + digestCache.init(); + cipherCache.init(); + + return true; +} + +MODULE_EXIT() +{ + if(PRINT_STATS) + { + pkeyCache.printStatistics(); + digestCache.printStatistics(); + cipherCache.printStatistics(); + } + + pkeyCache.clear(); +} diff --git a/plugins/openssl/openssl.hpp b/plugins/openssl/openssl.hpp new file mode 100644 index 00000000000..0156da45eb7 --- /dev/null +++ b/plugins/openssl/openssl.hpp @@ -0,0 +1,62 @@ +/*############################################################################## + + HPCC SYSTEMS software Copyright (C) 2025 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. +############################################################################## */ + +#ifndef _OPENSSL_INCL +#define _OPENSSL_INCL + +#ifdef _WIN32 +#define OPENSSL_CALL _cdecl +#else +#define OPENSSL_CALL +#endif + +#ifdef OPENSSL_EXPORTS +#define OPENSSL_API DECL_EXPORT +#else +#define OPENSSL_API DECL_IMPORT +#endif + +#include "platform.h" +#include "jthread.hpp" +#include "hqlplugins.hpp" +#include "eclrtl_imp.hpp" +#include "eclhelper.hpp" + +extern "C++" +{ +OPENSSL_API bool OPENSSL_CALL getECLPluginDefinition(ECLPluginDefinitionBlock *pb); + +// Digest functions +OPENSSL_API void OPENSSL_CALL digestAvailableAlgorithms(ICodeContext *ctx, size32_t & __lenResult, void * & __result); +OPENSSL_API void OPENSSL_CALL digestHash(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_indata, const void * _indata, const char * _hash_name); + +// Cipher functions +OPENSSL_API void OPENSSL_CALL cipherAvailableAlgorithms(ICodeContext *ctx, size32_t & __lenResult, void * & __result); +OPENSSL_API uint16_t OPENSSL_CALL cipherIVSize(ICodeContext *ctx, const char * algorithm); +OPENSSL_API void OPENSSL_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, const char * _algorithm, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt); +OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, const char * _algorithm, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt); + +// RSA functions +OPENSSL_API void OPENSSL_CALL rsaSeal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, bool isAll_pem_public_keys, size32_t len_pem_public_keys, const void * _pem_public_keys, const char * _symmetric_algorithm); +OPENSSL_API void OPENSSL_CALL rsaUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_pem_private_key, const char * _pem_private_key, const char * _symmetric_algorithm); +OPENSSL_API void OPENSSL_CALL rsaEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_pem_public_key, const char * _pem_public_key); +OPENSSL_API void OPENSSL_CALL rsaDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_pem_private_key, const char * _pem_private_key); +OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm); +OPENSSL_API bool OPENSSL_CALL rsaVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_passphrase, const void * passphrase, size32_t len_pem_public_key, const char * _pem_public_key, const char * _algorithm); +} + +#endif // ECL_OPENSSL_INCL diff --git a/plugins/proxies/CMakeLists.txt b/plugins/proxies/CMakeLists.txt index 459c161123c..1a309332896 100644 --- a/plugins/proxies/CMakeLists.txt +++ b/plugins/proxies/CMakeLists.txt @@ -21,6 +21,7 @@ install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_metaphone3.ecllib DESTINATION ${ install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_thorlib.ecllib DESTINATION ${proxies_out_dir} COMPONENT Runtime) install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_word.ecllib DESTINATION ${proxies_out_dir} COMPONENT Runtime) install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_fileservices.ecllib DESTINATION ${proxies_out_dir} COMPONENT Runtime) +install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_openssl.ecllib DESTINATION ${proxies_out_dir} COMPONENT Runtime) IF (USE_OPENSSL) install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_cryptolib.ecllib DESTINATION plugins COMPONENT Runtime) diff --git a/plugins/proxies/lib_openssl.ecllib b/plugins/proxies/lib_openssl.ecllib new file mode 100644 index 00000000000..93e678832e9 --- /dev/null +++ b/plugins/proxies/lib_openssl.ecllib @@ -0,0 +1,39 @@ +/*############################################################################## + + HPCC SYSTEMS software Copyright (C) 2025 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. +############################################################################## */ + +// Service definition +export OpenSSL := SERVICE : plugin('openssl') + + // Hash functions + DATASET({STRING name}) digestAvailableAlgorithms() : cpp,action,context,entrypoint='digestAvailableAlgorithms'; + DATA digestHash(DATA _indata, VARSTRING _hash_name) : cpp,action,context,entrypoint='digestHash'; + + // Symmetric ciphers + DATASET({STRING name}) cipherAvailableAlgorithms() : cpp,action,context,entrypoint='cipherAvailableAlgorithms'; + UNSIGNED2 cipherIVSize(VARSTRING algorithm) : cpp,action,context,entrypoint='cipherIVSize'; + DATA cipherEncrypt(DATA _plaintext, VARSTRING _algorithm, DATA _passphrase, DATA _iv = (DATA)'', DATA _salt = (DATA)'') : cpp,action,context,entrypoint='cipherEncrypt'; + DATA cipherDecrypt(DATA _ciphertext, VARSTRING _algorithm, DATA _passphrase, DATA _iv = (DATA)'', DATA _salt = (DATA)'') : cpp,action,context,entrypoint='cipherDecrypt'; + + // RSA + DATA rsaSeal(DATA _plaintext, SET OF STRING _pem_public_keys, VARSTRING _symmetric_algorithm) : cpp,action,context,entrypoint='rsaSeal'; + DATA rsaUnseal(DATA _ciphertext, STRING _pem_private_key, VARSTRING _symmetric_algorithm) : cpp,action,context,entrypoint='rsaUnseal'; + DATA rsaEncrypt(DATA _plaintext, STRING _pem_public_key) : cpp,action,context,entrypoint='rsaEncrypt'; + DATA rsaDecrypt(DATA _ciphertext, STRING _pem_private_key) : cpp,action,context,entrypoint='rsaDecrypt'; + DATA rsaSign(DATA _plaintext, DATA _passphrase, STRING _pem_private_key, VARSTRING _hash_name) : cpp,action,context,entrypoint='rsaSign'; + BOOLEAN rsaVerifySignature(DATA _signature, DATA _signedData, DATA _passphrase, STRING _pem_public_key, VARSTRING _hash_name) : cpp,action,context,entrypoint='rsaVerifySignature'; + +END; diff --git a/testing/regress/ecl/teststdlibrary.ecl b/testing/regress/ecl/teststdlibrary.ecl index 40cd8e2a305..b1f706ca6ba 100644 --- a/testing/regress/ecl/teststdlibrary.ecl +++ b/testing/regress/ecl/teststdlibrary.ecl @@ -28,6 +28,7 @@ //version tmod='Crypto' //version tmod='str' //version tmod='Math' +//version tmod='OpenSSL' //version tmod='DataPatterns' // /version tmod='DataPatterns.TestDataPatterns' From 3d43d66033f8bca2f3187a3a195624aaaa9e6535 Mon Sep 17 00:00:00 2001 From: Jack Del Vecchio Date: Thu, 5 Dec 2024 14:23:03 -0500 Subject: [PATCH 2/8] Hash Private/Public keys instead of using original string as key --- plugins/openssl/openssl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/openssl/openssl.cpp b/plugins/openssl/openssl.cpp index a39c66fd867..ab334337cdb 100644 --- a/plugins/openssl/openssl.cpp +++ b/plugins/openssl/openssl.cpp @@ -148,7 +148,7 @@ class PKeyCache { for (auto& c : cache) { - if (strncmp(std::get<0>(c).c_str(), key, keyLen) == 0) + if (hashc(reinterpret_cast(key), keyLen, 0) == std::get<0>(c)) { hits++; return std::get<1>(c); @@ -170,7 +170,7 @@ class PKeyCache BIO_free(bio); if (pkey) { - cache.emplace_front(std::string(key, keyLen), pkey); + cache.emplace_front(hashc(reinterpret_cast(key), keyLen, 0), pkey); if (cache.size() > OPENSSL_MAX_CACHE_SIZE) { EVP_PKEY_free(std::get<1>(cache.back())); @@ -195,7 +195,7 @@ class PKeyCache private: int hits; int misses; - std::list> cache; + std::list> cache; }; From 9cc65b7370fc251afded37037bd3ae1cac4a371b Mon Sep 17 00:00:00 2001 From: Jack Del Vecchio Date: Fri, 6 Dec 2024 08:17:43 -0500 Subject: [PATCH 3/8] Use passphrase when reading private keys - rsaSign accepted a passphrase as a parameter, but it didn't use it when reading from the private key buffer - Added a passphrase protected key for testing - Added a passphrase parameter to cipherDecrypt and cipherUnseal --- ecllibrary/std/OpenSSL.ecl | 22 ++- ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl | 150 ++++++++++++--------- plugins/openssl/openssl.cpp | 47 ++++--- plugins/openssl/openssl.hpp | 8 +- plugins/proxies/lib_openssl.ecllib | 6 +- 5 files changed, 139 insertions(+), 94 deletions(-) diff --git a/ecllibrary/std/OpenSSL.ecl b/ecllibrary/std/OpenSSL.ecl index 8c351dab67e..b0ef3bf28c7 100644 --- a/ecllibrary/std/OpenSSL.ecl +++ b/ecllibrary/std/OpenSSL.ecl @@ -225,6 +225,10 @@ EXPORT RSA := MODULE * keys, respectively. Their contents may be passed to this function. * * @param ciphertext The data to decrypt; REQUIRED + * @param passphrase Passphrase to use for private key; + * If no passphrase was used when generating + * the private key, an empty string must be + * passed in (e.g. (DATA)''); REQUIRED * @param pem_private_key An RSA public key in PEM format; REQUIRED * @param symmetric_algorithm The name of the symmetric algorithm to use * to decrypt the payload; must be one of those @@ -237,7 +241,7 @@ EXPORT RSA := MODULE * @see Seal() * Ciphers.AvailableAlgorithms() */ - EXPORT DATA Unseal(DATA ciphertext, STRING pem_private_key, VARSTRING symmetric_algorithm = 'aes-256-cbc') := lib_openssl.OpenSSL.rsaUnseal(ciphertext, pem_private_key, symmetric_algorithm); + EXPORT DATA Unseal(DATA ciphertext, DATA passphrase, STRING pem_private_key, VARSTRING symmetric_algorithm = 'aes-256-cbc') := lib_openssl.OpenSSL.rsaUnseal(ciphertext, passphrase, pem_private_key, symmetric_algorithm); /** * This function performs asymmetric encryption. It should be used to @@ -259,7 +263,11 @@ EXPORT RSA := MODULE * decrypt only small plaintext (e.g. less than 100 bytes) because it is * computationally expensive. * - * @param ciphertext The data to decrypt; REUIRED + * @param ciphertext The data to decrypt; REQUIRED + * @param passphrase Passphrase to use for private key; + * If no passphrase was used when generating + * the private key, an empty string must be + * passed in (e.g. (DATA)''); REQUIRED * @param pem_private_key The private key to use for decryption, in * PEM format; REQUIRED * @@ -267,7 +275,7 @@ EXPORT RSA := MODULE * * @see Encrypt() */ - EXPORT DATA Decrypt(DATA ciphertext, STRING pem_private_key) := lib_openssl.OpenSSL.rsaDecrypt(ciphertext, pem_private_key); + EXPORT DATA Decrypt(DATA ciphertext, DATA passphrase, STRING pem_private_key) := lib_openssl.OpenSSL.rsaDecrypt(ciphertext, passphrase, pem_private_key); /** * Create a digital signature of the given data, using the @@ -283,7 +291,10 @@ EXPORT RSA := MODULE * keys, respectively. Their contents may be passed to this function * * @param plaintext Contents to sign; REQUIRED - * @param passphrase Passphrase to use for private key; REQUIRED + * @param passphrase Passphrase to use for private key; + * If no passphrase was used when generating + * the private key, an empty string must be + * passed in (e.g. (DATA)''); REQUIRED * @param pem_private_key Private key to use for signing; REQUIRED * @param hash_name The name of the hash algorithm to use; * must be one of the values returned from @@ -311,7 +322,6 @@ EXPORT RSA := MODULE * * @param signature Signature to verify; REQUIRED * @param signedData Data used to create signature; REQUIRED - * @param passphrase Passphrase to use for private key; REQUIRED * @param pem_public_key Public key to use for verification; REQUIRED * @param hash_name The name of the hash algorithm to use; * must be one of the values returned from @@ -322,7 +332,7 @@ EXPORT RSA := MODULE * @see Digest.AvailableAlgorithms() * Sign() */ - EXPORT BOOLEAN VerifySignature(DATA signature, DATA signedData, DATA passphrase, STRING pem_public_key, VARSTRING hash_name) := lib_openssl.OpenSSL.rsaVerifySignature(signature, signedData, passphrase, pem_public_key, hash_name); + EXPORT BOOLEAN VerifySignature(DATA signature, DATA signedData, STRING pem_public_key, VARSTRING hash_name) := lib_openssl.OpenSSL.rsaVerifySignature(signature, signedData, pem_public_key, hash_name); END; // RSA diff --git a/ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl b/ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl index 82d32147318..5f8b8b7400b 100644 --- a/ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl +++ b/ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl @@ -92,69 +92,71 @@ EXPORT TestOpenSSL := MODULE EXPORT STRING RSA_PUBLIC_2 := '-----BEGIN RSA PUBLIC KEY-----' + '\n' + - 'MIICCgKCAgEAtHYNEH8DswZUtx3Xk90cPCLtf3vl7awjZvI4V/yJkOb5U/sQRgsw' + '\n' + - '60F84i8Okg3yBxGIEDiZ/cWKBYfQGsycbm+zljIHh0tt8S7hH9iwFiZB41urPZ4Q' + '\n' + - 'zSs84h05SZA9nCVPQOpFYi0I8n6QrGf9eokJf/jO/dZcvsIDYqtiLfTYWMLKibrY' + '\n' + - 'HgP9lIKxJieSmbrX4spYBEf+B9cSQqHBwThAP1mvkIzD2eGuYlQV6hXZb2dSXn8l' + '\n' + - 'Lakgq06mvkCxYglv6GEHKPrEd6KCZKgBLKZsEabvd5+eWXL4VcaAdXjQgRIa5aV2' + '\n' + - 'AJCk5V1ClMraJuw1aw62+2GTi7bTum4t+GJQdTfDSYreTBIZLUzHwlRnlbMrsthd' + '\n' + - 'aVWct3KId2BT/ntqmalBTcu+nK7H3XOEQGrFdQo2tQ459guchYqxk8QFZCVTkNzw' + '\n' + - 'Ky7SyJV9dqDDUhQQSTvwv42CbwpwbqSynE682h1IQThgk1LuDX/IIQRupIgbyJKo' + '\n' + - 'WrFYoNalhyoeXCgQT7gH2y5YdeoGf3oN7dn4HUDFdW2FOYPzpsSMLVr1MUhxelJc' + '\n' + - 'Ru1RUsJDwfkXBUOZM7ChgwGfQYWGjFcEOPK6AbUlSTER2vP3t5R/QPzN6uzih10y' + '\n' + - 'LFFeUxMuvLnmgpKSU9bVsXbN2D4hmInZW8vDRKugNeTrtaV6KkUus5sCAwEAAQ==' + '\n' + + 'MIICCgKCAgEA4AhX7olMaerm6IZEQQ3yhb4HWOtbMNuDcr8GEnjvxCP7JubdsJ82' + '\n' + + 'v9Agft1dmMPpqMrcoH0F06hzyyHBcnyFYAKsBG8v8nNFI9nxD/Yy4V86ROymQP4y' + '\n' + + '1OJNXhXQE3vO65lDRm5aru0cVKKymSDhD0lW+fFUYQdKm6U5yanFHFSlDpjs3dUl' + '\n' + + 'fmXrFkqzmMNs/jfHkxQy10aTcTh0aGucz5mlW/nbOiz9pcQULZU/WFcz+j8/cLr7' + '\n' + + 'oLUbwz4ZjJ3y+DLhFQF4cCdU9iein80pLwLvKiY6abQ/kBGrXDCHIH0UXQg/pjTF' + '\n' + + '+gVXI3phYBq60vbQvzpqdW6lUJov/E6GKc49aDN3Fe8t476Hm1KW2KqO55Ym3WGZ' + '\n' + + 'q5JS9kNBBqvNQ3ZX4GMxVwJkRBBWViV/wIWQQYbxpoGdqjMosRtJ9+xBJD+W7TB6' + '\n' + + '/cokgWz6OtYWKmlAEnGO1e4V6eokAlv5HfQRlQHFSafvpVs0B+CljfAtnxkO+4hy' + '\n' + + 'CisLsgT5RjheBrIimqPrGXmYsPVR7Kh/zaNUV8MVufqBd49zsVzyGclcLUZ8mTxN' + '\n' + + 'bly8yoSvoMGZ0P1BgEmhhvfHE/SGkPG0PSBnEKOQmw9gsN3t+dJWi41cSrnMnmmW' + '\n' + + 'JkTtyrvCsP0csQVBhgzCMoXrIL4Xooiu2qK5pZ3LdMBJPiV7TuVHZakCAwEAAQ==' + '\n' + '-----END RSA PUBLIC KEY-----'; EXPORT STRING RSA_PRIVATE_2 := '-----BEGIN RSA PRIVATE KEY-----' + '\n' + - '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' + '\n' + + 'Proc-Type: 4,ENCRYPTED' + '\n' + + 'DEK-Info: AES-128-CBC,48EDA073E8D55C8DF0D7FF600AB45FC1' + '\n' + '\n' + + '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' + '\n' + '-----END RSA PRIVATE KEY-----'; EXPORT UNSIGNED8 staticSalt := 123456789; @@ -167,8 +169,11 @@ EXPORT TestOpenSSL := MODULE EXPORT encrypt_my_iv_default_salt := Std.OpenSSL.Ciphers.Encrypt((DATA)PLAINTEXT, CIPHERS_CIPHER, (DATA)PASSPHRASE, iv := staticIV); EXPORT encrypt_default_iv_default_salt := Std.OpenSSL.Ciphers.Encrypt((DATA)PLAINTEXT, CIPHERS_CIPHER, (DATA)PASSPHRASE); EXPORT encrypt_rsa := Std.OpenSSL.RSA.Encrypt((DATA)PLAINTEXT, RSA_PUBLIC_1); + EXPORT encrypt_rsa_passphrase := Std.OpenSSL.RSA.Encrypt((DATA)PLAINTEXT, RSA_PUBLIC_2); EXPORT seal_rsa := Std.OpenSSL.RSA.Seal((DATA)PLAINTEXT, [RSA_PUBLIC_1, RSA_PUBLIC_2]); - EXPORT signed_rsa_sha256 := Std.OpenSSL.RSA.Sign((DATA)PLAINTEXT, (DATA)PASSPHRASE, RSA_PRIVATE_1, 'sha256'); + EXPORT signed_rsa_sha256 := Std.OpenSSL.RSA.Sign((DATA)PLAINTEXT, (DATA)'', RSA_PRIVATE_1, 'sha256'); + EXPORT signed_rsa_sha256_passphrase := Std.OpenSSL.RSA.Sign((DATA)PLAINTEXT, (DATA)PASSPHRASE, RSA_PRIVATE_2, 'SHA256'); + // EXPORT signed_rsa_sha256_wrong_passphrase := Std.OpenSSL.RSA.Sign((DATA)PLAINTEXT, (DATA)'notmypassphrase', RSA_PRIVATE_2, 'SHA256'); Fails with Error: -1: Error within loading a pkey: error:1C800064:Provider routines::bad decrypt EXPORT TestDigests := [ ASSERT(COUNT(Std.OpenSSL.Digest.AvailableAlgorithms()) > 0, 'No digest algorithms available'); @@ -202,10 +207,11 @@ EXPORT TestOpenSSL := MODULE EXPORT TestRSA := [ ASSERT(LENGTH(encrypt_rsa) = 512); - ASSERT((STRING)Std.OpenSSL.RSA.Decrypt((DATA)encrypt_rsa, RSA_PRIVATE_1) = PLAINTEXT); + ASSERT((STRING)Std.OpenSSL.RSA.Decrypt((DATA)encrypt_rsa, (DATA)'', RSA_PRIVATE_1) = PLAINTEXT); + ASSERT((STRING)Std.OpenSSL.RSA.Decrypt((DATA)encrypt_rsa_passphrase, (DATA)PASSPHRASE, RSA_PRIVATE_2) = PLAINTEXT); ASSERT(LENGTH(seal_rsa) = 1112); - ASSERT((STRING)Std.OpenSSL.RSA.Unseal((DATA)seal_rsa, RSA_PRIVATE_1) = PLAINTEXT); - ASSERT((STRING)Std.OpenSSL.RSA.Unseal((DATA)seal_rsa, RSA_PRIVATE_2) = PLAINTEXT); + ASSERT((STRING)Std.OpenSSL.RSA.Unseal((DATA)seal_rsa, (DATA)'', RSA_PRIVATE_1) = PLAINTEXT); + ASSERT((STRING)Std.OpenSSL.RSA.Unseal((DATA)seal_rsa, (DATA)PASSPHRASE, RSA_PRIVATE_2) = PLAINTEXT); ASSERT(Std.Str.ToHexPairs(signed_rsa_sha256) = '399F5FCB9B1A3C02D734BF3F1C9CB480681126B0F7505697E045ECF22E11A47FADCF7E2BA73761AD6345F6702AAD230957AFA1B0B3C8C29FC537AACA68' + '13B79DE0CDEF82B4BB6183D0637583D0E2AA78892EE190D7AB9CB20F9AC36D91DB2994A07F0C17A0CFB5AF0385EA4ABA9723FC72FB08081AE4C6C83E659AEBA1C103FB6F4E831EFDAA4CE037A3874D59664B1DE90' + @@ -215,8 +221,20 @@ EXPORT TestOpenSSL := MODULE 'C573C9EBE9FE472131A39D60ED53624745A79A29B31D07DE38D1FA64D3DB32EF447F62B64F8A07C012E55C06551F5C60509797A4521DC4E7CB33F9C0759E6B46DA6B758C86E26507CA9D79933532BE923FC449842' + '17A203F97B97606E18E9F4949DC5E6C21705A89844B316093EFD8C0CC'); ASSERT(LENGTH(signed_rsa_sha256) = 512); - ASSERT(Std.OpenSSL.RSA.VerifySignature((DATA)signed_rsa_sha256, (DATA)PLAINTEXT, (DATA)PASSPHRASE, RSA_PUBLIC_1, 'sha256') = TRUE); - ASSERT(Std.OpenSSL.RSA.VerifySignature((DATA)((UNSIGNED)signed_rsa_sha256 + 1), (DATA)PLAINTEXT, (DATA)PASSPHRASE, RSA_PUBLIC_1, 'sha256') = FALSE); + ASSERT(Std.OpenSSL.RSA.VerifySignature((DATA)signed_rsa_sha256, (DATA)PLAINTEXT, RSA_PUBLIC_1, 'sha256') = TRUE); + ASSERT(Std.OpenSSL.RSA.VerifySignature((DATA)((UNSIGNED)signed_rsa_sha256 + 1), (DATA)PLAINTEXT, RSA_PUBLIC_1, 'sha256') = FALSE); + ASSERT(Std.Str.ToHexPairs(signed_rsa_sha256_passphrase) = '448BD2397EB945D508E81A0AE45A01BB9799CAEDC8EEA779798BB07B5CB0C7D3FD571FF602298214F68B5215F039CEE1E2D6D75112A5CCD' + + 'A95875C2774779893101907F0F2BD7C259CB2A0519FAE1A015F48D025A446D69C9E50EA8DB0EC071E53178E6550E13E52ACDA9466D012590AAB358F25E68E91AAEC63E1323823CF48004D27406236079C0610347A' + + '9A6F4B9B58496DE430C0DDF4BFBD9DC333910EA14F3D8E9F7ADCF8FF9BE4C2AE4735CFE38C2B7F6D08313FA6CDF9E836B7156566851E65165907B74DB1A45D4C404423E5AF34C3972231AE4F18455C90448B0459F' + + '3365D037F997FDEB48458646BAE2F756E0A0A0EC68F4676F5426DB568ABE0914592CF0320202063C3F2A4850E7C3BDB801CE9CA8055FFAD5BFFCA2BD3EEC85FDC8C72DA109A7A879097F3B5B1BB106C655DE12C3D' + + '1F09DFDD98BF6CA52E021EEC7C39D07C982FDBA7888A88EFC506ADD915CAD4AEC9E6BED8598254322D684E5621DF97F557DFB585D424A877461EBA33C8AFFE0354DBBE9C283E11B03AEBD2974FB876F27292834D3' + + '012A8A61A76990085F386495BE729B16D6646D754D3F0AEAD89BA044A8BB9813437F344A579DA4676438CDB7BB98EA396C98E86CBB3FCA1BC46A392E23A52AE177F6C798793146081FD0FD637570D9A718C148E17' + + 'FFC502936F4FC09E35592B4B7C2FFB1DFE6B7F4CC766595D47A630AB1A58CDD11716'); + ASSERT(LENGTH(signed_rsa_sha256_passphrase) = 512); + ASSERT(Std.OpenSSL.RSA.VerifySignature((DATA)signed_rsa_sha256_passphrase, (DATA)PLAINTEXT, RSA_PUBLIC_2, 'SHA256') = TRUE); + ASSERT(Std.OpenSSL.RSA.VerifySignature((DATA)((UNSIGNED)signed_rsa_sha256_passphrase + 1), (DATA)PLAINTEXT, RSA_PUBLIC_2, 'SHA256') = FALSE); + + // ASSERT(LENGTH(signed_rsa_sha256_wrong_passphrase) = 0); // fails with "Error: -1: Error within loading a pkey: error:1C800064:Provider routines::bad decrypt" ASSERT(TRUE) ]; diff --git a/plugins/openssl/openssl.cpp b/plugins/openssl/openssl.cpp index ab334337cdb..5ecbbf6be0d 100644 --- a/plugins/openssl/openssl.cpp +++ b/plugins/openssl/openssl.cpp @@ -72,6 +72,19 @@ void failOpenSSLError(const std::string& context) rtlFail(-1, desc.c_str()); } +//called during PEM_read_bio_PrivateKey to set passphrase +int passphraseCB(char *passPhraseBuf, int passPhraseBufSize, int rwflag, void *pPassPhraseMB) +{ + size32_t len = ((MemoryBuffer*)pPassPhraseMB)->length(); + if (passPhraseBufSize >= (int)len) + { + memcpy(passPhraseBuf, ((MemoryBuffer*)pPassPhraseMB)->bufferBase(), len); + return len; + } + PROGLOG("Private Key Passphrase too long (%d bytes), max %d", len, passPhraseBufSize); + return 0; +} + static constexpr int OPENSSL_MAX_CACHE_SIZE = 10; static constexpr bool PRINT_STATS = false; template @@ -144,11 +157,11 @@ class PKeyCache misses = 0; }; - EVP_PKEY * checkCache(size32_t keyLen, const char * key) + EVP_PKEY * checkCache(size32_t keyLen, const char * key, size32_t passphraseLen, const void * passphrase) { for (auto& c : cache) { - if (hashc(reinterpret_cast(key), keyLen, 0) == std::get<0>(c)) + if (hashc(reinterpret_cast(passphrase), passphraseLen, hashc(reinterpret_cast(key), keyLen, 0)) == std::get<0>(c)) { hits++; return std::get<1>(c); @@ -165,12 +178,16 @@ class PKeyCache if (startsWith(key, "-----BEGIN RSA PUBLIC KEY-----")) pkey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); else - pkey = PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr); - + { + MemoryBuffer passphraseMB; + passphraseMB.setBuffer(passphraseLen, (void *)passphrase); + pkey = PEM_read_bio_PrivateKey(bio, nullptr, passphraseCB, static_cast(&passphraseMB)); + } BIO_free(bio); + if (pkey) { - cache.emplace_front(hashc(reinterpret_cast(key), keyLen, 0), pkey); + cache.emplace_front(hashc(reinterpret_cast(passphrase), passphraseLen, hashc(reinterpret_cast(key), keyLen, 0)), pkey); if (cache.size() > OPENSSL_MAX_CACHE_SIZE) { EVP_PKEY_free(std::get<1>(cache.back())); @@ -503,7 +520,7 @@ OPENSSL_API void OPENSSL_CALL rsaSeal(ICodeContext *ctx, size32_t & __lenResult, { const size32_t keySize = *(reinterpret_cast(pubKeyPtr)); pubKeyPtr += sizeof(keySize); - publicKeys.push_back(pkeyCache.checkCache(keySize, pubKeyPtr)); + publicKeys.push_back(pkeyCache.checkCache(keySize, pubKeyPtr, 0, nullptr)); pubKeyPtr += keySize; } @@ -598,7 +615,7 @@ OPENSSL_API void OPENSSL_CALL rsaSeal(ICodeContext *ctx, size32_t & __lenResult, } } -OPENSSL_API void OPENSSL_CALL rsaUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_pem_private_key, const char * _pem_private_key, const char * _symmetric_algorithm) +OPENSSL_API void OPENSSL_CALL rsaUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _symmetric_algorithm) { // Initial sanity check of our arguments if (len_pem_private_key == 0) @@ -614,7 +631,7 @@ OPENSSL_API void OPENSSL_CALL rsaUnseal(ICodeContext *ctx, size32_t & __lenResul try { // Load the private key - EVP_PKEY * privateKey = pkeyCache.checkCache(len_pem_private_key, _pem_private_key); + EVP_PKEY * privateKey = pkeyCache.checkCache(len_pem_private_key, _pem_private_key, len_passphrase, _passphrase); // Load the cipher const EVP_CIPHER * cipher = cipherCache.checkCache(_symmetric_algorithm); @@ -716,7 +733,7 @@ OPENSSL_API void OPENSSL_CALL rsaEncrypt(ICodeContext *ctx, size32_t & __lenResu try { // Load key from buffer - EVP_PKEY * publicKey = pkeyCache.checkCache(len_pem_public_key, _pem_public_key); + EVP_PKEY * publicKey = pkeyCache.checkCache(len_pem_public_key, _pem_public_key, 0, nullptr); // Create encryption context encryptCtx = EVP_PKEY_CTX_new(publicKey, nullptr); @@ -752,7 +769,7 @@ OPENSSL_API void OPENSSL_CALL rsaEncrypt(ICodeContext *ctx, size32_t & __lenResu } } -OPENSSL_API void OPENSSL_CALL rsaDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_pem_private_key, const char * _pem_private_key) +OPENSSL_API void OPENSSL_CALL rsaDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key) { __result = nullptr; __lenResult = 0; @@ -768,7 +785,7 @@ OPENSSL_API void OPENSSL_CALL rsaDecrypt(ICodeContext *ctx, size32_t & __lenResu try { // Load key from buffer - EVP_PKEY * privateKey = pkeyCache.checkCache(len_pem_private_key, _pem_private_key); + EVP_PKEY * privateKey = pkeyCache.checkCache(len_pem_private_key, _pem_private_key, len_passphrase, _passphrase); // Create decryption context decryptCtx = EVP_PKEY_CTX_new(privateKey, nullptr); @@ -804,14 +821,14 @@ OPENSSL_API void OPENSSL_CALL rsaDecrypt(ICodeContext *ctx, size32_t & __lenResu } } -OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _hash_name) +OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _hash_name) { EVP_MD_CTX *mdCtx = nullptr; try { // Load the private key from the PEM string - EVP_PKEY * privateKey = pkeyCache.checkCache(len_pem_private_key, _pem_private_key); + EVP_PKEY * privateKey = pkeyCache.checkCache(len_pem_private_key, _pem_private_key, len_passphrase, _passphrase); // Create and initialize the message digest context mdCtx = EVP_MD_CTX_new(); @@ -856,14 +873,14 @@ OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, } } -OPENSSL_API bool OPENSSL_CALL rsaVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_passphrase, const void * passphrase, size32_t len_pem_public_key, const char * _pem_public_key, const char * _hash_name) +OPENSSL_API bool OPENSSL_CALL rsaVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_pem_public_key, const char * _pem_public_key, const char * _hash_name) { EVP_MD_CTX *mdCtx = nullptr; try { // Load the public key from the PEM string - EVP_PKEY * publicKey = pkeyCache.checkCache(len_pem_public_key, _pem_public_key); + EVP_PKEY * publicKey = pkeyCache.checkCache(len_pem_public_key, _pem_public_key, 0, nullptr); // Create and initialize the message digest context mdCtx = EVP_MD_CTX_new(); diff --git a/plugins/openssl/openssl.hpp b/plugins/openssl/openssl.hpp index 0156da45eb7..6515e1b4efa 100644 --- a/plugins/openssl/openssl.hpp +++ b/plugins/openssl/openssl.hpp @@ -52,11 +52,11 @@ OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenR // RSA functions OPENSSL_API void OPENSSL_CALL rsaSeal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, bool isAll_pem_public_keys, size32_t len_pem_public_keys, const void * _pem_public_keys, const char * _symmetric_algorithm); -OPENSSL_API void OPENSSL_CALL rsaUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_pem_private_key, const char * _pem_private_key, const char * _symmetric_algorithm); +OPENSSL_API void OPENSSL_CALL rsaUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _symmetric_algorithm); OPENSSL_API void OPENSSL_CALL rsaEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_pem_public_key, const char * _pem_public_key); -OPENSSL_API void OPENSSL_CALL rsaDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_pem_private_key, const char * _pem_private_key); -OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm); -OPENSSL_API bool OPENSSL_CALL rsaVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_passphrase, const void * passphrase, size32_t len_pem_public_key, const char * _pem_public_key, const char * _algorithm); +OPENSSL_API void OPENSSL_CALL rsaDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key); +OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm); +OPENSSL_API bool OPENSSL_CALL rsaVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_pem_public_key, const char * _pem_public_key, const char * _algorithm); } #endif // ECL_OPENSSL_INCL diff --git a/plugins/proxies/lib_openssl.ecllib b/plugins/proxies/lib_openssl.ecllib index 93e678832e9..7a89127712c 100644 --- a/plugins/proxies/lib_openssl.ecllib +++ b/plugins/proxies/lib_openssl.ecllib @@ -30,10 +30,10 @@ export OpenSSL := SERVICE : plugin('openssl') // RSA DATA rsaSeal(DATA _plaintext, SET OF STRING _pem_public_keys, VARSTRING _symmetric_algorithm) : cpp,action,context,entrypoint='rsaSeal'; - DATA rsaUnseal(DATA _ciphertext, STRING _pem_private_key, VARSTRING _symmetric_algorithm) : cpp,action,context,entrypoint='rsaUnseal'; + DATA rsaUnseal(DATA _ciphertext, DATA _passphrase, STRING _pem_private_key, VARSTRING _symmetric_algorithm) : cpp,action,context,entrypoint='rsaUnseal'; DATA rsaEncrypt(DATA _plaintext, STRING _pem_public_key) : cpp,action,context,entrypoint='rsaEncrypt'; - DATA rsaDecrypt(DATA _ciphertext, STRING _pem_private_key) : cpp,action,context,entrypoint='rsaDecrypt'; + DATA rsaDecrypt(DATA _ciphertext, DATA _passphrase, STRING _pem_private_key) : cpp,action,context,entrypoint='rsaDecrypt'; DATA rsaSign(DATA _plaintext, DATA _passphrase, STRING _pem_private_key, VARSTRING _hash_name) : cpp,action,context,entrypoint='rsaSign'; - BOOLEAN rsaVerifySignature(DATA _signature, DATA _signedData, DATA _passphrase, STRING _pem_public_key, VARSTRING _hash_name) : cpp,action,context,entrypoint='rsaVerifySignature'; + BOOLEAN rsaVerifySignature(DATA _signature, DATA _signedData, STRING _pem_public_key, VARSTRING _hash_name) : cpp,action,context,entrypoint='rsaVerifySignature'; END; From d0ce48b89c57c191f20bcc5a5a47dc532dd01227 Mon Sep 17 00:00:00 2001 From: Jack Del Vecchio Date: Fri, 6 Dec 2024 08:49:05 -0500 Subject: [PATCH 4/8] Set consistent variable name for the selected algorithm to algorithm_name --- ecllibrary/std/OpenSSL.ecl | 120 +++++++++++++++-------------- plugins/openssl/openssl.cpp | 48 ++++++------ plugins/openssl/openssl.hpp | 16 ++-- plugins/proxies/lib_openssl.ecllib | 16 ++-- 4 files changed, 104 insertions(+), 96 deletions(-) diff --git a/ecllibrary/std/OpenSSL.ecl b/ecllibrary/std/OpenSSL.ecl index b0ef3bf28c7..6afac9ea558 100644 --- a/ecllibrary/std/OpenSSL.ecl +++ b/ecllibrary/std/OpenSSL.ecl @@ -24,9 +24,14 @@ EXPORT Digest := MODULE /** * Returns a list of the names of the available hash digest algorithms. * + * This is primarily an introspection/discovery function. Once + * you determine the algorithm you want to use, you should hardcode it. + * * @return A dataset containing the hash algorithm names. * * @see Hash() + * RSA.Sign() + * RSA.VerifySignature() */ EXPORT DATASET({STRING name}) AvailableAlgorithms() := lib_openssl.OpenSSL.digestAvailableAlgorithms(); @@ -34,17 +39,17 @@ EXPORT Digest := MODULE * Compute the hash of given data according to the named * hash algorithm. * - * @param indata The data to hash; REQUIRED - * @param hash_name The name of the hash algorithm to use; - * must be one of the values returned from - * the AvailableAlgorithms() function in - * this module; cannot be empty; REQUIRED + * @param indata The data to hash; REQUIRED + * @param algorithm_name The name of the hash algorithm to use; + * must be one of the values returned from + * the AvailableAlgorithms() function in + * this module; cannot be empty; REQUIRED * * @return A DATA value representing the hash value of indata. * * @see AvailableAlgorithms() */ - EXPORT DATA Hash(DATA _indata, VARSTRING _hash_name) := lib_openssl.OpenSSL.digesthash(_indata, _hash_name); + EXPORT DATA Hash(DATA indata, VARSTRING algorithm_name) := lib_openssl.OpenSSL.digesthash(indata, algorithm_name); END; // Digest @@ -54,6 +59,9 @@ EXPORT Ciphers := MODULE * Returns a list of the names of the available symmetric * cipher algorithms. * + * This is primarily an introspection/discovery function. Once + * you determine the algorithm you want to use, you should hardcode it. + * * @return A dataset containing the symmetric cipher algorithm names. * * @see IVSize() @@ -71,16 +79,16 @@ EXPORT Ciphers := MODULE * you determine the proper value for the algorithm you want to * use, you should hardcode it. * - * @param algorithm The name of the symmetric cipher to examine; - * must be one of the values returned from - * the AvailableAlgorithms() function in - * this module; cannot be empty; REQUIRED + * @param algorithm_name The name of the symmetric cipher to examine; + * must be one of the values returned from + * the AvailableAlgorithms() function in + * this module; cannot be empty; REQUIRED * * @return The size of the IV used by the given algorithm, in bytes. * * @see AvailableAlgorithms() */ - EXPORT UNSIGNED2 IVSize(VARSTRING algorithm) := lib_openssl.OpenSSL.cipherIVSize(algorithm); + EXPORT UNSIGNED2 IVSize(VARSTRING algorithm_name) := lib_openssl.OpenSSL.cipherIVSize(algorithm_name); /** * Return the size of the salt used for the given symmetric @@ -90,16 +98,16 @@ EXPORT Ciphers := MODULE * you determine the proper value for the algorithm you want to * use, you should hardcode it. * - * @param algorithm The name of the symmetric cipher to examine; - * must be one of the values returned from - * the AvailableAlgorithms() function in - * this module; cannot be empty; REQUIRED + * @param algorithm_name The name of the symmetric cipher to examine; + * must be one of the values returned from + * the AvailableAlgorithms() function in + * this module; cannot be empty; REQUIRED * * @return The size of the salt used by the given algorithm, in bytes. * * @see AvailableAlgorithms() */ - EXPORT UNSIGNED2 SaltSize(VARSTRING algorithm) := 8; + EXPORT UNSIGNED2 SaltSize(VARSTRING algorithm_name) := 8; /** * Encrypt some plaintext with the given symmetric cipher and a @@ -109,21 +117,21 @@ EXPORT Ciphers := MODULE * If IV or salt values are explicitly provided during encryption then * those same values must be provided during decryption. * - * @param plaintext The data to encrypt; REQUIRED - * @param algorithm The name of the symmetric cipher to use; - * must be one of the values returned from - * the AvailableAlgorithms() function in - * this module; cannot be empty; REQUIRED - * @param iv The IV to use during encryption; if not set - * then a random value will be generated; if set, - * it must be of the expected size for the given - * algorithm; OPTIONAL, defaults to creating a - * random value - * @param salt TCURRENT_OPENSSL_VERSIONencryption; if not set - * then a random value will be generated; if set, - * it must be of the expected size for the given - * algorithm; OPTIONAL, defaults to creating a - * random value + * @param plaintext The data to encrypt; REQUIRED + * @param algorithm_name The name of the symmetric cipher to use; + * must be one of the values returned from + * the AvailableAlgorithms() function in + * this module; cannot be empty; REQUIRED + * @param iv The IV to use during encryption; if not set + * then a random value will be generated; if set, + * it must be of the expected size for the given + * algorithm; OPTIONAL, defaults to creating a + * random value + * @param salt The salt to use during encryption; if not set + * then a random value will be generated; if set, + * it must be of the expected size for the given + * algorithm; OPTIONAL, defaults to creating a + * random value * * @return The ciphertext as a DATA type. * @@ -132,7 +140,7 @@ EXPORT Ciphers := MODULE * SaltSize() * Decrypt() */ - EXPORT DATA Encrypt(DATA plaintext, VARSTRING algorithm, DATA passphrase, DATA iv = (DATA)'', DATA salt = (DATA)'') := lib_openssl.OpenSSL.cipherEncrypt(plaintext, algorithm, passphrase, iv, salt); + EXPORT DATA Encrypt(DATA plaintext, VARSTRING algorithm_name, DATA passphrase, DATA iv = (DATA)'', DATA salt = (DATA)'') := lib_openssl.OpenSSL.cipherEncrypt(plaintext, algorithm_name, passphrase, iv, salt); /** @@ -140,21 +148,21 @@ EXPORT Ciphers := MODULE * passphrase. Optionally, you can specify static IV and salt values. * The decrypted plaintext is returned as a DATA value. * - * @param ciphertext The data to decrypt; REQUIRED - * @param algorithm The name of the symmetric cipher to use; - * must be one of the values returned from - * the AvailableAlgorithms() function in - * this module; cannot be empty; REQUIRED - * @param iv The IV to use during decryption; if not set - * then a random value will be used; if set, - * it must be of the expected size for the given - * algorithm; OPTIONAL, defaults to creating a - * random value - * @param salt The salt to use during decryption; if not set - * then a random value will be used; if set, - * it must be of the expected size for the given - * algorithm; OPTIONAL, defaults to creating a - * random value + * @param ciphertext The data to decrypt; REQUIRED + * @param algorithm_name The name of the symmetric cipher to use; + * must be one of the values returned from + * the AvailableAlgorithms() function in + * this module; cannot be empty; REQUIRED + * @param iv The IV to use during decryption; if not set + * then a random value will be used; if set, + * it must be of the expected size for the given + * algorithm; OPTIONAL, defaults to creating a + * random value + * @param salt The salt to use during decryption; if not set + * then a random value will be used; if set, + * it must be of the expected size for the given + * algorithm; OPTIONAL, defaults to creating a + * random value * * @return The plaintext as a DATA type. * @@ -163,7 +171,7 @@ EXPORT Ciphers := MODULE * SaltSize() * Encrypt() */ - EXPORT DATA Decrypt(DATA ciphertext, VARSTRING algorithm, DATA passphrase, DATA iv = (DATA)'', DATA salt = (DATA)'') := lib_openssl.OpenSSL.cipherDecrypt(ciphertext, algorithm, passphrase, iv, salt); + EXPORT DATA Decrypt(DATA ciphertext, VARSTRING algorithm_name, DATA passphrase, DATA iv = (DATA)'', DATA salt = (DATA)'') := lib_openssl.OpenSSL.cipherDecrypt(ciphertext, algorithm_name, passphrase, iv, salt); END; // Ciphers EXPORT RSA := MODULE @@ -192,7 +200,7 @@ EXPORT RSA := MODULE * more than one public key here, and the resulting * ciphertext can be decrypted by any one of the * corresponding private keys; REQUIRED - * @param symmetric_algorithm The name of the symmetric algorithm to use + * @param algorithm_name The name of the symmetric algorithm to use * to encrypt the payload; must be one of those * returned by Ciphers.AvailableAlgorithms(); * OPTIONAL, defaults to aes-256-cbc @@ -202,7 +210,7 @@ EXPORT RSA := MODULE * @see Unseal() * Ciphers.AvailableAlgorithms() */ - EXPORT DATA Seal(DATA plaintext, SET OF STRING pem_public_keys, VARSTRING symmetric_algorithm = 'aes-256-cbc') := lib_openssl.OpenSSL.rsaSeal(plaintext, pem_public_keys, symmetric_algorithm); + EXPORT DATA Seal(DATA plaintext, SET OF STRING pem_public_keys, VARSTRING algorithm_name = 'aes-256-cbc') := lib_openssl.OpenSSL.rsaSeal(plaintext, pem_public_keys, algorithm_name); /** * Decrypts ciphertext previously generated by the Seal() function. @@ -230,7 +238,7 @@ EXPORT RSA := MODULE * the private key, an empty string must be * passed in (e.g. (DATA)''); REQUIRED * @param pem_private_key An RSA public key in PEM format; REQUIRED - * @param symmetric_algorithm The name of the symmetric algorithm to use + * @param algorithm_name The name of the symmetric algorithm to use * to decrypt the payload; must be one of those * returned by Ciphers.AvailableAlgorithms() and * it must match the algorithm used to create the @@ -241,7 +249,7 @@ EXPORT RSA := MODULE * @see Seal() * Ciphers.AvailableAlgorithms() */ - EXPORT DATA Unseal(DATA ciphertext, DATA passphrase, STRING pem_private_key, VARSTRING symmetric_algorithm = 'aes-256-cbc') := lib_openssl.OpenSSL.rsaUnseal(ciphertext, passphrase, pem_private_key, symmetric_algorithm); + EXPORT DATA Unseal(DATA ciphertext, DATA passphrase, STRING pem_private_key, VARSTRING algorithm_name = 'aes-256-cbc') := lib_openssl.OpenSSL.rsaUnseal(ciphertext, passphrase, pem_private_key, algorithm_name); /** * This function performs asymmetric encryption. It should be used to @@ -296,7 +304,7 @@ EXPORT RSA := MODULE * the private key, an empty string must be * passed in (e.g. (DATA)''); REQUIRED * @param pem_private_key Private key to use for signing; REQUIRED - * @param hash_name The name of the hash algorithm to use; + * @param algorithm_name The name of the hash algorithm to use; * must be one of the values returned from * the AvailableAlgorithms() function in * the Digest module; cannot be empty; REQUIRED @@ -305,7 +313,7 @@ EXPORT RSA := MODULE * @see Digest.AvailableAlgorithms() * VerifySignature() */ - EXPORT DATA Sign(DATA plaintext, DATA passphrase, STRING pem_private_key, VARSTRING hash_name) := lib_openssl.OpenSSL.rsaSign(plaintext, passphrase, pem_private_key, hash_name); + EXPORT DATA Sign(DATA plaintext, DATA passphrase, STRING pem_private_key, VARSTRING algorithm_name) := lib_openssl.OpenSSL.rsaSign(plaintext, passphrase, pem_private_key, algorithm_name); /** * Verify the given digital signature of the given data, using @@ -323,7 +331,7 @@ EXPORT RSA := MODULE * @param signature Signature to verify; REQUIRED * @param signedData Data used to create signature; REQUIRED * @param pem_public_key Public key to use for verification; REQUIRED - * @param hash_name The name of the hash algorithm to use; + * @param algorithm_name The name of the hash algorithm to use; * must be one of the values returned from * the AvailableAlgorithms() function in * the Digest module; cannot be empty; REQUIRED @@ -332,7 +340,7 @@ EXPORT RSA := MODULE * @see Digest.AvailableAlgorithms() * Sign() */ - EXPORT BOOLEAN VerifySignature(DATA signature, DATA signedData, STRING pem_public_key, VARSTRING hash_name) := lib_openssl.OpenSSL.rsaVerifySignature(signature, signedData, pem_public_key, hash_name); + EXPORT BOOLEAN VerifySignature(DATA signature, DATA signedData, STRING pem_public_key, VARSTRING algorithm_name) := lib_openssl.OpenSSL.rsaVerifySignature(signature, signedData, pem_public_key, algorithm_name); END; // RSA diff --git a/plugins/openssl/openssl.cpp b/plugins/openssl/openssl.cpp index 5ecbbf6be0d..3f1c54d00a4 100644 --- a/plugins/openssl/openssl.cpp +++ b/plugins/openssl/openssl.cpp @@ -91,21 +91,21 @@ template class OpenSSLCache { public: - const T * checkCache(const char * algorithm) + const T * checkCache(const char * algorithm_name) { for (auto& c : cache) { - if (std::get<0>(c) == algorithm) + if (std::get<0>(c) == algorithm_name) { hits++; return std::get<1>(c); } } misses++; - const T * newObj = getObjectByName(algorithm); + const T * newObj = getObjectByName(algorithm_name); if (newObj) { - cache.emplace_front(algorithm, newObj); + cache.emplace_front(algorithm_name, newObj); if (cache.size() > OPENSSL_MAX_CACHE_SIZE) cache.pop_back(); } @@ -262,12 +262,12 @@ OPENSSL_API void OPENSSL_CALL digestAvailableAlgorithms(ICodeContext *ctx, size3 } } -OPENSSL_API void OPENSSL_CALL digestHash(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_indata, const void * _indata, const char * _hash_name) +OPENSSL_API void OPENSSL_CALL digestHash(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_indata, const void * _indata, const char * _algorithm_name) { - if (strlen(_hash_name) == 0) + if (strlen(_algorithm_name) == 0) rtlFail(-1, "No hash digest name provided"); - const EVP_MD * md = digestCache.checkCache(_hash_name); + const EVP_MD * md = digestCache.checkCache(_algorithm_name); EVP_MD_CTX * mdContext = EVP_MD_CTX_new(); if (!mdContext) @@ -334,18 +334,18 @@ OPENSSL_API void OPENSSL_CALL cipherAvailableAlgorithms(ICodeContext *ctx, size3 } } -OPENSSL_API uint16_t OPENSSL_CALL cipherIVSize(ICodeContext *ctx, const char * algorithm) +OPENSSL_API uint16_t OPENSSL_CALL cipherIVSize(ICodeContext *ctx, const char * algorithm_name) { - if (strlen(algorithm) == 0) + if (strlen(algorithm_name) == 0) rtlFail(-1, "No algorithm name provided"); // Load the cipher - const EVP_CIPHER * cipher = cipherCache.checkCache(algorithm); + const EVP_CIPHER * cipher = cipherCache.checkCache(algorithm_name); return static_cast(EVP_CIPHER_iv_length(cipher)); } -OPENSSL_API void OPENSSL_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, const char * _algorithm, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt) +OPENSSL_API void OPENSSL_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, const char * _algorithm_name, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt) { __result = nullptr; __lenResult = 0; @@ -354,7 +354,7 @@ OPENSSL_API void OPENSSL_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenR bool hasSalt = (len_salt > 0); // Initial sanity check of our arguments - if (strlen(_algorithm) == 0) + if (strlen(_algorithm_name) == 0) rtlFail(-1, "No algorithm name provided"); if (len_passphrase == 0) rtlFail(-1, "No passphrase provided"); @@ -364,7 +364,7 @@ OPENSSL_API void OPENSSL_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenR if (len_plaintext > 0) { // Load the cipher - const EVP_CIPHER * cipher = cipherCache.checkCache(_algorithm); + const EVP_CIPHER * cipher = cipherCache.checkCache(_algorithm_name); int cipherIVSize = EVP_CIPHER_iv_length(cipher); if (hasIV && len_iv != static_cast(cipherIVSize)) @@ -420,7 +420,7 @@ OPENSSL_API void OPENSSL_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenR } } -OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, const char * _algorithm, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt) +OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, const char * _algorithm_name, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt) { __result = nullptr; __lenResult = 0; @@ -429,7 +429,7 @@ OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenR bool hasSalt = (len_salt > 0); // Initial sanity check of our arguments - if (strlen(_algorithm) == 0) + if (strlen(_algorithm_name) == 0) rtlFail(-1, "No algorithm name provided"); if (len_passphrase == 0) rtlFail(-1, "No passphrase provided"); @@ -439,7 +439,7 @@ OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenR if (len_ciphertext > 0) { // Load the cipher - const EVP_CIPHER * cipher = cipherCache.checkCache(_algorithm); + const EVP_CIPHER * cipher = cipherCache.checkCache(_algorithm_name); int cipherIVSize = EVP_CIPHER_iv_length(cipher); if (hasIV && len_iv != static_cast(cipherIVSize)) @@ -497,7 +497,7 @@ OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenR // RSA functions -OPENSSL_API void OPENSSL_CALL rsaSeal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, bool isAll_pem_public_keys, size32_t len_pem_public_keys, const void * _pem_public_keys, const char * _symmetric_algorithm) +OPENSSL_API void OPENSSL_CALL rsaSeal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, bool isAll_pem_public_keys, size32_t len_pem_public_keys, const void * _pem_public_keys, const char * _algorithm_name) { // Initial sanity check of our arguments if (len_pem_public_keys == 0) @@ -525,7 +525,7 @@ OPENSSL_API void OPENSSL_CALL rsaSeal(ICodeContext *ctx, size32_t & __lenResult, } // Load the cipher - const EVP_CIPHER * cipher = cipherCache.checkCache(_symmetric_algorithm); + const EVP_CIPHER * cipher = cipherCache.checkCache(_algorithm_name); // Allocate memory for encrypted keys size_t keyCount = publicKeys.size(); @@ -615,7 +615,7 @@ OPENSSL_API void OPENSSL_CALL rsaSeal(ICodeContext *ctx, size32_t & __lenResult, } } -OPENSSL_API void OPENSSL_CALL rsaUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _symmetric_algorithm) +OPENSSL_API void OPENSSL_CALL rsaUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name) { // Initial sanity check of our arguments if (len_pem_private_key == 0) @@ -634,7 +634,7 @@ OPENSSL_API void OPENSSL_CALL rsaUnseal(ICodeContext *ctx, size32_t & __lenResul EVP_PKEY * privateKey = pkeyCache.checkCache(len_pem_private_key, _pem_private_key, len_passphrase, _passphrase); // Load the cipher - const EVP_CIPHER * cipher = cipherCache.checkCache(_symmetric_algorithm); + const EVP_CIPHER * cipher = cipherCache.checkCache(_algorithm_name); // Allocate memory for the symmetric key and IV int keyLen = EVP_PKEY_size(privateKey); @@ -821,7 +821,7 @@ OPENSSL_API void OPENSSL_CALL rsaDecrypt(ICodeContext *ctx, size32_t & __lenResu } } -OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _hash_name) +OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name) { EVP_MD_CTX *mdCtx = nullptr; @@ -835,7 +835,7 @@ OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, if (!mdCtx) failOpenSSLError("EVP_MD_CTX_new (rsaSign)"); - const EVP_MD *md = digestCache.checkCache(_hash_name); + const EVP_MD *md = digestCache.checkCache(_algorithm_name); if (EVP_DigestSignInit(mdCtx, nullptr, md, nullptr, privateKey) <= 0) failOpenSSLError("EVP_DigestSignInit (rsaSign)"); @@ -873,7 +873,7 @@ OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, } } -OPENSSL_API bool OPENSSL_CALL rsaVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_pem_public_key, const char * _pem_public_key, const char * _hash_name) +OPENSSL_API bool OPENSSL_CALL rsaVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_pem_public_key, const char * _pem_public_key, const char * _algorithm_name) { EVP_MD_CTX *mdCtx = nullptr; @@ -887,7 +887,7 @@ OPENSSL_API bool OPENSSL_CALL rsaVerifySignature(ICodeContext *ctx, size32_t len if (!mdCtx) failOpenSSLError("EVP_MD_CTX_new"); - const EVP_MD *md = digestCache.checkCache(_hash_name); + const EVP_MD *md = digestCache.checkCache(_algorithm_name); if (EVP_DigestVerifyInit(mdCtx, nullptr, md, nullptr, publicKey) <= 0) failOpenSSLError("EVP_DigestVerifyInit (rsaVerifySignature)"); diff --git a/plugins/openssl/openssl.hpp b/plugins/openssl/openssl.hpp index 6515e1b4efa..fa6bca30e66 100644 --- a/plugins/openssl/openssl.hpp +++ b/plugins/openssl/openssl.hpp @@ -42,21 +42,21 @@ OPENSSL_API bool OPENSSL_CALL getECLPluginDefinition(ECLPluginDefinitionBlock *p // Digest functions OPENSSL_API void OPENSSL_CALL digestAvailableAlgorithms(ICodeContext *ctx, size32_t & __lenResult, void * & __result); -OPENSSL_API void OPENSSL_CALL digestHash(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_indata, const void * _indata, const char * _hash_name); +OPENSSL_API void OPENSSL_CALL digestHash(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_indata, const void * _indata, const char * _algorithm_name); // Cipher functions OPENSSL_API void OPENSSL_CALL cipherAvailableAlgorithms(ICodeContext *ctx, size32_t & __lenResult, void * & __result); -OPENSSL_API uint16_t OPENSSL_CALL cipherIVSize(ICodeContext *ctx, const char * algorithm); -OPENSSL_API void OPENSSL_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, const char * _algorithm, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt); -OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, const char * _algorithm, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt); +OPENSSL_API uint16_t OPENSSL_CALL cipherIVSize(ICodeContext *ctx, const char * _algorithm_name); +OPENSSL_API void OPENSSL_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, const char * _algorithm_name, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt); +OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, const char * _algorithm_name, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt); // RSA functions -OPENSSL_API void OPENSSL_CALL rsaSeal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, bool isAll_pem_public_keys, size32_t len_pem_public_keys, const void * _pem_public_keys, const char * _symmetric_algorithm); -OPENSSL_API void OPENSSL_CALL rsaUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _symmetric_algorithm); +OPENSSL_API void OPENSSL_CALL rsaSeal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, bool isAll_pem_public_keys, size32_t len_pem_public_keys, const void * _pem_public_keys, const char * _algorithm_name); +OPENSSL_API void OPENSSL_CALL rsaUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name); OPENSSL_API void OPENSSL_CALL rsaEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_pem_public_key, const char * _pem_public_key); OPENSSL_API void OPENSSL_CALL rsaDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key); -OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm); -OPENSSL_API bool OPENSSL_CALL rsaVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_pem_public_key, const char * _pem_public_key, const char * _algorithm); +OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name); +OPENSSL_API bool OPENSSL_CALL rsaVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_pem_public_key, const char * _pem_public_key, const char * _algorithm_name); } #endif // ECL_OPENSSL_INCL diff --git a/plugins/proxies/lib_openssl.ecllib b/plugins/proxies/lib_openssl.ecllib index 7a89127712c..e0f67e4f2fe 100644 --- a/plugins/proxies/lib_openssl.ecllib +++ b/plugins/proxies/lib_openssl.ecllib @@ -20,20 +20,20 @@ export OpenSSL := SERVICE : plugin('openssl') // Hash functions DATASET({STRING name}) digestAvailableAlgorithms() : cpp,action,context,entrypoint='digestAvailableAlgorithms'; - DATA digestHash(DATA _indata, VARSTRING _hash_name) : cpp,action,context,entrypoint='digestHash'; + DATA digestHash(DATA _indata, VARSTRING _algorithm_name) : cpp,action,context,entrypoint='digestHash'; // Symmetric ciphers DATASET({STRING name}) cipherAvailableAlgorithms() : cpp,action,context,entrypoint='cipherAvailableAlgorithms'; - UNSIGNED2 cipherIVSize(VARSTRING algorithm) : cpp,action,context,entrypoint='cipherIVSize'; - DATA cipherEncrypt(DATA _plaintext, VARSTRING _algorithm, DATA _passphrase, DATA _iv = (DATA)'', DATA _salt = (DATA)'') : cpp,action,context,entrypoint='cipherEncrypt'; - DATA cipherDecrypt(DATA _ciphertext, VARSTRING _algorithm, DATA _passphrase, DATA _iv = (DATA)'', DATA _salt = (DATA)'') : cpp,action,context,entrypoint='cipherDecrypt'; + UNSIGNED2 cipherIVSize(VARSTRING _algorithm_name) : cpp,action,context,entrypoint='cipherIVSize'; + DATA cipherEncrypt(DATA _plaintext, VARSTRING _algorithm_name, DATA _passphrase, DATA _iv = (DATA)'', DATA _salt = (DATA)'') : cpp,action,context,entrypoint='cipherEncrypt'; + DATA cipherDecrypt(DATA _ciphertext, VARSTRING _algorithm_name, DATA _passphrase, DATA _iv = (DATA)'', DATA _salt = (DATA)'') : cpp,action,context,entrypoint='cipherDecrypt'; // RSA - DATA rsaSeal(DATA _plaintext, SET OF STRING _pem_public_keys, VARSTRING _symmetric_algorithm) : cpp,action,context,entrypoint='rsaSeal'; - DATA rsaUnseal(DATA _ciphertext, DATA _passphrase, STRING _pem_private_key, VARSTRING _symmetric_algorithm) : cpp,action,context,entrypoint='rsaUnseal'; + DATA rsaSeal(DATA _plaintext, SET OF STRING _pem_public_keys, VARSTRING _algorithm_name) : cpp,action,context,entrypoint='rsaSeal'; + DATA rsaUnseal(DATA _ciphertext, DATA _passphrase, STRING _pem_private_key, VARSTRING _algorithm_name) : cpp,action,context,entrypoint='rsaUnseal'; DATA rsaEncrypt(DATA _plaintext, STRING _pem_public_key) : cpp,action,context,entrypoint='rsaEncrypt'; DATA rsaDecrypt(DATA _ciphertext, DATA _passphrase, STRING _pem_private_key) : cpp,action,context,entrypoint='rsaDecrypt'; - DATA rsaSign(DATA _plaintext, DATA _passphrase, STRING _pem_private_key, VARSTRING _hash_name) : cpp,action,context,entrypoint='rsaSign'; - BOOLEAN rsaVerifySignature(DATA _signature, DATA _signedData, STRING _pem_public_key, VARSTRING _hash_name) : cpp,action,context,entrypoint='rsaVerifySignature'; + DATA rsaSign(DATA _plaintext, DATA _passphrase, STRING _pem_private_key, VARSTRING _algorithm_name) : cpp,action,context,entrypoint='rsaSign'; + BOOLEAN rsaVerifySignature(DATA _signature, DATA _signedData, STRING _pem_public_key, VARSTRING _algorithm_name) : cpp,action,context,entrypoint='rsaVerifySignature'; END; From 65534b392deb7517f044040d9b96430a510ee6f5 Mon Sep 17 00:00:00 2001 From: Jack Del Vecchio Date: Tue, 10 Dec 2024 14:47:13 -0500 Subject: [PATCH 5/8] Use passphrases with private keys if they are passed in --- ecllibrary/std/OpenSSL.ecl | 30 +++++---- ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl | 33 ++++++---- plugins/openssl/CMakeLists.txt | 74 +++++++++++----------- plugins/openssl/openssl.cpp | 48 +++++++++----- plugins/openssl/openssl.hpp | 14 ++-- plugins/proxies/CMakeLists.txt | 5 +- plugins/proxies/lib_openssl.ecllib | 14 ++-- 7 files changed, 127 insertions(+), 91 deletions(-) diff --git a/ecllibrary/std/OpenSSL.ecl b/ecllibrary/std/OpenSSL.ecl index 6afac9ea558..8ccb08ef125 100644 --- a/ecllibrary/std/OpenSSL.ecl +++ b/ecllibrary/std/OpenSSL.ecl @@ -122,6 +122,10 @@ EXPORT Ciphers := MODULE * must be one of the values returned from * the AvailableAlgorithms() function in * this module; cannot be empty; REQUIRED + * @param passphrase Passphrase to use for private key; + * If no passphrase was used when generating + * the private key, an empty string must be + * passed in (e.g. (DATA)''); REQUIRED * @param iv The IV to use during encryption; if not set * then a random value will be generated; if set, * it must be of the expected size for the given @@ -153,6 +157,10 @@ EXPORT Ciphers := MODULE * must be one of the values returned from * the AvailableAlgorithms() function in * this module; cannot be empty; REQUIRED + * @param passphrase Passphrase to use for private key; + * If no passphrase was used when generating + * the private key, an empty string must be + * passed in (e.g. (DATA)''); REQUIRED * @param iv The IV to use during decryption; if not set * then a random value will be used; if set, * it must be of the expected size for the given @@ -174,7 +182,7 @@ EXPORT Ciphers := MODULE EXPORT DATA Decrypt(DATA ciphertext, VARSTRING algorithm_name, DATA passphrase, DATA iv = (DATA)'', DATA salt = (DATA)'') := lib_openssl.OpenSSL.cipherDecrypt(ciphertext, algorithm_name, passphrase, iv, salt); END; // Ciphers -EXPORT RSA := MODULE +EXPORT PublicKey := MODULE /** * Perform a hybrid encryption using one or more RSA public keys. @@ -210,7 +218,7 @@ EXPORT RSA := MODULE * @see Unseal() * Ciphers.AvailableAlgorithms() */ - EXPORT DATA Seal(DATA plaintext, SET OF STRING pem_public_keys, VARSTRING algorithm_name = 'aes-256-cbc') := lib_openssl.OpenSSL.rsaSeal(plaintext, pem_public_keys, algorithm_name); + EXPORT DATA RSASeal(DATA plaintext, SET OF STRING pem_public_keys, VARSTRING algorithm_name = 'aes-256-cbc') := lib_openssl.OpenSSL.pkRSASeal(plaintext, pem_public_keys, algorithm_name); /** * Decrypts ciphertext previously generated by the Seal() function. @@ -249,7 +257,7 @@ EXPORT RSA := MODULE * @see Seal() * Ciphers.AvailableAlgorithms() */ - EXPORT DATA Unseal(DATA ciphertext, DATA passphrase, STRING pem_private_key, VARSTRING algorithm_name = 'aes-256-cbc') := lib_openssl.OpenSSL.rsaUnseal(ciphertext, passphrase, pem_private_key, algorithm_name); + EXPORT DATA RSAUnseal(DATA ciphertext, DATA passphrase, STRING pem_private_key, VARSTRING algorithm_name = 'aes-256-cbc') := lib_openssl.OpenSSL.pkRSAUnseal(ciphertext, passphrase, pem_private_key, algorithm_name); /** * This function performs asymmetric encryption. It should be used to @@ -264,7 +272,7 @@ EXPORT RSA := MODULE * * @see Decrypt() */ - EXPORT DATA Encrypt(DATA plaintext, STRING pem_public_key) := lib_openssl.OpenSSL.rsaEncrypt(plaintext, pem_public_key); + EXPORT DATA Encrypt(DATA plaintext, STRING pem_public_key) := lib_openssl.OpenSSL.pkEncrypt(plaintext, pem_public_key); /** * This function performs asymmetric decryption. It should be used to @@ -283,7 +291,7 @@ EXPORT RSA := MODULE * * @see Encrypt() */ - EXPORT DATA Decrypt(DATA ciphertext, DATA passphrase, STRING pem_private_key) := lib_openssl.OpenSSL.rsaDecrypt(ciphertext, passphrase, pem_private_key); + EXPORT DATA Decrypt(DATA ciphertext, DATA passphrase, STRING pem_private_key) := lib_openssl.OpenSSL.pkDecrypt(ciphertext, passphrase, pem_private_key); /** * Create a digital signature of the given data, using the @@ -306,14 +314,14 @@ EXPORT RSA := MODULE * @param pem_private_key Private key to use for signing; REQUIRED * @param algorithm_name The name of the hash algorithm to use; * must be one of the values returned from - * the AvailableAlgorithms() function in - * the Digest module; cannot be empty; REQUIRED + * the AvailableAlgorithms() function in the + * Digest module; OPTIONAL, defaults to sha256 * @return Computed Digital signature * * @see Digest.AvailableAlgorithms() * VerifySignature() */ - EXPORT DATA Sign(DATA plaintext, DATA passphrase, STRING pem_private_key, VARSTRING algorithm_name) := lib_openssl.OpenSSL.rsaSign(plaintext, passphrase, pem_private_key, algorithm_name); + EXPORT DATA Sign(DATA plaintext, DATA passphrase, STRING pem_private_key, VARSTRING algorithm_name = 'sha256') := lib_openssl.OpenSSL.pkSign(plaintext, passphrase, pem_private_key, algorithm_name); /** * Verify the given digital signature of the given data, using @@ -333,14 +341,14 @@ EXPORT RSA := MODULE * @param pem_public_key Public key to use for verification; REQUIRED * @param algorithm_name The name of the hash algorithm to use; * must be one of the values returned from - * the AvailableAlgorithms() function in - * the Digest module; cannot be empty; REQUIRED + * the AvailableAlgorithms() function in the + * Digest module; OPTIONAL, defaults to sha256 * @return Boolean TRUE/FALSE * * @see Digest.AvailableAlgorithms() * Sign() */ - EXPORT BOOLEAN VerifySignature(DATA signature, DATA signedData, STRING pem_public_key, VARSTRING algorithm_name) := lib_openssl.OpenSSL.rsaVerifySignature(signature, signedData, pem_public_key, algorithm_name); + EXPORT BOOLEAN VerifySignature(DATA signature, DATA signedData, STRING pem_public_key, VARSTRING algorithm_name = 'sha256') := lib_openssl.OpenSSL.pkVerifySignature(signature, signedData, pem_public_key, algorithm_name); END; // RSA diff --git a/ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl b/ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl index 5f8b8b7400b..8d45cceb1fc 100644 --- a/ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl +++ b/ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl @@ -168,12 +168,15 @@ EXPORT TestOpenSSL := MODULE EXPORT encrypt_default_iv_my_salt := Std.OpenSSL.Ciphers.Encrypt((DATA)PLAINTEXT, CIPHERS_CIPHER, (DATA)PASSPHRASE, salt := (>DATA<)staticSalt); EXPORT encrypt_my_iv_default_salt := Std.OpenSSL.Ciphers.Encrypt((DATA)PLAINTEXT, CIPHERS_CIPHER, (DATA)PASSPHRASE, iv := staticIV); EXPORT encrypt_default_iv_default_salt := Std.OpenSSL.Ciphers.Encrypt((DATA)PLAINTEXT, CIPHERS_CIPHER, (DATA)PASSPHRASE); - EXPORT encrypt_rsa := Std.OpenSSL.RSA.Encrypt((DATA)PLAINTEXT, RSA_PUBLIC_1); - EXPORT encrypt_rsa_passphrase := Std.OpenSSL.RSA.Encrypt((DATA)PLAINTEXT, RSA_PUBLIC_2); - EXPORT seal_rsa := Std.OpenSSL.RSA.Seal((DATA)PLAINTEXT, [RSA_PUBLIC_1, RSA_PUBLIC_2]); - EXPORT signed_rsa_sha256 := Std.OpenSSL.RSA.Sign((DATA)PLAINTEXT, (DATA)'', RSA_PRIVATE_1, 'sha256'); - EXPORT signed_rsa_sha256_passphrase := Std.OpenSSL.RSA.Sign((DATA)PLAINTEXT, (DATA)PASSPHRASE, RSA_PRIVATE_2, 'SHA256'); - // EXPORT signed_rsa_sha256_wrong_passphrase := Std.OpenSSL.RSA.Sign((DATA)PLAINTEXT, (DATA)'notmypassphrase', RSA_PRIVATE_2, 'SHA256'); Fails with Error: -1: Error within loading a pkey: error:1C800064:Provider routines::bad decrypt + EXPORT encrypt_rsa := Std.OpenSSL.PublicKey.Encrypt((DATA)PLAINTEXT, RSA_PUBLIC_1); + EXPORT encrypt_rsa_passphrase := Std.OpenSSL.PublicKey.Encrypt((DATA)PLAINTEXT, RSA_PUBLIC_2); + EXPORT seal_rsa := Std.OpenSSL.PublicKey.RSASeal((DATA)PLAINTEXT, [RSA_PUBLIC_1, RSA_PUBLIC_2]); + EXPORT signed_rsa_sha256 := Std.OpenSSL.PublicKey.Sign((DATA)PLAINTEXT, (DATA)'', RSA_PRIVATE_1); + EXPORT signed_rsa_sha256_passphrase := Std.OpenSSL.PublicKey.Sign((DATA)PLAINTEXT, (DATA)PASSPHRASE, RSA_PRIVATE_2, 'SHA256'); + + // Fails to sign with the wrong passphrase and throws an exception + // There is no clean way to capture this exception, so it is not tested here + // EXPORT signed_rsa_sha256_wrong_passphrase := Std.OpenSSL.PublicKey.Sign((DATA)PLAINTEXT, (DATA)'notmypassphrase', RSA_PRIVATE_2, 'SHA256'); Fails with Error: -1: Error within loading a pkey: error:1C800064:Provider routines::bad decrypt EXPORT TestDigests := [ ASSERT(COUNT(Std.OpenSSL.Digest.AvailableAlgorithms()) > 0, 'No digest algorithms available'); @@ -207,11 +210,11 @@ EXPORT TestOpenSSL := MODULE EXPORT TestRSA := [ ASSERT(LENGTH(encrypt_rsa) = 512); - ASSERT((STRING)Std.OpenSSL.RSA.Decrypt((DATA)encrypt_rsa, (DATA)'', RSA_PRIVATE_1) = PLAINTEXT); - ASSERT((STRING)Std.OpenSSL.RSA.Decrypt((DATA)encrypt_rsa_passphrase, (DATA)PASSPHRASE, RSA_PRIVATE_2) = PLAINTEXT); + ASSERT((STRING)Std.OpenSSL.PublicKey.Decrypt((DATA)encrypt_rsa, (DATA)'', RSA_PRIVATE_1) = PLAINTEXT); + ASSERT((STRING)Std.OpenSSL.PublicKey.Decrypt((DATA)encrypt_rsa_passphrase, (DATA)PASSPHRASE, RSA_PRIVATE_2) = PLAINTEXT); ASSERT(LENGTH(seal_rsa) = 1112); - ASSERT((STRING)Std.OpenSSL.RSA.Unseal((DATA)seal_rsa, (DATA)'', RSA_PRIVATE_1) = PLAINTEXT); - ASSERT((STRING)Std.OpenSSL.RSA.Unseal((DATA)seal_rsa, (DATA)PASSPHRASE, RSA_PRIVATE_2) = PLAINTEXT); + ASSERT((STRING)Std.OpenSSL.PublicKey.RSAUnseal((DATA)seal_rsa, (DATA)'', RSA_PRIVATE_1) = PLAINTEXT); + ASSERT((STRING)Std.OpenSSL.PublicKey.RSAUnseal((DATA)seal_rsa, (DATA)PASSPHRASE, RSA_PRIVATE_2) = PLAINTEXT); ASSERT(Std.Str.ToHexPairs(signed_rsa_sha256) = '399F5FCB9B1A3C02D734BF3F1C9CB480681126B0F7505697E045ECF22E11A47FADCF7E2BA73761AD6345F6702AAD230957AFA1B0B3C8C29FC537AACA68' + '13B79DE0CDEF82B4BB6183D0637583D0E2AA78892EE190D7AB9CB20F9AC36D91DB2994A07F0C17A0CFB5AF0385EA4ABA9723FC72FB08081AE4C6C83E659AEBA1C103FB6F4E831EFDAA4CE037A3874D59664B1DE90' + @@ -221,8 +224,8 @@ EXPORT TestOpenSSL := MODULE 'C573C9EBE9FE472131A39D60ED53624745A79A29B31D07DE38D1FA64D3DB32EF447F62B64F8A07C012E55C06551F5C60509797A4521DC4E7CB33F9C0759E6B46DA6B758C86E26507CA9D79933532BE923FC449842' + '17A203F97B97606E18E9F4949DC5E6C21705A89844B316093EFD8C0CC'); ASSERT(LENGTH(signed_rsa_sha256) = 512); - ASSERT(Std.OpenSSL.RSA.VerifySignature((DATA)signed_rsa_sha256, (DATA)PLAINTEXT, RSA_PUBLIC_1, 'sha256') = TRUE); - ASSERT(Std.OpenSSL.RSA.VerifySignature((DATA)((UNSIGNED)signed_rsa_sha256 + 1), (DATA)PLAINTEXT, RSA_PUBLIC_1, 'sha256') = FALSE); + ASSERT(Std.OpenSSL.PublicKey.VerifySignature((DATA)signed_rsa_sha256, (DATA)PLAINTEXT, RSA_PUBLIC_1, 'sha256') = TRUE); + ASSERT(Std.OpenSSL.PublicKey.VerifySignature((DATA)((UNSIGNED)signed_rsa_sha256 + 1), (DATA)PLAINTEXT, RSA_PUBLIC_1, 'sha256') = FALSE); ASSERT(Std.Str.ToHexPairs(signed_rsa_sha256_passphrase) = '448BD2397EB945D508E81A0AE45A01BB9799CAEDC8EEA779798BB07B5CB0C7D3FD571FF602298214F68B5215F039CEE1E2D6D75112A5CCD' + 'A95875C2774779893101907F0F2BD7C259CB2A0519FAE1A015F48D025A446D69C9E50EA8DB0EC071E53178E6550E13E52ACDA9466D012590AAB358F25E68E91AAEC63E1323823CF48004D27406236079C0610347A' + '9A6F4B9B58496DE430C0DDF4BFBD9DC333910EA14F3D8E9F7ADCF8FF9BE4C2AE4735CFE38C2B7F6D08313FA6CDF9E836B7156566851E65165907B74DB1A45D4C404423E5AF34C3972231AE4F18455C90448B0459F' + @@ -231,9 +234,11 @@ EXPORT TestOpenSSL := MODULE '012A8A61A76990085F386495BE729B16D6646D754D3F0AEAD89BA044A8BB9813437F344A579DA4676438CDB7BB98EA396C98E86CBB3FCA1BC46A392E23A52AE177F6C798793146081FD0FD637570D9A718C148E17' + 'FFC502936F4FC09E35592B4B7C2FFB1DFE6B7F4CC766595D47A630AB1A58CDD11716'); ASSERT(LENGTH(signed_rsa_sha256_passphrase) = 512); - ASSERT(Std.OpenSSL.RSA.VerifySignature((DATA)signed_rsa_sha256_passphrase, (DATA)PLAINTEXT, RSA_PUBLIC_2, 'SHA256') = TRUE); - ASSERT(Std.OpenSSL.RSA.VerifySignature((DATA)((UNSIGNED)signed_rsa_sha256_passphrase + 1), (DATA)PLAINTEXT, RSA_PUBLIC_2, 'SHA256') = FALSE); + ASSERT(Std.OpenSSL.PublicKey.VerifySignature((DATA)signed_rsa_sha256_passphrase, (DATA)PLAINTEXT, RSA_PUBLIC_2, 'SHA256') = TRUE); + ASSERT(Std.OpenSSL.PublicKey.VerifySignature((DATA)((UNSIGNED)signed_rsa_sha256_passphrase + 1), (DATA)PLAINTEXT, RSA_PUBLIC_2, 'SHA256') = FALSE); + // Fails to sign with the wrong passphrase and throws an exception + // There is no clean way to capture this exception, so it is not tested here // ASSERT(LENGTH(signed_rsa_sha256_wrong_passphrase) = 0); // fails with "Error: -1: Error within loading a pkey: error:1C800064:Provider routines::bad decrypt" ASSERT(TRUE) diff --git a/plugins/openssl/CMakeLists.txt b/plugins/openssl/CMakeLists.txt index 6d56cfa6447..6960d1f83a7 100644 --- a/plugins/openssl/CMakeLists.txt +++ b/plugins/openssl/CMakeLists.txt @@ -24,39 +24,41 @@ project(openssl) -find_package(OpenSSL REQUIRED) - -set( - SRCS - openssl.hpp - openssl.cpp -) - -include_directories( - ${HPCC_SOURCE_DIR}/system/include - ${HPCC_SOURCE_DIR}/rtl/eclrtl - ${HPCC_SOURCE_DIR}/rtl/include - ${HPCC_SOURCE_DIR}/common/deftype - ${HPCC_SOURCE_DIR}/system/jlib -) - -add_definitions(-D_USRDLL -DECL_OPENSSL_EXPORTS) -HPCC_ADD_LIBRARY(openssl SHARED ${SRCS}) - -install( - TARGETS openssl - DESTINATION plugins CALC_DEPS -) -install( - FILES ${OPENSSL_LIBRARIES} - DESTINATION ${LIB_DIR} - COMPONENT Runtime -) - -target_link_libraries( - openssl - eclrtl - jlib - OpenSSL::SSL - OpenSSL::Crypto -) +if (PLATFORM AND USE_OPENSSLV3) + find_package(OpenSSL REQUIRED) + + set( + SRCS + openssl.hpp + openssl.cpp + ) + + include_directories( + ${HPCC_SOURCE_DIR}/system/include + ${HPCC_SOURCE_DIR}/rtl/eclrtl + ${HPCC_SOURCE_DIR}/rtl/include + ${HPCC_SOURCE_DIR}/common/deftype + ${HPCC_SOURCE_DIR}/system/jlib + ) + + add_definitions(-D_USRDLL -DECL_OPENSSL_EXPORTS) + HPCC_ADD_LIBRARY(openssl SHARED ${SRCS}) + + install( + TARGETS openssl + DESTINATION plugins CALC_DEPS + ) + install( + FILES ${OPENSSL_LIBRARIES} + DESTINATION ${LIB_DIR} + COMPONENT Runtime + ) + + target_link_libraries( + openssl + eclrtl + jlib + OpenSSL::SSL + OpenSSL::Crypto + ) +endif() \ No newline at end of file diff --git a/plugins/openssl/openssl.cpp b/plugins/openssl/openssl.cpp index 3f1c54d00a4..4e5daa19211 100644 --- a/plugins/openssl/openssl.cpp +++ b/plugins/openssl/openssl.cpp @@ -24,6 +24,7 @@ #include "jlog.hpp" #include +#include #include #define CURRENT_OPENSSL_VERSION "openssl plugin 1.0.0" @@ -85,6 +86,19 @@ int passphraseCB(char *passPhraseBuf, int passPhraseBufSize, int rwflag, void *p return 0; } +bool isPublicKey(size32_t keyLen, const char * key) +{ + for (int i = 0; key[i] != '\n' && i < keyLen; i++) + { + if (key[i] == 'P') + { + if (strncmp(key + i + 1, "UBLIC KEY-----", 14) == 0) + return true; + } + } + return false; +} + static constexpr int OPENSSL_MAX_CACHE_SIZE = 10; static constexpr bool PRINT_STATS = false; template @@ -124,6 +138,8 @@ class OpenSSLCache misses = 0; }; + void clear() {cache.clear();}; + private: int hits; int misses; @@ -175,7 +191,7 @@ class PKeyCache failOpenSSLError("creating buffer for EVP_PKEY"); EVP_PKEY * pkey; - if (startsWith(key, "-----BEGIN RSA PUBLIC KEY-----")) + if (isPublicKey(keyLen, key)) pkey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); else { @@ -495,9 +511,9 @@ OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenR } } -// RSA functions +// pk functions -OPENSSL_API void OPENSSL_CALL rsaSeal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, bool isAll_pem_public_keys, size32_t len_pem_public_keys, const void * _pem_public_keys, const char * _algorithm_name) +OPENSSL_API void OPENSSL_CALL pkRSASeal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, bool isAll_pem_public_keys, size32_t len_pem_public_keys, const void * _pem_public_keys, const char * _algorithm_name) { // Initial sanity check of our arguments if (len_pem_public_keys == 0) @@ -615,7 +631,7 @@ OPENSSL_API void OPENSSL_CALL rsaSeal(ICodeContext *ctx, size32_t & __lenResult, } } -OPENSSL_API void OPENSSL_CALL rsaUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name) +OPENSSL_API void OPENSSL_CALL pkRSAUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name) { // Initial sanity check of our arguments if (len_pem_private_key == 0) @@ -717,7 +733,7 @@ OPENSSL_API void OPENSSL_CALL rsaUnseal(ICodeContext *ctx, size32_t & __lenResul } } -OPENSSL_API void OPENSSL_CALL rsaEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_pem_public_key, const char * _pem_public_key) +OPENSSL_API void OPENSSL_CALL pkEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_pem_public_key, const char * _pem_public_key) { __result = nullptr; __lenResult = 0; @@ -769,7 +785,7 @@ OPENSSL_API void OPENSSL_CALL rsaEncrypt(ICodeContext *ctx, size32_t & __lenResu } } -OPENSSL_API void OPENSSL_CALL rsaDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key) +OPENSSL_API void OPENSSL_CALL pkDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key) { __result = nullptr; __lenResult = 0; @@ -821,7 +837,7 @@ OPENSSL_API void OPENSSL_CALL rsaDecrypt(ICodeContext *ctx, size32_t & __lenResu } } -OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name) +OPENSSL_API void OPENSSL_CALL pkSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name) { EVP_MD_CTX *mdCtx = nullptr; @@ -833,28 +849,28 @@ OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, // Create and initialize the message digest context mdCtx = EVP_MD_CTX_new(); if (!mdCtx) - failOpenSSLError("EVP_MD_CTX_new (rsaSign)"); + failOpenSSLError("EVP_MD_CTX_new (pkSign)"); const EVP_MD *md = digestCache.checkCache(_algorithm_name); if (EVP_DigestSignInit(mdCtx, nullptr, md, nullptr, privateKey) <= 0) - failOpenSSLError("EVP_DigestSignInit (rsaSign)"); + failOpenSSLError("EVP_DigestSignInit (pkSign)"); // Add plaintext to context if (EVP_DigestSignUpdate(mdCtx, _plaintext, len_plaintext) <= 0) - failOpenSSLError("EVP_DigestSignUpdate (rsaSign)"); + failOpenSSLError("EVP_DigestSignUpdate (pkSign)"); // Determine the buffer length for the signature size_t signatureLen = 0; if (EVP_DigestSignFinal(mdCtx, nullptr, &signatureLen) <= 0) - failOpenSSLError("determining result length (rsaSign)"); + failOpenSSLError("determining result length (pkSign)"); // Allocate memory for the signature MemoryBuffer signatureBuffer(signatureLen); // Perform the actual signing if (EVP_DigestSignFinal(mdCtx, static_cast(signatureBuffer.bufferBase()), &signatureLen) <= 0) - failOpenSSLError("signing (rsaSign)"); + failOpenSSLError("signing (pkSign)"); // Set the result __lenResult = signatureLen; @@ -873,7 +889,7 @@ OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, } } -OPENSSL_API bool OPENSSL_CALL rsaVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_pem_public_key, const char * _pem_public_key, const char * _algorithm_name) +OPENSSL_API bool OPENSSL_CALL pkVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_pem_public_key, const char * _pem_public_key, const char * _algorithm_name) { EVP_MD_CTX *mdCtx = nullptr; @@ -890,10 +906,10 @@ OPENSSL_API bool OPENSSL_CALL rsaVerifySignature(ICodeContext *ctx, size32_t len const EVP_MD *md = digestCache.checkCache(_algorithm_name); if (EVP_DigestVerifyInit(mdCtx, nullptr, md, nullptr, publicKey) <= 0) - failOpenSSLError("EVP_DigestVerifyInit (rsaVerifySignature)"); + failOpenSSLError("EVP_DigestVerifyInit (pkVerifySignature)"); if (EVP_DigestVerifyUpdate(mdCtx, _signedData, len_signedData) <= 0) - failOpenSSLError("EVP_DigestVerifyUpdate (rsaVerifySignature)"); + failOpenSSLError("EVP_DigestVerifyUpdate (pkVerifySignature)"); // Perform the actual verification int res = EVP_DigestVerifyFinal(mdCtx, reinterpret_cast(_signature), len_signature); @@ -929,4 +945,6 @@ MODULE_EXIT() } pkeyCache.clear(); + digestCache.clear(); + cipherCache.clear(); } diff --git a/plugins/openssl/openssl.hpp b/plugins/openssl/openssl.hpp index fa6bca30e66..ecbf7ffc2b1 100644 --- a/plugins/openssl/openssl.hpp +++ b/plugins/openssl/openssl.hpp @@ -50,13 +50,13 @@ OPENSSL_API uint16_t OPENSSL_CALL cipherIVSize(ICodeContext *ctx, const char * _ OPENSSL_API void OPENSSL_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, const char * _algorithm_name, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt); OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, const char * _algorithm_name, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt); -// RSA functions -OPENSSL_API void OPENSSL_CALL rsaSeal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, bool isAll_pem_public_keys, size32_t len_pem_public_keys, const void * _pem_public_keys, const char * _algorithm_name); -OPENSSL_API void OPENSSL_CALL rsaUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name); -OPENSSL_API void OPENSSL_CALL rsaEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_pem_public_key, const char * _pem_public_key); -OPENSSL_API void OPENSSL_CALL rsaDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key); -OPENSSL_API void OPENSSL_CALL rsaSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name); -OPENSSL_API bool OPENSSL_CALL rsaVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_pem_public_key, const char * _pem_public_key, const char * _algorithm_name); +// Public Key functions +OPENSSL_API void OPENSSL_CALL pkRSASeal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, bool isAll_pem_public_keys, size32_t len_pem_public_keys, const void * _pem_public_keys, const char * _algorithm_name); +OPENSSL_API void OPENSSL_CALL pkRSAUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name); +OPENSSL_API void OPENSSL_CALL pkEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_pem_public_key, const char * _pem_public_key); +OPENSSL_API void OPENSSL_CALL pkDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key); +OPENSSL_API void OPENSSL_CALL pkSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name); +OPENSSL_API bool OPENSSL_CALL pkVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_pem_public_key, const char * _pem_public_key, const char * _algorithm_name); } #endif // ECL_OPENSSL_INCL diff --git a/plugins/proxies/CMakeLists.txt b/plugins/proxies/CMakeLists.txt index 1a309332896..23c4f4f17bd 100644 --- a/plugins/proxies/CMakeLists.txt +++ b/plugins/proxies/CMakeLists.txt @@ -21,8 +21,11 @@ install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_metaphone3.ecllib DESTINATION ${ install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_thorlib.ecllib DESTINATION ${proxies_out_dir} COMPONENT Runtime) install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_word.ecllib DESTINATION ${proxies_out_dir} COMPONENT Runtime) install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_fileservices.ecllib DESTINATION ${proxies_out_dir} COMPONENT Runtime) -install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_openssl.ecllib DESTINATION ${proxies_out_dir} COMPONENT Runtime) IF (USE_OPENSSL) install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_cryptolib.ecllib DESTINATION plugins COMPONENT Runtime) ENDIF() + +IF (USE_OPENSSLV3) + install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_openssl.ecllib DESTINATION ${proxies_out_dir} COMPONENT Runtime) +ENDIF() diff --git a/plugins/proxies/lib_openssl.ecllib b/plugins/proxies/lib_openssl.ecllib index e0f67e4f2fe..c42b35b9b3a 100644 --- a/plugins/proxies/lib_openssl.ecllib +++ b/plugins/proxies/lib_openssl.ecllib @@ -28,12 +28,12 @@ export OpenSSL := SERVICE : plugin('openssl') DATA cipherEncrypt(DATA _plaintext, VARSTRING _algorithm_name, DATA _passphrase, DATA _iv = (DATA)'', DATA _salt = (DATA)'') : cpp,action,context,entrypoint='cipherEncrypt'; DATA cipherDecrypt(DATA _ciphertext, VARSTRING _algorithm_name, DATA _passphrase, DATA _iv = (DATA)'', DATA _salt = (DATA)'') : cpp,action,context,entrypoint='cipherDecrypt'; - // RSA - DATA rsaSeal(DATA _plaintext, SET OF STRING _pem_public_keys, VARSTRING _algorithm_name) : cpp,action,context,entrypoint='rsaSeal'; - DATA rsaUnseal(DATA _ciphertext, DATA _passphrase, STRING _pem_private_key, VARSTRING _algorithm_name) : cpp,action,context,entrypoint='rsaUnseal'; - DATA rsaEncrypt(DATA _plaintext, STRING _pem_public_key) : cpp,action,context,entrypoint='rsaEncrypt'; - DATA rsaDecrypt(DATA _ciphertext, DATA _passphrase, STRING _pem_private_key) : cpp,action,context,entrypoint='rsaDecrypt'; - DATA rsaSign(DATA _plaintext, DATA _passphrase, STRING _pem_private_key, VARSTRING _algorithm_name) : cpp,action,context,entrypoint='rsaSign'; - BOOLEAN rsaVerifySignature(DATA _signature, DATA _signedData, STRING _pem_public_key, VARSTRING _algorithm_name) : cpp,action,context,entrypoint='rsaVerifySignature'; + // Public Key functions + DATA pkRSASeal(DATA _plaintext, SET OF STRING _pem_public_keys, VARSTRING _algorithm_name) : cpp,action,context,entrypoint='pkRSASeal'; + DATA pkRSAUnseal(DATA _ciphertext, DATA _passphrase, STRING _pem_private_key, VARSTRING _algorithm_name) : cpp,action,context,entrypoint='pkRSAUnseal'; + DATA pkEncrypt(DATA _plaintext, STRING _pem_public_key) : cpp,action,context,entrypoint='pkEncrypt'; + DATA pkDecrypt(DATA _ciphertext, DATA _passphrase, STRING _pem_private_key) : cpp,action,context,entrypoint='pkDecrypt'; + DATA pkSign(DATA _plaintext, DATA _passphrase, STRING _pem_private_key, VARSTRING _algorithm_name) : cpp,action,context,entrypoint='pkSign'; + BOOLEAN pkVerifySignature(DATA _signature, DATA _signedData, STRING _pem_public_key, VARSTRING _algorithm_name) : cpp,action,context,entrypoint='pkVerifySignature'; END; From eeb5b48933f3782725bf29fdeb60cb5fe308fdcc Mon Sep 17 00:00:00 2001 From: Jack Del Vecchio Date: Tue, 10 Dec 2024 16:27:46 -0500 Subject: [PATCH 6/8] Fix isPublicKey - Fix comments in OpenSSL.ecl --- ecllibrary/std/OpenSSL.ecl | 12 ++++++------ plugins/openssl/CMakeLists.txt | 2 +- plugins/openssl/openssl.cpp | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ecllibrary/std/OpenSSL.ecl b/ecllibrary/std/OpenSSL.ecl index 8ccb08ef125..9aabea328d5 100644 --- a/ecllibrary/std/OpenSSL.ecl +++ b/ecllibrary/std/OpenSSL.ecl @@ -30,8 +30,8 @@ EXPORT Digest := MODULE * @return A dataset containing the hash algorithm names. * * @see Hash() - * RSA.Sign() - * RSA.VerifySignature() + * PublicKey.Sign() + * PublicKey.VerifySignature() */ EXPORT DATASET({STRING name}) AvailableAlgorithms() := lib_openssl.OpenSSL.digestAvailableAlgorithms(); @@ -215,13 +215,13 @@ EXPORT PublicKey := MODULE * * @return The encrypted ciphertext. * - * @see Unseal() + * @see RSAUnseal() * Ciphers.AvailableAlgorithms() */ EXPORT DATA RSASeal(DATA plaintext, SET OF STRING pem_public_keys, VARSTRING algorithm_name = 'aes-256-cbc') := lib_openssl.OpenSSL.pkRSASeal(plaintext, pem_public_keys, algorithm_name); /** - * Decrypts ciphertext previously generated by the Seal() function. + * Decrypts ciphertext previously generated by the RSASeal() function. * * Because asymmetric encryption is computationally expensive, large * payloads are actually encrypted with a symmetric cipher and a @@ -254,7 +254,7 @@ EXPORT PublicKey := MODULE * * @return The decrypted plaintext. * - * @see Seal() + * @see RSASeal() * Ciphers.AvailableAlgorithms() */ EXPORT DATA RSAUnseal(DATA ciphertext, DATA passphrase, STRING pem_private_key, VARSTRING algorithm_name = 'aes-256-cbc') := lib_openssl.OpenSSL.pkRSAUnseal(ciphertext, passphrase, pem_private_key, algorithm_name); @@ -350,6 +350,6 @@ EXPORT PublicKey := MODULE */ EXPORT BOOLEAN VerifySignature(DATA signature, DATA signedData, STRING pem_public_key, VARSTRING algorithm_name = 'sha256') := lib_openssl.OpenSSL.pkVerifySignature(signature, signedData, pem_public_key, algorithm_name); -END; // RSA +END; // PublicKey END; diff --git a/plugins/openssl/CMakeLists.txt b/plugins/openssl/CMakeLists.txt index 6960d1f83a7..42d4915ae31 100644 --- a/plugins/openssl/CMakeLists.txt +++ b/plugins/openssl/CMakeLists.txt @@ -61,4 +61,4 @@ if (PLATFORM AND USE_OPENSSLV3) OpenSSL::SSL OpenSSL::Crypto ) -endif() \ No newline at end of file +endif() diff --git a/plugins/openssl/openssl.cpp b/plugins/openssl/openssl.cpp index 4e5daa19211..7e723c6c63a 100644 --- a/plugins/openssl/openssl.cpp +++ b/plugins/openssl/openssl.cpp @@ -88,7 +88,7 @@ int passphraseCB(char *passPhraseBuf, int passPhraseBufSize, int rwflag, void *p bool isPublicKey(size32_t keyLen, const char * key) { - for (int i = 0; key[i] != '\n' && i < keyLen; i++) + for (int i = 0; key[i] != '\n' && i < (keyLen - 15); i++) { if (key[i] == 'P') { From 51110d66fe0984bea26aac450ddce3f5f6bb81d5 Mon Sep 17 00:00:00 2001 From: Jack Del Vecchio Date: Thu, 12 Dec 2024 16:08:31 -0500 Subject: [PATCH 7/8] Change name to sslservices --- ecllibrary/std/OpenSSL.ecl | 26 +-- ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl | 2 +- plugins/CMakeLists.txt | 4 +- plugins/openssl/openssl.hpp | 62 ----- plugins/proxies/CMakeLists.txt | 2 +- ..._openssl.ecllib => lib_sslservices.ecllib} | 2 +- .../{openssl => sslservices}/CMakeLists.txt | 16 +- .../sslservices.cpp} | 213 ++++++++---------- plugins/sslservices/sslservices.hpp | 62 +++++ 9 files changed, 186 insertions(+), 203 deletions(-) delete mode 100644 plugins/openssl/openssl.hpp rename plugins/proxies/{lib_openssl.ecllib => lib_sslservices.ecllib} (97%) rename plugins/{openssl => sslservices}/CMakeLists.txt (87%) rename plugins/{openssl/openssl.cpp => sslservices/sslservices.cpp} (77%) create mode 100644 plugins/sslservices/sslservices.hpp diff --git a/ecllibrary/std/OpenSSL.ecl b/ecllibrary/std/OpenSSL.ecl index 9aabea328d5..d8adcda2c2f 100644 --- a/ecllibrary/std/OpenSSL.ecl +++ b/ecllibrary/std/OpenSSL.ecl @@ -17,7 +17,7 @@ EXPORT OpenSSL := MODULE -IMPORT lib_openssl; +IMPORT lib_sslservices; EXPORT Digest := MODULE @@ -33,7 +33,7 @@ EXPORT Digest := MODULE * PublicKey.Sign() * PublicKey.VerifySignature() */ - EXPORT DATASET({STRING name}) AvailableAlgorithms() := lib_openssl.OpenSSL.digestAvailableAlgorithms(); + EXPORT DATASET({STRING name}) AvailableAlgorithms() := lib_sslservices.SSLServices.digestAvailableAlgorithms(); /** * Compute the hash of given data according to the named @@ -49,7 +49,7 @@ EXPORT Digest := MODULE * * @see AvailableAlgorithms() */ - EXPORT DATA Hash(DATA indata, VARSTRING algorithm_name) := lib_openssl.OpenSSL.digesthash(indata, algorithm_name); + EXPORT DATA Hash(DATA indata, VARSTRING algorithm_name) := lib_sslservices.SSLServices.digesthash(indata, algorithm_name); END; // Digest @@ -69,7 +69,7 @@ EXPORT Ciphers := MODULE * Encrypt() * Decrypt() */ - EXPORT DATASET({STRING name}) AvailableAlgorithms() := lib_openssl.OpenSSL.cipherAvailableAlgorithms(); + EXPORT DATASET({STRING name}) AvailableAlgorithms() := lib_sslservices.SSLServices.cipherAvailableAlgorithms(); /** * Return the size of the IV used for the given symmetric @@ -88,7 +88,7 @@ EXPORT Ciphers := MODULE * * @see AvailableAlgorithms() */ - EXPORT UNSIGNED2 IVSize(VARSTRING algorithm_name) := lib_openssl.OpenSSL.cipherIVSize(algorithm_name); + EXPORT UNSIGNED2 IVSize(VARSTRING algorithm_name) := lib_sslservices.SSLServices.cipherIVSize(algorithm_name); /** * Return the size of the salt used for the given symmetric @@ -144,7 +144,7 @@ EXPORT Ciphers := MODULE * SaltSize() * Decrypt() */ - EXPORT DATA Encrypt(DATA plaintext, VARSTRING algorithm_name, DATA passphrase, DATA iv = (DATA)'', DATA salt = (DATA)'') := lib_openssl.OpenSSL.cipherEncrypt(plaintext, algorithm_name, passphrase, iv, salt); + EXPORT DATA Encrypt(DATA plaintext, VARSTRING algorithm_name, DATA passphrase, DATA iv = (DATA)'', DATA salt = (DATA)'') := lib_sslservices.SSLServices.cipherEncrypt(plaintext, algorithm_name, passphrase, iv, salt); /** @@ -179,7 +179,7 @@ EXPORT Ciphers := MODULE * SaltSize() * Encrypt() */ - EXPORT DATA Decrypt(DATA ciphertext, VARSTRING algorithm_name, DATA passphrase, DATA iv = (DATA)'', DATA salt = (DATA)'') := lib_openssl.OpenSSL.cipherDecrypt(ciphertext, algorithm_name, passphrase, iv, salt); + EXPORT DATA Decrypt(DATA ciphertext, VARSTRING algorithm_name, DATA passphrase, DATA iv = (DATA)'', DATA salt = (DATA)'') := lib_sslservices.SSLServices.cipherDecrypt(ciphertext, algorithm_name, passphrase, iv, salt); END; // Ciphers EXPORT PublicKey := MODULE @@ -218,7 +218,7 @@ EXPORT PublicKey := MODULE * @see RSAUnseal() * Ciphers.AvailableAlgorithms() */ - EXPORT DATA RSASeal(DATA plaintext, SET OF STRING pem_public_keys, VARSTRING algorithm_name = 'aes-256-cbc') := lib_openssl.OpenSSL.pkRSASeal(plaintext, pem_public_keys, algorithm_name); + EXPORT DATA RSASeal(DATA plaintext, SET OF STRING pem_public_keys, VARSTRING algorithm_name = 'aes-256-cbc') := lib_sslservices.SSLServices.pkRSASeal(plaintext, pem_public_keys, algorithm_name); /** * Decrypts ciphertext previously generated by the RSASeal() function. @@ -257,7 +257,7 @@ EXPORT PublicKey := MODULE * @see RSASeal() * Ciphers.AvailableAlgorithms() */ - EXPORT DATA RSAUnseal(DATA ciphertext, DATA passphrase, STRING pem_private_key, VARSTRING algorithm_name = 'aes-256-cbc') := lib_openssl.OpenSSL.pkRSAUnseal(ciphertext, passphrase, pem_private_key, algorithm_name); + EXPORT DATA RSAUnseal(DATA ciphertext, DATA passphrase, STRING pem_private_key, VARSTRING algorithm_name = 'aes-256-cbc') := lib_sslservices.SSLServices.pkRSAUnseal(ciphertext, passphrase, pem_private_key, algorithm_name); /** * This function performs asymmetric encryption. It should be used to @@ -272,7 +272,7 @@ EXPORT PublicKey := MODULE * * @see Decrypt() */ - EXPORT DATA Encrypt(DATA plaintext, STRING pem_public_key) := lib_openssl.OpenSSL.pkEncrypt(plaintext, pem_public_key); + EXPORT DATA Encrypt(DATA plaintext, STRING pem_public_key) := lib_sslservices.SSLServices.pkEncrypt(plaintext, pem_public_key); /** * This function performs asymmetric decryption. It should be used to @@ -291,7 +291,7 @@ EXPORT PublicKey := MODULE * * @see Encrypt() */ - EXPORT DATA Decrypt(DATA ciphertext, DATA passphrase, STRING pem_private_key) := lib_openssl.OpenSSL.pkDecrypt(ciphertext, passphrase, pem_private_key); + EXPORT DATA Decrypt(DATA ciphertext, DATA passphrase, STRING pem_private_key) := lib_sslservices.SSLServices.pkDecrypt(ciphertext, passphrase, pem_private_key); /** * Create a digital signature of the given data, using the @@ -321,7 +321,7 @@ EXPORT PublicKey := MODULE * @see Digest.AvailableAlgorithms() * VerifySignature() */ - EXPORT DATA Sign(DATA plaintext, DATA passphrase, STRING pem_private_key, VARSTRING algorithm_name = 'sha256') := lib_openssl.OpenSSL.pkSign(plaintext, passphrase, pem_private_key, algorithm_name); + EXPORT DATA Sign(DATA plaintext, DATA passphrase, STRING pem_private_key, VARSTRING algorithm_name = 'sha256') := lib_sslservices.SSLServices.pkSign(plaintext, passphrase, pem_private_key, algorithm_name); /** * Verify the given digital signature of the given data, using @@ -348,7 +348,7 @@ EXPORT PublicKey := MODULE * @see Digest.AvailableAlgorithms() * Sign() */ - EXPORT BOOLEAN VerifySignature(DATA signature, DATA signedData, STRING pem_public_key, VARSTRING algorithm_name = 'sha256') := lib_openssl.OpenSSL.pkVerifySignature(signature, signedData, pem_public_key, algorithm_name); + EXPORT BOOLEAN VerifySignature(DATA signature, DATA signedData, STRING pem_public_key, VARSTRING algorithm_name = 'sha256') := lib_sslservices.SSLServices.pkVerifySignature(signature, signedData, pem_public_key, algorithm_name); END; // PublicKey diff --git a/ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl b/ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl index 8d45cceb1fc..9a58a756cd2 100644 --- a/ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl +++ b/ecllibrary/teststd/OpenSSL/TestOpenSSL.ecl @@ -212,7 +212,7 @@ EXPORT TestOpenSSL := MODULE ASSERT(LENGTH(encrypt_rsa) = 512); ASSERT((STRING)Std.OpenSSL.PublicKey.Decrypt((DATA)encrypt_rsa, (DATA)'', RSA_PRIVATE_1) = PLAINTEXT); ASSERT((STRING)Std.OpenSSL.PublicKey.Decrypt((DATA)encrypt_rsa_passphrase, (DATA)PASSPHRASE, RSA_PRIVATE_2) = PLAINTEXT); - ASSERT(LENGTH(seal_rsa) = 1112); + ASSERT(LENGTH(seal_rsa) = 1100); ASSERT((STRING)Std.OpenSSL.PublicKey.RSAUnseal((DATA)seal_rsa, (DATA)'', RSA_PRIVATE_1) = PLAINTEXT); ASSERT((STRING)Std.OpenSSL.PublicKey.RSAUnseal((DATA)seal_rsa, (DATA)PASSPHRASE, RSA_PRIVATE_2) = PLAINTEXT); diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 42be5b1e56b..3b0198016b3 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -44,10 +44,12 @@ add_subdirectory (couchbase) add_subdirectory (sqs) add_subdirectory (mongodb) add_subdirectory (parquet) -add_subdirectory (openssl) IF ( INCLUDE_EE_PLUGINS ) add_subdirectory (eeproxies) ENDIF() IF (USE_OPENSSL) add_subdirectory (cryptolib) ENDIF() +IF (USE_OPENSSLV3) +add_subdirectory (sslservices) +ENDIF() diff --git a/plugins/openssl/openssl.hpp b/plugins/openssl/openssl.hpp deleted file mode 100644 index ecbf7ffc2b1..00000000000 --- a/plugins/openssl/openssl.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/*############################################################################## - - HPCC SYSTEMS software Copyright (C) 2025 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. -############################################################################## */ - -#ifndef _OPENSSL_INCL -#define _OPENSSL_INCL - -#ifdef _WIN32 -#define OPENSSL_CALL _cdecl -#else -#define OPENSSL_CALL -#endif - -#ifdef OPENSSL_EXPORTS -#define OPENSSL_API DECL_EXPORT -#else -#define OPENSSL_API DECL_IMPORT -#endif - -#include "platform.h" -#include "jthread.hpp" -#include "hqlplugins.hpp" -#include "eclrtl_imp.hpp" -#include "eclhelper.hpp" - -extern "C++" -{ -OPENSSL_API bool OPENSSL_CALL getECLPluginDefinition(ECLPluginDefinitionBlock *pb); - -// Digest functions -OPENSSL_API void OPENSSL_CALL digestAvailableAlgorithms(ICodeContext *ctx, size32_t & __lenResult, void * & __result); -OPENSSL_API void OPENSSL_CALL digestHash(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_indata, const void * _indata, const char * _algorithm_name); - -// Cipher functions -OPENSSL_API void OPENSSL_CALL cipherAvailableAlgorithms(ICodeContext *ctx, size32_t & __lenResult, void * & __result); -OPENSSL_API uint16_t OPENSSL_CALL cipherIVSize(ICodeContext *ctx, const char * _algorithm_name); -OPENSSL_API void OPENSSL_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, const char * _algorithm_name, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt); -OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, const char * _algorithm_name, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt); - -// Public Key functions -OPENSSL_API void OPENSSL_CALL pkRSASeal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, bool isAll_pem_public_keys, size32_t len_pem_public_keys, const void * _pem_public_keys, const char * _algorithm_name); -OPENSSL_API void OPENSSL_CALL pkRSAUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name); -OPENSSL_API void OPENSSL_CALL pkEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_pem_public_key, const char * _pem_public_key); -OPENSSL_API void OPENSSL_CALL pkDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key); -OPENSSL_API void OPENSSL_CALL pkSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name); -OPENSSL_API bool OPENSSL_CALL pkVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_pem_public_key, const char * _pem_public_key, const char * _algorithm_name); -} - -#endif // ECL_OPENSSL_INCL diff --git a/plugins/proxies/CMakeLists.txt b/plugins/proxies/CMakeLists.txt index 23c4f4f17bd..1f2234599a8 100644 --- a/plugins/proxies/CMakeLists.txt +++ b/plugins/proxies/CMakeLists.txt @@ -27,5 +27,5 @@ install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_cryptolib.ecllib DESTINATION plu ENDIF() IF (USE_OPENSSLV3) - install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_openssl.ecllib DESTINATION ${proxies_out_dir} COMPONENT Runtime) + install ( FILES ${CMAKE_CURRENT_SOURCE_DIR}/lib_sslservices.ecllib DESTINATION ${proxies_out_dir} COMPONENT Runtime) ENDIF() diff --git a/plugins/proxies/lib_openssl.ecllib b/plugins/proxies/lib_sslservices.ecllib similarity index 97% rename from plugins/proxies/lib_openssl.ecllib rename to plugins/proxies/lib_sslservices.ecllib index c42b35b9b3a..dc33ed75481 100644 --- a/plugins/proxies/lib_openssl.ecllib +++ b/plugins/proxies/lib_sslservices.ecllib @@ -16,7 +16,7 @@ ############################################################################## */ // Service definition -export OpenSSL := SERVICE : plugin('openssl') +export SSLServices := SERVICE : plugin('sslservices') // Hash functions DATASET({STRING name}) digestAvailableAlgorithms() : cpp,action,context,entrypoint='digestAvailableAlgorithms'; diff --git a/plugins/openssl/CMakeLists.txt b/plugins/sslservices/CMakeLists.txt similarity index 87% rename from plugins/openssl/CMakeLists.txt rename to plugins/sslservices/CMakeLists.txt index 42d4915ae31..c203be2fa74 100644 --- a/plugins/openssl/CMakeLists.txt +++ b/plugins/sslservices/CMakeLists.txt @@ -14,23 +14,23 @@ # limitations under the License. ############################################################################## -# Component: openssl +# Component: sslservices ############################################################# # Description: # ----------- -# Cmake Input File for openssl +# Cmake Input File for sslservices ############################################################# -project(openssl) +project(sslservices) if (PLATFORM AND USE_OPENSSLV3) find_package(OpenSSL REQUIRED) set( SRCS - openssl.hpp - openssl.cpp + sslservices.hpp + sslservices.cpp ) include_directories( @@ -42,10 +42,10 @@ if (PLATFORM AND USE_OPENSSLV3) ) add_definitions(-D_USRDLL -DECL_OPENSSL_EXPORTS) - HPCC_ADD_LIBRARY(openssl SHARED ${SRCS}) + HPCC_ADD_LIBRARY(sslservices SHARED ${SRCS}) install( - TARGETS openssl + TARGETS sslservices DESTINATION plugins CALC_DEPS ) install( @@ -55,7 +55,7 @@ if (PLATFORM AND USE_OPENSSLV3) ) target_link_libraries( - openssl + sslservices eclrtl jlib OpenSSL::SSL diff --git a/plugins/openssl/openssl.cpp b/plugins/sslservices/sslservices.cpp similarity index 77% rename from plugins/openssl/openssl.cpp rename to plugins/sslservices/sslservices.cpp index 7e723c6c63a..583a50262a3 100644 --- a/plugins/openssl/openssl.cpp +++ b/plugins/sslservices/sslservices.cpp @@ -15,7 +15,7 @@ limitations under the License. ############################################################################## */ -#include "openssl.hpp" +#include "sslservices.hpp" #include "openssl/err.h" #include "openssl/evp.h" @@ -24,21 +24,21 @@ #include "jlog.hpp" #include -#include +#include #include -#define CURRENT_OPENSSL_VERSION "openssl plugin 1.0.0" +#define CURRENT_SSLSERVICES_VERSION "sslservices plugin 1.0.0" -static const char* opensslCompatibleVersions[] = { - CURRENT_OPENSSL_VERSION, +static const char* sslservicesCompatibleVersions[] = { + CURRENT_SSLSERVICES_VERSION, NULL }; -OPENSSL_API bool OPENSSL_CALL getECLPluginDefinition(ECLPluginDefinitionBlock* pb) +SSLSERVICES_API bool SSLSERVICES_CALL getECLPluginDefinition(ECLPluginDefinitionBlock* pb) { if (pb->size == sizeof(ECLPluginDefinitionBlockEx)) { ECLPluginDefinitionBlockEx* pbx = static_cast(pb); - pbx->compatibleVersions = opensslCompatibleVersions; + pbx->compatibleVersions = sslservicesCompatibleVersions; } else if (pb->size != sizeof(ECLPluginDefinitionBlock)) { @@ -46,8 +46,8 @@ OPENSSL_API bool OPENSSL_CALL getECLPluginDefinition(ECLPluginDefinitionBlock* p } pb->magicVersion = PLUGIN_VERSION; - pb->version = CURRENT_OPENSSL_VERSION; - pb->moduleName = "openssl"; + pb->version = CURRENT_SSLSERVICES_VERSION; + pb->moduleName = "sslservices"; pb->ECL = NULL; pb->flags = PLUGIN_IMPLICIT_MODULE; pb->description = "ECL plugin library for the C++ API in OpenSSL"; @@ -55,13 +55,13 @@ OPENSSL_API bool OPENSSL_CALL getECLPluginDefinition(ECLPluginDefinitionBlock* p return true; } -namespace nsOpenSSL +namespace nsSSLServices { void failOpenSSLError(const std::string& context) { - unsigned long errCode = 0; - char buffer[120]; + size_t errCode = 0; + char buffer[120]; ERR_error_string_n(ERR_get_error(), buffer, sizeof(buffer)); @@ -77,7 +77,7 @@ void failOpenSSLError(const std::string& context) int passphraseCB(char *passPhraseBuf, int passPhraseBufSize, int rwflag, void *pPassPhraseMB) { size32_t len = ((MemoryBuffer*)pPassPhraseMB)->length(); - if (passPhraseBufSize >= (int)len) + if (passPhraseBufSize >= len) { memcpy(passPhraseBuf, ((MemoryBuffer*)pPassPhraseMB)->bufferBase(), len); return len; @@ -88,7 +88,7 @@ int passphraseCB(char *passPhraseBuf, int passPhraseBufSize, int rwflag, void *p bool isPublicKey(size32_t keyLen, const char * key) { - for (int i = 0; key[i] != '\n' && i < (keyLen - 15); i++) + for (size32_t i = 0; key[i] != '\n' && i < (keyLen - 15); i++) { if (key[i] == 'P') { @@ -99,10 +99,10 @@ bool isPublicKey(size32_t keyLen, const char * key) return false; } -static constexpr int OPENSSL_MAX_CACHE_SIZE = 10; +static constexpr size32_t SSLSERVICES_MAX_CACHE_SIZE = 10; static constexpr bool PRINT_STATS = false; template -class OpenSSLCache +class AlgorithmCache { public: const T * checkCache(const char * algorithm_name) @@ -120,29 +120,29 @@ class OpenSSLCache if (newObj) { cache.emplace_front(algorithm_name, newObj); - if (cache.size() > OPENSSL_MAX_CACHE_SIZE) + if (cache.size() > SSLSERVICES_MAX_CACHE_SIZE) cache.pop_back(); } else failOpenSSLError("adding new object to cache"); return newObj; - }; + } - void printStatistics() {DBGLOG("OPENSSL %s CACHE STATS: HITS = %d, MISSES = %d", cacheName.c_str(), hits, misses);}; + void printStatistics() {DBGLOG("SSLSERVICES %s CACHE STATS: HITS = %d, MISSES = %d", cacheName.c_str(), hits, misses);} void init() { setCacheName(); hits = 0; misses = 0; - }; + } - void clear() {cache.clear();}; + void clear() {cache.clear();} private: - int hits; - int misses; + size32_t hits; + size32_t misses; std::string cacheName; std::list> cache; @@ -151,16 +151,17 @@ class OpenSSLCache }; template <> -void OpenSSLCache::setCacheName() { cacheName = "CIPHER"; } +void AlgorithmCache::setCacheName() {cacheName = "CIPHER";} + template <> -void OpenSSLCache::setCacheName() { cacheName = "DIGEST"; } +void AlgorithmCache::setCacheName() {cacheName = "DIGEST";} template <> -const EVP_CIPHER * OpenSSLCache::getObjectByName(const char * name) { return EVP_get_cipherbyname(name); } +const EVP_CIPHER * AlgorithmCache::getObjectByName(const char * name) { return EVP_get_cipherbyname(name); } template <> -const EVP_MD * OpenSSLCache::getObjectByName(const char * name) { return EVP_get_digestbyname(name); } +const EVP_MD * AlgorithmCache::getObjectByName(const char * name) { return EVP_get_digestbyname(name); } // PEM Public/Private keys require parsing from a string // Store the hash of the original string and parsed key @@ -171,7 +172,7 @@ class PKeyCache { hits = 0; misses = 0; - }; + } EVP_PKEY * checkCache(size32_t keyLen, const char * key, size32_t passphraseLen, const void * passphrase) { @@ -180,7 +181,7 @@ class PKeyCache if (hashc(reinterpret_cast(passphrase), passphraseLen, hashc(reinterpret_cast(key), keyLen, 0)) == std::get<0>(c)) { hits++; - return std::get<1>(c); + return std::get<1>(c).get(); } } @@ -203,51 +204,42 @@ class PKeyCache if (pkey) { - cache.emplace_front(hashc(reinterpret_cast(passphrase), passphraseLen, hashc(reinterpret_cast(key), keyLen, 0)), pkey); - if (cache.size() > OPENSSL_MAX_CACHE_SIZE) - { - EVP_PKEY_free(std::get<1>(cache.back())); + cache.emplace_front(hashc(reinterpret_cast(passphrase), passphraseLen, hashc(reinterpret_cast(key), keyLen, 0)), std::move(std::unique_ptr(pkey, EVP_PKEY_free))); + if (cache.size() > SSLSERVICES_MAX_CACHE_SIZE) cache.pop_back(); - } } else failOpenSSLError("loading a pkey"); return pkey; - }; + } - void clear() - { - for (auto& c : cache) - EVP_PKEY_free(std::get<1>(c)); - cache.clear(); - }; + void clear() {cache.clear();} - void printStatistics() {DBGLOG("OPENSSL PKEY CACHE STATS: HITS = %d, MISSES = %d", hits, misses);}; + void printStatistics() {DBGLOG("SSLSERVICES PKEY CACHE STATS: HITS = %d, MISSES = %d", hits, misses);} private: - int hits; - int misses; - std::list> cache; + size32_t hits; + size32_t misses; + std::list>> cache; }; static thread_local PKeyCache pkeyCache; -static thread_local OpenSSLCache cipherCache; -static thread_local OpenSSLCache digestCache; -} // nsOpenSSL +static thread_local AlgorithmCache cipherCache; +static thread_local AlgorithmCache digestCache; +} // nsSSLServices -using namespace nsOpenSSL; +using namespace nsSSLServices; //-------------------------------------------------------------------------- -// Advertised Entry Point Functions +// Advertised Entry Posize32_t Functions //-------------------------------------------------------------------------- -OPENSSL_API void OPENSSL_CALL digestAvailableAlgorithms(ICodeContext *ctx, size32_t & __lenResult, void * & __result) +SSLSERVICES_API void SSLSERVICES_CALL digestAvailableAlgorithms(ICodeContext *ctx, size32_t & __lenResult, void * & __result) { // Get all the hash (digest) names - OpenSSL_add_all_digests(); std::vector digestNames; EVP_MD_do_all([](const EVP_MD * md, const char * name, const char * description, void * arg) { std::vector * digestNames = static_cast*>(arg); @@ -278,7 +270,7 @@ OPENSSL_API void OPENSSL_CALL digestAvailableAlgorithms(ICodeContext *ctx, size3 } } -OPENSSL_API void OPENSSL_CALL digestHash(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_indata, const void * _indata, const char * _algorithm_name) +SSLSERVICES_API void SSLSERVICES_CALL digestHash(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_indata, const void * _indata, const char * _algorithm_name) { if (strlen(_algorithm_name) == 0) rtlFail(-1, "No hash digest name provided"); @@ -316,10 +308,9 @@ OPENSSL_API void OPENSSL_CALL digestHash(ICodeContext *ctx, size32_t & __lenResu // Symmetric ciphers -OPENSSL_API void OPENSSL_CALL cipherAvailableAlgorithms(ICodeContext *ctx, size32_t & __lenResult, void * & __result) +SSLSERVICES_API void SSLSERVICES_CALL cipherAvailableAlgorithms(ICodeContext *ctx, size32_t & __lenResult, void * & __result) { // Get all the cipher names - OpenSSL_add_all_ciphers(); std::vector cipherNames; EVP_CIPHER_do_all([](const EVP_CIPHER * cipher, const char * from, const char * to, void * x) { auto cipherNames = static_cast *>(x); @@ -350,7 +341,7 @@ OPENSSL_API void OPENSSL_CALL cipherAvailableAlgorithms(ICodeContext *ctx, size3 } } -OPENSSL_API uint16_t OPENSSL_CALL cipherIVSize(ICodeContext *ctx, const char * algorithm_name) +SSLSERVICES_API uint16_t SSLSERVICES_CALL cipherIVSize(ICodeContext *ctx, const char * algorithm_name) { if (strlen(algorithm_name) == 0) rtlFail(-1, "No algorithm name provided"); @@ -361,7 +352,7 @@ OPENSSL_API uint16_t OPENSSL_CALL cipherIVSize(ICodeContext *ctx, const char * a return static_cast(EVP_CIPHER_iv_length(cipher)); } -OPENSSL_API void OPENSSL_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, const char * _algorithm_name, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt) +SSLSERVICES_API void SSLSERVICES_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, const char * _algorithm_name, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt) { __result = nullptr; __lenResult = 0; @@ -382,7 +373,7 @@ OPENSSL_API void OPENSSL_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenR // Load the cipher const EVP_CIPHER * cipher = cipherCache.checkCache(_algorithm_name); - int cipherIVSize = EVP_CIPHER_iv_length(cipher); + size32_t cipherIVSize = EVP_CIPHER_iv_length(cipher); if (hasIV && len_iv != static_cast(cipherIVSize)) rtlFail(-1, "Supplied IV is an incorrect size"); @@ -407,17 +398,17 @@ OPENSSL_API void OPENSSL_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenR try { - int len = 0; - int ciphertextLen = 0; + size32_t len = 0; + size32_t ciphertextLen = 0; if (EVP_EncryptInit_ex(encryptCtx, cipher, nullptr, static_cast(key.bufferBase()),static_cast(iv.bufferBase())) != 1) failOpenSSLError("EVP_EncryptInit_ex"); - if (EVP_EncryptUpdate(encryptCtx, static_cast(resultBuffer.bufferBase()), &len, static_cast(_plaintext), len_plaintext) != 1) + if (EVP_EncryptUpdate(encryptCtx, static_cast(resultBuffer.bufferBase()), reinterpret_cast(&len), static_cast(_plaintext), len_plaintext) != 1) failOpenSSLError("EVP_EncryptUpdate"); ciphertextLen = len; - if (EVP_EncryptFinal_ex(encryptCtx, static_cast(resultBuffer.bufferBase()) + len, &len) != 1) + if (EVP_EncryptFinal_ex(encryptCtx, static_cast(resultBuffer.bufferBase()) + len, reinterpret_cast(&len)) != 1) failOpenSSLError("EVP_EncryptFinal_ex"); ciphertextLen += len; __lenResult = ciphertextLen; @@ -436,7 +427,7 @@ OPENSSL_API void OPENSSL_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenR } } -OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, const char * _algorithm_name, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt) +SSLSERVICES_API void SSLSERVICES_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, const char * _algorithm_name, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt) { __result = nullptr; __lenResult = 0; @@ -457,7 +448,7 @@ OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenR // Load the cipher const EVP_CIPHER * cipher = cipherCache.checkCache(_algorithm_name); - int cipherIVSize = EVP_CIPHER_iv_length(cipher); + size32_t cipherIVSize = EVP_CIPHER_iv_length(cipher); if (hasIV && len_iv != static_cast(cipherIVSize)) rtlFail(-1, "Supplied IV is an incorrect size"); @@ -482,17 +473,17 @@ OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenR try { - int len = 0; - int plaintextLen = 0; + size32_t len = 0; + size32_t plaintextLen = 0; if (EVP_DecryptInit_ex(decryptCtx, cipher, nullptr, static_cast(key.bufferBase()), static_cast(iv.bufferBase())) != 1) failOpenSSLError("EVP_DecryptInit_ex"); - if (EVP_DecryptUpdate(decryptCtx, static_cast(resultBuffer.bufferBase()), &len, static_cast(_ciphertext), len_ciphertext) != 1) + if (EVP_DecryptUpdate(decryptCtx, static_cast(resultBuffer.bufferBase()), reinterpret_cast(&len), static_cast(_ciphertext), len_ciphertext) != 1) failOpenSSLError("EVP_DecryptUpdate"); plaintextLen = len; - if (EVP_DecryptFinal_ex(decryptCtx, static_cast(resultBuffer.bufferBase()) + len, &len) != 1) + if (EVP_DecryptFinal_ex(decryptCtx, static_cast(resultBuffer.bufferBase()) + len, reinterpret_cast(&len)) != 1) failOpenSSLError("EVP_DecryptFinal_ex"); plaintextLen += len; __lenResult = plaintextLen; @@ -511,9 +502,9 @@ OPENSSL_API void OPENSSL_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenR } } -// pk functions +// PublicKey functions -OPENSSL_API void OPENSSL_CALL pkRSASeal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, bool isAll_pem_public_keys, size32_t len_pem_public_keys, const void * _pem_public_keys, const char * _algorithm_name) +SSLSERVICES_API void SSLSERVICES_CALL pkRSASeal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, bool isAll_pem_public_keys, size32_t len_pem_public_keys, const void * _pem_public_keys, const char * _algorithm_name) { // Initial sanity check of our arguments if (len_pem_public_keys == 0) @@ -544,17 +535,17 @@ OPENSSL_API void OPENSSL_CALL pkRSASeal(ICodeContext *ctx, size32_t & __lenResul const EVP_CIPHER * cipher = cipherCache.checkCache(_algorithm_name); // Allocate memory for encrypted keys - size_t keyCount = publicKeys.size(); - encryptedKeys = static_cast(rtlMalloc(sizeof(byte *) * keyCount)); - for (size_t x = 0; x < keyCount; x++) - encryptedKeys[x] = static_cast(rtlMalloc(EVP_PKEY_size(publicKeys[x]))); + size32_t keyCount = publicKeys.size(); + encryptedKeys = new byte *[keyCount]; + for (size32_t x = 0; x < keyCount; x++) + encryptedKeys[x] = new byte [EVP_PKEY_size(publicKeys[x])]; // Allocate memory for the IV - int ivLen = EVP_CIPHER_iv_length(cipher); + size32_t ivLen = EVP_CIPHER_iv_length(cipher); iv.ensureCapacity(ivLen); // Allocate buffer for ciphertext - int ciphertextLen = len_plaintext + EVP_CIPHER_block_size(cipher); + size32_t ciphertextLen = len_plaintext + EVP_CIPHER_block_size(cipher); ciphertext.ensureCapacity(ciphertextLen); // Create and initialize the context @@ -568,32 +559,32 @@ OPENSSL_API void OPENSSL_CALL pkRSASeal(ICodeContext *ctx, size32_t & __lenResul failOpenSSLError("EVP_SealInit"); // Update the envelope (encrypt the plaintext) - int len = 0; - if (EVP_SealUpdate(encryptCtx, static_cast(ciphertext.bufferBase()), &len, reinterpret_cast(_plaintext), len_plaintext) != 1) + size32_t len = 0; + if (EVP_SealUpdate(encryptCtx, static_cast(ciphertext.bufferBase()), reinterpret_cast(&len), reinterpret_cast(_plaintext), len_plaintext) != 1) failOpenSSLError("EVP_SealUpdate"); ciphertextLen = len; // Finalize the envelope's ciphertext - if (EVP_SealFinal(encryptCtx, static_cast(ciphertext.bufferBase()) + len, &len) != 1) + if (EVP_SealFinal(encryptCtx, static_cast(ciphertext.bufferBase()) + len, reinterpret_cast(&len)) != 1) failOpenSSLError("EVP_SealFinal"); ciphertextLen += len; - int totalKeyLen = 0; - for (int i = 0; i < keyCount; i++) + size32_t totalKeyLen = 0; + for (size32_t i = 0; i < keyCount; i++) totalKeyLen += keyLens[i]; // We need to prepend the ciphertext with metadata so the blob can be decrypted; // this is potentially nonstandard MemoryBuffer outBuffer; - outBuffer.ensureCapacity(ivLen + (sizeof(size_t)*(keyCount+1)) + totalKeyLen + ciphertextLen); + outBuffer.ensureCapacity(ivLen + (sizeof(size32_t)*(keyCount+1)) + totalKeyLen + ciphertextLen); // IV comes first; its length can be derived from the cipher outBuffer.append(ivLen, static_cast(iv.bufferBase())); - // Number of keys (size_t) + // Number of keys (size32_t) outBuffer.append(sizeof(keyCount), reinterpret_cast(&keyCount)); - // Keys; each is (size_t) + - for (size_t x = 0; x < keyCount; x++) + // Keys; each is (size32_t) + + for (size32_t x = 0; x < keyCount; x++) { - size_t keyLen = keyLens[x]; + size32_t keyLen = keyLens[x]; outBuffer.append(sizeof(keyLen), reinterpret_cast(&keyLen)); outBuffer.append(keyLen, encryptedKeys[x]); } @@ -606,23 +597,13 @@ OPENSSL_API void OPENSSL_CALL pkRSASeal(ICodeContext *ctx, size32_t & __lenResul // Cleanup EVP_CIPHER_CTX_free(encryptCtx); - for (size_t x = 0; x < publicKeys.size(); x++) - rtlFree(encryptedKeys[x]); - rtlFree(encryptedKeys); + delete [] encryptedKeys; } catch (...) { if (encryptCtx) EVP_CIPHER_CTX_free(encryptCtx); - if (encryptedKeys) - { - for (size_t x = 0; x < publicKeys.size(); x++) - { - if (encryptedKeys[x]) - rtlFree(encryptedKeys[x]); - } - rtlFree(encryptedKeys); - } + delete [] encryptedKeys; __lenResult = 0; rtlFree(__result); __result = nullptr; @@ -631,7 +612,7 @@ OPENSSL_API void OPENSSL_CALL pkRSASeal(ICodeContext *ctx, size32_t & __lenResul } } -OPENSSL_API void OPENSSL_CALL pkRSAUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name) +SSLSERVICES_API void SSLSERVICES_CALL pkRSAUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name) { // Initial sanity check of our arguments if (len_pem_private_key == 0) @@ -653,9 +634,9 @@ OPENSSL_API void OPENSSL_CALL pkRSAUnseal(ICodeContext *ctx, size32_t & __lenRes const EVP_CIPHER * cipher = cipherCache.checkCache(_algorithm_name); // Allocate memory for the symmetric key and IV - int keyLen = EVP_PKEY_size(privateKey); + size32_t keyLen = EVP_PKEY_size(privateKey); symmetricKey.ensureCapacity(keyLen); - int ivLen = EVP_CIPHER_iv_length(cipher); + size32_t ivLen = EVP_CIPHER_iv_length(cipher); iv.ensureCapacity(ivLen); // Unpack the structured ciphertext to extract the metadata @@ -663,15 +644,15 @@ OPENSSL_API void OPENSSL_CALL pkRSAUnseal(ICodeContext *ctx, size32_t & __lenRes // IV comes first, length determined by the cipher iv.append(ivLen, inPtr); inPtr += ivLen; - // Number of keys embedded in the metadata (size_t) - size_t keyCount = 0; + // Number of keys embedded in the metadata (size32_t) + size32_t keyCount = 0; memcpy(&keyCount, inPtr, sizeof(keyCount)); inPtr += sizeof(keyCount); - // The keys; each has a length (size_t) then contents + // The keys; each has a length (size32_t) then contents std::vector encryptedKeys; - for (size_t x = 0; x < keyCount; x++) + for (size32_t x = 0; x < keyCount; x++) { - size_t keySize = 0; + size32_t keySize = 0; memcpy(&keySize, inPtr, sizeof(keySize)); inPtr += sizeof(keySize); encryptedKeys.emplace_back(reinterpret_cast(inPtr), keySize); @@ -679,7 +660,7 @@ OPENSSL_API void OPENSSL_CALL pkRSAUnseal(ICodeContext *ctx, size32_t & __lenRes } const byte * newCipherText = inPtr; - size_t newCipherTextLen = (len_ciphertext - (reinterpret_cast(inPtr) - static_cast(_ciphertext))); + size32_t newCipherTextLen = (len_ciphertext - (reinterpret_cast(inPtr) - static_cast(_ciphertext))); // Initialize the context for decryption decryptCtx = EVP_CIPHER_CTX_new(); @@ -700,15 +681,15 @@ OPENSSL_API void OPENSSL_CALL pkRSAUnseal(ICodeContext *ctx, size32_t & __lenRes failOpenSSLError("EVP_OpenInit"); // Allocate memory for the plaintext - int plaintextLen = newCipherTextLen; + size32_t plaintextLen = newCipherTextLen; plaintext.ensureCapacity(plaintextLen); - int len = 0; - if (EVP_OpenUpdate(decryptCtx, static_cast(plaintext.bufferBase()), &len, newCipherText, newCipherTextLen) != 1) + size32_t len = 0; + if (EVP_OpenUpdate(decryptCtx, static_cast(plaintext.bufferBase()), reinterpret_cast(&len), newCipherText, newCipherTextLen) != 1) failOpenSSLError("EVP_OpenUpdate"); plaintextLen = len; - if (EVP_OpenFinal(decryptCtx, static_cast(plaintext.bufferBase()) + len, &len) != 1) + if (EVP_OpenFinal(decryptCtx, static_cast(plaintext.bufferBase()) + len, reinterpret_cast(&len)) != 1) failOpenSSLError("EVP_OpenFinal"); plaintextLen += len; @@ -733,7 +714,7 @@ OPENSSL_API void OPENSSL_CALL pkRSAUnseal(ICodeContext *ctx, size32_t & __lenRes } } -OPENSSL_API void OPENSSL_CALL pkEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_pem_public_key, const char * _pem_public_key) +SSLSERVICES_API void SSLSERVICES_CALL pkEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_pem_public_key, const char * _pem_public_key) { __result = nullptr; __lenResult = 0; @@ -785,7 +766,7 @@ OPENSSL_API void OPENSSL_CALL pkEncrypt(ICodeContext *ctx, size32_t & __lenResul } } -OPENSSL_API void OPENSSL_CALL pkDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key) +SSLSERVICES_API void SSLSERVICES_CALL pkDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key) { __result = nullptr; __lenResult = 0; @@ -837,7 +818,7 @@ OPENSSL_API void OPENSSL_CALL pkDecrypt(ICodeContext *ctx, size32_t & __lenResul } } -OPENSSL_API void OPENSSL_CALL pkSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name) +SSLSERVICES_API void SSLSERVICES_CALL pkSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name) { EVP_MD_CTX *mdCtx = nullptr; @@ -889,7 +870,7 @@ OPENSSL_API void OPENSSL_CALL pkSign(ICodeContext *ctx, size32_t & __lenResult, } } -OPENSSL_API bool OPENSSL_CALL pkVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_pem_public_key, const char * _pem_public_key, const char * _algorithm_name) +SSLSERVICES_API bool SSLSERVICES_CALL pkVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_pem_public_key, const char * _pem_public_key, const char * _algorithm_name) { EVP_MD_CTX *mdCtx = nullptr; @@ -912,7 +893,7 @@ OPENSSL_API bool OPENSSL_CALL pkVerifySignature(ICodeContext *ctx, size32_t len_ failOpenSSLError("EVP_DigestVerifyUpdate (pkVerifySignature)"); // Perform the actual verification - int res = EVP_DigestVerifyFinal(mdCtx, reinterpret_cast(_signature), len_signature); + size32_t res = EVP_DigestVerifyFinal(mdCtx, reinterpret_cast(_signature), len_signature); // Clean up EVP_MD_CTX_free(mdCtx); diff --git a/plugins/sslservices/sslservices.hpp b/plugins/sslservices/sslservices.hpp new file mode 100644 index 00000000000..b796afe19c1 --- /dev/null +++ b/plugins/sslservices/sslservices.hpp @@ -0,0 +1,62 @@ +/*############################################################################## + + HPCC SYSTEMS software Copyright (C) 2025 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. +############################################################################## */ + +#ifndef _SSLSERVICES_INCL +#define _SSLSERVICES_INCL + +#ifdef _WIN32 +#define SSLSERVICES_CALL _cdecl +#else +#define SSLSERVICES_CALL +#endif + +#ifdef SSLSERVICES_EXPORTS +#define SSLSERVICES_API DECL_EXPORT +#else +#define SSLSERVICES_API DECL_IMPORT +#endif + +#include "platform.h" +#include "jthread.hpp" +#include "hqlplugins.hpp" +#include "eclrtl_imp.hpp" +#include "eclhelper.hpp" + +extern "C++" +{ +SSLSERVICES_API bool SSLSERVICES_CALL getECLPluginDefinition(ECLPluginDefinitionBlock *pb); + +// Digest functions +SSLSERVICES_API void SSLSERVICES_CALL digestAvailableAlgorithms(ICodeContext *ctx, size32_t & __lenResult, void * & __result); +SSLSERVICES_API void SSLSERVICES_CALL digestHash(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_indata, const void * _indata, const char * _algorithm_name); + +// Cipher functions +SSLSERVICES_API void SSLSERVICES_CALL cipherAvailableAlgorithms(ICodeContext *ctx, size32_t & __lenResult, void * & __result); +SSLSERVICES_API uint16_t SSLSERVICES_CALL cipherIVSize(ICodeContext *ctx, const char * _algorithm_name); +SSLSERVICES_API void SSLSERVICES_CALL cipherEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, const char * _algorithm_name, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt); +SSLSERVICES_API void SSLSERVICES_CALL cipherDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, const char * _algorithm_name, size32_t len_passphrase, const void * _passphrase, size32_t len_iv, const void * _iv, size32_t len_salt, const void * _salt); + +// Public Key functions +SSLSERVICES_API void SSLSERVICES_CALL pkRSASeal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, bool isAll_pem_public_keys, size32_t len_pem_public_keys, const void * _pem_public_keys, const char * _algorithm_name); +SSLSERVICES_API void SSLSERVICES_CALL pkRSAUnseal(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name); +SSLSERVICES_API void SSLSERVICES_CALL pkEncrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_pem_public_key, const char * _pem_public_key); +SSLSERVICES_API void SSLSERVICES_CALL pkDecrypt(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_ciphertext, const void * _ciphertext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key); +SSLSERVICES_API void SSLSERVICES_CALL pkSign(ICodeContext *ctx, size32_t & __lenResult, void * & __result, size32_t len_plaintext, const void * _plaintext, size32_t len_passphrase, const void * _passphrase, size32_t len_pem_private_key, const char * _pem_private_key, const char * _algorithm_name); +SSLSERVICES_API bool SSLSERVICES_CALL pkVerifySignature(ICodeContext *ctx, size32_t len_signature, const void * _signature, size32_t len_signedData, const void * _signedData, size32_t len_pem_public_key, const char * _pem_public_key, const char * _algorithm_name); +} + +#endif // ECL_SSLSERVICES_INCL From a1b1a449e75833b74c7bbfc7f7b19cb346e094a7 Mon Sep 17 00:00:00 2001 From: Jack Del Vecchio Date: Tue, 19 Nov 2024 10:26:41 -0500 Subject: [PATCH 8/8] Revert some changes to size32_t - Where the api requests an int - Hit and Misses counters in the caches - The hash of the PKey stored in the cash Add typedef for unique pointer and clean up code for adding to the cache --- plugins/sslservices/sslservices.cpp | 47 +++++++++++++++-------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/plugins/sslservices/sslservices.cpp b/plugins/sslservices/sslservices.cpp index 583a50262a3..8a58cafdab1 100644 --- a/plugins/sslservices/sslservices.cpp +++ b/plugins/sslservices/sslservices.cpp @@ -60,7 +60,6 @@ namespace nsSSLServices void failOpenSSLError(const std::string& context) { - size_t errCode = 0; char buffer[120]; ERR_error_string_n(ERR_get_error(), buffer, sizeof(buffer)); @@ -77,7 +76,7 @@ void failOpenSSLError(const std::string& context) int passphraseCB(char *passPhraseBuf, int passPhraseBufSize, int rwflag, void *pPassPhraseMB) { size32_t len = ((MemoryBuffer*)pPassPhraseMB)->length(); - if (passPhraseBufSize >= len) + if (((size32_t)passPhraseBufSize) >= len) { memcpy(passPhraseBuf, ((MemoryBuffer*)pPassPhraseMB)->bufferBase(), len); return len; @@ -141,8 +140,8 @@ class AlgorithmCache void clear() {cache.clear();} private: - size32_t hits; - size32_t misses; + unsigned hits; + unsigned misses; std::string cacheName; std::list> cache; @@ -153,7 +152,6 @@ class AlgorithmCache template <> void AlgorithmCache::setCacheName() {cacheName = "CIPHER";} - template <> void AlgorithmCache::setCacheName() {cacheName = "DIGEST";} @@ -163,6 +161,8 @@ const EVP_CIPHER * AlgorithmCache::getObjectByName(const char * name template <> const EVP_MD * AlgorithmCache::getObjectByName(const char * name) { return EVP_get_digestbyname(name); } +typedef std::unique_ptr UniquePKey; + // PEM Public/Private keys require parsing from a string // Store the hash of the original string and parsed key class PKeyCache @@ -204,7 +204,8 @@ class PKeyCache if (pkey) { - cache.emplace_front(hashc(reinterpret_cast(passphrase), passphraseLen, hashc(reinterpret_cast(key), keyLen, 0)), std::move(std::unique_ptr(pkey, EVP_PKEY_free))); + unsigned PkeyHash = hashc(reinterpret_cast(passphrase), passphraseLen, hashc(reinterpret_cast(key), keyLen, 0)); + cache.emplace_front(PkeyHash, std::move(UniquePKey(pkey, EVP_PKEY_free))); if (cache.size() > SSLSERVICES_MAX_CACHE_SIZE) cache.pop_back(); } @@ -219,9 +220,9 @@ class PKeyCache void printStatistics() {DBGLOG("SSLSERVICES PKEY CACHE STATS: HITS = %d, MISSES = %d", hits, misses);} private: - size32_t hits; - size32_t misses; - std::list>> cache; + unsigned hits; + unsigned misses; + std::list> cache; }; @@ -234,7 +235,7 @@ static thread_local AlgorithmCache digestCache; using namespace nsSSLServices; //-------------------------------------------------------------------------- -// Advertised Entry Posize32_t Functions +// Advertised Entry Point Functions //-------------------------------------------------------------------------- SSLSERVICES_API void SSLSERVICES_CALL digestAvailableAlgorithms(ICodeContext *ctx, size32_t & __lenResult, void * & __result) @@ -398,17 +399,17 @@ SSLSERVICES_API void SSLSERVICES_CALL cipherEncrypt(ICodeContext *ctx, size32_t try { - size32_t len = 0; + int len = 0; size32_t ciphertextLen = 0; if (EVP_EncryptInit_ex(encryptCtx, cipher, nullptr, static_cast(key.bufferBase()),static_cast(iv.bufferBase())) != 1) failOpenSSLError("EVP_EncryptInit_ex"); - if (EVP_EncryptUpdate(encryptCtx, static_cast(resultBuffer.bufferBase()), reinterpret_cast(&len), static_cast(_plaintext), len_plaintext) != 1) + if (EVP_EncryptUpdate(encryptCtx, static_cast(resultBuffer.bufferBase()), &len, static_cast(_plaintext), len_plaintext) != 1) failOpenSSLError("EVP_EncryptUpdate"); ciphertextLen = len; - if (EVP_EncryptFinal_ex(encryptCtx, static_cast(resultBuffer.bufferBase()) + len, reinterpret_cast(&len)) != 1) + if (EVP_EncryptFinal_ex(encryptCtx, static_cast(resultBuffer.bufferBase()) + len, &len) != 1) failOpenSSLError("EVP_EncryptFinal_ex"); ciphertextLen += len; __lenResult = ciphertextLen; @@ -473,17 +474,17 @@ SSLSERVICES_API void SSLSERVICES_CALL cipherDecrypt(ICodeContext *ctx, size32_t try { - size32_t len = 0; + int len = 0; size32_t plaintextLen = 0; if (EVP_DecryptInit_ex(decryptCtx, cipher, nullptr, static_cast(key.bufferBase()), static_cast(iv.bufferBase())) != 1) failOpenSSLError("EVP_DecryptInit_ex"); - if (EVP_DecryptUpdate(decryptCtx, static_cast(resultBuffer.bufferBase()), reinterpret_cast(&len), static_cast(_ciphertext), len_ciphertext) != 1) + if (EVP_DecryptUpdate(decryptCtx, static_cast(resultBuffer.bufferBase()), &len, static_cast(_ciphertext), len_ciphertext) != 1) failOpenSSLError("EVP_DecryptUpdate"); plaintextLen = len; - if (EVP_DecryptFinal_ex(decryptCtx, static_cast(resultBuffer.bufferBase()) + len, reinterpret_cast(&len)) != 1) + if (EVP_DecryptFinal_ex(decryptCtx, static_cast(resultBuffer.bufferBase()) + len, &len) != 1) failOpenSSLError("EVP_DecryptFinal_ex"); plaintextLen += len; __lenResult = plaintextLen; @@ -559,13 +560,13 @@ SSLSERVICES_API void SSLSERVICES_CALL pkRSASeal(ICodeContext *ctx, size32_t & __ failOpenSSLError("EVP_SealInit"); // Update the envelope (encrypt the plaintext) - size32_t len = 0; - if (EVP_SealUpdate(encryptCtx, static_cast(ciphertext.bufferBase()), reinterpret_cast(&len), reinterpret_cast(_plaintext), len_plaintext) != 1) + int len = 0; + if (EVP_SealUpdate(encryptCtx, static_cast(ciphertext.bufferBase()), &len, reinterpret_cast(_plaintext), len_plaintext) != 1) failOpenSSLError("EVP_SealUpdate"); ciphertextLen = len; // Finalize the envelope's ciphertext - if (EVP_SealFinal(encryptCtx, static_cast(ciphertext.bufferBase()) + len, reinterpret_cast(&len)) != 1) + if (EVP_SealFinal(encryptCtx, static_cast(ciphertext.bufferBase()) + len, &len) != 1) failOpenSSLError("EVP_SealFinal"); ciphertextLen += len; @@ -603,6 +604,8 @@ SSLSERVICES_API void SSLSERVICES_CALL pkRSASeal(ICodeContext *ctx, size32_t & __ { if (encryptCtx) EVP_CIPHER_CTX_free(encryptCtx); + for (size_t i = 0; i < publicKeys.size(); i++) + delete [] encryptedKeys[i]; delete [] encryptedKeys; __lenResult = 0; rtlFree(__result); @@ -684,12 +687,12 @@ SSLSERVICES_API void SSLSERVICES_CALL pkRSAUnseal(ICodeContext *ctx, size32_t & size32_t plaintextLen = newCipherTextLen; plaintext.ensureCapacity(plaintextLen); - size32_t len = 0; - if (EVP_OpenUpdate(decryptCtx, static_cast(plaintext.bufferBase()), reinterpret_cast(&len), newCipherText, newCipherTextLen) != 1) + int len = 0; + if (EVP_OpenUpdate(decryptCtx, static_cast(plaintext.bufferBase()), &len, newCipherText, newCipherTextLen) != 1) failOpenSSLError("EVP_OpenUpdate"); plaintextLen = len; - if (EVP_OpenFinal(decryptCtx, static_cast(plaintext.bufferBase()) + len, reinterpret_cast(&len)) != 1) + if (EVP_OpenFinal(decryptCtx, static_cast(plaintext.bufferBase()) + len, &len) != 1) failOpenSSLError("EVP_OpenFinal"); plaintextLen += len;