/* LibTomCrypt, modular cryptographic library -- Tom St Denis */ /* SPDX-License-Identifier: Unlicense */ #include "tomcrypt_private.h" #ifdef LTC_PKCS_8 /** PKCS#8 decrypt if necessary & flexi-decode @param in Pointer to the ASN.1 encoded input data @param inlen Length of the input data @param pwd Pointer to the password that was used when encrypting @param pwdlen Length of the password @param decoded_list Pointer to a pointer for the flexi-decoded list @return CRYPT_OK on success */ int pkcs8_decode_flexi(const unsigned char *in, unsigned long inlen, const password_ctx *pw_ctx, ltc_asn1_list **decoded_list) { unsigned long len = inlen; unsigned long dec_size; unsigned char *dec_data = NULL; ltc_asn1_list *l = NULL; int err; pbes_arg pbes; LTC_ARGCHK(in != NULL); LTC_ARGCHK(decoded_list != NULL); XMEMSET(&pbes, 0, sizeof(pbes)); *decoded_list = NULL; if ((err = der_decode_sequence_flexi(in, &len, &l)) == CRYPT_OK) { /* the following "if" detects whether it is encrypted or not */ /* PKCS8 Setup * 0:d=0 hl=4 l= 380 cons: SEQUENCE * 4:d=1 hl=2 l= 78 cons: SEQUENCE * 6:d=2 hl=2 l= 9 prim: OBJECT :OID indicating PBES1 or PBES2 (== *lalgoid) * 17:d=2 hl=2 l= 65 cons: SEQUENCE * Stuff in between is dependent on whether it's PBES1 or PBES2 * 84:d=1 hl=4 l= 296 prim: OCTET STRING :bytes (== encrypted data) */ if (l->type == LTC_ASN1_SEQUENCE && LTC_ASN1_IS_TYPE(l->child, LTC_ASN1_SEQUENCE) && LTC_ASN1_IS_TYPE(l->child->child, LTC_ASN1_OBJECT_IDENTIFIER) && LTC_ASN1_IS_TYPE(l->child->child->next, LTC_ASN1_SEQUENCE) && LTC_ASN1_IS_TYPE(l->child->next, LTC_ASN1_OCTET_STRING)) { ltc_asn1_list *lalgoid = l->child->child; if ((pw_ctx == NULL) || (pw_ctx->callback == NULL)) { err = CRYPT_PW_CTX_MISSING; goto LBL_DONE; } if (pbes1_extract(lalgoid, &pbes) == CRYPT_OK) { /* Successfully extracted PBES1 parameters */ } else if (pbes2_extract(lalgoid, &pbes) == CRYPT_OK) { /* Successfully extracted PBES2 parameters */ } else { /* unsupported encryption */ err = CRYPT_INVALID_PACKET; goto LBL_DONE; } if (pw_ctx->callback(&pbes.pw.pw, &pbes.pw.l, pw_ctx->userdata)) { err = CRYPT_ERROR; goto LBL_DONE; } pbes.enc_data = l->child->next; dec_size = pbes.enc_data->size; if ((dec_data = XMALLOC(dec_size)) == NULL) { err = CRYPT_MEM; goto LBL_DONE; } if ((err = pbes_decrypt(&pbes, dec_data, &dec_size)) != CRYPT_OK) goto LBL_DONE; der_free_sequence_flexi(l); l = NULL; err = der_decode_sequence_flexi(dec_data, &dec_size, &l); if (err != CRYPT_OK) goto LBL_DONE; *decoded_list = l; } else { /* not encrypted */ err = CRYPT_OK; *decoded_list = l; } /* Set l to NULL so it won't be free'd */ l = NULL; } LBL_DONE: if (dec_data) { zeromem(dec_data, dec_size); XFREE(dec_data); } password_free(&pbes.pw, pw_ctx); if (l) der_free_sequence_flexi(l); return err; } #endif