[Asterisk-code-review] crypto: Use EVP API's instead of legacy API's (asterisk[master])
Philip Prindeville
asteriskteam at digium.com
Fri May 6 11:34:19 CDT 2022
Philip Prindeville has uploaded this change for review. ( https://gerrit.asterisk.org/c/asterisk/+/18534 )
Change subject: crypto: Use EVP API's instead of legacy API's
......................................................................
crypto: Use EVP API's instead of legacy API's
ASTERISK-30046 #close
Signed-off-by: Philip Prindeville <philipp at redfish-solutions.com>
Change-Id: I5c738756de75fd27ebad54be144c0ac6193f21b2
---
M channels/chan_iax2.c
M include/asterisk/crypto.h
M res/res_crypto.c
3 files changed, 236 insertions(+), 46 deletions(-)
git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/34/18534/1
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 6d76dc5..a465649 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -6383,7 +6383,7 @@
{
int i;
for (i = 0; i < 60; i++) {
- if (ecx->rd_key[i]) {
+ if (ecx->raw[i]) {
return 0; /* stop if we encounter anything non-zero */
}
}
diff --git a/include/asterisk/crypto.h b/include/asterisk/crypto.h
index ff294ee..18cccd0 100644
--- a/include/asterisk/crypto.h
+++ b/include/asterisk/crypto.h
@@ -30,14 +30,15 @@
#include "asterisk/optional_api.h"
#include "asterisk/logger.h"
-#ifdef HAVE_CRYPTO
-#include "openssl/aes.h"
-typedef AES_KEY ast_aes_encrypt_key;
-typedef AES_KEY ast_aes_decrypt_key;
-#else /* !HAVE_CRYPTO */
-typedef char ast_aes_encrypt_key;
-typedef char ast_aes_decrypt_key;
-#endif /* HAVE_CRYPTO */
+#define AST_CRYPTO_RSA_KEY_BITS 1024
+#define AST_CRYPTO_AES_BLOCKSIZE 128
+
+struct aes_key {
+ unsigned char raw[AST_CRYPTO_AES_BLOCKSIZE / 8];
+};
+
+typedef struct aes_key ast_aes_encrypt_key;
+typedef struct aes_key ast_aes_decrypt_key;
#define AST_CRYPTO_RSA_KEY_BITS 1024
#define AST_CRYPTO_AES_BLOCKSIZE 128
@@ -168,7 +169,7 @@
* \param ctx address of an aes encryption context filled in with ast_aes_set_encrypt_key
*/
AST_OPTIONAL_API(void, ast_aes_encrypt,
- (const unsigned char *in, unsigned char *out, const ast_aes_encrypt_key *ctx),
+ (const unsigned char *in, unsigned char *out, const ast_aes_encrypt_key *key),
{ ast_log(LOG_WARNING, "AES encryption disabled. Install OpenSSL.\n");return; });
/*!
@@ -178,7 +179,7 @@
* \param ctx address of an aes encryption context filled in with ast_aes_set_decrypt_key
*/
AST_OPTIONAL_API(void, ast_aes_decrypt,
- (const unsigned char *in, unsigned char *out, const ast_aes_decrypt_key *ctx),
+ (const unsigned char *in, unsigned char *out, const ast_aes_decrypt_key *key),
{ ast_log(LOG_WARNING, "AES encryption disabled. Install OpenSSL.\n");return; });
AST_OPTIONAL_API(int, ast_crypto_loaded, (void), { return 0; });
diff --git a/res/res_crypto.c b/res/res_crypto.c
index 5645458..b97667d 100644
--- a/res/res_crypto.c
+++ b/res/res_crypto.c
@@ -41,8 +41,8 @@
#include <openssl/err.h> /* for ERR_print_errors_fp */
#include <openssl/ssl.h> /* for NID_sha1, RSA */
#include <openssl/pem.h> /* for PEM_read_RSAPrivateKey, PEM_read_... */
-#include <openssl/rsa.h> /* for RSA_free, RSA_private_decrypt, RSA */
#include <openssl/sha.h> /* for SHA1 */
+#include <openssl/evp.h> /* for EVP_PKEY, EVP_sha1(), ... */
#include "asterisk/cli.h" /* for ast_cli, ast_cli_args, ast_cli_entry */
#include "asterisk/compat.h" /* for strcasecmp */
@@ -73,6 +73,8 @@
#define KEY_NEEDS_PASSCODE (1 << 16)
+#define RSA_PKCS_OAEP_PADDING_LEN 41
+
struct ast_key {
/*! Name of entity */
char name[80];
@@ -80,8 +82,8 @@
char fn[256];
/*! Key type (AST_KEY_PUB or AST_KEY_PRIV, along with flags from above) */
int ktype;
- /*! RSA structure (if successfully loaded) */
- RSA *rsa;
+ /*! RSA key structure (if successfully loaded) */
+ EVP_PKEY *pkey;
/*! Whether we should be deleted */
int delme;
/*! FD for input (or -1 if no input allowed, or -2 if we needed input) */
@@ -256,13 +258,13 @@
rewind(f);
/* Now load the key with the right method */
if (ktype == AST_KEY_PUBLIC) {
- key->rsa = PEM_read_RSA_PUBKEY(f, NULL, pw_cb, key);
+ PEM_read_PUBKEY(f, &key->pkey, pw_cb, key);
} else {
- key->rsa = PEM_read_RSAPrivateKey(f, NULL, pw_cb, key);
+ PEM_read_PrivateKey(f, &key->pkey, pw_cb, key);
}
fclose(f);
- if (key->rsa) {
- if (RSA_size(key->rsa) == 128) {
+ if (key->pkey) {
+ if (EVP_PKEY_size(key->pkey) == (AST_CRYPTO_RSA_KEY_BITS / 8)) {
/* Key loaded okay */
key->ktype &= ~KEY_NEEDS_PASSCODE;
ast_verb(3, "Loaded %s key '%s'\n", key->ktype == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE", key->name);
@@ -301,6 +303,35 @@
return key;
}
+static int evp_pkey_sign(EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, unsigned char *sig, unsigned *siglen, unsigned padding)
+{
+ EVP_PKEY_CTX *ctx = NULL;
+ int res = -1;
+ size_t _siglen;
+
+ if (*siglen < EVP_PKEY_size(pkey))
+ return -1;
+
+ do {
+ if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL)
+ break;
+
+ if ((res = EVP_PKEY_sign_init(ctx)) <= 0)
+ break;
+ if ((res = EVP_PKEY_CTX_set_rsa_padding(ctx, padding)) <= 0)
+ break;
+ if ((res = EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha1())) <= 0)
+ break;
+ _siglen = *siglen;
+ if ((res = EVP_PKEY_sign(ctx, sig, &_siglen, in, inlen)) <= 0)
+ break;
+ *siglen = _siglen;
+ } while (0);
+
+ EVP_PKEY_CTX_free(ctx);
+ return res;
+}
+
/*!
* \brief signs outgoing message with public key
* \see ast_sign_bin
@@ -316,82 +347,155 @@
return -1;
}
+ if (siglen < EVP_PKEY_size(key->pkey)) {
+ ast_log(LOG_WARNING, "Signature buffer too small\n");
+ return -1;
+ }
+
/* Calculate digest of message */
SHA1((unsigned char *)msg, msglen, digest);
/* Verify signature */
- if ((res = RSA_sign(NID_sha1, digest, sizeof(digest), dsig, &siglen, key->rsa)) != 1) {
- ast_log(LOG_WARNING, "RSA Signature (key %s) failed\n", key->name);
+ if ((res = evp_pkey_sign(key->pkey, digest, sizeof(digest), dsig, &siglen, RSA_PKCS1_PADDING)) <= 0) {
+ ast_log(LOG_WARNING, "RSA Signature (key %s) failed %d\n", key->name, res);
return -1;
}
- if (siglen != 128) {
- ast_log(LOG_WARNING, "Unexpected signature length %d, expecting %d\n", (int)siglen, (int)128);
+ if (siglen != EVP_PKEY_size(key->pkey)) {
+ ast_log(LOG_WARNING, "Unexpected signature length %u, expecting %d\n", siglen, EVP_PKEY_size(key->pkey));
return -1;
}
return 0;
}
+static int evp_pkey_decrypt(EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, unsigned char *out, unsigned *outlen, unsigned padding)
+{
+ EVP_PKEY_CTX *ctx = NULL;
+ int res = -1;
+ size_t _outlen;
+
+ if (*outlen < EVP_PKEY_size(pkey))
+ return -1;
+
+ if (inlen != EVP_PKEY_size(pkey))
+ return -1;
+
+ do {
+ if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL)
+ break;
+
+ if ((res = EVP_PKEY_decrypt_init(ctx)) <= 0)
+ break;
+ if ((res = EVP_PKEY_CTX_set_rsa_padding(ctx, padding)) <= 0)
+ break;
+ _outlen = *outlen;
+ if ((res = EVP_PKEY_decrypt(ctx, out, &_outlen, in, inlen)) <= 0)
+ break;
+ res = *outlen = _outlen;
+ } while (0);
+
+ EVP_PKEY_CTX_free(ctx);
+ return res;
+}
+
/*!
* \brief decrypt a message
* \see ast_decrypt_bin
*/
int AST_OPTIONAL_API_NAME(ast_decrypt_bin)(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
{
- int res, pos = 0;
+ int res;
+ unsigned pos = 0, dstlen, blocksize;
if (key->ktype != AST_KEY_PRIVATE) {
ast_log(LOG_WARNING, "Cannot decrypt with a public key\n");
return -1;
}
- if (srclen % 128) {
- ast_log(LOG_NOTICE, "Tried to decrypt something not a multiple of 128 bytes\n");
+ blocksize = EVP_PKEY_size(key->pkey);
+
+ if (srclen % blocksize) {
+ ast_log(LOG_NOTICE, "Tried to decrypt something not a multiple of %u bytes\n", blocksize);
return -1;
}
- while (srclen) {
+ while (srclen > 0) {
/* Process chunks 128 bytes at a time */
- if ((res = RSA_private_decrypt(128, src, dst, key->rsa, RSA_PKCS1_OAEP_PADDING)) < 0) {
+ dstlen = blocksize;
+ if ((res = evp_pkey_decrypt(key->pkey, src, blocksize, dst, &dstlen, RSA_PKCS1_OAEP_PADDING)) <= 0) {
return -1;
}
- pos += res;
- src += 128;
- srclen -= 128;
- dst += res;
+ pos += dstlen;
+ src += blocksize;
+ srclen -= blocksize;
+ dst += dstlen;
}
return pos;
}
+static int evp_pkey_encrypt(EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, unsigned char *out, unsigned *outlen, unsigned padding)
+{
+ EVP_PKEY_CTX *ctx = NULL;
+ int res = -1;
+ size_t _outlen;
+
+ if (inlen > EVP_PKEY_size(pkey) - RSA_PKCS_OAEP_PADDING_LEN)
+ return -1;
+
+ if (*outlen < EVP_PKEY_size(pkey))
+ return -1;
+
+ do {
+ if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL)
+ break;
+
+ if ((res = EVP_PKEY_encrypt_init(ctx)) <= 0)
+ break;
+ if ((res = EVP_PKEY_CTX_set_rsa_padding(ctx, padding)) <= 0)
+ break;
+ _outlen = *outlen;
+ if ((res = EVP_PKEY_encrypt(ctx, out, &_outlen, in, inlen)) <= 0)
+ break;
+ res = *outlen = _outlen;
+ } while (0);
+
+ EVP_PKEY_CTX_free(ctx);
+ return res;
+}
+
/*!
* \brief encrypt a message
* \see ast_encrypt_bin
*/
int AST_OPTIONAL_API_NAME(ast_encrypt_bin)(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
{
- int res, bytes, pos = 0;
+ unsigned bytes, pos = 0, dstlen, blocksize;
+ int res;
if (key->ktype != AST_KEY_PUBLIC) {
ast_log(LOG_WARNING, "Cannot encrypt with a private key\n");
return -1;
}
+ blocksize = EVP_PKEY_size(key->pkey);
+
while (srclen) {
bytes = srclen;
- if (bytes > 128 - 41) {
- bytes = 128 - 41;
+ if (bytes > blocksize - RSA_PKCS_OAEP_PADDING_LEN) {
+ bytes = blocksize - RSA_PKCS_OAEP_PADDING_LEN;
}
/* Process chunks 128-41 bytes at a time */
- if ((res = RSA_public_encrypt(bytes, src, dst, key->rsa, RSA_PKCS1_OAEP_PADDING)) != 128) {
+ dstlen = blocksize;
+ if ((res = evp_pkey_encrypt(key->pkey, src, bytes, dst, &dstlen, RSA_PKCS1_OAEP_PADDING)) != blocksize) {
ast_log(LOG_NOTICE, "How odd, encrypted size is %d\n", res);
return -1;
}
src += bytes;
srclen -= bytes;
- pos += res;
- dst += res;
+ pos += dstlen;
+ dst += dstlen;
}
return pos;
}
@@ -402,6 +506,7 @@
*/
int AST_OPTIONAL_API_NAME(ast_sign)(struct ast_key *key, char *msg, char *sig)
{
+ /* assumes 1024 bit RSA key size */
unsigned char dsig[128];
int siglen = sizeof(dsig), res;
@@ -413,6 +518,32 @@
return res;
}
+static int evp_pkey_verify(EVP_PKEY *pkey, const unsigned char *in, unsigned inlen, const unsigned char *sig, unsigned siglen, unsigned padding)
+{
+ EVP_PKEY_CTX *ctx = NULL;
+ int res = -1;
+
+ if (siglen < EVP_PKEY_size(pkey))
+ return -1;
+
+ do {
+ if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL)
+ break;
+
+ if ((res = EVP_PKEY_verify_init(ctx)) <= 0)
+ break;
+ if ((res = EVP_PKEY_CTX_set_rsa_padding(ctx, padding)) <= 0)
+ break;
+ if ((res = EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha1())) <= 0)
+ break;
+ if ((res = EVP_PKEY_verify(ctx, sig, siglen, in, inlen)) <= 0)
+ break;
+ } while (0);
+
+ EVP_PKEY_CTX_free(ctx);
+ return res;
+}
+
/*!
* \brief check signature of a message
* \see ast_check_signature_bin
@@ -433,7 +564,7 @@
SHA1((unsigned char *)msg, msglen, digest);
/* Verify signature */
- if ((res = RSA_verify(NID_sha1, digest, sizeof(digest), (unsigned char *)dsig, 128, key->rsa)) != 1) {
+ if (!(res = evp_pkey_verify(key->pkey, (const unsigned char *)digest, sizeof(digest), (unsigned char *)dsig, 128, RSA_PKCS1_PADDING))) {
ast_debug(1, "Key failed verification: %s\n", key->name);
return -1;
}
@@ -475,22 +606,80 @@
int AST_OPTIONAL_API_NAME(ast_aes_set_encrypt_key)(const unsigned char *key, ast_aes_encrypt_key *ctx)
{
- return AES_set_encrypt_key(key, 128, ctx);
+ if (key == NULL || ctx == NULL)
+ return -1;
+ memcpy(ctx->raw, key, AST_CRYPTO_AES_BLOCKSIZE / 8);
+ return 0;
}
int AST_OPTIONAL_API_NAME(ast_aes_set_decrypt_key)(const unsigned char *key, ast_aes_decrypt_key *ctx)
{
- return AES_set_decrypt_key(key, 128, ctx);
+ if (key == NULL || ctx == NULL)
+ return -1;
+ memcpy(ctx->raw, key, AST_CRYPTO_AES_BLOCKSIZE / 8);
+ return 0;
}
-void AST_OPTIONAL_API_NAME(ast_aes_encrypt)(const unsigned char *in, unsigned char *out, const ast_aes_encrypt_key *ctx)
+static int evp_cipher_aes_encrypt(const unsigned char *in, unsigned char *out, unsigned inlen, const ast_aes_encrypt_key *key)
{
- return AES_encrypt(in, out, ctx);
+ EVP_CIPHER_CTX *ctx;
+ int res, outlen, finallen;
+ unsigned char final[AST_CRYPTO_AES_BLOCKSIZE / 8];
+
+ if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
+ return -1;
+
+ do {
+ if ((res = EVP_EncryptInit(ctx, EVP_aes_128_ecb(), key->raw, NULL)) <= 0)
+ break;
+ if ((res = EVP_EncryptUpdate(ctx, out, &outlen, in, inlen)) <= 0)
+ break;
+ /* for ECB, this is a no-op */
+ if ((res = EVP_EncryptFinal(ctx, final, &finallen)) <= 0)
+ break;
+
+ res = outlen;
+ } while (0);
+
+ EVP_CIPHER_CTX_free(ctx);
+
+ return res;
}
-void AST_OPTIONAL_API_NAME(ast_aes_decrypt)(const unsigned char *in, unsigned char *out, const ast_aes_decrypt_key *ctx)
+void AST_OPTIONAL_API_NAME(ast_aes_encrypt)(const unsigned char *in, unsigned char *out, const ast_aes_encrypt_key *key)
{
- return AES_decrypt(in, out, ctx);
+ evp_cipher_aes_encrypt(in, out, AST_CRYPTO_AES_BLOCKSIZE / 8, key);
+}
+
+static int evp_cipher_aes_decrypt(const unsigned char *in, unsigned char *out, unsigned inlen, const ast_aes_decrypt_key *key)
+{
+ EVP_CIPHER_CTX *ctx;
+ int res, outlen, finallen;
+ unsigned char final[AST_CRYPTO_AES_BLOCKSIZE / 8];
+
+ if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
+ return -1;
+
+ do {
+ if ((res = EVP_DecryptInit(ctx, EVP_aes_128_ecb(), key->raw, NULL)) <= 0)
+ break;
+ if ((res = EVP_DecryptUpdate(ctx, out, &outlen, in, inlen)) <= 0)
+ break;
+ /* for ECB, this is a no-op */
+ if ((res = EVP_DecryptFinal(ctx, final, &finallen)) <= 0)
+ break;
+
+ res = outlen;
+ } while (0);
+
+ EVP_CIPHER_CTX_free(ctx);
+
+ return res;
+}
+
+void AST_OPTIONAL_API_NAME(ast_aes_decrypt)(const unsigned char *in, unsigned char *out, const ast_aes_decrypt_key *key)
+{
+ evp_cipher_aes_decrypt(in, out, AST_CRYPTO_AES_BLOCKSIZE / 8, key);
}
/*!
@@ -533,8 +722,8 @@
if (key->delme) {
ast_debug(1, "Deleting key %s type %d\n", key->name, key->ktype);
AST_RWLIST_REMOVE_CURRENT(list);
- if (key->rsa) {
- RSA_free(key->rsa);
+ if (key->pkey) {
+ EVP_PKEY_free(key->pkey);
}
ast_free(key);
}
--
To view, visit https://gerrit.asterisk.org/c/asterisk/+/18534
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Change-Id: I5c738756de75fd27ebad54be144c0ac6193f21b2
Gerrit-Change-Number: 18534
Gerrit-PatchSet: 1
Gerrit-Owner: Philip Prindeville <philipp at redfish-solutions.com>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20220506/1c8ae574/attachment-0001.html>
More information about the asterisk-code-review
mailing list