Skip to content

Commit

Permalink
fix: require V2 signatures
Browse files Browse the repository at this point in the history
This is part of deprecation described in ipfs/js-ipfs#4197
- record creation continues to create both V1 and V2  signatures
- record validation no longer accepts V1 signatures

Meaning:
- modern nodes are 100% V2, they ignore V1 signatures
- legacy nodes (go-ipfs < v0.9.0, js-ipfs before Jun 2021) are still
  able to resolve names created by js-ipns, because V1 is still present
  • Loading branch information
lidel committed Sep 12, 2022
1 parent 0f5340a commit b93d957
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 11 deletions.
3 changes: 1 addition & 2 deletions README.md
@@ -1,7 +1,6 @@
# ipns <!-- omit in toc -->

[![ipfs.io](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io)
[![IRC](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs)
[![ipfs.tech](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](https://ipfs.tech)
[![Discord](https://img.shields.io/discord/806902334369824788?style=flat-square)](https://discord.gg/ipfs)
[![codecov](https://img.shields.io/codecov/c/github/ipfs/js-ipns.svg?style=flat-square)](https://codecov.io/gh/ipfs/js-ipns)
[![CI](https://img.shields.io/github/workflow/status/ipfs/js-ipns/test%20&%20maybe%20release/master?style=flat-square)](https://github.com/ipfs/js-ipns/actions/workflows/js-test-and-release.yml)
Expand Down
6 changes: 3 additions & 3 deletions src/index.ts
Expand Up @@ -95,7 +95,7 @@ const _create = async (peerId: PeerId, value: Uint8Array, seq: number | bigint,
}

const privateKey = await unmarshalPrivateKey(peerId.privateKey)
const signatureV1 = await sign(privateKey, value, validityType, isoValidity)
const signatureV1 = await signLegacyV1(privateKey, value, validityType, isoValidity)
const data = createCborData(value, isoValidity, validityType, seq, ttl)
const sigData = ipnsEntryDataForV2Sig(data)
const signatureV2 = await privateKey.sign(sigData)
Expand Down Expand Up @@ -144,9 +144,9 @@ export { peerIdToRoutingKey } from './utils.js'
export { peerIdFromRoutingKey } from './utils.js'

/**
* Sign ipns record data
* Sign ipns record data using the legacy V1 signature scheme
*/
const sign = async (privateKey: PrivateKey, value: Uint8Array, validityType: IpnsEntry.ValidityType, validity: Uint8Array) => {
const signLegacyV1 = async (privateKey: PrivateKey, value: Uint8Array, validityType: IpnsEntry.ValidityType, validity: Uint8Array) => {
try {
const dataForSignature = ipnsEntryDataForV1Sig(value, validityType, validity)

Expand Down
5 changes: 2 additions & 3 deletions src/validator.ts
Expand Up @@ -2,7 +2,7 @@ import errCode from 'err-code'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
import { IpnsEntry } from './pb/ipns.js'
import { parseRFC3339, extractPublicKey, ipnsEntryDataForV1Sig, ipnsEntryDataForV2Sig, unmarshal, peerIdFromRoutingKey, parseCborData } from './utils.js'
import { parseRFC3339, extractPublicKey, ipnsEntryDataForV2Sig, unmarshal, peerIdFromRoutingKey, parseCborData } from './utils.js'
import * as ERRORS from './errors.js'
import type { IPNSEntry } from './index.js'
import type { PublicKey } from '@libp2p/interface-keys'
Expand All @@ -27,8 +27,7 @@ export const validate = async (publicKey: PublicKey, entry: IPNSEntry) => {

validateCborDataMatchesPbData(entry)
} else {
signature = entry.signature ?? new Uint8Array(0)
dataForSignature = ipnsEntryDataForV1Sig(value, validityType, validity)
throw errCode(new Error('missing data or signatureV2'), ERRORS.ERR_SIGNATURE_VERIFICATION)
}

// Validate Signature
Expand Down
24 changes: 21 additions & 3 deletions test/index.spec.ts
Expand Up @@ -60,17 +60,35 @@ describe('ipns', function () {
await ipnsValidator(peerIdToRoutingKey(peerId), marshal(entry))
})

it('should validate a v1 message', async () => {
it('should fail to validate a v1 (deprecated legacy) message', async () => {
const sequence = 0
const validity = 1000000

const entry = await ipns.create(peerId, cid, sequence, validity)

// extra fields added for v2 sigs
// remove the extra fields added for v2 sigs
delete entry.data
delete entry.signatureV2

await ipnsValidator(peerIdToRoutingKey(peerId), marshal(entry))
// confirm a v1 exists
expect(entry).to.have.property('signature')

await expect(ipnsValidator(peerIdToRoutingKey(peerId), marshal(entry))).to.eventually.be.rejected().with.property('code', ERRORS.ERR_SIGNATURE_VERIFICATION)
})

it('should fail to validate a v2 without v2 signature (ignore v1)', async () => {
const sequence = 0
const validity = 1000000

const entry = await ipns.create(peerId, cid, sequence, validity)

// remove v2 sig
delete entry.signatureV2

// confirm a v1 exists
expect(entry).to.have.property('signature')

await expect(ipnsValidator(peerIdToRoutingKey(peerId), marshal(entry))).to.eventually.be.rejected().with.property('code', ERRORS.ERR_SIGNATURE_VERIFICATION)
})

it('should fail to validate a bad record', async () => {
Expand Down

0 comments on commit b93d957

Please sign in to comment.