Headline
CVE-2021-43085: CMAC encryption result error caused by wrong implementation of CMAC_Final() · Issue #16873 · openssl/openssl
An Insecure Permissions vulnerability exists in the OpenSSL Project 3.0 due to an error in the implementation of the CMAC_Final() function.
Hello.
I found a wrong output of CMAC encryption when using OpenSSL 3.0.0. The testfile is as follows:
#include <openssl/cmac.h>
#include <iostream>
#include <cstdio>
#include <iomanip>
using namespace std;
void cmac_aes_128_ecb(){
const EVP_CIPHER* cipher = EVP_aes_128_ecb();
CMAC_CTX* cmac_ctx = CMAC_CTX_new();
const uint8_t key[] = {0x9b, 0xe8, 0x42, 0x04, 0xa7, 0x1e, 0x31, 0xeb, 0xf4, 0xe0, 0xb1, 0x1a, 0xe2, 0x5c, 0xac, 0x2f};
const uint8_t msg[] = {0x9b, 0x6b, 0x6a, 0x5c, 0x1f, 0x0c, 0x5b, 0x7b, 0x01, 0x9b, 0x6b, 0x6a, 0x5c, 0x1f, 0x0c, 0x5b, 0x7b, 0x01} ;
if(!CMAC_Init(cmac_ctx,key,sizeof(key),cipher,0)){
printf("err1\n");
return;
}
if(!CMAC_Update(cmac_ctx,msg,sizeof(msg))){
printf("err2\n");
return;
}
uint8_t res[32]={0};
size_t len = 0;
if(!CMAC_Final(cmac_ctx, res, &len)){
printf("err3\n");
return;
}
for(int i = 0; i < sizeof(res); i++){
printf("%02x ", res[i]);
}
printf("\n");
}
int main(){
printf("OpenSSL result:\n");
cmac_aes_128_ecb();
return 0;
}
The expected output and OpenSSL’s output are:
expected output: 77 ab ed ce eb 46 8f 03 17 7e 66 7f eb 4d 85 24
OpenSSL's output: 43 be 6f 41 19 8a 60 ea e5 33 7d fc 8b 83 ae 09
By reading the source code, I found that OpenSSL has an error in the implementation of the CMAC_Final() function. According to CMAC algorithm, the final encryption logic should be:
However, the OpenSSL’s implementation is:
The wrong place is probably in line 220~230 of openssl/crypto/cmac/cmac.c. I have confirmed that this error still exists in the latest version of the code.
I tried the following modifications and found that I can get the correct output:
if (lb == bl) {
for (i = 0; i < bl; i++)
ctx->last_block[i] = ctx->last_block[i] ^ ctx->k1[i];
} else {
ctx->last_block[lb] = 0x80;
if (bl - lb > 1)
memset(ctx->last_block + lb + 1, 0, bl - lb - 1);
for (i = 0; i < bl; i++)
ctx->last_block[i] = ctx->last_block[i] ^ ctx->k2[i];
}
for (i = 0; i < bl; i++)
ctx->last_block[i] = ctx->last_block[i] ^ ctx->tbl[i];
if (!EVP_Cipher(ctx->cctx, ctx->tbl, ctx->last_block, bl)) {
OPENSSL_cleanse(out, bl);
return 0;
}
for (i = 0; i < bl; i++)
out[i] = ctx->tbl[i];
I hope that you can check this issue and I’m looking forward to your reply.
Have a good day!