зеркало из https://github.com/microsoft/CCF.git
Co-authored-by: Max <maxtropets@microsoft.com>
This commit is contained in:
Родитель
6006f8b9a0
Коммит
9217756d92
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -9,6 +9,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||||
|
|
||||||
[5.0.2]: https://github.com/microsoft/CCF/releases/tag/ccf-5.0.2
|
[5.0.2]: https://github.com/microsoft/CCF/releases/tag/ccf-5.0.2
|
||||||
|
|
||||||
|
### Developer API
|
||||||
|
|
||||||
|
#### C++
|
||||||
|
|
||||||
|
- `RSAKeyPair::sign` and `RSAKeyPair::verify` now use `RSA-PSS` instead of `RSASSA-PKCS1-v1_5`.
|
||||||
|
- Users can specify `salt_length` (defaulted to `0`).
|
||||||
|
|
||||||
|
#### TypeScript/JavaScript
|
||||||
|
|
||||||
|
- `ccfapp.crypto.sign()` and `ccfapp.crypto.verifySignature()` no longer support `RSASSA-PKCS1-v1_5`, instead `RSA-PSS` has been added.
|
||||||
|
- `SigningAlgorithm` has been extended with optional `saltLength`, defaulted to `0` if not passed.
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
- The `/tx` endpoint returns more accurate error messages for incorrectly formed transactions ids (#6359).
|
- The `/tx` endpoint returns more accurate error messages for incorrectly formed transactions ids (#6359).
|
||||||
|
|
|
@ -55,26 +55,31 @@ namespace ccf::crypto
|
||||||
virtual std::vector<uint8_t> public_key_der() const = 0;
|
virtual std::vector<uint8_t> public_key_der() const = 0;
|
||||||
|
|
||||||
virtual std::vector<uint8_t> sign(
|
virtual std::vector<uint8_t> sign(
|
||||||
std::span<const uint8_t> d, MDType md_type = MDType::NONE) const = 0;
|
std::span<const uint8_t> d,
|
||||||
|
MDType md_type = MDType::NONE,
|
||||||
|
size_t salt_length = 0) const = 0;
|
||||||
|
|
||||||
virtual bool verify(
|
virtual bool verify(
|
||||||
const uint8_t* contents,
|
const uint8_t* contents,
|
||||||
size_t contents_size,
|
size_t contents_size,
|
||||||
const uint8_t* signature,
|
const uint8_t* signature,
|
||||||
size_t signature_size,
|
size_t signature_size,
|
||||||
MDType md_type = MDType::NONE) = 0;
|
MDType md_type = MDType::NONE,
|
||||||
|
size_t salt_length = 0) = 0;
|
||||||
|
|
||||||
virtual bool verify(
|
virtual bool verify(
|
||||||
const std::vector<uint8_t>& contents,
|
const std::vector<uint8_t>& contents,
|
||||||
const std::vector<uint8_t>& signature,
|
const std::vector<uint8_t>& signature,
|
||||||
MDType md_type = MDType::NONE)
|
MDType md_type = MDType::NONE,
|
||||||
|
size_t salt_length = 0)
|
||||||
{
|
{
|
||||||
return verify(
|
return verify(
|
||||||
contents.data(),
|
contents.data(),
|
||||||
contents.size(),
|
contents.size(),
|
||||||
signature.data(),
|
signature.data(),
|
||||||
signature.size(),
|
signature.size(),
|
||||||
md_type);
|
md_type,
|
||||||
|
salt_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual JsonWebKeyRSAPrivate private_key_jwk_rsa(
|
virtual JsonWebKeyRSAPrivate private_key_jwk_rsa(
|
||||||
|
|
|
@ -81,7 +81,8 @@ namespace ccf::crypto
|
||||||
size_t contents_size,
|
size_t contents_size,
|
||||||
const uint8_t* signature,
|
const uint8_t* signature,
|
||||||
size_t signature_size,
|
size_t signature_size,
|
||||||
MDType md_type = MDType::NONE) = 0;
|
MDType md_type = MDType::NONE,
|
||||||
|
size_t salt_legth = 0) = 0;
|
||||||
|
|
||||||
struct Components
|
struct Components
|
||||||
{
|
{
|
||||||
|
|
|
@ -231,7 +231,7 @@ export interface CryptoKeyPair {
|
||||||
publicKey: string;
|
publicKey: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AlgorithmName = "RSASSA-PKCS1-v1_5" | "ECDSA" | "EdDSA" | "HMAC";
|
export type AlgorithmName = "RSA-PSS" | "ECDSA" | "EdDSA" | "HMAC";
|
||||||
|
|
||||||
export type DigestAlgorithm = "SHA-256" | "SHA-384" | "SHA-512";
|
export type DigestAlgorithm = "SHA-256" | "SHA-384" | "SHA-512";
|
||||||
|
|
||||||
|
@ -239,9 +239,14 @@ export interface SigningAlgorithm {
|
||||||
name: AlgorithmName;
|
name: AlgorithmName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Digest algorithm. It's necessary for "RSASSA-PKCS1-v1_5", "ECDSA", and "HMAC"
|
* Digest algorithm. It's necessary for "RSA-PSS", "ECDSA", and "HMAC"
|
||||||
*/
|
*/
|
||||||
hash?: DigestAlgorithm;
|
hash?: DigestAlgorithm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Salt length, necessary for "RSA-PSS".
|
||||||
|
*/
|
||||||
|
saltLength?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -142,8 +142,8 @@ class CCFPolyfill implements CCF {
|
||||||
let padding = undefined;
|
let padding = undefined;
|
||||||
const privKey = jscrypto.createPrivateKey(key);
|
const privKey = jscrypto.createPrivateKey(key);
|
||||||
if (privKey.asymmetricKeyType == "rsa") {
|
if (privKey.asymmetricKeyType == "rsa") {
|
||||||
if (algorithm.name === "RSASSA-PKCS1-v1_5") {
|
if (algorithm.name === "RSA-PSS") {
|
||||||
padding = jscrypto.constants.RSA_PKCS1_PADDING;
|
padding = jscrypto.constants.RSA_PKCS1_PSS_PADDING;
|
||||||
} else {
|
} else {
|
||||||
throw new Error("incompatible signing algorithm for given key type");
|
throw new Error("incompatible signing algorithm for given key type");
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,7 @@ class CCFPolyfill implements CCF {
|
||||||
key: privKey,
|
key: privKey,
|
||||||
dsaEncoding: "ieee-p1363",
|
dsaEncoding: "ieee-p1363",
|
||||||
padding: padding,
|
padding: padding,
|
||||||
|
saltLength: algorithm.saltLength ?? 0,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
verifySignature(
|
verifySignature(
|
||||||
|
@ -179,8 +180,8 @@ class CCFPolyfill implements CCF {
|
||||||
let padding = undefined;
|
let padding = undefined;
|
||||||
const pubKey = jscrypto.createPublicKey(key);
|
const pubKey = jscrypto.createPublicKey(key);
|
||||||
if (pubKey.asymmetricKeyType == "rsa") {
|
if (pubKey.asymmetricKeyType == "rsa") {
|
||||||
if (algorithm.name === "RSASSA-PKCS1-v1_5") {
|
if (algorithm.name === "RSA-PSS") {
|
||||||
padding = jscrypto.constants.RSA_PKCS1_PADDING;
|
padding = jscrypto.constants.RSA_PKCS1_PSS_PADDING;
|
||||||
} else {
|
} else {
|
||||||
throw new Error("incompatible signing algorithm for given key type");
|
throw new Error("incompatible signing algorithm for given key type");
|
||||||
}
|
}
|
||||||
|
@ -211,6 +212,7 @@ class CCFPolyfill implements CCF {
|
||||||
key: pubKey,
|
key: pubKey,
|
||||||
dsaEncoding: "ieee-p1363",
|
dsaEncoding: "ieee-p1363",
|
||||||
padding: padding,
|
padding: padding,
|
||||||
|
saltLength: algorithm.saltLength ?? 0,
|
||||||
},
|
},
|
||||||
new Uint8Array(signature),
|
new Uint8Array(signature),
|
||||||
);
|
);
|
||||||
|
|
|
@ -167,7 +167,7 @@ describe("polyfill", function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("sign", function () {
|
describe("sign", function () {
|
||||||
it("performs RSASSA-PKCS1-v1_5 sign correctly", function () {
|
it("performs RSA-PSS sign correctly", function () {
|
||||||
const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
|
const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
|
||||||
modulusLength: 2048,
|
modulusLength: 2048,
|
||||||
publicKeyEncoding: {
|
publicKeyEncoding: {
|
||||||
|
@ -182,7 +182,7 @@ describe("polyfill", function () {
|
||||||
const data = ccf.strToBuf("foo");
|
const data = ccf.strToBuf("foo");
|
||||||
const signature = ccf.crypto.sign(
|
const signature = ccf.crypto.sign(
|
||||||
{
|
{
|
||||||
name: "RSASSA-PKCS1-v1_5",
|
name: "RSA-PSS",
|
||||||
hash: "SHA-256",
|
hash: "SHA-256",
|
||||||
},
|
},
|
||||||
privateKey,
|
privateKey,
|
||||||
|
@ -198,6 +198,7 @@ describe("polyfill", function () {
|
||||||
{
|
{
|
||||||
key: publicKey,
|
key: publicKey,
|
||||||
dsaEncoding: "ieee-p1363",
|
dsaEncoding: "ieee-p1363",
|
||||||
|
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
||||||
},
|
},
|
||||||
new Uint8Array(signature),
|
new Uint8Array(signature),
|
||||||
),
|
),
|
||||||
|
@ -208,7 +209,7 @@ describe("polyfill", function () {
|
||||||
assert.isTrue(
|
assert.isTrue(
|
||||||
ccf.crypto.verifySignature(
|
ccf.crypto.verifySignature(
|
||||||
{
|
{
|
||||||
name: "RSASSA-PKCS1-v1_5",
|
name: "RSA-PSS",
|
||||||
hash: "SHA-256",
|
hash: "SHA-256",
|
||||||
},
|
},
|
||||||
publicKey,
|
publicKey,
|
||||||
|
@ -392,7 +393,7 @@ describe("polyfill", function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("verifySignature", function () {
|
describe("verifySignature", function () {
|
||||||
it("performs RSASSA-PKCS1-v1_5 validation correctly", function () {
|
it("performs RSA-PSS validation correctly", function () {
|
||||||
const { cert, publicKey, privateKey } = generateSelfSignedCert();
|
const { cert, publicKey, privateKey } = generateSelfSignedCert();
|
||||||
const signer = crypto.createSign("sha256");
|
const signer = crypto.createSign("sha256");
|
||||||
const data = ccf.strToBuf("foo");
|
const data = ccf.strToBuf("foo");
|
||||||
|
@ -400,12 +401,13 @@ describe("polyfill", function () {
|
||||||
signer.end();
|
signer.end();
|
||||||
const signature = signer.sign({
|
const signature = signer.sign({
|
||||||
key: crypto.createPrivateKey(privateKey),
|
key: crypto.createPrivateKey(privateKey),
|
||||||
padding: crypto.constants.RSA_PKCS1_PADDING,
|
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
||||||
|
saltLength: 0,
|
||||||
});
|
});
|
||||||
assert.isTrue(
|
assert.isTrue(
|
||||||
ccf.crypto.verifySignature(
|
ccf.crypto.verifySignature(
|
||||||
{
|
{
|
||||||
name: "RSASSA-PKCS1-v1_5",
|
name: "RSA-PSS",
|
||||||
hash: "SHA-256",
|
hash: "SHA-256",
|
||||||
},
|
},
|
||||||
cert,
|
cert,
|
||||||
|
@ -416,7 +418,7 @@ describe("polyfill", function () {
|
||||||
assert.isTrue(
|
assert.isTrue(
|
||||||
ccf.crypto.verifySignature(
|
ccf.crypto.verifySignature(
|
||||||
{
|
{
|
||||||
name: "RSASSA-PKCS1-v1_5",
|
name: "RSA-PSS",
|
||||||
hash: "SHA-256",
|
hash: "SHA-256",
|
||||||
},
|
},
|
||||||
publicKey,
|
publicKey,
|
||||||
|
@ -427,7 +429,7 @@ describe("polyfill", function () {
|
||||||
assert.isNotTrue(
|
assert.isNotTrue(
|
||||||
ccf.crypto.verifySignature(
|
ccf.crypto.verifySignature(
|
||||||
{
|
{
|
||||||
name: "RSASSA-PKCS1-v1_5",
|
name: "RSA-PSS",
|
||||||
hash: "SHA-256",
|
hash: "SHA-256",
|
||||||
},
|
},
|
||||||
cert,
|
cert,
|
||||||
|
@ -494,7 +496,7 @@ describe("polyfill", function () {
|
||||||
assert.throws(() =>
|
assert.throws(() =>
|
||||||
ccf.crypto.verifySignature(
|
ccf.crypto.verifySignature(
|
||||||
{
|
{
|
||||||
name: "RSASSA-PKCS1-v1_5",
|
name: "RSA-PSS",
|
||||||
hash: "SHA-256",
|
hash: "SHA-256",
|
||||||
},
|
},
|
||||||
publicKey,
|
publicKey,
|
||||||
|
@ -543,7 +545,7 @@ describe("polyfill", function () {
|
||||||
assert.throws(() =>
|
assert.throws(() =>
|
||||||
ccf.crypto.verifySignature(
|
ccf.crypto.verifySignature(
|
||||||
{
|
{
|
||||||
name: "RSASSA-PKCS1-v1_5",
|
name: "RSA-PSS",
|
||||||
hash: "SHA-256",
|
hash: "SHA-256",
|
||||||
},
|
},
|
||||||
publicKey,
|
publicKey,
|
||||||
|
|
|
@ -205,12 +205,14 @@ namespace ccf::crypto
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> RSAKeyPair_OpenSSL::sign(
|
std::vector<uint8_t> RSAKeyPair_OpenSSL::sign(
|
||||||
std::span<const uint8_t> d, MDType md_type) const
|
std::span<const uint8_t> d, MDType md_type, size_t salt_length) const
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> r(2048);
|
std::vector<uint8_t> r(2048);
|
||||||
auto hash = OpenSSLHashProvider().Hash(d.data(), d.size(), md_type);
|
auto hash = OpenSSLHashProvider().Hash(d.data(), d.size(), md_type);
|
||||||
Unique_EVP_PKEY_CTX pctx(key);
|
Unique_EVP_PKEY_CTX pctx(key);
|
||||||
CHECK1(EVP_PKEY_sign_init(pctx));
|
CHECK1(EVP_PKEY_sign_init(pctx));
|
||||||
|
CHECK1(EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING));
|
||||||
|
CHECK1(EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, salt_length));
|
||||||
CHECK1(EVP_PKEY_CTX_set_signature_md(pctx, get_md_type(md_type)));
|
CHECK1(EVP_PKEY_CTX_set_signature_md(pctx, get_md_type(md_type)));
|
||||||
size_t olen = r.size();
|
size_t olen = r.size();
|
||||||
CHECK1(EVP_PKEY_sign(pctx, r.data(), &olen, hash.data(), hash.size()));
|
CHECK1(EVP_PKEY_sign(pctx, r.data(), &olen, hash.data(), hash.size()));
|
||||||
|
@ -223,10 +225,11 @@ namespace ccf::crypto
|
||||||
size_t contents_size,
|
size_t contents_size,
|
||||||
const uint8_t* signature,
|
const uint8_t* signature,
|
||||||
size_t signature_size,
|
size_t signature_size,
|
||||||
MDType md_type)
|
MDType md_type,
|
||||||
|
size_t salt_length)
|
||||||
{
|
{
|
||||||
return RSAPublicKey_OpenSSL::verify(
|
return RSAPublicKey_OpenSSL::verify(
|
||||||
contents, contents_size, signature, signature_size, md_type);
|
contents, contents_size, signature, signature_size, md_type, salt_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonWebKeyRSAPrivate RSAKeyPair_OpenSSL::private_key_jwk_rsa(
|
JsonWebKeyRSAPrivate RSAKeyPair_OpenSSL::private_key_jwk_rsa(
|
||||||
|
|
|
@ -36,14 +36,17 @@ namespace ccf::crypto
|
||||||
virtual std::vector<uint8_t> public_key_der() const override;
|
virtual std::vector<uint8_t> public_key_der() const override;
|
||||||
|
|
||||||
virtual std::vector<uint8_t> sign(
|
virtual std::vector<uint8_t> sign(
|
||||||
std::span<const uint8_t> d, MDType md_type = MDType::NONE) const override;
|
std::span<const uint8_t> d,
|
||||||
|
MDType md_type = MDType::NONE,
|
||||||
|
size_t salt_length = 0) const override;
|
||||||
|
|
||||||
virtual bool verify(
|
virtual bool verify(
|
||||||
const uint8_t* contents,
|
const uint8_t* contents,
|
||||||
size_t contents_size,
|
size_t contents_size,
|
||||||
const uint8_t* signature,
|
const uint8_t* signature,
|
||||||
size_t signature_size,
|
size_t signature_size,
|
||||||
MDType md_type = MDType::NONE) override;
|
MDType md_type = MDType::NONE,
|
||||||
|
size_t salt_length = 0) override;
|
||||||
|
|
||||||
virtual JsonWebKeyRSAPrivate private_key_jwk_rsa(
|
virtual JsonWebKeyRSAPrivate private_key_jwk_rsa(
|
||||||
const std::optional<std::string>& kid = std::nullopt) const override;
|
const std::optional<std::string>& kid = std::nullopt) const override;
|
||||||
|
|
|
@ -195,11 +195,14 @@ namespace ccf::crypto
|
||||||
size_t contents_size,
|
size_t contents_size,
|
||||||
const uint8_t* signature,
|
const uint8_t* signature,
|
||||||
size_t signature_size,
|
size_t signature_size,
|
||||||
MDType md_type)
|
MDType md_type,
|
||||||
|
size_t salt_length)
|
||||||
{
|
{
|
||||||
auto hash = OpenSSLHashProvider().Hash(contents, contents_size, md_type);
|
auto hash = OpenSSLHashProvider().Hash(contents, contents_size, md_type);
|
||||||
Unique_EVP_PKEY_CTX pctx(key);
|
Unique_EVP_PKEY_CTX pctx(key);
|
||||||
CHECK1(EVP_PKEY_verify_init(pctx));
|
CHECK1(EVP_PKEY_verify_init(pctx));
|
||||||
|
CHECK1(EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING));
|
||||||
|
CHECK1(EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, salt_length));
|
||||||
CHECK1(EVP_PKEY_CTX_set_signature_md(pctx, get_md_type(md_type)));
|
CHECK1(EVP_PKEY_CTX_set_signature_md(pctx, get_md_type(md_type)));
|
||||||
return EVP_PKEY_verify(
|
return EVP_PKEY_verify(
|
||||||
pctx, signature, signature_size, hash.data(), hash.size()) == 1;
|
pctx, signature, signature_size, hash.data(), hash.size()) == 1;
|
||||||
|
|
|
@ -52,7 +52,8 @@ namespace ccf::crypto
|
||||||
size_t contents_size,
|
size_t contents_size,
|
||||||
const uint8_t* signature,
|
const uint8_t* signature,
|
||||||
size_t signature_size,
|
size_t signature_size,
|
||||||
MDType md_type = MDType::NONE) override;
|
MDType md_type = MDType::NONE,
|
||||||
|
size_t salt_length = 0) override;
|
||||||
|
|
||||||
virtual Components components() const override;
|
virtual Components components() const override;
|
||||||
|
|
||||||
|
|
|
@ -932,3 +932,47 @@ TEST_CASE("Incremental hash")
|
||||||
}
|
}
|
||||||
ccf::crypto::openssl_sha256_shutdown();
|
ccf::crypto::openssl_sha256_shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Sign and verify with RSA key")
|
||||||
|
{
|
||||||
|
const auto kp = ccf::crypto::make_rsa_key_pair();
|
||||||
|
const auto pub = ccf::crypto::make_rsa_public_key(kp->public_key_pem());
|
||||||
|
const auto mdtype = ccf::crypto::MDType::SHA256;
|
||||||
|
vector<uint8_t> contents(contents_.begin(), contents_.end());
|
||||||
|
|
||||||
|
{
|
||||||
|
constexpr size_t salt_length = 0;
|
||||||
|
const auto sig = kp->sign(contents, mdtype, salt_length);
|
||||||
|
REQUIRE(pub->verify(
|
||||||
|
contents.data(),
|
||||||
|
contents.size(),
|
||||||
|
sig.data(),
|
||||||
|
sig.size(),
|
||||||
|
mdtype,
|
||||||
|
salt_length));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
constexpr size_t sign_salt_length = 0, verify_salt_legth = 32;
|
||||||
|
const auto sig = kp->sign(contents, mdtype, sign_salt_length);
|
||||||
|
REQUIRE(!pub->verify(
|
||||||
|
contents.data(),
|
||||||
|
contents.size(),
|
||||||
|
sig.data(),
|
||||||
|
sig.size(),
|
||||||
|
mdtype,
|
||||||
|
verify_salt_legth));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
constexpr size_t sign_salt_length = 32, verify_salt_legth = 32;
|
||||||
|
const auto sig = kp->sign(contents, mdtype, sign_salt_length);
|
||||||
|
REQUIRE(pub->verify(
|
||||||
|
contents.data(),
|
||||||
|
contents.size(),
|
||||||
|
sig.data(),
|
||||||
|
sig.size(),
|
||||||
|
mdtype,
|
||||||
|
verify_salt_legth));
|
||||||
|
}
|
||||||
|
}
|
|
@ -884,10 +884,19 @@ namespace ccf::js::extensions
|
||||||
sig_der, key_pair->get_curve_id());
|
sig_der, key_pair->get_curve_id());
|
||||||
return JS_NewArrayBufferCopy(ctx, sig.data(), sig.size());
|
return JS_NewArrayBufferCopy(ctx, sig.data(), sig.size());
|
||||||
}
|
}
|
||||||
else if (algo_name == "RSASSA-PKCS1-v1_5")
|
else if (algo_name == "RSA-PSS")
|
||||||
{
|
{
|
||||||
auto key_pair = ccf::crypto::make_rsa_key_pair(key);
|
auto key_pair = ccf::crypto::make_rsa_key_pair(key);
|
||||||
auto sig = key_pair->sign(contents, mdtype);
|
|
||||||
|
int64_t salt_length{};
|
||||||
|
std::ignore = JS_ToInt64(
|
||||||
|
jsctx,
|
||||||
|
&salt_length,
|
||||||
|
jsctx.get_property(algorithm, "saltLength").val);
|
||||||
|
|
||||||
|
auto sig =
|
||||||
|
key_pair->sign(contents, mdtype, static_cast<size_t>(salt_length));
|
||||||
|
|
||||||
return JS_NewArrayBufferCopy(ctx, sig.data(), sig.size());
|
return JS_NewArrayBufferCopy(ctx, sig.data(), sig.size());
|
||||||
}
|
}
|
||||||
else if (algo_name == "HMAC")
|
else if (algo_name == "HMAC")
|
||||||
|
@ -900,8 +909,8 @@ namespace ccf::js::extensions
|
||||||
{
|
{
|
||||||
return JS_ThrowRangeError(
|
return JS_ThrowRangeError(
|
||||||
ctx,
|
ctx,
|
||||||
"Unsupported signing algorithm, supported: RSASSA-PKCS1-v1_5, "
|
"Unsupported signing algorithm, supported: RSA-PSS, ECDSA, EdDSA, "
|
||||||
"ECDSA, EdDSA, HMAC");
|
"HMAC");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception& ex)
|
catch (const std::exception& ex)
|
||||||
|
@ -1010,12 +1019,12 @@ namespace ccf::js::extensions
|
||||||
ctx, "Unsupported hash algorithm, supported: SHA-256");
|
ctx, "Unsupported hash algorithm, supported: SHA-256");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (algo_name != "RSASSA-PKCS1-v1_5" && algo_name != "ECDSA")
|
if (algo_name != "RSA-PSS" && algo_name != "ECDSA")
|
||||||
{
|
{
|
||||||
return JS_ThrowRangeError(
|
return JS_ThrowRangeError(
|
||||||
ctx,
|
ctx,
|
||||||
"Unsupported signing algorithm, supported: RSASSA-PKCS1-v1_5, "
|
"Unsupported signing algorithm, supported: RSA-PSS, ECDSA, "
|
||||||
"ECDSA, EdDSA");
|
"EdDSA");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> sig(signature, signature + signature_size);
|
std::vector<uint8_t> sig(signature, signature + signature_size);
|
||||||
|
@ -1035,13 +1044,29 @@ namespace ccf::js::extensions
|
||||||
valid =
|
valid =
|
||||||
verifier->verify(data, data_size, sig.data(), sig.size(), mdtype);
|
verifier->verify(data, data_size, sig.data(), sig.size(), mdtype);
|
||||||
}
|
}
|
||||||
else
|
else if (algo_name == "ECDSA")
|
||||||
{
|
{
|
||||||
auto public_key = ccf::crypto::make_public_key(key);
|
auto public_key = ccf::crypto::make_public_key(key);
|
||||||
valid =
|
valid =
|
||||||
public_key->verify(data, data_size, sig.data(), sig.size(), mdtype);
|
public_key->verify(data, data_size, sig.data(), sig.size(), mdtype);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int64_t salt_length{};
|
||||||
|
std::ignore = JS_ToInt64(
|
||||||
|
jsctx,
|
||||||
|
&salt_length,
|
||||||
|
jsctx.get_property(algorithm, "saltLength").val);
|
||||||
|
|
||||||
|
auto public_key = ccf::crypto::make_rsa_public_key(key);
|
||||||
|
valid = public_key->verify(
|
||||||
|
data,
|
||||||
|
data_size,
|
||||||
|
sig.data(),
|
||||||
|
sig.size(),
|
||||||
|
mdtype,
|
||||||
|
static_cast<size_t>(salt_length));
|
||||||
|
}
|
||||||
return JS_NewBool(ctx, valid);
|
return JS_NewBool(ctx, valid);
|
||||||
}
|
}
|
||||||
catch (const std::exception& ex)
|
catch (const std::exception& ex)
|
||||||
|
|
|
@ -213,8 +213,15 @@ def sign(algorithm: dict, key_pem: str, data: bytes) -> bytes:
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unsupported hash algorithm")
|
raise ValueError("Unsupported hash algorithm")
|
||||||
if isinstance(key, rsa.RSAPrivateKey):
|
if isinstance(key, rsa.RSAPrivateKey):
|
||||||
if algorithm["name"] == "RSASSA-PKCS1-v1_5":
|
if algorithm["name"] == "RSA-PSS":
|
||||||
return key.sign(data, padding.PKCS1v15(), hash_alg)
|
return key.sign(
|
||||||
|
data,
|
||||||
|
padding=padding.PSS(
|
||||||
|
mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
||||||
|
salt_length=algorithm.get("saltLength", 0),
|
||||||
|
),
|
||||||
|
algorithm=hash_alg,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unsupported signing algorithm")
|
raise ValueError("Unsupported signing algorithm")
|
||||||
elif isinstance(key, ec.EllipticCurvePrivateKey):
|
elif isinstance(key, ec.EllipticCurvePrivateKey):
|
||||||
|
@ -254,7 +261,15 @@ def verify_signature(algorithm: dict, signature: bytes, data: bytes, key_pub_pem
|
||||||
if isinstance(key_pub, rsa.RSAPublicKey):
|
if isinstance(key_pub, rsa.RSAPublicKey):
|
||||||
if algorithm["hash"] != "SHA-256":
|
if algorithm["hash"] != "SHA-256":
|
||||||
raise ValueError("Unsupported hash algorithm")
|
raise ValueError("Unsupported hash algorithm")
|
||||||
key_pub.verify(signature, data, padding.PKCS1v15(), hashes.SHA256())
|
key_pub.verify(
|
||||||
|
signature,
|
||||||
|
data,
|
||||||
|
padding.PSS(
|
||||||
|
mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
||||||
|
salt_length=algorithm.get("saltLength", 0),
|
||||||
|
),
|
||||||
|
hashes.SHA256(),
|
||||||
|
)
|
||||||
elif isinstance(key_pub, ec.EllipticCurvePublicKey):
|
elif isinstance(key_pub, ec.EllipticCurvePublicKey):
|
||||||
if algorithm["hash"] != "SHA-256":
|
if algorithm["hash"] != "SHA-256":
|
||||||
raise ValueError("Unsupported hash algorithm")
|
raise ValueError("Unsupported hash algorithm")
|
||||||
|
|
|
@ -438,7 +438,7 @@ def test_npm_app(network, args):
|
||||||
|
|
||||||
# Test RSA signing + verification
|
# Test RSA signing + verification
|
||||||
key_priv_pem, key_pub_pem = infra.crypto.generate_rsa_keypair(2048)
|
key_priv_pem, key_pub_pem = infra.crypto.generate_rsa_keypair(2048)
|
||||||
algorithm = {"name": "RSASSA-PKCS1-v1_5", "hash": "SHA-256"}
|
algorithm = {"name": "RSA-PSS", "hash": "SHA-256", "saltLength": 32}
|
||||||
data = rand_bytes(random.randint(2, 50))
|
data = rand_bytes(random.randint(2, 50))
|
||||||
r = c.post(
|
r = c.post(
|
||||||
"/app/sign",
|
"/app/sign",
|
||||||
|
@ -551,7 +551,7 @@ def test_npm_app(network, args):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
key_priv_pem, key_pub_pem = infra.crypto.generate_rsa_keypair(2048)
|
key_priv_pem, key_pub_pem = infra.crypto.generate_rsa_keypair(2048)
|
||||||
algorithm = {"name": "RSASSA-PKCS1-v1_5", "hash": "SHA-256"}
|
algorithm = {"name": "RSA-PSS", "hash": "SHA-256", "saltLength": 32}
|
||||||
signature = infra.crypto.sign(algorithm, key_priv_pem, data)
|
signature = infra.crypto.sign(algorithm, key_priv_pem, data)
|
||||||
r = c.post(
|
r = c.post(
|
||||||
"/app/verifySignature",
|
"/app/verifySignature",
|
||||||
|
|
Загрузка…
Ссылка в новой задаче