node icon indicating copy to clipboard operation
node copied to clipboard

crypto: add support for SM2

Open tniessen opened this issue 4 years ago • 8 comments

These commits add support for SM2 from the SM9 standard. It requires a fair amount of hacks within our codebase, so if anyone has any other integration ideas, I'd be happy to hear them.

Asymmetric Key Type 'sm2'

A new asymmetric key type is added: 'sm2'.

Unlike previous asymmetric key types, it does not have a unique OID, and does, in fact, share an OID with 'ec', meaning that there is no longer a 1:1 correlation between OIDs and asymmetric key types.

Key Pair Generation

SM2 key pairs can be generated using crypto.generateKeyPair('sm2').

No options are accepted.

Digital Signatures

SM2 signatures require an additional "identifier" that must be specified by the signing and the verifying party. To accomodate this, an sm2Identifier option was added to crypto.sign and crypto.verify.

There is no documented way of producing SM2 signatures with the OpenSSL APIs that we are using in the Sign and Verify classes. Therefore, these classes currently do not support SM2 signatures.

Key Agreement

Currently not implemented due to lack of support within OpenSSL. Might also be insecure in its original form, see Xu et al. doi:10.1007/978-3-642-25513-7_12:

In this paper, we have shown that the SM2 key exchange protocol is potentially vulnerable to an unknown key-share attack. The weakness is due to the fact that the identifiers of the communicants are not appropriately integrated into the exchanged cryptographic messages. However, the attack presented here should not discourage use of the SM2 protocol, as long as appropriate countermeasures are taken. We also have suggested a simple modification to resist our described attacks while the merits of the original protocol are left unchanged.

Should be added to crypto.diffieHellman() if it makes sense in the future.

Key Import

Because the PKCS#8 and SPKI encodings of SM2 keys are indistinguishable from EC keys on the SM2 curve, the createPublicKey and createPrivateKey functions now accept an additional asymmetricKeyType option. If specified, Node.js will attempt to create a KeyObject of the given type. As a side effect, this allows users to enforce a specific asymmetric key type when importing key material, e.g., 'rsa'. For SM2, this means that the key will first be parsed as EC, and its type will then be changed to SM2 if the user specified asymmetricKeyType: 'sm2'.

The default behavior matches OpenSSL: When loading a key with OID 1.2.840.10045.2.1 on the SM2 curve without specifying asymmetricKeyType: 'sm2', it will create an EC key, not an SM2 key.

Note on SM3

While OpenSSL 1.1.1 supports SM3 as a hash function and as the digest for SM2 signatures, it does not allow SM3 as the digest for other signatures. Future releases might change that.

tniessen avatar Jan 25 '21 19:01 tniessen

CI failures are expected due to #37055.

tniessen avatar Jan 25 '21 19:01 tniessen

Where is SM2 used?

mscdex avatar Jan 25 '21 19:01 mscdex

Where is SM2 used?

Not sure. I am trying to address the remaining key types from https://github.com/nodejs/node/issues/26996.

tniessen avatar Jan 26 '21 12:01 tniessen

As far as I know, SM2 is primarily used in China (it was developed by a Chinese agency). There's not a lot of literature available on it or where exactly it is used, if at all, outside of that region. It seems specialized enough that I'm not really convinced that there's justification for exposing it generally in core.

jasnell avatar Jan 26 '21 15:01 jasnell

I would vote to just leave it out for now and if there is a pressing need to add it in the future we can revisit it then, especially considering it requires some hacks to add support for it.

mscdex avatar Jan 26 '21 21:01 mscdex

@nodejs/crypto @jasnell @mscdex The switch to OpenSSL 3 has changed how Node.js treats EC keys on the SM2 curve, see https://github.com/nodejs/node/issues/40106#issuecomment-936412898 and https://github.com/nodejs/node/pull/38512#issuecomment-938040117.

While OpenSSL now defaults to SM2 for such keys, I understand that there is no interest in this feature from this project.

Given the status quo, which allows importing keys that Node.js does not support, I see the following options:

  1. Assign the 'sm2' type to the EVP_PKEY_SM2 key type so that asymmetricKeyType would at least not be undefined for SM2 keys.
    • Using the keys would still be difficult/impossible.
    • Key generation is also inconsistent, in that generating an EC key on the SM2 curve yields an EC key, but importing the key yields an SM2 key.
  2. Restore the pre-17 behavior and convert all EVP_PKEY_SM2 keys into EVP_PKEY_EC keys upon import.
    • I am not entirely sure how to do this, but it's likely possible.
    • It goes against the decision made by OpenSSL.
  3. Throw upon loading an EC key on the SM2 curve, avoiding any ambiguities.
    • This is possible, but probably semver-major.

I can update this PR with whatever approach is chosen.

tniessen avatar Oct 26 '21 14:10 tniessen

Ping @nodejs/crypto

tniessen avatar Nov 02 '21 16:11 tniessen

Of the choices, I'd vote for option 3.

mscdex avatar Nov 02 '21 18:11 mscdex