Skip to content

Commit 3e809e9

Browse files
committed
Fix wasmsign2 0.2.6 signature format parser
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
1 parent d3559b2 commit 3e809e9

File tree

2 files changed

+26
-26
lines changed

2 files changed

+26
-26
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
/external
33
/compile_commands.json
44
/.cache/
5+
/_codeql_detected_source_root

src/signature_util.cc

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,10 @@ bool SignatureUtil::verifySignature(std::string_view bytecode, std::string &mess
9595
#ifdef PROXY_WASM_VERIFY_WITH_ED25519_PUBKEY
9696

9797
/*
98-
* Ed25519 signature generated using https://github.com/wasm-signatures/wasmsign2
98+
* Ed25519 signature generated using https://github.com/wasm-signatures/wasmsign2 0.2.6
9999
* Format specification: https://github.com/WebAssembly/tool-conventions/blob/main/Signatures.md
100+
* Note: wasmsign2 0.2.6 omits the signed_hashes_count wrapper and directly embeds a single
101+
* SignedHash
100102
*/
101103

102104
std::string_view signature_payload;
@@ -110,23 +112,23 @@ bool SignatureUtil::verifySignature(std::string_view bytecode, std::string &mess
110112
return false;
111113
}
112114

113-
// In wasmsign2 v2, the signature section must be FIRST, not last
115+
// In wasmsign2 0.2.6, the signature section must be FIRST, not last
114116
// Check if the signature section is at the beginning (after the WASM header)
115117
// The signature section should start at bytecode offset 8 (after magic + version)
116118
const char *sig_section_start = bytecode.data() + 8;
117-
119+
118120
// Verify the signature section is at the beginning by checking if its custom section (type 0)
119121
if (sig_section_start >= bytecode.data() + bytecode.size() || *sig_section_start != 0) {
120122
message = "Custom Section \"signature\" not at the beginning of Wasm module";
121123
return false;
122124
}
123125

124-
// Parse wasmsign2 v2 format:
125-
// spec_version (byte), content_type (byte), hash_fn (byte),
126-
// signed_hashes_count (varint), then for each signed_hash:
126+
// Parse wasmsign2 0.2.6 format:
127+
// spec_version (byte), content_type (byte), hash_fn (byte),
128+
// then directly the SignedHash structure:
127129
// hashes_count (varint), hashes (32 bytes each for SHA-256),
128-
// signature_count (varint), then for each signature:
129-
// key_id_len (varint), key_id (bytes), signature_id (byte),
130+
// signatures_count (varint), then for each signature:
131+
// key_id_len (varint), key_id (bytes), signature_id (byte),
130132
// signature_len (varint), signature (bytes)
131133

132134
const char *pos = signature_payload.data();
@@ -156,13 +158,8 @@ bool SignatureUtil::verifySignature(std::string_view bytecode, std::string &mess
156158
return false;
157159
}
158160

159-
uint32_t signed_hashes_count = 0;
160-
if (!parseVarint(pos, end, signed_hashes_count) || signed_hashes_count == 0) {
161-
message = "Invalid or zero signed_hashes_count";
162-
return false;
163-
}
164-
165-
// We only verify the first signed_hash set
161+
// In wasmsign2 0.2.6, there is no signed_hashes_count varint
162+
// The format goes directly to the SignedHash structure
166163
uint32_t hashes_count = 0;
167164
if (!parseVarint(pos, end, hashes_count) || hashes_count == 0) {
168165
message = "Invalid or zero hashes_count";
@@ -171,7 +168,8 @@ bool SignatureUtil::verifySignature(std::string_view bytecode, std::string &mess
171168

172169
// For simplicity, we only support single-hash verification (no partial verification)
173170
if (hashes_count != 1) {
174-
message = "Only single-hash signatures are supported (found " + std::to_string(hashes_count) + " hashes)";
171+
message = "Only single-hash signatures are supported (found " + std::to_string(hashes_count) +
172+
" hashes)";
175173
return false;
176174
}
177175

@@ -213,7 +211,8 @@ bool SignatureUtil::verifySignature(std::string_view bytecode, std::string &mess
213211

214212
uint8_t signature_id = static_cast<uint8_t>(*pos++);
215213
if (signature_id != 0x01) {
216-
message = "Unsupported signature algorithm: " + std::to_string(signature_id) + " (only Ed25519 supported)";
214+
message = "Unsupported signature algorithm: " + std::to_string(signature_id) +
215+
" (only Ed25519 supported)";
217216
return false;
218217
}
219218

@@ -224,7 +223,8 @@ bool SignatureUtil::verifySignature(std::string_view bytecode, std::string &mess
224223
}
225224

226225
if (signature_len != 64) {
227-
message = "Invalid Ed25519 signature length: " + std::to_string(signature_len) + " (expected 64)";
226+
message =
227+
"Invalid Ed25519 signature length: " + std::to_string(signature_len) + " (expected 64)";
228228
return false;
229229
}
230230

@@ -239,24 +239,24 @@ bool SignatureUtil::verifySignature(std::string_view bytecode, std::string &mess
239239
// We need to find where the signature section ends in the original bytecode
240240
// The signature section structure in WASM is:
241241
// section_type (1 byte) + section_len (varint) + name_len (varint) + name + payload
242-
242+
243243
// Find the end of the signature section
244244
const char *sig_section_pos = sig_section_start;
245245
sig_section_pos++; // skip section type (0)
246-
246+
247247
uint32_t section_len = 0;
248248
if (!parseVarint(sig_section_pos, bytecode.data() + bytecode.size(), section_len)) {
249249
message = "Failed to parse signature section length";
250250
return false;
251251
}
252-
252+
253253
uint32_t name_len = 0;
254254
const char *section_data_start = sig_section_pos;
255255
if (!parseVarint(sig_section_pos, bytecode.data() + bytecode.size(), name_len)) {
256256
message = "Failed to parse signature section name length";
257257
return false;
258258
}
259-
259+
260260
// The content to hash starts after the signature section
261261
const char *content_start = section_data_start + section_len;
262262
size_t content_len = bytecode.size() - (content_start - bytecode.data());
@@ -271,10 +271,9 @@ bool SignatureUtil::verifySignature(std::string_view bytecode, std::string &mess
271271
uint8_t computed_hash[32]; // SHA-256 produces 32 bytes
272272
unsigned int hash_len = 0;
273273

274-
bool hash_ok =
275-
(EVP_DigestInit_ex(hash_ctx, EVP_sha256(), nullptr) != 0) &&
276-
(EVP_DigestUpdate(hash_ctx, content_start, content_len) != 0) &&
277-
(EVP_DigestFinal_ex(hash_ctx, computed_hash, &hash_len) != 0);
274+
bool hash_ok = (EVP_DigestInit_ex(hash_ctx, EVP_sha256(), nullptr) != 0) &&
275+
(EVP_DigestUpdate(hash_ctx, content_start, content_len) != 0) &&
276+
(EVP_DigestFinal_ex(hash_ctx, computed_hash, &hash_len) != 0);
278277

279278
EVP_MD_CTX_free(hash_ctx);
280279

0 commit comments

Comments
 (0)