Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/utils/src/utils/networked-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,13 @@ export const getCidBlockVerifierFunction = (cid: CID, hasher: MultihashHasher):
hash = res
}

if (hash.digest.length > cid.multihash.size) {
hash = {
...hash,
digest: hash.digest.subarray(0, cid.multihash.size)
}
}
Comment on lines +414 to +419

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing this without sufficient checks is not a good idea from a security perspective. Go has https://github.com/ipfs/boxo/tree/main/verifcid to help stop people from ending up in unsafe situations, it's used in places where you'd be importing data into the system whether the data is locally imported or coming from the network.

For some history on this see ipfs/kubo#4371 and linked issues / PRs.


if (!uint8ArrayEquals(hash.digest, cid.multihash.digest)) {
// if a hash mismatch occurs for a TrustlessGatewayBlockBroker, we should try another gateway
throw new InvalidMultihashError('Hash of downloaded block did not match multihash from passed CID')
Expand Down
25 changes: 24 additions & 1 deletion packages/utils/test/utils/networked-storage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import all from 'it-all'
import drain from 'it-drain'
import { CID } from 'multiformats/cid'
import * as raw from 'multiformats/codecs/raw'
import { create } from 'multiformats/hashes/digest'
import { identity } from 'multiformats/hashes/identity'
import { sha512 } from 'multiformats/hashes/sha2'
import Sinon from 'sinon'
import { stubInterface } from 'sinon-ts'
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import { getHasher } from '../../src/utils/get-hasher.js'
import { NetworkedStorage } from '../../src/utils/networked-storage.js'
import { NetworkedStorage, getCidBlockVerifierFunction } from '../../src/utils/networked-storage.js'
import { createBlock } from '../fixtures/create-block.js'
import type { NetworkedStorageComponents } from '../../src/utils/networked-storage.js'
import type { BlockBroker } from '@helia/interface/blocks'
Expand Down Expand Up @@ -212,4 +214,25 @@ describe('networked-storage', () => {
expect(block).to.equalBytes(blocks[0].block)
expect(slowBroker.retrieve.getCall(0)).to.have.nested.property('args[1].signal.aborted', true)
})

it('truncates hash digest when longer than multihash size', async () => {
const testData = uint8ArrayFromString('hello world test data')

// Create a full SHA-512 hash
const fullHash = await sha512.digest(testData)

// Create a truncated digest (32 bytes instead of 64)
const truncatedDigest = create(sha512.code, fullHash.digest.subarray(0, 32))

// Create a CID with the truncated hash
const cid = CID.createV1(raw.code, truncatedDigest)

// Get the hasher and create the verifier function
const hasher = await getHasher()(sha512.code)
const verifyFn = getCidBlockVerifierFunction(cid, hasher)

// This should not throw - the verifier should truncate the full SHA-512 digest
// to match the 32-byte truncated digest in the CID
await expect(verifyFn(testData)).to.not.be.rejected()
})
})
Loading