mbox series

[00/18] Implement RSASSA-PSS signature verification

Message ID 20210330202829.4825-1-varad.gautam@suse.com
Headers show
Series Implement RSASSA-PSS signature verification | expand

Message

Varad Gautam March 30, 2021, 8:28 p.m. UTC
Linux currently supports RSA PKCSv1.5 encoding scheme for
signing / verification. This adds support for RSASSA PSS signature
verification as described in RFC8017 [1].

Patch 1 extends the x509 certificate parser to unpack PSS signature
  parameters.
Patches 2-8 pull out the common functions / struct definitions from
  rsa-pkcs1pad.c into rsa-common.c, to be shared across RSA encoding
  scheme implementations.
Patches 9, 10 provide some more plumbing to export the data needed to
  perform PSS operations (salt length, RSA modulus).
Patches 11-16 set up PSS scaffolding and provide the verification
  operation per RFC8017.
Patches 17, 18 turn the final knobs on to allow lowering PSS signatures
  for verification via keyctl.

The patchset is available as a git tree at [2].

Testing:
The implementation was tested by adding reference public keys to the
kernel's keyring via `keyctl padd` and then verifying a known
message digest / signature against this public key via `keyctl pkey_verify`.
The reference vectors were taken from:
- the Wycheproof testsuite [3]
- FIPS 186-2 and 186-4 test vectors [4]

The test harness is available at [5].

Example keyctl usage for PSS verification:
rsa_bits=4096 # 2048/3072/4096
hash_algo=sha256 # sha1/sha224/sha256/sha384/sha512
saltlen=32
# Generate keys, certificate:
openssl req -x509 -newkey rsa:$rsa_bits -nodes -keyout private.pem -out cert.der \
  -days 100 -outform der -$hash_algo -sigopt rsa_padding_mode:pss \
  -sigopt rsa_pss_saltlen:$saltlen -sigopt rsa_mgf1_md:$hash_algo

# Sign data.txt:
openssl dgst -${hash_algo} -sign private.pem -sigopt rsa_padding_mode:pss \
  -sigopt rsa_pss_saltlen:${saltlen} -out sig.bin data.txt

# Digest data.txt:
openssl dgst -${hash_algo} -binary -out data.${hash_algo}.raw data.txt

# Load pubkey into the kernel's keyring:
kv=$(keyctl padd asymmetric "test-key" @u < cert.der)

# Verify with `enc=pss`:
keyctl pkey_verify $kv "0" data.${hash_algo}.raw sig.bin "enc=pss hash=${hash_algo} slen=${saltlen}"

[1] https://tools.ietf.org/html/rfc8017#section-8.1
[2] https://github.com/varadgautam/kernel/tree/rsassa-psspad
[3] https://github.com/google/wycheproof/blob/master/testvectors/
[4] https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/digital-signatures#rsavs
[5] https://github.com/varadgautam/keyctl-rsa-tests

Varad Gautam (18):
  X.509: Parse RSASSA-PSS style certificates
  crypto: rsa-pkcs1pad: Rename pkcs1pad-specific functions to rsapad
  crypto: rsa-pkcs1pad: Extract pkcs1pad_create into a generic helper
  crypto: rsa-pkcs1pad: Pull out child req processing code into helpers
  crypto: rsa-pkcs1pad: Rename pkcs1pad_* structs to rsapad_*
  crypto: rsa: Start moving RSA common code to rsa-common
  crypto: rsa: Move more common code to rsa-common
  crypto: rsa: Move rsapad_akcipher_setup_child and callback to
    rsa-common
  crypto: Extend akcipher API to pass signature parameters
  crypto: rsa: Move struct rsa_mpi_key definition to rsa.h
  crypto: Scaffolding for RSA-PSS signature style
  crypto: rsa-psspad: Introduce shash alloc/dealloc helpers
  crypto: rsa-psspad: Get signature salt length from a given signature
  crypto: Implement MGF1 Mask Generation Function for RSASSA-PSS
  crypto: rsa-psspad: Provide PSS signature verify operation
  crypto: rsa-psspad: Implement signature verify callback
  crypto: Accept pss as valid encoding during signature verification
  keyctl_pkey: Add pkey parameter slen to pass in PSS salt length

 crypto/Kconfig                            |   6 +
 crypto/Makefile                           |   2 +
 crypto/asymmetric_keys/Makefile           |   5 +-
 crypto/asymmetric_keys/asymmetric_type.c  |   1 +
 crypto/asymmetric_keys/public_key.c       |  18 +-
 crypto/asymmetric_keys/x509_cert_parser.c | 152 ++++++++
 crypto/asymmetric_keys/x509_rsassa.asn1   |  17 +
 crypto/rsa-common.c                       | 291 ++++++++++++++++
 crypto/rsa-pkcs1pad.c                     | 400 +++-------------------
 crypto/rsa-psspad.c                       | 283 +++++++++++++++
 crypto/rsa.c                              |  26 +-
 include/crypto/akcipher.h                 |  26 ++
 include/crypto/internal/rsa-common.h      |  60 ++++
 include/crypto/internal/rsa.h             |   8 +
 include/crypto/public_key.h               |   4 +
 include/linux/keyctl.h                    |   1 +
 include/linux/oid_registry.h              |   3 +
 security/keys/keyctl_pkey.c               |   6 +
 18 files changed, 945 insertions(+), 364 deletions(-)
 create mode 100644 crypto/asymmetric_keys/x509_rsassa.asn1
 create mode 100644 crypto/rsa-common.c
 create mode 100644 crypto/rsa-psspad.c
 create mode 100644 include/crypto/internal/rsa-common.h

Comments

Jarkko Sakkinen March 31, 2021, 11:14 p.m. UTC | #1
On Tue, Mar 30, 2021 at 10:28:28PM +0200, Varad Gautam wrote:
> Accept pss encoding for public_key_verify_signature. If

> CONFIG_CRYPTO_RSASSA_PSS is disabled, crypto_alloc_akcipher will

> fail to find a pss backend anyway.

> 

> Signed-off-by: Varad Gautam <varad.gautam@suse.com>

> ---


Acked-by: Jarkko Sakkinen <jarkko@kernel.org>


/Jarkko

>  crypto/asymmetric_keys/public_key.c | 18 +++++++++++++-----

>  1 file changed, 13 insertions(+), 5 deletions(-)

> 

> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c

> index 788a4ba1e2e7..b9cc83ba7a12 100644

> --- a/crypto/asymmetric_keys/public_key.c

> +++ b/crypto/asymmetric_keys/public_key.c

> @@ -69,19 +69,20 @@ int software_key_determine_akcipher(const char *encoding,

>  {

>  	int n;

>  

> -	if (strcmp(encoding, "pkcs1") == 0) {

> +	if (strcmp(encoding, "pkcs1") == 0 || strcmp(encoding, "pss") == 0) {

>  		/* The data wangled by the RSA algorithm is typically padded

>  		 * and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447

> -		 * sec 8.2].

> +		 * sec 8.2] or EMSA-PSS [RFC8017 sec 9.1].

>  		 */

>  		if (!hash_algo)

>  			n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,

> -				     "pkcs1pad(%s)",

> +				     "%spad(%s)",

> +				     encoding,

>  				     pkey->pkey_algo);

>  		else

>  			n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,

> -				     "pkcs1pad(%s,%s)",

> -				     pkey->pkey_algo, hash_algo);

> +				     "%spad(%s,%s)",

> +				     encoding, pkey->pkey_algo, hash_algo);

>  		return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;

>  	}

>  

> @@ -363,6 +364,13 @@ int public_key_verify_signature(const struct public_key *pkey,

>  			goto error_free_key;

>  	}

>  

> +	if (strcmp(sig->encoding, "pss") == 0) {

> +		ret = crypto_akcipher_set_sig_params(tfm, sig, sizeof(*sig));

> +		if (ret) {

> +			goto error_free_key;

> +		}

> +	}

> +

>  	sg_init_table(src_sg, 2);

>  	sg_set_buf(&src_sg[0], sig->s, sig->s_size);

>  	sg_set_buf(&src_sg[1], sig->digest, sig->digest_size);

> -- 

> 2.30.2

> 

>
Herbert Xu April 1, 2021, 1:09 a.m. UTC | #2
On Tue, Mar 30, 2021 at 10:28:12PM +0200, Varad Gautam wrote:
> An X.509 wrapper for a RSASSA-PSS signature contains additional

> signature parameters over the PKCSv.15 encoding scheme. Extend the

> x509 parser to allow parsing RSASSA-PSS encoded certificates, with

> the defaults taken from RFC8017.


Where is the cover letter for this series?

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Varad Gautam April 1, 2021, 7:43 a.m. UTC | #3
On 4/1/21 3:09 AM, Herbert Xu wrote:
> On Tue, Mar 30, 2021 at 10:28:12PM +0200, Varad Gautam wrote:

>> An X.509 wrapper for a RSASSA-PSS signature contains additional

>> signature parameters over the PKCSv.15 encoding scheme. Extend the

>> x509 parser to allow parsing RSASSA-PSS encoded certificates, with

>> the defaults taken from RFC8017.

> 

> Where is the cover letter for this series?

> 


I realized the cover letter initially only went to linux-crypto@.
I've resent it to the missing destinations with the original Message-ID
to plug it back into the series [1].

[1] https://lore.kernel.org/lkml/20210330202829.4825-1-varad.gautam@suse.com/

Thanks,
Varad

> Thanks,

> 


-- 
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5
90409 Nürnberg
Germany

HRB 36809, AG Nürnberg
Geschäftsführer: Felix Imendörffer
Hongbo Li April 7, 2021, 8:27 a.m. UTC | #4
Hello Varad,

I also made an implementation of rsa pss: "[PATCH v3 0/4] crypto: add
rsa pss support for x509".
I notice your patches and did some review,  find the following
differences between our patches:
1. You rework the rsa pad framework. This is reasonable.
2. You did some changes on the keyctl and asymmetric struct. I don't
see the reason.
    Because for x509 layer, it only need to know the hash param, and
could ignore other params(salt len, mgfhash).
    Let rsa-pss itself parse the pss related params. So it seems we
don't need to change asymmetric's
    common struct.
3. Why reject the cert whose MGF is different from the hash function
used for signature generation?
   My implementation could support different hashes, so don't get your point.
4. I add a test vector and a patch to support using rsa-pss for iam.
5. Other implementation difference, i.e. the mgf and verify functions.

Maybe we could merge our patches, what's your opinion?

Best regards

Hongbo

Varad Gautam <varad.gautam@suse.com> 于2021年3月31日周三 上午4:31写道:
>

> An X.509 wrapper for a RSASSA-PSS signature contains additional

> signature parameters over the PKCSv.15 encoding scheme. Extend the

> x509 parser to allow parsing RSASSA-PSS encoded certificates, with

> the defaults taken from RFC8017.

>

> A certificate is rejected if the hash function used for the MGF is

> different from the hash function used for signature generation,

> although this is allowed in RFC8017.

>

> References: https://tools.ietf.org/html/rfc8017#appendix-C

> Signed-off-by: Varad Gautam <varad.gautam@suse.com>

> ---

>  crypto/asymmetric_keys/Makefile           |   5 +-

>  crypto/asymmetric_keys/x509_cert_parser.c | 152 ++++++++++++++++++++++

>  crypto/asymmetric_keys/x509_rsassa.asn1   |  17 +++

>  include/crypto/public_key.h               |   4 +

>  include/linux/oid_registry.h              |   3 +

>  5 files changed, 180 insertions(+), 1 deletion(-)

>  create mode 100644 crypto/asymmetric_keys/x509_rsassa.asn1

>
Varad Gautam April 7, 2021, 9:20 p.m. UTC | #5
Hi Hongbo,

On 4/7/21 10:27 AM, hongbo li wrote:
> Hello Varad,

> 

> I also made an implementation of rsa pss: "[PATCH v3 0/4] crypto: add

> rsa pss support for x509".

> I notice your patches and did some review,  find the following

> differences between our patches:

> 1. You rework the rsa pad framework. This is reasonable.

> 2. You did some changes on the keyctl and asymmetric struct. I don't

> see the reason.

>     Because for x509 layer, it only need to know the hash param, and

> could ignore other params(salt len, mgfhash).

>     Let rsa-pss itself parse the pss related params. So it seems we

> don't need to change asymmetric's

>     common struct.


A signature might be generated with a different set of params than those
used for signing the x509 certificate that wraps the corresponding pubkey.
In this case, using the params that came in when the pubkey was loaded,
instead of params for the actual signature would be incorrect. I see
struct public_key_signature as the right place to store such state,
regardless of where the signature came from (detached or selfsigned).

For the same reason, I also prefer the parsing machinery for signature
params be kept in x509_cert_parser instead of unpacking a buffer in the
PSS akcipher's set_pub_key implementation [1]. Going that way, we also end
up parsing these params twice, since x509 needs to unpack the hash
algorithm in a pss-specific way anyway.

For the IMA usecase, since x509_key_preparse() would have already filled
in the params in public_key_signature, asymmetric_verify should be able
to find and set these from key->payload before calling verify_signature().

> 3. Why reject the cert whose MGF is different from the hash function

> used for signature generation?

>    My implementation could support different hashes, so don't get your point.


The verify operation (psspad_verify_complete [3]) in theory supports it,
which I've tested against such certificates crafted via openssl.

I chose to reject such certificates early on during x509 parsing since,
- these are not a common occurence in practice, and
- testing (besides via openssl) without a set of reference vectors to harden
  the verification against seemed insufficient.

I've had some more test runs complete in the meantime, and I'll drop that
check in the next round.

> 4. I add a test vector and a patch to support using rsa-pss for iam.

> 5. Other implementation difference, i.e. the mgf and verify functions.

> 

> Maybe we could merge our patches, what's your opinion?

> 


Sounds good. I'll send out a v2 soon, and if you agree, the test vector [4]
and IMA [5] can go on top of it?

[1] https://patchwork.kernel.org/project/linux-crypto/patch/1617802906-30513-3-git-send-email-herbert.tencent@gmail.com/
[2] https://patchwork.kernel.org/project/linux-crypto/patch/1617802906-30513-5-git-send-email-herbert.tencent@gmail.com/
[3] https://patchwork.kernel.org/project/linux-crypto/patch/20210330202829.4825-2-varad.gautam@suse.com/
[4] https://patchwork.kernel.org/project/linux-crypto/patch/1617802906-30513-4-git-send-email-herbert.tencent@gmail.com/

Regards,
Varad

> Best regards

> 

> Hongbo

> 

> Varad Gautam <varad.gautam@suse.com> 于2021年3月31日周三 上午4:31写道:

>>

>> An X.509 wrapper for a RSASSA-PSS signature contains additional

>> signature parameters over the PKCSv.15 encoding scheme. Extend the

>> x509 parser to allow parsing RSASSA-PSS encoded certificates, with

>> the defaults taken from RFC8017.

>>

>> A certificate is rejected if the hash function used for the MGF is

>> different from the hash function used for signature generation,

>> although this is allowed in RFC8017.

>>

>> References: https://tools.ietf.org/html/rfc8017#appendix-C

>> Signed-off-by: Varad Gautam <varad.gautam@suse.com>

>> ---

>>  crypto/asymmetric_keys/Makefile           |   5 +-

>>  crypto/asymmetric_keys/x509_cert_parser.c | 152 ++++++++++++++++++++++

>>  crypto/asymmetric_keys/x509_rsassa.asn1   |  17 +++

>>  include/crypto/public_key.h               |   4 +

>>  include/linux/oid_registry.h              |   3 +

>>  5 files changed, 180 insertions(+), 1 deletion(-)

>>  create mode 100644 crypto/asymmetric_keys/x509_rsassa.asn1

>>

> 


-- 
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5
90409 Nürnberg
Germany

HRB 36809, AG Nürnberg
Geschäftsführer: Felix Imendörffer
Varad Gautam April 8, 2021, 2:21 p.m. UTC | #6
On 4/8/21 4:29 AM, hongbo li wrote:
> Hi Varad,

> 

> Varad Gautam <varad.gautam@suse.com <mailto:varad.gautam@suse.com>> 于2021年4月8日周四 上午5:20写道:

>>

>> Hi Hongbo,

>>

>> On 4/7/21 10:27 AM, hongbo li wrote:

>> > Hello Varad,

>> >

>> > I also made an implementation of rsa pss: "[PATCH v3 0/4] crypto: add

>> > rsa pss support for x509".

>> > I notice your patches and did some review,  find the following

>> > differences between our patches:

>> > 1. You rework the rsa pad framework. This is reasonable.

>> > 2. You did some changes on the keyctl and asymmetric struct. I don't

>> > see the reason.

>> >     Because for x509 layer, it only need to know the hash param, and

>> > could ignore other params(salt len, mgfhash).

>> >     Let rsa-pss itself parse the pss related params. So it seems we

>> > don't need to change asymmetric's

>> >     common struct.

>>

>> A signature might be generated with a different set of params than those

>> used for signing the x509 certificate that wraps the corresponding pubkey.

>> In this case, using the params that came in when the pubkey was loaded,

>> instead of params for the actual signature would be incorrect. I see

>> struct public_key_signature as the right place to store such state,

>> regardless of where the signature came from (detached or selfsigned).

>>

> 

> As what the comments in x509_note_params()  say:

> In crypto/asymmetric_keys/x509.asn1, AlgorithmIdentifier is used three times :

> 1. The signature AlgorithmIdentifier in TBSCertificate.

> 2. The algorithm in SubjectPublicKeyInfo

> 3. The signatureAlgorithm after tbsCertificate.

> When the pubkey was loaded, it is the third one. According to rfc5280 [1],

> the third has the same value as the first one.  Your patch use the first, and I

> use the third, I think both are fine.

> 


Consider the following to illustrate my point:

# Generate a key pair:
slen=20
mgfhash=sha384
openssl req -x509 -newkey rsa:4096 -nodes -keyout private.pem -out pss-0.der \
    -days 100 -outform der -config x509.genkey -sha384 -sigopt rsa_padding_mode:pss \
    -sigopt rsa_pss_saltlen:$slen -sigopt rsa_mgf1_md:$mgfhash

openssl x509 -in pss-0.der -inform der -pubkey -noout > public.pem

# Sign some data:
echo data > data.txt
slen=30
mgfhash=sha256
openssl dgst -sha384 -sign private.pem -sigopt rsa_padding_mode:pss \
    -sigopt rsa_pss_saltlen:$slen -sigopt rsa_mgf1_md:$mgfhash \
    -out sig.bin data.txt

sig.bin has a different slen and mgfhash vs the signature stored in pss-0.der.
Since psspad_set_pub_key() here [1] will unpack the params that correspond to
pss-0.der, verifying sig.bin (eg via keyctl pkey_verify) would fail.

>> For the same reason, I also prefer the parsing machinery for signature

>> params be kept in x509_cert_parser instead of unpacking a buffer in the

>> PSS akcipher's set_pub_key implementation [1]. Going that way, we also end

>> up parsing these params twice, since x509 needs to unpack the hash

>> algorithm in a pss-specific way anyway.

>>

> 

> Yes, my patch needs to parse the params twice, my purpose is to make small

> change to x509 layer.

> 

>> For the IMA usecase, since x509_key_preparse() would have already filled

>> in the params in public_key_signature, asymmetric_verify should be able

>> to find and set these from key->payload before calling verify_signature().

>>

>> > 3. Why reject the cert whose MGF is different from the hash function

>> > used for signature generation?

>> >    My implementation could support different hashes, so don't get your point.

>>

>> The verify operation (psspad_verify_complete [3]) in theory supports it,

>> which I've tested against such certificates crafted via openssl.

>>

>> I chose to reject such certificates early on during x509 parsing since,

>> - these are not a common occurence in practice, and

>> - testing (besides via openssl) without a set of reference vectors to harden

>>   the verification against seemed insufficient.

>>

>> I've had some more test runs complete in the meantime, and I'll drop that

>> check in the next round.

>>

>> > 4. I add a test vector and a patch to support using rsa-pss for iam.

>> > 5. Other implementation difference, i.e. the mgf and verify functions.

>> >

>> > Maybe we could merge our patches, what's your opinion?

>> >

>>

>> Sounds good. I'll send out a v2 soon, and if you agree, the test vector [4]

>> and IMA [5] can go on top of it?

> 

> Sure, Thank you.


I've posted a v2 at [2].

[1] https://patchwork.kernel.org/project/linux-crypto/patch/1617802906-30513-3-git-send-email-herbert.tencent@gmail.com/
[2] https://lkml.org/lkml/2021/4/8/775

Regards,
Varad

>>

>> [1] https://patchwork.kernel.org/project/linux-crypto/patch/1617802906-30513-3-git-send-email-herbert.tencent@gmail.com/ <https://patchwork.kernel.org/project/linux-crypto/patch/1617802906-30513-3-git-send-email-herbert.tencent@gmail.com/>

>> [2] https://patchwork.kernel.org/project/linux-crypto/patch/1617802906-30513-5-git-send-email-herbert.tencent@gmail.com/ <https://patchwork.kernel.org/project/linux-crypto/patch/1617802906-30513-5-git-send-email-herbert.tencent@gmail.com/>

>> [3] https://patchwork.kernel.org/project/linux-crypto/patch/20210330202829.4825-2-varad.gautam@suse.com/ <https://patchwork.kernel.org/project/linux-crypto/patch/20210330202829.4825-2-varad.gautam@suse.com/>

>> [4] https://patchwork.kernel.org/project/linux-crypto/patch/1617802906-30513-4-git-send-email-herbert.tencent@gmail.com/ <https://patchwork.kernel.org/project/linux-crypto/patch/1617802906-30513-4-git-send-email-herbert.tencent@gmail.com/>

>>

>> Regards,

>> Varad

>>

>> > Best regards

>> >

> 

> [1] https://tools.ietf.org/html/rfc5280#section-4.1.1.2 <https://tools.ietf.org/html/rfc5280#section-4.1.1.2>

> 

> Best Regards

> Hongbo

> 


-- 
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5
90409 Nürnberg
Germany

HRB 36809, AG Nürnberg
Geschäftsführer: Felix Imendörffer