Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rsassa-pss not supported with openssl ts -verify #7904

Open
brndrdck opened this issue Dec 14, 2018 · 20 comments
Open

rsassa-pss not supported with openssl ts -verify #7904

brndrdck opened this issue Dec 14, 2018 · 20 comments
Labels
branch: master Merge to master branch help wanted triaged: feature The issue/pr requests/adds a feature
Milestone

Comments

@brndrdck
Copy link

With openssl 1.1.1 rsassa-pss is supported. During my tests I could successfully verify certificates or certificate chains where this algorithm was used.
Unfortunately the verification of a timestamp that was signed using rsassa-pss failed. After a look at the source code I noticed, that it is not supported in "openssl ts -verify". The functions as well as the error messages are missing.
Is it possible to add the corresponding code in one of the next sub releases?

@d34d10cc
Copy link
Contributor

I am currently looking into this; seems to be a valid point.

@d34d10cc
Copy link
Contributor

Could you clarify exactly what your issue with timestamp verification is, because I've just successfully verified a TS response signed with a rsassa-pss cert (which was in turn signed by a root rsassa-pss CA cert)?

@brndrdck
Copy link
Author

brndrdck commented Dec 20, 2018 via email

@brndrdck
Copy link
Author

brndrdck commented Dec 28, 2018 via email

@d34d10cc
Copy link
Contributor

Thank you for your detailed reply, I'll look into it as soon as I can. Although, as I understand from your reply, you wanted to attach an archive to it, but I found nothing attached (GitHub doesn't have file upload functionality, AFAIK, you might want to use an external file host and reply with the link).

Unless I misunderstood you and you are talking (and quoted the email you received) about the archive you were sent? It would be much easier to debug if the test files were publicly available here, though.

@brndrdck
Copy link
Author

I hope that the upload worked now.
rsassa.zip

@brndrdck brndrdck reopened this Dec 29, 2018
@d34d10cc
Copy link
Contributor

It did work, thank you. I'll look into this ASAP

@brndrdck
Copy link
Author

brndrdck commented Jan 9, 2019

Hi Quantomicus,
do you have any ideas what is going wrong? If you need more information please let me know.

@brndrdck
Copy link
Author

brndrdck commented Jan 9, 2019

BTW.: Certificate (chain) can be verified on W7

@cucho
Copy link

cucho commented Jan 29, 2019

I have the same issue as @brndrdck. Please find in openssl-issue-7904.zip the following files to reproduce the error:

  • cert.pem: The issuer signing certificate.
  • token-rsaencryption.der: The timestamp token with rsaEncryption.
  • token-rsassapss.der: The timestamp token with rsassaPss.

Both timestamp tokens are signed by the same certificate, but they timestamp different hashes.

Here is a diff of the asn1parse of both tokens (interesting part is in line 72).

The token with rsaEncryption is verified:

$ openssl ts -verify -partial_chain -in token-rsaencryption.der -token_in \
> -digest bcbfcee484a9b243bafad6b8a43e0ddc1bf091837463e7c717495395eefbc2a6 \
> -CAfile cert.pem -untrusted cert.pem
Verification: OK
Using configuration from C:/Program Files/Git/mingw64/ssl/openssl.cnf

The token with rsassaPss fails to verify:

$ openssl ts -verify -partial_chain -in token-rsassapss.der -token_in \
> -digest 00017f0b41ce9649602a0218cd02ed0b0a3d93130329451cc782b7dfda79ce71 \
> -CAfile cert.pem -untrusted cert.pem
Verification: FAILED
Using configuration from C:/Program Files/Git/mingw64/ssl/openssl.cnf 
14548:error:0407008A:rsa routines:RSA_padding_check_PKCS1_type_1:invalid padding:../openssl-1.1.1a/crypto/rsa/rsa_pk1.c:67:
14548:error:04067072:rsa routines:rsa_ossl_public_decrypt:padding check failed:../openssl-1.1.1a/crypto/rsa/rsa_ossl.c:582:
14548:error:21071069:PKCS7 routines:PKCS7_signatureVerify:signature failure:../openssl-1.1.1a/crypto/pkcs7/pk7_doit.c:1037:
14548:error:2F06A06D:time stamp routines:TS_RESP_verify_signature:signature failure:../openssl-1.1.1a/crypto/ts/ts_rsp_verify.c:143:

Note: I am using OpenSSL v1.1.1a bundled with Git for Windows.

@starcmed
Copy link

starcmed commented Feb 15, 2019

Hello, I think the cause is the signer's certificate.

The sample data show me the following:

The public key in the signer's certificate has the type EVP_PKEY_RSA. When verifying, the key is used without further comparison. But according to the SignerInfo in the timestamp, the signature was encrypted using EVP_PKEY_RSA_PSS.

(Unfortunately, I do not know if the timestamp creator makes a mistake here or if the verification should detect this case.)

Anyway, I have developed a helper solution that in this case uses a temporary public key with the type according to SignerInfo.

For this I have developed a new function

EVP_PKEY * X509_PUBKEY_for_alg (X509_PUBKEY * pubkey, X509_ALGOR * alg)

and stored in "crypto\x509\x_pubkey.c". (It is a copy of an already existing function with slight changes for my purposes. The error processing (X509err (...)) still needs to be adjusted.)

I use the new function in "crypto\ pkcs7\pk7_doit.c" in the function "int PKCS7_signatureVerify (...)".

As you can see, I have no experience with the source and structure of the library. But I hope that the analysis is not entirely wrong and the proposed changes help someone else.

Here are both functions (openssl 1.1.1):

(crypto\x509\x_pubkey.c)

EVP_PKEY *X509_PUBKEY_for_alg(X509_PUBKEY *pubkey, X509_ALGOR *alg)
{
    EVP_PKEY *pkey = EVP_PKEY_new();

    if (pkey == NULL) {
        X509err(X509_F_X509_PUBKEY_DECODE, ERR_R_MALLOC_FAILURE);
        return NULL;
    }

    if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(alg->algorithm))) {
        X509err(X509_F_X509_PUBKEY_DECODE, X509_R_UNSUPPORTED_ALGORITHM);
        goto error;
    }

    if (pkey->ameth->pub_decode) {
        /*
         * Treat any failure of pub_decode as a decode error. In
         * future we could have different return codes for decode
         * errors and fatal errors such as malloc failure.
         */
        if (!pkey->ameth->pub_decode(pkey, pubkey)) {
            X509err(X509_F_X509_PUBKEY_DECODE, X509_R_PUBLIC_KEY_DECODE_ERROR);
            goto error;
        }
    } else {
        X509err(X509_F_X509_PUBKEY_DECODE, X509_R_METHOD_NOT_SUPPORTED);
        goto error;
    }

    return pkey;

 error:
    EVP_PKEY_free(pkey);
    return NULL;
}

(crypto\pkcs7\pk7_doit.c)

int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
                          X509 *x509)
{
    ASN1_OCTET_STRING *os;
    EVP_MD_CTX *mdc_tmp, *mdc;
    int ret = 0, i;
    int md_type;
    STACK_OF(X509_ATTRIBUTE) *sk;
    BIO *btmp;
    EVP_PKEY *pkey_signer;
    EVP_PKEY *pkey;

    mdc_tmp = EVP_MD_CTX_new();
    if (mdc_tmp == NULL) {
        PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_MALLOC_FAILURE);
        goto err;
    }

    if (!PKCS7_type_is_signed(p7) && !PKCS7_type_is_signedAndEnveloped(p7)) {
        PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_WRONG_PKCS7_TYPE);
        goto err;
    }

    md_type = OBJ_obj2nid(si->digest_alg->algorithm);

    btmp = bio;
    for (;;) {
        if ((btmp == NULL) ||
            ((btmp = BIO_find_type(btmp, BIO_TYPE_MD)) == NULL)) {
            PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
                     PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
            goto err;
        }
        BIO_get_md_ctx(btmp, &mdc);
        if (mdc == NULL) {
            PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_INTERNAL_ERROR);
            goto err;
        }
        if (EVP_MD_CTX_type(mdc) == md_type)
            break;
        /*
         * Workaround for some broken clients that put the signature OID
         * instead of the digest OID in digest_alg->algorithm
         */
        if (EVP_MD_pkey_type(EVP_MD_CTX_md(mdc)) == md_type)
            break;
        btmp = BIO_next(btmp);
    }

    /*
     * mdc is the digest ctx that we want, unless there are attributes, in
     * which case the digest is the signed attributes
     */
    if (!EVP_MD_CTX_copy_ex(mdc_tmp, mdc))
        goto err;

    sk = si->auth_attr;
    if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) {
        unsigned char md_dat[EVP_MAX_MD_SIZE], *abuf = NULL;
        unsigned int md_len;
        int alen;
        ASN1_OCTET_STRING *message_digest;

        if (!EVP_DigestFinal_ex(mdc_tmp, md_dat, &md_len))
            goto err;
        message_digest = PKCS7_digest_from_attributes(sk);
        if (!message_digest) {
            PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
                     PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
            goto err;
        }
        if ((message_digest->length != (int)md_len) ||
            (memcmp(message_digest->data, md_dat, md_len))) {
            PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_DIGEST_FAILURE);
            ret = -1;
            goto err;
        }

        if (!EVP_VerifyInit_ex(mdc_tmp, EVP_get_digestbynid(md_type), NULL))
            goto err;

        alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf,
                             ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY));
        if (alen <= 0) {
            PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_ASN1_LIB);
            ret = -1;
            goto err;
        }
        if (!EVP_VerifyUpdate(mdc_tmp, abuf, alen))
            goto err;

        OPENSSL_free(abuf);
    }

    os = si->enc_digest;
    pkey_signer = X509_get0_pubkey(x509);
    if (!pkey_signer) {
        ret = -1;
        goto err;
    }
    int pkey_type_signer = EVP_PKEY_base_id(pkey_signer);    
    int pkey_type_si = OBJ_obj2nid(si->digest_enc_alg->algorithm);
    if (pkey_type_signer == pkey_type_si) {
        pkey = pkey_signer;
    } else {      
        X509_PUBKEY * pubkey = X509_get_X509_PUBKEY(x509);
        if ( !pubkey ) {
          ret = -1;
          goto err;
        }
        pkey = X509_PUBKEY_for_alg(pubkey, si->digest_enc_alg);
        if ( !pkey ) {
          ret = -1;
          goto err;
        }
    }

    i = EVP_VerifyFinal(mdc_tmp, os->data, os->length, pkey);
    if (i <= 0) {
        PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_SIGNATURE_FAILURE);
        ret = -1;
        goto err;
    }
    ret = 1;
 err:
    EVP_MD_CTX_free(mdc_tmp);
    if (pkey != pkey_signer) EVP_PKEY_free(pkey);
    return ret;
}

@pavel-kokolemin
Copy link

pavel-kokolemin commented Feb 19, 2019

I also have similar problem:

$ openssl smime -verify -in pkcs7_rsa_pss.txt -inform pem -noverify > /dev/null
Verification failure
139823960600640:error:0407008A:rsa routines:RSA_padding_check_PKCS1_type_1:invalid padding:../crypto/rsa/rsa_pk1.c:67:
139823960600640:error:04067072:rsa routines:rsa_ossl_public_decrypt:padding check failed:../crypto/rsa/rsa_ossl.c:573:
139823960600640:error:21071069:PKCS7 routines:PKCS7_signatureVerify:signature failure:../crypto/pkcs7/pk7_doit.c:1037:
139823960600640:error:21075069:PKCS7 routines:PKCS7_verify:signature failure:../crypto/pkcs7/pk7_smime.c:353:

Version with @starcmed's fix works correctly (@starcmed, thank you!):

$ LD_LIBRARY_PATH=<...> <...>/apps/openssl smime -verify -in pkcs7_rsa_pss.txt -inform pem -noverify > /dev/null
Verification successful
    0:d=0  hl=4 l=2444 cons: SEQUENCE          
    4:d=1  hl=2 l=   9 prim: OBJECT            :pkcs7-signedData
   15:d=1  hl=4 l=2429 cons: cont [ 0 ]        
   19:d=2  hl=4 l=2425 cons: SEQUENCE          
   23:d=3  hl=2 l=   1 prim: INTEGER           :03
   26:d=3  hl=2 l=  13 cons: SET               
   28:d=4  hl=2 l=  11 cons: SEQUENCE          
   30:d=5  hl=2 l=   9 prim: OBJECT            :sha256
   41:d=3  hl=4 l= 272 cons: SEQUENCE          
   45:d=4  hl=2 l=   6 prim: OBJECT            :2.<skip>
   53:d=4  hl=4 l= 260 cons: cont [ 0 ]        
   57:d=5  hl=4 l= 256 prim: OCTET STRING      [HEX DUMP]:3081F<skip>
  317:d=3  hl=4 l=1609 cons: cont [ 0 ]        
  321:d=4  hl=4 l=1605 cons: SEQUENCE          
  325:d=5  hl=4 l=1017 cons: SEQUENCE          
  329:d=6  hl=2 l=   3 cons: cont [ 0 ]        
  331:d=7  hl=2 l=   1 prim: INTEGER           :02
  334:d=6  hl=2 l=   8 prim: INTEGER           :20A4E5B7FA811CFF
  344:d=6  hl=2 l=  65 cons: SEQUENCE          
  346:d=7  hl=2 l=   9 prim: OBJECT            :rsassaPss
<skip>

@csware
Copy link

csware commented Nov 20, 2019

More and more people having this issue. Could you please look into this issue?

@levitte
Copy link
Member

levitte commented Nov 20, 2019

To begin with, which openssl version are you all referring to?

@csware
Copy link

csware commented Nov 21, 2019

To begin with, which openssl version are you all referring to?

In my case:

$ openssl version
OpenSSL 1.1.1d  10 Sep 2019
$ cat /etc/debian_version
10.2

@starcmed
Copy link

In my case: 'openssl-1.1.1b'

I attached some test files to this message.

In this test, I use a timestamp generated by an official TSA:

openssl ts -verify -queryfile test.tsq -in test.tsr -CAfile certs.txt

As can be seen, the verification does not work:

Verification: FAILED
4228:error:0407008A:rsa routines:RSA_padding_check_PKCS1_type_1:invalid padding:crypto\rsa\rsa_pk1.c:67:
4228:error:04067072:rsa routines:rsa_ossl_public_decrypt:padding check failed:crypto\rsa\rsa_ossl.c:588:
4228:error:21071069:PKCS7 routines:PKCS7_signatureVerify:signature failure:crypto\pkcs7\pk7_doit.c:1041:
4228:error:2F06A06D:time stamp routines:TS_RESP_verify_signature:signature failure:crypto\ts\ts_rsp_verify.c:143:

Tests.zip

@fbett
Copy link

fbett commented Jan 25, 2021

I can confirm the issue of @starcmed in comment 557014714
using the same qualified timestamp service (dgnservice) and "OpenSSL 1.1.1d"

@fbett
Copy link

fbett commented Jan 26, 2021

The problem also exists in the current master (b897b35):

00715D9E8A7F0000:error:0200008A:rsa routines:RSA_padding_check_PKCS1_type_1:invalid padding:crypto/rsa/rsa_pk1.c:75:
00715D9E8A7F0000:error:02000072:rsa routines:rsa_ossl_public_decrypt:padding check failed:crypto/rsa/rsa_ossl.c:607:
00715D9E8A7F0000:error:1C800004:Provider routines:rsa_verify:reason(4):providers/implementations/signature/rsa.c:652:
00715D9E8A7F0000:error:10800069:PKCS7 routines:PKCS7_signatureVerify:signature failure:crypto/pkcs7/pk7_doit.c:1182:
00715D9E8A7F0000:error:1780006D:time stamp routines:TS_RESP_verify_signature:signature failure:crypto/ts/ts_rsp_verify.c:140:`

@t8m t8m added triaged: feature The issue/pr requests/adds a feature branch: 1.1.1 Merge to OpenSSL_1_1_1-stable branch branch: master Merge to master branch help wanted labels Jan 26, 2021
@dirkx-gavirate-2021
Copy link

Cause is indeed RSA_padding_check_PKCS1_type_1 called in rsa_ossl.c not containing support for PSS.

A possible/quick work around is switching to CMS_verify() which supports PSS.

@t8m t8m removed the branch: 1.1.1 Merge to OpenSSL_1_1_1-stable branch label Jul 23, 2021
@t8m t8m added this to the Post 3.0.0 milestone Jul 23, 2021
@TaaviE
Copy link

TaaviE commented Mar 19, 2024

I was just trying to validate S/MIME signatures that use RSA-PSS and I'm really surprised that OpenSSL 3.0.10 does not make it available through openssl smime -verify .

Verification failure
40A74B1EE47F0000:error:0200008A:rsa routines:RSA_padding_check_PKCS1_type_1:invalid padding:../crypto/rsa/rsa_pk1.c:79:
40A74B1EE47F0000:error:02000072:rsa routines:rsa_ossl_public_decrypt:padding check failed:../crypto/rsa/rsa_ossl.c:697:
40A74B1EE47F0000:error:1C880004:Provider routines:rsa_verify:RSA lib:../providers/implementations/signature/rsa_sig.c:774:
40A74B1EE47F0000:error:10800069:PKCS7 routines:PKCS7_signatureVerify:signature failure:../crypto/pkcs7/pk7_doit.c:1137:
40A74B1EE47F0000:error:10800069:PKCS7 routines:PKCS7_verify:signature failure:../crypto/pkcs7/pk7_smime.c:363:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
branch: master Merge to master branch help wanted triaged: feature The issue/pr requests/adds a feature
Projects
None yet
Development

No branches or pull requests