esig / dss-demonstrations

Examples of DSS integration
GNU Lesser General Public License v2.1
92 stars 70 forks source link

Error "The time-stamp message imprint is not intact!" while trying to increment the level of signature in PAdES B-T #57

Closed IonutCorbu closed 2 months ago

IonutCorbu commented 2 months ago

Hello! I'm trying to increment the level of my signature after I already saved the file with PAdES B-B signature. In order to do this, I searched for the ByteRanges and I got the last one in order to don't invalidate the higher signatures. After I got the signature hex-encoded, I transformed it in unsigned char and after this, I used CMS_ContentInfo structure from OpenSSL in order to add the token from TS response in CMS_SignerInfo* cms_info. After I added this, I transformed it again in hexa and put it in the file. Now, the problem is that the file is recognized as B-T by DSS, but i receive this error message for the signature-time-stamp: image

I understood that the hash is not the correct one, but I don't understand why because I got it identically as my direct approach (without saving in file the B-B) and in that situation, I don't receive this error.

Could you help me? I attached here the file signed, DSS report and the code that I used: default_signed.pdf DSS-Detailed-report.pdf

PDFDoc& PadesSignatureService::UpgradeToLevelT(unsigned char* pfxcontent, int fileLength, const char* password, const char* hash_chosen, const char* tsa_url)
{
    PadesSignatureTHandler* handler = new PadesSignatureTHandler(pfxcontent, fileLength, password, hash_chosen, tsa_url);
    this->output_filename = get_output_filename(this->filename);
    std::string content=readPDF(this->filename);
    std::regex pattern("ByteRange \\[\\d+ (\\d+) (\\d+) \\d+\\]");

    std::sregex_iterator it(content.begin(), content.end(), pattern);
    std::sregex_iterator end;

    int signature_start, signature_end;

    for (; it != end; ++it) {
        std::smatch match = *it;
        if (match.size() == 3) {
            signature_start = std::stoi(match[1].str());
            signature_end = std::stoi(match[2].str());
        }
        else {
            std::cerr << "Invalid match found." << std::endl;
        }
        //break;
    }

    std::string signature=content.substr(signature_start+1, signature_end - signature_start-2);
    std::vector<unsigned char> bytes = hexToBytes(signature);
    unsigned char* content_bytes = &(bytes[0]);
    CMS_ContentInfo* cms=CMS_ContentInfo_new();
    cms=d2i_CMS_ContentInfo(&cms, (const unsigned char**) & content_bytes, bytes.size());
    if (cms == NULL)
    {
        cout << "Problem\n";
    }
    STACK_OF(CMS_SignerInfo)* signers = CMS_get0_SignerInfos(cms);
    CMS_SignerInfo* cms_info = sk_CMS_SignerInfo_value(signers, 0);
    ASN1_OCTET_STRING* signature_cms_info = CMS_SignerInfo_get0_signature(cms_info);

    unsigned char* signature_from_cms = (unsigned char*)malloc(signature_cms_info->length * sizeof(unsigned char));
    memcpy(signature_from_cms, signature_cms_info->data, signature_cms_info->length);
    EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
    const EVP_MD* md = EVP_get_digestbyname(hash_chosen);

    unsigned char* hash = (unsigned char*)malloc(handler->getDigestSize() * sizeof(unsigned char));
    EVP_DigestInit_ex(mdctx, md, NULL);
    EVP_DigestUpdate(mdctx, signature_cms_info, signature_cms_info->length);
    unsigned int hash_len;
    EVP_DigestFinal_ex(mdctx, hash, &hash_len);

    if (handler->getDigestSize() != hash_len)
    {
        printf("Error\n");
        exit(1);
    }

    TS_RESP* tsResp = getTS_for_update(tsa_url, hash_chosen, hash, handler->getDigestSize());
    PKCS7* token = TS_RESP_get_token(tsResp);
    int ts_token_length = i2d_PKCS7(token, NULL);
    unsigned char* ts_token_string = (unsigned char*)malloc(ts_token_length * sizeof(unsigned char));
    unsigned char* copy_ts = ts_token_string;
    i2d_PKCS7(token, &copy_ts);

    ASN1_STRING* time_seq = ASN1_STRING_new();
    ASN1_STRING_set(time_seq, ts_token_string, ts_token_length);
    CMS_unsigned_add1_attr_by_NID(cms_info, NID_id_smime_aa_timeStampToken, V_ASN1_SEQUENCE, ts_token_string, ts_token_length);

    int cmsLen = i2d_CMS_ContentInfo(cms, NULL);
    if (cmsLen < 0) {
        CMS_ContentInfo_free(cms);
    }
    std::vector<unsigned char> result(cmsLen);
    unsigned char* pCmsBuf = result.data();
    if (i2d_CMS_ContentInfo(cms, &pCmsBuf) < 0) {
        CMS_ContentInfo_free(cms);
    }

    unsigned char* new_signature = &(result[0]);
    std::string hexSignature = bytesToHexString(new_signature, result.size());
    replaceSignatureInPDF(this->filename, hexSignature, signature_start, signature_end - signature_start - 2);
    this->document->Save(this->output_filename, SDFDoc::e_incremental, NULL);
    PDFDoc *doc=new PDFDoc(this->output_filename);

    return *doc;

}

Thank you for reading!

IonutCorbu commented 2 months ago

I made a mistake at this line: EVP_DigestUpdate(mdctx, signature_cms_info, signature_cms_info->length);

after I took the signature I have to use signature_cms_info->data for the signature itself, and the hash was wrong because I tried to do the hash on the ASN1_OCTET_STRING* and not on the signature itself. Sorry for the issue!