node
node copied to clipboard
crypto: add support for SM2
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.
CI failures are expected due to #37055.
Where is SM2 used?
Where is SM2 used?
Not sure. I am trying to address the remaining key types from https://github.com/nodejs/node/issues/26996.
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.
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.
@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:
- Assign the
'sm2'
type to theEVP_PKEY_SM2
key type so thatasymmetricKeyType
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.
- Restore the pre-17 behavior and convert all
EVP_PKEY_SM2
keys intoEVP_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.
- 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.
Ping @nodejs/crypto
Of the choices, I'd vote for option 3.