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

enable CMS sign/verify for provider-implemented PKEYs #17733

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 0 additions & 23 deletions crypto/cms/cms_ec.c
Expand Up @@ -388,26 +388,3 @@ int ossl_cms_ecdh_envelope(CMS_RecipientInfo *ri, int decrypt)
ERR_raise(ERR_LIB_CMS, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
return 0;
}

/* ECDSA and DSA implementation is the same */
int ossl_cms_ecdsa_dsa_sign(CMS_SignerInfo *si, int verify)
{
assert(verify == 0 || verify == 1);

if (!verify) {
int snid, hnid;
X509_ALGOR *alg1, *alg2;
EVP_PKEY *pkey = si->pkey;

CMS_SignerInfo_get0_algs(si, NULL, NULL, &alg1, &alg2);
if (alg1 == NULL || alg1->algorithm == NULL)
return -1;
hnid = OBJ_obj2nid(alg1->algorithm);
if (hnid == NID_undef)
return -1;
if (!OBJ_find_sigid_by_algs(&snid, hnid, EVP_PKEY_get_id(pkey)))
return -1;
return X509_ALGOR_set0(alg2, OBJ_nid2obj(snid), V_ASN1_UNDEF, NULL);
}
return 1;
}
1 change: 0 additions & 1 deletion crypto/cms/cms_local.h
Expand Up @@ -479,7 +479,6 @@ int ossl_cms_check_signing_certs(const CMS_SignerInfo *si,
int ossl_cms_dh_envelope(CMS_RecipientInfo *ri, int decrypt);
int ossl_cms_ecdh_envelope(CMS_RecipientInfo *ri, int decrypt);
int ossl_cms_rsa_envelope(CMS_RecipientInfo *ri, int decrypt);
int ossl_cms_ecdsa_dsa_sign(CMS_SignerInfo *si, int verify);
int ossl_cms_rsa_sign(CMS_SignerInfo *si, int verify);

DECLARE_ASN1_ITEM(CMS_CertificateChoices)
Expand Down
37 changes: 34 additions & 3 deletions crypto/cms/cms_sd.c
Expand Up @@ -227,19 +227,50 @@ int ossl_cms_SignerIdentifier_cert_cmp(CMS_SignerIdentifier *sid, X509 *cert)
return -1;
}

/* Method to map any, incl. provider-implemented PKEY types to OIDs */
/* ECDSA and DSA and all provider-delivered signatures implementation is the same */
static int cms_generic_sign(CMS_SignerInfo *si, int verify)
{
if (!ossl_assert(verify == 0 || verify == 1))
return -1;

if (!verify) {
int snid, hnid, pknid;
X509_ALGOR *alg1, *alg2;
EVP_PKEY *pkey = si->pkey;
pknid = EVP_PKEY_get_id(pkey);

CMS_SignerInfo_get0_algs(si, NULL, NULL, &alg1, &alg2);
if (alg1 == NULL || alg1->algorithm == NULL)
return -1;
hnid = OBJ_obj2nid(alg1->algorithm);
if (hnid == NID_undef)
return -1;
mattcaswell marked this conversation as resolved.
Show resolved Hide resolved
if (pknid <= 0) { /* check whether a provider registered a NID */
const char *typename = EVP_PKEY_get0_type_name(pkey);
if (typename != NULL)
pknid = OBJ_txt2nid(typename);
}
if (!OBJ_find_sigid_by_algs(&snid, hnid, pknid))
return -1;
return X509_ALGOR_set0(alg2, OBJ_nid2obj(snid), V_ASN1_UNDEF, NULL);
}
return 1;
}

static int cms_sd_asn1_ctrl(CMS_SignerInfo *si, int cmd)
{
EVP_PKEY *pkey = si->pkey;
int i;

if (EVP_PKEY_is_a(pkey, "DSA") || EVP_PKEY_is_a(pkey, "EC"))
return ossl_cms_ecdsa_dsa_sign(si, cmd);
return cms_generic_sign(si, cmd);
else if (EVP_PKEY_is_a(pkey, "RSA") || EVP_PKEY_is_a(pkey, "RSA-PSS"))
return ossl_cms_rsa_sign(si, cmd);

/* Something else? We'll give engines etc a chance to handle this */
/* Now give engines, providers, etc a chance to handle this */
if (pkey->ameth == NULL || pkey->ameth->pkey_ctrl == NULL)
return 1;
return cms_generic_sign(si, cmd);
i = pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_CMS_SIGN, cmd, si);
if (i == -2) {
ERR_raise(ERR_LIB_CMS, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
Expand Down
12 changes: 10 additions & 2 deletions crypto/objects/obj_xref.c
Expand Up @@ -36,7 +36,14 @@ static int sigx_cmp(const nid_triple *const *a, const nid_triple *const *b)
int ret;

ret = (*a)->hash_id - (*b)->hash_id;
if (ret != 0)
/* The "b" side of the comparison carries the algorithms already
* registered. A NID_undef for 'hash_id' there means that the
* signature algorithm doesn't need a digest to operate OK. In
* such case, any hash_id/digest algorithm on the test side (a),
* incl. NID_undef, is acceptable. signature algorithm NID
* (pkey_id) must match in any case.
*/
if ((ret != 0) && ((*b)->hash_id != NID_undef))
mattcaswell marked this conversation as resolved.
Show resolved Hide resolved
return ret;
return (*a)->pkey_id - (*b)->pkey_id;
}
Expand Down Expand Up @@ -105,7 +112,8 @@ int OBJ_find_sigid_by_algs(int *psignid, int dig_nid, int pkey_nid)
const nid_triple **rv;
int idx;

if (dig_nid == NID_undef || pkey_nid == NID_undef)
/* permitting searches for sig algs without digest: */
if (pkey_nid == NID_undef)
return 0;

tmp.hash_id = dig_nid;
Expand Down
52 changes: 44 additions & 8 deletions test/upcallstest.c
Expand Up @@ -27,6 +27,7 @@ static const OSSL_DISPATCH obj_dispatch_table[] = {
static OSSL_FUNC_core_obj_add_sigid_fn *c_obj_add_sigid = NULL;
static OSSL_FUNC_core_obj_create_fn *c_obj_create = NULL;

/* test signature ids requiring digest */
#define SIG_OID "1.3.6.1.4.1.16604.998877.1"
#define SIG_SN "my-sig"
#define SIG_LN "my-sig-long"
Expand All @@ -37,6 +38,14 @@ static OSSL_FUNC_core_obj_create_fn *c_obj_create = NULL;
#define SIGALG_SN "my-sigalg"
#define SIGALG_LN "my-sigalg-long"

/* test signature ids requiring no digest */
#define NODIG_SIG_OID "1.3.6.1.4.1.16604.998877.4"
#define NODIG_SIG_SN "my-nodig-sig"
#define NODIG_SIG_LN "my-nodig-sig-long"
#define NODIG_SIGALG_OID "1.3.6.1.4.1.16604.998877.5"
#define NODIG_SIGALG_SN "my-nodig-sigalg"
#define NODIG_SIGALG_LN "my-nodig-sigalg-long"

static int obj_provider_init(const OSSL_CORE_HANDLE *handle,
const OSSL_DISPATCH *in,
const OSSL_DISPATCH **out,
Expand All @@ -45,7 +54,7 @@ static int obj_provider_init(const OSSL_CORE_HANDLE *handle,
*provctx = (void *)handle;
*out = obj_dispatch_table;

for (; in->function_id != 0; in++) {
for (; in->function_id != 0; in++) {
switch (in->function_id) {
case OSSL_FUNC_CORE_OBJ_ADD_SIGID:
c_obj_add_sigid = OSSL_FUNC_core_obj_add_sigid(in);
Expand All @@ -65,17 +74,18 @@ static int obj_provider_init(const OSSL_CORE_HANDLE *handle,
|| !c_obj_create(handle, SIGALG_OID, SIGALG_SN, SIGALG_LN))
return 0;

if (!c_obj_create(handle, NODIG_SIG_OID, NODIG_SIG_SN, NODIG_SIG_LN)
|| !c_obj_create(handle, NODIG_SIGALG_OID, NODIG_SIGALG_SN, NODIG_SIGALG_LN))
return 0;

if (!c_obj_add_sigid(handle, SIGALG_OID, DIGEST_SN, SIG_LN))
return 0;

/* additional tests checking empty digest algs are accepted, too */
if (!c_obj_add_sigid(handle, SIGALG_OID, "", SIG_LN))
if (!c_obj_add_sigid(handle, NODIG_SIGALG_OID, "", NODIG_SIG_LN))
return 0;
/* checking wrong digest alg name is rejected: */
if (c_obj_add_sigid(handle, SIGALG_OID, "NonsenseAlg", SIG_LN))
return 0;
/* Testing actual triplet addition under separate sig alg */
if (!c_obj_add_sigid(handle, SIG_OID, NULL, SIG_LN))
if (c_obj_add_sigid(handle, NODIG_SIGALG_OID, "NonsenseAlg", NODIG_SIG_LN))
return 0;

return 1;
Expand All @@ -85,7 +95,7 @@ static int obj_create_test(void)
{
OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
OSSL_PROVIDER *objprov = NULL;
int sigalgnid, digestnid, signid;
int sigalgnid, digestnid, signid, foundsid;
int testresult = 0;

if (!TEST_ptr(libctx))
Expand All @@ -107,13 +117,39 @@ static int obj_create_test(void)
goto err;

/* Check empty digest alg storage capability */
sigalgnid = OBJ_txt2nid(SIG_OID);
sigalgnid = OBJ_txt2nid(NODIG_SIGALG_OID);
if (!TEST_int_ne(sigalgnid, NID_undef)
|| !TEST_true(OBJ_find_sigid_algs(sigalgnid, &digestnid, &signid))
|| !TEST_int_eq(digestnid, NID_undef)
|| !TEST_int_ne(signid, NID_undef))
goto err;

/* Testing OBJ_find_sigid_by_algs */
/* First check exact sig/digest recall: */
sigalgnid = OBJ_sn2nid(SIGALG_SN);
digestnid = OBJ_sn2nid(DIGEST_SN);
signid = OBJ_ln2nid(SIG_LN);
if ((!OBJ_find_sigid_by_algs(&foundsid, digestnid, signid)) ||
(foundsid != sigalgnid))
return 0;
/* Check wrong signature/digest combination is rejected */
if ((OBJ_find_sigid_by_algs(&foundsid, OBJ_sn2nid("SHA512"), signid)) &&
(foundsid == sigalgnid))
return 0;
/* Now also check signature not needing digest is found */
/* a) when some digest is given */
sigalgnid = OBJ_sn2nid(NODIG_SIGALG_SN);
digestnid = OBJ_sn2nid("SHA512");
signid = OBJ_ln2nid(NODIG_SIG_LN);
if ((!OBJ_find_sigid_by_algs(&foundsid, digestnid, signid)) ||
(foundsid != sigalgnid))
return 0;
/* b) when NID_undef is passed */
digestnid = NID_undef;
if ((!OBJ_find_sigid_by_algs(&foundsid, digestnid, signid)) ||
(foundsid != sigalgnid))
return 0;

testresult = 1;
err:
OSSL_PROVIDER_unload(objprov);
Expand Down