Improve & test legacy mbedtls_pkcs12_pbe

* Prevent pkcs12_pbe encryption when PKCS7 padding has been
  disabled since this not part of the specs.
* Allow decryption when PKCS7 padding is disabled for legacy
  reasons, However, invalid padding is not checked.
* Document new behaviour, known limitations and possible
  security concerns.
* Add tests to check these scenarios. Test data has been
  generated by the below code using OpenSSL as a reference:

#include <openssl/pkcs12.h>
#include <openssl/evp.h>
#include <openssl/des.h>
#include <openssl/asn1.h>
#include "crypto/asn1.h"
#include <string.h>

int main()
{
    char pass[] = "\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB";
    unsigned char salt[] = "\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC\xCC";
    unsigned char plaintext[] = "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA";
    unsigned char *ciphertext = NULL;
    int iter = 10;
    X509_ALGOR *alg =  X509_ALGOR_new();
    int ciphertext_len = 0;
    int alg_nid = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
    alg->parameter = ASN1_TYPE_new();
    struct asn1_object_st * aobj;
    PKCS5_pbe_set0_algor(alg, alg_nid, iter,
                         salt, sizeof(salt)-1);

    aobj = alg->algorithm;
    printf("\"30%.2X", 2 + aobj->length + alg->parameter->value.asn1_string->length);
    printf("06%.2X", aobj->length);
    for (int i = 0; i < aobj->length; i++) {
        printf("%.2X", aobj->data[i]);
    }

    for (int i = 0; i < alg->parameter->value.asn1_string->length; i++) {
        printf("%.2X", alg->parameter->value.asn1_string->data[i]);
    }
    printf("\":\"");

    for (int i = 0; i < sizeof(pass)-1; i++) {
        printf("%.2X", pass[i] & 0xFF);
    }
    printf("\":\"");
    for (int i = 0; i < sizeof(plaintext)-1; i++) {
        printf("%.2X", plaintext[i]);
    }
    printf("\":");
    printf("0");
    printf(":\"");

    unsigned char * res = PKCS12_pbe_crypt(alg, pass, sizeof(pass)-1, plaintext, sizeof(plaintext)-1, &ciphertext, &ciphertext_len, 1);

    if (res == NULL)
        printf("Encryption failed!\n");
    for (int i = 0; i < ciphertext_len; i++) {
        printf("%.2X", res[i]);
    }
    printf("\"\n");

    return 0;
}

Signed-off-by: Waleed Elmelegy <waleed.elmelegy@arm.com>
#
This commit is contained in:
Waleed Elmelegy 2023-09-04 15:11:22 +01:00
parent 1a8ebe39bf
commit 255db80910
4 changed files with 159 additions and 5 deletions

View file

@ -56,6 +56,21 @@ extern "C" {
* \brief PKCS12 Password Based function (encryption / decryption)
* for cipher-based and mbedtls_md-based PBE's
*
* \note When encrypting, #MBEDTLS_CIPHER_PADDING_PKCS7 must
* be enabled at compile time.
*
* \warning When decrypting:
* - if #MBEDTLS_CIPHER_PADDING_PKCS7 is enabled at compile
* time, this function validates the CBC padding and returns
* #MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH if the padding is
* invalid. Note that this can help active adversaries
* attempting to brute-forcing the password. Note also that
* there is no guarantee that an invalid password will be
* detected (the chances of a valid padding with a random
* password are about 1/255).
* - if #MBEDTLS_CIPHER_PADDING_PKCS7 is disabled at compile
* time, this function does not validate the CBC padding.
*
* \param pbe_params an ASN1 buffer containing the pkcs-12 PbeParams structure
* \param mode either #MBEDTLS_PKCS12_PBE_ENCRYPT or
* #MBEDTLS_PKCS12_PBE_DECRYPT
@ -66,7 +81,15 @@ extern "C" {
* \param pwdlen length of the password (may be 0)
* \param input the input data
* \param len data length
* \param output the output buffer
* \param output Output buffer.
* On success, it contains the encrypted or decrypted data,
* possibly followed by the CBC padding.
* On failure, the content is indeterminate.
* For decryption, there must be enough room for \p len
* bytes.
* For encryption, there must be enough room for
* \p len + 1 bytes, rounded up to the block size of
* the block cipher identified by \p pbe_params.
*
* \return 0 if successful, or a MBEDTLS_ERR_XXX code
*/