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

An alternative to address the SM2 ID issues #7113

Closed
wants to merge 10 commits into from

Conversation

InfoHunter
Copy link
Member

@InfoHunter InfoHunter commented Sep 4, 2018

This is an alternative to #6757 , to fix some SM2 ID relevant issues. Comments are very appreciated.

The idea in this PR is:

  1. the ID in SM2 is a "Distinguishing Identifier" defined as "OCTET STRING" instead of ASCII style string. So this PR implements the ID as a pointer-length style instead of assuming it as a null-terminated one.
  2. Rename some variables to match the only official English SM2 standard - "ISO/IEC-14888".
  3. Don't bother with the default ID '1234567812345678' anymore, that should be the responsibility of the consumer of SM2, not the SM2 low level algorithm.
  4. Make it more flexible for the null-length ID, since the base SM2 algorithm makes this thing very unclear. Although GM/T 0009-2012 defines the default ID, but for the algorithm itself, no specification says null-length ID in invalid.
  5. Avoid the 'two-calls' to EVP_DigestSign/VerifyInit. Introduce a method to pass an EVP_PKEY_CTX to MD and make it configurable before calling EVP_DigestSign/VerifyInit, so the current sequence of calls is something as follows:
/* obtain an EVP_PKEY from whatever methods... */
EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2);
mctx = EVP_MD_CTX_new();
pctx = EVP_PKEY_CTX_new(pkey, NULL);
EVP_PKEY_CTX_set_sm2_id(pctx, id, id_len);
EVP_MD_CTX_set_pkey_ctx(mctx, pctx);;
EVP_DigestVerifyInit(mctx, NULL, EVP_sm3(), NULL, pkey);
EVP_DigestVerifyUpdate(mctx, msg, msg_len);
EVP_DigestVerifyFinal(mctx, sig, sig_len)

Document is not updated and test cases are not complete, if this concept is accepted then it should be very easy to complete them.

I borrowed some test code from #6757 to test the correctness of the ID involved signature verification process.

Actually there is another much simpler way of doing this, by using the EVP_ctrl stuffs to set the ID and compute the 'Z' digest after the calls to EVP_DigestSign/VerifyInit. But that will cut the whole algorithm into separated parts so I finally abandoned that idea.

Checklist
  • documentation is added or updated
  • tests are added or updated

@InfoHunter
Copy link
Member Author

Resolving the travis failures

Copy link
Member

@mattcaswell mattcaswell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. My initial review comments below. Also if I understood you correctly some of the test stuff was lifted from the other PR. Can that bit be in a separate commit with appropriate git author attribution?

@@ -22,28 +22,35 @@ typedef struct {
EC_GROUP *gen_group;
/* message digest */
const EVP_MD *md;
/* Distinguishing Identifier, ISO/IEC 15946-3 */
uint8_t *id;
int id_len;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably this should be size_t

SM2err(SM2_F_PKEY_SM2_INIT, ERR_R_MALLOC_FAILURE);
return 0;
}

ctx->data = dctx;
/* -1 indicates there is no ID set yet */
smctx->id_len = -1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...but this is problematic if it were to be size_t. I still think it should be though...I had too much pain sorting out the "it's a size_t, no it's a long, no it's an int" mess that we used to have in libssl (casts everywhere).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I used size_t initially and changed that to int in 7659f41. Because without the -1 value, it can distinguish if the ID is set or not, any ideas on this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps just add an additional flag into the ctx?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps just add an additional flag into the ctx?

That is workable

return 0;
}
memcpy(dctx->id, sctx->id, sctx->id_len);
dctx->id_len = sctx->id_len;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably you need to copy id_len unconditionally to pick up the -1 initialisation

*(const EVP_MD **)p2 = smctx->md;
return 1;

case EVP_PKEY_CTRL_SM2_SET_ID:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably this should be ...SET1_ID?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a little confused with the number after get/set, so 1 here stands for the caller could free the passed-in parameter at his will?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The number is supposed to give you a hint about the memory management:

get0 == returns a pointer to the internal data. The caller should therefore not free it
get1 == creates a copy of the data or ups a ref count. The caller should free.
set0 == the caller passes ownership of the pointer to the library, so the caller should not subsequently free it
set1 == the caller does not pass ownership of the pointer to the library. The library will take a copy or up a ref count. The caller should free the original pointer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, thanks for the clear explanation.

/*
* If no ID is set, reject to compute the 'Z' value. This allows to
* set a null-ID to SM2, although which is not clear in the relevant
* specifications. We implement as this to stay flexibility.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps reword as: "An ID value must be set. The specifications are not clear whether a NULL is allowed. We only allow it if set explicitly for maximum flexibility"

@@ -1429,6 +1429,19 @@ void EC_KEY_METHOD_get_verify(const EC_KEY_METHOD *meth,
EVP_PKEY_OP_DERIVE, \
EVP_PKEY_CTRL_GET_EC_KDF_UKM, 0, (void *)(p))

/* SM2 will skip the operation check so no need to pass operation here */
# define EVP_PKEY_CTX_set_sm2_id(ctx, id, id_len) \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...set1_sm2_id?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I wonder whether we should lose the sm2 bit altogether. This seems like a fairly general concept that might be needed for other algs in the future. Similarly for the macros below.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be no sm2 in the name ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But how to deal with the EVP_PKEY_SM2 parameter in EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_SM2, ...?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps set that to -1?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is what is done elsewhere.

@@ -181,6 +181,9 @@ int (*EVP_MD_meth_get_ctrl(const EVP_MD *md))(EVP_MD_CTX *ctx, int cmd,
*/
# define EVP_MD_CTX_FLAG_FINALISE 0x0200

/* Don't free up ctx->pctx in EVP_MD_CTX_reset */
# define EVP_MD_CTX_FLAG_NEGLECT_PCTX 0x0400
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels misplaced in the public header - although I understand why you put it there.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should also have a different name - it is do-not-free and neglect isn't the right name to use.
Perhaps EVP_MD_CTX_FLAG_KEEP_PKEY_CTX ... I'd also not abbreviate to PCTX ...

@@ -1321,6 +1325,8 @@ void EVP_PKEY_asn1_set_security_bits(EVP_PKEY_ASN1_METHOD *ameth,
* Method handles all operations: don't assume any digest related defaults.
*/
# define EVP_PKEY_FLAG_SIGCTX_CUSTOM 4
/* Do a customized hashing process */
# define EVP_PKEY_FLAG_DIGEST_CUSTOM 8
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly this seems misplaced.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, if this is placed in an internal header file, then the value of the flag should be chosen safe...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest a comment in the public header stating that the value 8 is reserved for internal use. In the internal header file where we put the definition we add a reference to the public header values.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this flag even needed? If there's a non-NULL digest_custom in a EVP_PKEY_METHOD, then it has a digest custom function... isn't that enough?
(I know that we have sometimes used flags to tell if certain pointers are defined or not, but that's from the time when all structures were public, so flagging was done to allow for a certain level of ABI backward compatibility, to tell if added fields could be relied upon. Since EVP_PKEY_METHOD is opaque, this methodology is no longer needed)

@@ -294,7 +294,8 @@ static int test_sm2_sign(const EC_GROUP *group,
goto done;

start_fake_rand(k_hex);
sig = sm2_do_sign(key, EVP_sm3(), userid, (const uint8_t *)message, msg_len);
sig = sm2_do_sign(key, EVP_sm3(), (const uint8_t *)userid, (int)strlen(userid),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the type were size_t the int cast would not be needed here.

ok = sm2_do_verify(key, EVP_sm3(), sig, userid, (const uint8_t *)message,
msg_len);
ok = sm2_do_verify(key, EVP_sm3(), sig, (const uint8_t *)userid,
(int)strlen(userid), (const uint8_t *)message, msg_len);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...and here

@mattcaswell mattcaswell added this to the 1.1.1 milestone Sep 4, 2018
@InfoHunter
Copy link
Member Author

Also if I understood you correctly some of the test stuff was lifted from the other PR. Can that bit be in a separate commit with appropriate git author attribution?

Makes sense, will do that.

@InfoHunter InfoHunter self-assigned this Sep 4, 2018
@@ -1321,6 +1325,8 @@ void EVP_PKEY_asn1_set_security_bits(EVP_PKEY_ASN1_METHOD *ameth,
* Method handles all operations: don't assume any digest related defaults.
*/
# define EVP_PKEY_FLAG_SIGCTX_CUSTOM 4
/* Do a customized hashing process */
# define EVP_PKEY_FLAG_DIGEST_CUSTOM 8
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this flag even needed? If there's a non-NULL digest_custom in a EVP_PKEY_METHOD, then it has a digest custom function... isn't that enough?
(I know that we have sometimes used flags to tell if certain pointers are defined or not, but that's from the time when all structures were public, so flagging was done to allow for a certain level of ABI backward compatibility, to tell if added fields could be relied upon. Since EVP_PKEY_METHOD is opaque, this methodology is no longer needed)

EVP_PKEY_CTX_free(ctx->pctx);
/*
* pctx should be freed by the user of EVP_MD_CTX
* if EVP_MD_CTX_FLAG_NEGLECT_PCTX is set
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment needs editing, since that flag doesn't exist.

@@ -75,6 +75,14 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
return 1;
if (!EVP_DigestInit_ex(ctx, type, e))
return 0;
if (ctx->pctx->pmeth->flags & EVP_PKEY_FLAG_DIGEST_CUSTOM) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EVP_PKEY_FLAG_DIGEST_CUSTOM is unnecessary, it should be enough to check that digest_custom is non-NULL

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, makes sense

if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl) {
EVPerr(EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_COMMAND_NOT_SUPPORTED);
return -2;
}
if ((keytype != -1) && (ctx->pmeth->pkey_id != keytype))
return -1;

/* Skip the operation checks since this is called in a very early stage */
if (ctx->pmeth->flags & EVP_PKEY_FLAG_DIGEST_CUSTOM)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check that digest_custom is non-NULL instead

@@ -10,6 +10,14 @@
#include <openssl/evp.h>
#include "internal/refcount.h"

/* Do a customized hashing process, use the reserved flag value in evp.h */
#define EVP_PKEY_FLAG_DIGEST_CUSTOM 8
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I argued before, not necessary, just throw it away

@@ -1321,6 +1323,7 @@ void EVP_PKEY_asn1_set_security_bits(EVP_PKEY_ASN1_METHOD *ameth,
* Method handles all operations: don't assume any digest related defaults.
*/
# define EVP_PKEY_FLAG_SIGCTX_CUSTOM 4
/* NOTE: 8 is reserved for internal usage in evp_int.h */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this line

@InfoHunter
Copy link
Member Author

Document is updated to reflect the modification in this PR

int (**pdigest_custom) (EVP_PKEY_CTX *ctx,
EVP_MD_CTX *mctx))
{
if (*pdigest_custom)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that void *foo(EVP_PKEY_METHOD *pmeth) { void *p; EVP_PKEY_meth_get_digest_custom(pmeth, &p); return p; } might return sensible or garbage value. But even if corrected, the check is arguably inappropriate. In sense that it's more appropriate to punish caller with crash if programmer didn't care to arrange proper location that would receive the value, than to let caller believe that everything is fine. "Is fine" means that there is no way of telling it's not fine.

The remark applies to multiple cases. [Which in turn effectively means review process failure.]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These checks exist in other (not all???) method function getters, but are implemented differently in some. I don't think it's a fix to do in this PR, but it would be good to clean this up.

In my opinion, the check should be this:

    if (pdigest_custom)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree to the form that Richard suggested

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a fix to do in this PR,

So suggestion is to perpetuate bugs?

but it would be good to clean this up.

??? "Good" to "clean up"? It's not something that would be "good to do". They are bugs that has to be fixed.

the check should be this:

It's equivalent to demanding NULL-check in memcpy(NULL, p, 1).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opened an issue (#7130) to keep track of this.

@@ -334,6 +342,15 @@ key-pair, the public component and parameters respectively for a given B<pkey>.
They could be called by L<EVP_PKEY_check(3)>, L<EVP_PKEY_public_check(3)> and
L<EVP_PKEY_param_check(3)> respectively.

int (*digest_custom) (EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx);

The digest_custom() method is used to generate customzied degest content before
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/degest/digest/

@levitte
Copy link
Member

levitte commented Sep 5, 2018

Looking at this had me stumble on stuff I haven't looked at before, the custom signctx functions... and the similarity with what digest_custom is used for is striking! That has me wonder if digest_custom reimplements something that's already there, just in sliiiiightly different form. @InfoHunter, is this something you have explored?

@@ -460,6 +460,13 @@ EVP_PKEY_CTX *EVP_MD_CTX_pkey_ctx(const EVP_MD_CTX *ctx)
return ctx->pctx;
}

void EVP_MD_CTX_set_pkey_ctx(EVP_MD_CTX *ctx, EVP_PKEY_CTX *pctx)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this function be called with a NULL pctx (e.g. say if you want to clear one that was previously set)?
What should happen if ctx->pctx is not NULL when this function is called?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. TBH I didn't consider the 'set to NULL' or the 'clear' scenario. But after a quick thinking, I think it would be useful to allow users to set ctx->pctx to NULL (for instance someone wants to reuse the MD_CTX). So the current implementation supports that already.

If ctx->pctx is not NULL when this function is called, then I think it should be the user's responsibility to free the old pctx attached in MD_CTX, makes sense?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If ctx->pctx is not NULL when this function is called, then I think it should be the user's responsibility to free the old pctx attached in MD_CTX, makes sense?

Yes, if EVP_MD_CTX_FLAG_KEEP_PKEY_CTX is set - but not otherwise.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, nah, the flag should also be cleared if the ctx->pctx is set to NULL if someone wants to reuse the MD_CTX. So I think there should be a separated EVP_MD_CTX_clr_pkey_ctx` function to do this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or we could mix the set/clr behavior into one function by doing something like:

if (pctx == NULL) {
    /* clear the flag... */
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm..I'm not sure that is necessary. Surely all we need is something like this:

if (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX))
    EVP_PKEY_CTX_free(ctx->pctx);
ctx->pctx = pctx;
if (pctx != NULL)
    EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX);
else
    EVP_MD_CTX_clear_flags(out, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I get the point - It's complicated to deal with such stuffs: one pointer holds two different memory management strategy objects...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my experience, another way is to have two pointers containing system-created and user-created objects respectively - if the user-created on is used, the the system one will always be NULL. Thus it would make it simpler. But this time let's just mix them together

* This indicates the current algorithm requires
* special treatment before hashing the tbs-message.
*/
if (ctx->pctx->pmeth->digest_custom)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add != NULL

int (**pdigest_custom) (EVP_PKEY_CTX *ctx,
EVP_MD_CTX *mctx))
{
if (*pdigest_custom)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!= NULL

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Facepalm.

case EVP_PKEY_CTRL_SET1_ID:
OPENSSL_free(smctx->id);
if (p1 > 0) {
smctx->id = OPENSSL_malloc(p1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we free any pre-existing id?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, you mean if malloc fails, then we should not touch the original previous set smctx->id?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No I mean if there was a pre-existing id then we just introduced a mem leak because we didn't free the old one. So I think you need to add OPENSSL_free(smctx->id); before the malloc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that is already there. But I improved the logical to defer OPNESSL_free to a more suitable position in the new version of this function.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duh...why did I not see that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

;-)

@@ -31,6 +31,10 @@ B<*pctx> is overwritten. The EVP_PKEY_CTX value returned must not be freed
directly by the application (it will be freed automatically when the EVP_MD_CTX
is freed). The digest B<type> may be NULL if the signing algorithm supports it.

There is no B<EVP_PKEY_CTX> will be created by EVP_DigestSignInit() if the passed
B<ctx> is already assigned with an B<EVP_PKEY_CTX>, take L<EVP_MD_CTX_set_pkey_ctx(3)>
and L<SM2(7)> as references.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"No B<EVP_PKEY_CTX> will be created by EVP_DigsetSignInit() if the passed B<ctx> has already been assigned one via L<EVP_MD_CTX_set_ctx(3)>. See also L<SM2(7)>."

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh...but wait...there is no SM2(7)!? There probably needs to be something (maybe not in this PR) - otherwise how will people know about the special hoops they need to jump through to be able to use SM2?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact I forgot to include that SM2(7)... I used 'git add -u' so the new SM2.pod file is left on my disk...now added

are used to manipulate special identifier field for specific signature algorithm
such as SM2. The EVP_PKEY_CTX_get1_id_len() returns the length of the ID set in
algorihtm related context. The length is usually used to allocate adequate memory
for further calls to EVP_PKEY_CTX_get1_id().
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no description here of how EVP_PKEY_CTX_set1_id() and EVP_PKEY_get1_id() actually work and what the parameters mean. There should at least be a sentence about the memory management aspects I think.

@@ -179,7 +191,8 @@ L<EVP_PKEY_keygen(3)>

=head1 HISTORY

These functions were first added to OpenSSL 1.0.0.
EVP_PKEY_CTX_set1_id(), EVP_PKEY_CTX_get1_id() and EVP_PKEY_CTX_get1_id_len() are
added in 1.1.1, other functions were first added to OpenSSL 1.0.0.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/are added/were added/

@@ -334,6 +342,15 @@ key-pair, the public component and parameters respectively for a given B<pkey>.
They could be called by L<EVP_PKEY_check(3)>, L<EVP_PKEY_public_check(3)> and
L<EVP_PKEY_param_check(3)> respectively.

int (*digest_custom) (EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx);

The digest_custom() method is used to generate customzied degest content before
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: customized

the real message is passed to functions like L<EVP_DigestSignUpdate(3)> or
L<EVP_DigestVerifyInit(3)>. This is usually required by some public key
signature algorithms like SM2 which requires a hashed prefix to the message to
be signed. The digest_custom() could be called by L<EVP_DigestSignInit(3)> and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/could/will/ ?

* NULL is allowed. We only allow it if set explicitly for maximum
* flexibility.
*/
return 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably there needs to be a call to SM2err here.

@InfoHunter
Copy link
Member Author

That has me wonder if digest_custom reimplements something that's already there, just in sliiiiightly different form. @InfoHunter, is this something you have explored?

The real difference is the position of triggering for signctx (or other function pointers) and digest_custom. Actually we need a calling point right after the 'digest' is initialized and before the 'DigestSign/Verify' is initialized. There is no such thing yet, which makes it's very hard to be fit in some scenarios...

@InfoHunter
Copy link
Member Author

I forgot to include a man(7) page of SM2, now updated...

@levitte
Copy link
Member

levitte commented Sep 5, 2018

The real difference is the position of triggering for signctx (or other function pointers) and digest_custom. Actually we need a calling point right after the 'digest' is initialized and before the 'DigestSign/Verify' is initialized. There is no such thing yet, which makes it's very hard to be fit in some scenarios...

Good, so you looked at least. I gotta admit, signctx is new to me, and seems to have multiple applications (depending on the flag EVP_PKEY_FLAG_SIGCTX_CUSTOM); I haven't quite wrapped my head around the differences.

It does worry me, though, that we seems to add more hooks for almost, but not quite the same the same things. I guess that's a future clean-up job 😉

@InfoHunter
Copy link
Member Author

It does worry me, though, that we seems to add more hooks for almost, but not quite the same the same things. I guess that's a future clean-up job

Right. The concept behind this is the 'calling points' for these hooks should be considered and defined carefully and precisely. A very challenging job to design a decent framework as current EVP...

if (sctx->id != NULL) {
dctx->id = OPENSSL_malloc(sctx->id_len);
if (dctx->id == NULL) {
pkey_sm2_cleanup(dst);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it is missing an SM2err(SM2_F_PKEY_SM2_COPY, ERR_R_MALLOC_FAILURE) call ... for consistency with the other error handling.

if (p1 > 0) {
tmp_id = OPENSSL_malloc(p1);
if (tmp_id == NULL)
return 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it is missing an SM2err(SM2_F_PKEY_SM2_CTRL, ERR_R_MALLOC_FAILURE) call ... for consistency with the other error handling.

Copy link
Member

@t-j-h t-j-h left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once you have added the SM2err calls for malloc failures and fixed the typo in the SM2.pod file this is good to go.

doc/man7/SM2.pod Outdated

B<SM2> algorithm is first defined by the Chinese national standard GM/T 0003-2012
and is standardized by ISO as ISO/IEC 14888. B<SM2> is actually an elliptic curve
based algorithm. Currnet implementation in OpenSSL supports both signature and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currnet -> The current

Copy link
Member

@t-j-h t-j-h left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@InfoHunter
Copy link
Member Author

Oops, a nit is fixed

@InfoHunter
Copy link
Member Author

Travis failures are not related. Force a push to re-trigger it...

@t-j-h t-j-h added approval: done This pull request has the required number of approvals branch: 1.1.1 Merge to OpenSSL_1_1_1-stable branch labels Sep 6, 2018
@InfoHunter
Copy link
Member Author

There is adequate approvals for merging this PR. I would squash and cleanup the commits soon.

@InfoHunter
Copy link
Member Author

I squashed the commits into proper styles - no actual code modified after the 'ready' label is assigned so I don't think this needs to re-approve for the approval by Tim

Copy link
Member

@mattcaswell mattcaswell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of comments but I think they're all minor nits in the documentation which should be easy to fix. This looks almost ready.

@@ -160,6 +166,17 @@ For maximum compatibility the named curve form should be used. Note: the
B<OPENSSL_EC_NAMED_CURVE> value was only added to OpenSSL 1.1.0; previous
versions should use 0 instead.

The EVP_PKEY_CTX_set1_id(), EVP_PKEY_CTX_get1_id() and EVP_PKEY_CTX_get1_id_len()
are used to manipulate special identifier field for specific signature algorithm
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: manipulate the special identifier field
Nit: for specific signature algorithms

Assigns an B<EVP_PKEY_CTX> to B<EVP_MD_CTX>. This is usually used to provide
a customzied B<EVP_PKEY_CTX> to L<EVP_DigestSignInit(3)> or
L<EVP_DigestVerifyInit(3)>. The B<pctx> passed to this function should be freed
by the caller. A null B<pctx> pointer is also allowed to clear the B<EVP_PKEY_CTX>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: s/null/NULL/

such as SM2. The EVP_PKEY_set1_id() sets an ID pointed by B<id> with the length
B<id_len> to the library. The library maintains the memory management stuffs so
the caller can safely free the original memory pointed by B<id>. The
EVP_PKEY_CTX_get1_id_len() returns the length of the ID set via a previous call
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

insert the word "macro" before "returns"

B<id_len> to the library. The library maintains the memory management stuffs so
the caller can safely free the original memory pointed by B<id>. The
EVP_PKEY_CTX_get1_id_len() returns the length of the ID set via a previous call
to EVP_PKEY_set1_id(). The length is usually used to allocate adequate memory for
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: EVP_PKEY_CTX_set1_id()

the caller can safely free the original memory pointed by B<id>. The
EVP_PKEY_CTX_get1_id_len() returns the length of the ID set via a previous call
to EVP_PKEY_set1_id(). The length is usually used to allocate adequate memory for
further calls to EVP_PKEY_CTX_get1_id(). The EVP_PKEY_CTX_get1_id() returns the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Insert the word "macro" before "returns"

doc/man7/SM2.pod Outdated

EVP_MD_CTX_set_pkey_ctx(mctx, pctx);

And normally there is no need to pass a B<pctx> parameter to EVP_DeigestSignInit()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: EVP_DigestSignInit()

doc/man7/SM2.pod Outdated
EVP_MD_CTX_set_pkey_ctx(mctx, pctx);

And normally there is no need to pass a B<pctx> parameter to EVP_DeigestSignInit()
or EVP_DigestVerifyInit() in such scenario.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

such a scenario

doc/man7/SM2.pod Outdated

=head1 EXAMPLE

This example demonstrates the calling sequence on how to use an B<EVP_PKEY> to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calling sequence for using an B<EVP_PKEY>...

doc/man7/SM2.pod Outdated
=head1 EXAMPLE

This example demonstrates the calling sequence on how to use an B<EVP_PKEY> to
sign a message with SM2 signature algorithm and SM3 hash algorithm:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with the SM2....and the SM3

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps add this sentence. "The example below omits error checking code for clarity. Application code should check the return codes of function calls for errors."

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The text above says this is an example for signing. But actually its an example for verifying a signature.

doc/man7/SM2.pod Outdated

#include <openssl/evp.h>

/* obtain an EVP_PKEY from whatever methods... */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using whatever method

@ronaldtse
Copy link
Contributor

Sounds like things here moved much, much faster here compared to at #6757 . Our unfamiliarity with OpenSSL internals is apparent. Happy to see this merged with appropriate attribution. Thanks @InfoHunter !

@t-j-h
Copy link
Member

t-j-h commented Sep 6, 2018

Approval still stands after @mattcaswell suggested doc changes applied.

@InfoHunter
Copy link
Member Author

Doc nits are all fixed

@InfoHunter
Copy link
Member Author

@mattcaswell , it seems I could merge this now, right?

Copy link
Member

@mattcaswell mattcaswell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry a few more nits. Approved assuming you fix those.

@@ -160,6 +166,17 @@ For maximum compatibility the named curve form should be used. Note: the
B<OPENSSL_EC_NAMED_CURVE> value was only added to OpenSSL 1.1.0; previous
versions should use 0 instead.

The EVP_PKEY_CTX_set1_id(), EVP_PKEY_CTX_get1_id() and EVP_PKEY_CTX_get1_id_len()
are used to manipulate the special identifier field for specific signature
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Insert the word "macros" before "are used"

@@ -160,6 +166,17 @@ For maximum compatibility the named curve form should be used. Note: the
B<OPENSSL_EC_NAMED_CURVE> value was only added to OpenSSL 1.1.0; previous
versions should use 0 instead.

The EVP_PKEY_CTX_set1_id(), EVP_PKEY_CTX_get1_id() and EVP_PKEY_CTX_get1_id_len()
are used to manipulate the special identifier field for specific signature
algorithms such as SM2. The EVP_PKEY_set1_id() sets an ID pointed by B<id> with
Copy link
Member

@mattcaswell mattcaswell Sep 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: EVP_PKEY_CTX_set1_id()

are used to manipulate the special identifier field for specific signature
algorithms such as SM2. The EVP_PKEY_set1_id() sets an ID pointed by B<id> with
the length B<id_len> to the library. The library maintains the memory management
stuffs so the caller can safely free the original memory pointed by B<id>. The
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change this to "The library takes a copy of the id so that the caller can safely free the original memory pointed to by B<id>"

EVP_PKEY_CTX_get1_id_len() macro returns the length of the ID set via a previous
call to EVP_PKEY_CTX_set1_id(). The length is usually used to allocate adequate
memory for further calls to EVP_PKEY_CTX_get1_id(). The EVP_PKEY_CTX_get1_id()
macro returns the previously set ID value to caller into B<id>, caller should
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to the caller in B<id>. The caller should...

doc/man7/SM2.pod Outdated
signature.

The B<EVP_PKEY> structure will default to using ECDSA for signatures when it is
created. Itshould be set to B<EVP_PKEY_SM2> by calling:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: missing space "It should"

doc/man7/SM2.pod Outdated

EVP_PKEY_CTX_set1_id(pctx, id, id_len);

When calling the EVP_DeigestSignInit() or EVP_DigestVerifyInit() functions, a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: EVP_DigestSignInit(()

doc/man7/SM2.pod Outdated

=head1 EXAMPLE

This example demonstrates the calling sequence for using an B<EVP_PKEY> to sign
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/sign/verify/

levitte pushed a commit that referenced this pull request Sep 7, 2018
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #7113)
levitte pushed a commit that referenced this pull request Sep 7, 2018
Thus users can use this function to set customized EVP_PKEY_CTX to
EVP_MD_CTX structure.

Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #7113)
levitte pushed a commit that referenced this pull request Sep 7, 2018
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #7113)
levitte pushed a commit that referenced this pull request Sep 7, 2018
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #7113)
levitte pushed a commit that referenced this pull request Sep 7, 2018
zero-length ID is allowed, but it's not allowed to skip the ID.

Fixes: #6534

Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #7113)
levitte pushed a commit that referenced this pull request Sep 7, 2018
This test case is originally submitted in #6757, by Jack Lloyd. The test
case has been modified to use the a different method to set the ID when
computing the Z hash of SM2 signature.

Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Paul Yang <yang.yang@baishancloud.com>
(Merged from #7113)
levitte pushed a commit that referenced this pull request Sep 7, 2018
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #7113)
levitte pushed a commit that referenced this pull request Sep 7, 2018
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #7113)
levitte pushed a commit that referenced this pull request Sep 7, 2018
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #7113)
levitte pushed a commit that referenced this pull request Sep 7, 2018
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #7113)
@InfoHunter
Copy link
Member Author

New nits are fixed, Merged to master from 5bd0abe to f922dac. Closing...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approval: done This pull request has the required number of approvals branch: 1.1.1 Merge to OpenSSL_1_1_1-stable branch
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants