From: Hongbo Li <herberthbli@xxxxxxxxxxx> This patch make x509 support eddsa(currently ed25519). According to RFC8032 section 5.1.7[1], the digest is not on the original message, but on a special formated message string: SHA512(dom2(F, C) || R || A || PH(M)) [1]: https://tools.ietf.org/html/rfc8032#section-5.1.7 Signed-off-by: Hongbo Li <herberthbli@xxxxxxxxxxx> --- crypto/asymmetric_keys/public_key.c | 73 +++++++++++++++++++++++++++---- crypto/asymmetric_keys/x509_cert_parser.c | 14 +++++- crypto/asymmetric_keys/x509_public_key.c | 4 +- include/linux/oid_registry.h | 1 + 4 files changed, 82 insertions(+), 10 deletions(-) diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index 4fefb21..c1236a8 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -251,8 +251,8 @@ static int software_key_eds_op(struct kernel_pkey_params *params, } #if IS_REACHABLE(CONFIG_CRYPTO_SM2) -static int cert_sig_digest_update(const struct public_key_signature *sig, - struct crypto_akcipher *tfm_pkey) +static int sm2_cert_sig_digest_update(const struct public_key_signature *sig, + struct crypto_akcipher *tfm_pkey) { struct crypto_shash *tfm; struct shash_desc *desc; @@ -297,7 +297,7 @@ static int cert_sig_digest_update(const struct public_key_signature *sig, return ret; } #else -static inline int cert_sig_digest_update( +static inline int sm2_cert_sig_digest_update( const struct public_key_signature *sig, struct crypto_akcipher *tfm_pkey) { @@ -305,6 +305,58 @@ static inline int cert_sig_digest_update( } #endif /* ! IS_REACHABLE(CONFIG_CRYPTO_SM2) */ +static int eddsa_cert_sig_digest_update(const struct public_key *pub, + const struct public_key_signature *sig) +{ + struct crypto_shash *tfm = NULL; + struct shash_desc *desc = NULL; + int key_size, ret = 0; + + if (strcmp(pub->pkey_algo, "eddsa-25519")) + return -ENOPKG; + + tfm = crypto_alloc_shash(sig->hash_algo, 0, 0); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); + + desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL); + if (!desc) { + ret = -ENOMEM; + goto free; + } + + desc->tfm = tfm; + + /* RFC8032 section 5.1.7 + * step 2. SHA512(dom2(F, C) || R || A || PH(M)) + */ + key_size = 32; + if (sig->s_size != key_size * 2 || + pub->keylen != key_size) { + ret = -EINVAL; + goto free; + } + + ret = crypto_shash_init(desc); + if (ret < 0) + goto free; + + ret = crypto_shash_update(desc, sig->s, key_size); + if (ret < 0) + goto free; + + ret = crypto_shash_update(desc, pub->key, key_size); + if (ret < 0) + goto free; + + ret = crypto_shash_finup(desc, sig->data, sig->data_size, sig->digest); + +free: + kfree(desc); + crypto_free_shash(tfm); + return ret; +} + /* * Verify a signature using a public key. */ @@ -358,11 +410,16 @@ int public_key_verify_signature(const struct public_key *pkey, if (ret) goto error_free_key; - if (sig->pkey_algo && strcmp(sig->pkey_algo, "sm2") == 0 && - sig->data_size) { - ret = cert_sig_digest_update(sig, tfm); - if (ret) - goto error_free_key; + if (sig->pkey_algo && sig->data_size) { + if (strcmp(sig->pkey_algo, "sm2") == 0) { + ret = sm2_cert_sig_digest_update(sig, tfm); + if (ret) + goto error_free_key; + } else if (strcmp(sig->pkey_algo, "eddsa") == 0) { + ret = eddsa_cert_sig_digest_update(pkey, sig); + if (ret) + goto error_free_key; + } } sg_init_table(src_sg, 2); diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 6d00309..3f60c57 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -258,6 +258,9 @@ int x509_note_pkey_algo(void *context, size_t hdrlen, case OID_SM2_with_SM3: ctx->cert->sig->hash_algo = "sm3"; goto sm2; + case OID_ed25519: + ctx->cert->sig->hash_algo = "sha512"; + goto eddsa; } rsa_pkcs1: @@ -280,6 +283,11 @@ int x509_note_pkey_algo(void *context, size_t hdrlen, ctx->cert->sig->encoding = "x962"; ctx->algo_oid = ctx->last_oid; return 0; +eddsa: + ctx->cert->sig->pkey_algo = "eddsa"; + ctx->cert->sig->encoding = "raw"; + ctx->algo_oid = ctx->last_oid; + return 0; } /* @@ -302,7 +310,8 @@ int x509_note_signature(void *context, size_t hdrlen, if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 || strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0 || strcmp(ctx->cert->sig->pkey_algo, "sm2") == 0 || - strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0) { + strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0 || + strcmp(ctx->cert->sig->pkey_algo, "eddsa") == 0) { /* Discard the BIT STRING metadata */ if (vlen < 1 || *(const u8 *)value != 0) return -EBADMSG; @@ -517,6 +526,9 @@ int x509_extract_key_data(void *context, size_t hdrlen, return -ENOPKG; } break; + case OID_ed25519: + ctx->cert->pub->pkey_algo = "eddsa-25519"; + break; default: return -ENOPKG; } diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 3d45161..a8fd368 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -131,7 +131,9 @@ int x509_check_for_self_signed(struct x509_certificate *cert) ret = -EKEYREJECTED; if (strcmp(cert->pub->pkey_algo, cert->sig->pkey_algo) != 0 && (strncmp(cert->pub->pkey_algo, "ecdsa-", 6) != 0 || - strcmp(cert->sig->pkey_algo, "ecdsa") != 0)) + strcmp(cert->sig->pkey_algo, "ecdsa") != 0) && + (strncmp(cert->pub->pkey_algo, "eddsa-", 6) != 0 || + strcmp(cert->sig->pkey_algo, "eddsa") != 0)) goto out; ret = public_key_verify_signature(cert->pub, cert->sig); diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h index cc64d94..d84bb86 100644 --- a/include/linux/oid_registry.h +++ b/include/linux/oid_registry.h @@ -64,6 +64,7 @@ enum OID { OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ OID_sha1, /* 1.3.14.3.2.26 */ + OID_ed25519, /* 1.3.101.112 */ OID_id_ansip384r1, /* 1.3.132.0.34 */ OID_sha256, /* 2.16.840.1.101.3.4.2.1 */ OID_sha384, /* 2.16.840.1.101.3.4.2.2 */ -- 1.8.3.1