Conversation
|
As long as the diverse |
|
Agree that we must avoid having bad patterns in the code (or adding any more...) I had an idea: these new functions return 1 on success, 0 on failure and -1 for not found. This allows mandatory params via: I think we're going to see a lot of both types, so making a short coding pattern for each seems useful. The other possibilities I can think of are an extra argument or another set of calls to distinguish between the two. Of these, I prefer the latter. |
|
I think it is only the set functions that need to care about about mandatory or not. The get functions will always have to check if the value was retrieved or not. |
What set functions and what get functions? If it's this API you're talking about, i.e. the likes of |
|
Also, I think that it's not up to this API to decide what's mandatory and what's not. For example, for an RSA key that can have numbers assigned (which would be typical for our default provider, yeah?), it would be perfectly plausible to only set the 'n' and 'e' numbers, without making it mandatory to specify the rest of the possible numbers. |
The example that triggered this in #8513 is setting things that were not in the params array. The setters are required. Does your comment mean the getters aren't? I can't think of a use case where param is got but the caller doesn't need to check if it existed. I've added a number of OSSL_PARAM_optional_set_XXX() calls to distinguish the two usages. |
And here I see where I think you get confused. The function in question is
You will need a set of |
|
I see the source of the confusion. Thanks for the clarification. |
|
I insist, there should be |
doc/man3/OSSL_PARAM_TYPE.pod
Outdated
There was a problem hiding this comment.
I disagree with the error, but good catch on the NULL check. The code should be:
if ((p = OSSL_PARAM_locate(params, "foo")) != NULL)
OSSL_PARAM_set_utf8_ptr(p, "foo value");
if ((p = OSSL_PARAM_locate(params, "bar")) != NULL)
OSSL_PARAM_set_utf8_ptr(p, "bar value");
if ((p = OSSL_PARAM_locate(params, "cookie")) != NULL)
OSSL_PARAM_set_utf8_ptr(p, "cookie value");The rationale is still the same, if the other end is only interested in the cookie value, why should it be obligated to also get the foo and bar values?
There was a problem hiding this comment.
Perhaps, the RSA example would work better. n and e being mandatory, the rest being optional?
There was a problem hiding this comment.
If the caller is only interested in getting the values of p and q (if those are accessible)?
doc/man3/OSSL_PARAM_TYPE.pod
Outdated
There was a problem hiding this comment.
OSSL_PARAM_optional_set_utf8_ptr(params, "foo", "foo value");
OSSL_PARAM_optional_set_utf8_string(params, "bar", "bar value");
OSSL_PARAM_optional_set_utf8_string(params, "cookie", "cookie value");There was a problem hiding this comment.
If you really want to make an valuable example of mandatory parameters, it would be to use a mixture of locate_get and optional_get functions. Personally, I rather imagine that some parameters might have to be grouped together. For example, that if "foo" is set by the caller, so must "bar".
|
I've added the optional get functions, although I still don't see why. |
These combine an OSSL_PARAM_locate call with the corresponding get/set call.
| return OSSL_PARAM_set_octet_ptr(OSSL_PARAM_locate(p, key), val, used_len); | ||
| } | ||
|
|
||
| int OSSL_PARAM_optional_get_int(const OSSL_PARAM *p, const char *key, int *val) |
There was a problem hiding this comment.
The optional "get" forms don't seem very useful. With a "success" return you can't tell whether key and val have been updated or not. Applications would be better off just using OSSL_PARAM_locate_get_int which returns fail if it wasn't found.
There was a problem hiding this comment.
Let's say we have a provider that offers RSA, and with which applications (or libcrypto) can set the RSA object parameters n, e and d.
The application (or libcrypto for that matter) wants to create a public key, so tries this:
OSSL_PARAM params[3];
size_t n = 0;
unsigned char e_buf[16];
unsigned char n_buf[512];
BN_bn2nativepad(rsa_e, e_buf, sizeof(e_buf));
BN_bn2nativepad(rsa_n, n_buf, sizeof(n_buf));
params[n++] = OSSL_PARAM_construct_BN("e", rsa_e, sizeof(rsa_e), NULL);
params[n++] = OSSL_PARAM_construct_BN("n", rsa_n, sizeof(rsa_n), NULL);
params[n].key = NULL;
if (!EVP_PKEY_set_params(rsa_pkey, params))
fprintf(stderr, "ERROR\n");
Now, on the provider end, set_params is defined like this:
static int rsa_set_params(void *vrsa, const OSSL_PARAM *params)
{
PROV_RSA *rsa = vrsa;
return OSSL_PARAM_locate_get_BN(params, "n", rsa->n)
&& OSSL_PARAM_locate_get_BN(params, "e", rsa->e)
&& OSSL_PARAM_locate_get_BN(params, "d", rsa->d);
}With this construction, creating a public key with parameters fails.
There was a problem hiding this comment.
Before saying that this won't happen, consider test/testrsapub.pem. How do you imagine that this file will become a default provider PKEY?
There was a problem hiding this comment.
Right, so "d" truly is optional in this case. So write it like this:
static int rsa_set_params(void *vrsa, const OSSL_PARAM *params)
{
PROV_RSA *rsa = vrsa;
OSSL_PARAM_locate_get_BN(params, "d", rsa->d);
return OSSL_PARAM_locate_get_BN(params, "n", rsa->n)
&& OSSL_PARAM_locate_get_BN(params, "e", rsa->e);
}
There was a problem hiding this comment.
And then, another dude just wants to sign with a private key and passes d and n...
And oh, what if the passed d param was invalid?
There was a problem hiding this comment.
Maybe it could be left as an exercise to those who write the receiving end to figure out what values have to be grouped together and how to code that properly?
I'm getting worried that this API gets over engineered and tries to solve everything instead of being a set of tools. That comes with a cost.
There was a problem hiding this comment.
I'd prefer to lose the optional get calls in favour of the receiver figuring it out.
There was a problem hiding this comment.
The way I see it now, that speaks for this PR as a whole.
There was a problem hiding this comment.
Okay, I'll close unless somebody does think this is beneficial.
|
Adding several dozen functions to avoid one line of code seems like the wrong trade-off to me. |
|
It's one line of code that will be repeated a large number of times. |
So, let's write the code without these dozens of functions and then refactor out the common case. It will be a lot more clear to the programmer what is going on, rather than recalling the semantics of dozens of new functions. |
|
|
||
| params[n++] = OSSL_PARAM_construct_BN("n", n_buf, sizeof(n_buf), NULL); | ||
| params[n++] = OSSL_PARAM_construct_uint32("e", rsa_e, NULL); | ||
| params[n] = OSSL_PARAM_END; |
There was a problem hiding this comment.
Heh, have you tested that this line goes through a compiler?
There was a problem hiding this comment.
I wondered if anyone would notice :)
Add a number of functions that combine a get/set with a locate.