On Mon, Mar 06, 2023 at 10:52:31AM +0000, Job Snijders wrote: > Hi, > > RFC 7935 states in section 3: "The RSA key pairs used to compute the > signatures MUST have a 2048-bit modulus and a public exponent (e) of > 65,537." > > The below adds a check for that.
That's a good first step. See comments below. > OK? > > Kind regards, > > Job > > Index: cms.c > =================================================================== > RCS file: /cvs/src/usr.sbin/rpki-client/cms.c,v > retrieving revision 1.28 > diff -u -p -r1.28 cms.c > --- cms.c 6 Mar 2023 09:14:29 -0000 1.28 > +++ cms.c 6 Mar 2023 10:50:33 -0000 > @@ -23,6 +23,7 @@ > #include <unistd.h> > > #include <openssl/bio.h> > +#include <openssl/bn.h> > #include <openssl/cms.h> > > #include "extern.h" > @@ -76,10 +77,15 @@ cms_parse_validate_internal(X509 **xp, c > STACK_OF(X509_CRL) *crls; > STACK_OF(CMS_SignerInfo) *sinfos; > CMS_SignerInfo *si; > + EVP_PKEY *pkey; > X509_ALGOR *pdig, *psig; > + RSA *rsa; > + const BIGNUM *rsa_e; > + BN_ULONG e_value; > int i, nattrs, nid; > int has_ct = 0, has_md = 0, has_st = 0, > has_bst = 0; > + int key_bits; > int rc = 0; > > *xp = NULL; > @@ -184,7 +190,7 @@ cms_parse_validate_internal(X509 **xp, c > } > > /* Check digest and signature algorithms */ > - CMS_SignerInfo_get0_algs(si, NULL, NULL, &pdig, &psig); > + CMS_SignerInfo_get0_algs(si, &pkey, NULL, &pdig, &psig); > X509_ALGOR_get0(&obj, NULL, NULL, pdig); > nid = OBJ_obj2nid(obj); > if (nid != NID_sha256) { > @@ -198,6 +204,29 @@ cms_parse_validate_internal(X509 **xp, c > if (nid != NID_rsaEncryption && nid != NID_sha256WithRSAEncryption) { > warnx("%s: RFC 6488: wrong signature algorithm %s, want %s", > fn, OBJ_nid2ln(nid), OBJ_nid2ln(NID_rsaEncryption)); > + goto out; > + } I think we should avoid making cms_parse_validate_internal() longer than it already is. Since we anticipate that we need this check elsewhere, perhaps it's better to split it into a helper from the start. How about adding this to cms.c for now: static int validate_pkey(const EVP_PKEY *pkey) { } so cms_parse_validate_internal() only gets a pkey variable and can do if (!validate_pkey(pkey)) goto err; This could be moved to validate.c later when we identify the other places that need this check. > + if ((key_bits = EVP_PKEY_bits(pkey)) <= 0) { > + cryptowarnx("%s: failed to get cryptographic key length", fn); > + goto out; > + } > + if (key_bits != 2048) { > + warnx("%s: RFC 7935: expected 2048-bit modulus", fn); > + goto out; > + } Merge the previous two checks for simplicity: if ((key_bits = EVP_PKEY_bits(pkey)) != 2048) { warnx("%s: RFC 7935: expected 2048-bit modulus, got %d bits", fn, key_bits); goto out; } > + if ((rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) { > + warnx("%s: failed to extract RSA public key", fn); > + goto out; > + } > + > + RSA_get0_key(rsa, NULL, &rsa_e, NULL); I would prefer using the more explicit RSA_get0_e() (available since LibreSSL 3.5, which is the minimum supported version in portable): if ((rsa_e = RSA_get0_e(rsa)) == NULL) { > + if (rsa_e == NULL) { > + warnx("%s: failed to get RSA exponent", fn); > + goto out; > + } > + e_value = BN_get_word(rsa_e); > + if (e_value != 65537) { No need for e_value: if (!BN_is_word(rsa_e, 65537)) { > + warnx("%s: incorrect exponent (e) in RSA public key", fn); Should this error mention RFC 7935? > goto out; > } > >