@relaycorp/dnssec
Advanced tools
Comparing version 1.2.0 to 1.3.0
@@ -0,2 +1,9 @@ | ||
export { DnsClass } from './lib/dns/DnsClass'; | ||
export { Header } from './lib/dns/Header'; | ||
export { Message } from './lib/dns/Message'; | ||
export { Question } from './lib/dns/Question'; | ||
export { Record } from './lib/dns/Record'; | ||
export { RRSet } from './lib/dns/RRSet'; | ||
export { DatePeriod } from './lib/verification/DatePeriod'; | ||
export { Resolver } from './lib/verification/Resolver'; | ||
export { UnverifiedChain } from './lib/verification/UnverifiedChain'; |
@@ -0,3 +1,10 @@ | ||
// DNS-related | ||
export { DnsClass } from './lib/dns/DnsClass'; | ||
export { Message } from './lib/dns/Message'; | ||
export { Question } from './lib/dns/Question'; | ||
export { Record } from './lib/dns/Record'; | ||
export { RRSet } from './lib/dns/RRSet'; | ||
// DNSSEC-related | ||
export { DatePeriod } from './lib/verification/DatePeriod'; | ||
export { UnverifiedChain } from './lib/verification/UnverifiedChain'; | ||
//# sourceMappingURL=index.js.map |
/// <reference types="node" /> | ||
import { DNSClass } from './DNSClass'; | ||
import { DnsClass } from './DnsClass'; | ||
export interface QuestionFields { | ||
readonly name: string; | ||
readonly type: number; | ||
readonly class: DNSClass; | ||
readonly class: DnsClass; | ||
} | ||
@@ -11,4 +11,4 @@ export declare class Question { | ||
readonly type: number; | ||
readonly class_: DNSClass; | ||
constructor(name: string, type: number, class_: DNSClass); | ||
readonly class_: DnsClass; | ||
constructor(name: string, type: number, class_: DnsClass); | ||
get key(): string; | ||
@@ -15,0 +15,0 @@ equals(differentQuestion: Question): boolean; |
/// <reference types="node" /> | ||
import { DNSClass } from './DNSClass'; | ||
import { DnsClass } from './DnsClass'; | ||
import { Question } from './Question'; | ||
@@ -7,3 +7,3 @@ interface RecordFields { | ||
readonly type: number; | ||
readonly class: DNSClass; | ||
readonly class: DnsClass; | ||
readonly ttl: number; | ||
@@ -18,6 +18,6 @@ readonly dataSerialised: Buffer; | ||
readonly type: number; | ||
readonly class_: DNSClass; | ||
readonly class_: DnsClass; | ||
readonly ttl: number; | ||
readonly dataSerialised: Buffer; | ||
constructor(name: string, type: number, class_: DNSClass, ttl: number, dataSerialised: Buffer); | ||
constructor(name: string, type: number, class_: DnsClass, ttl: number, dataSerialised: Buffer); | ||
serialise(): Buffer; | ||
@@ -24,0 +24,0 @@ shallowCopy(partialRecord: Partial<RecordFields>): Record; |
import { Record } from './Record'; | ||
import { DNSClass } from './DNSClass'; | ||
import { DnsClass } from './DnsClass'; | ||
import { Question } from './Question'; | ||
@@ -9,3 +9,3 @@ /** | ||
readonly name: string; | ||
readonly class_: DNSClass; | ||
readonly class_: DnsClass; | ||
readonly type: number; | ||
@@ -21,3 +21,3 @@ readonly ttl: number; | ||
static init(question: Question, records: readonly Record[]): RRSet; | ||
protected constructor(name: string, class_: DNSClass, type: number, ttl: number, records: readonly Record[]); | ||
protected constructor(name: string, class_: DnsClass, type: number, ttl: number, records: readonly Record[]); | ||
} |
import { addSeconds, setMilliseconds } from 'date-fns'; | ||
import { Record } from '../dns/Record'; | ||
import { DNSClass } from '../dns/DNSClass'; | ||
import { DnsClass } from '../dns/DnsClass'; | ||
import { generateKeyPair } from './keyGen'; | ||
@@ -38,3 +38,3 @@ import { DigestType } from '../DigestType'; | ||
const ttl = options.ttl ?? FIVE_MINUTES_IN_SECONDS; | ||
const record = new Record(this.zoneName, DnssecRecordType.DNSKEY, DNSClass.IN, ttl, data.serialise()); | ||
const record = new Record(this.zoneName, DnssecRecordType.DNSKEY, DnsClass.IN, ttl, data.serialise()); | ||
const rrset = RRSet.init(record.makeQuestion(), [record, ...(options.additionalDnskeys ?? [])]); | ||
@@ -51,3 +51,3 @@ const rrsig = this.generateRrsig(rrset, data.calculateKeyTag(), options); | ||
const data = new DsData(childDnskey.data.calculateKeyTag(), childDnskey.data.algorithm, digestType, DsData.calculateDnskeyDigest(childDnskey, digestType)); | ||
const record = new Record(childZoneName, DnssecRecordType.DS, DNSClass.IN, options.ttl ?? FIVE_MINUTES_IN_SECONDS, data.serialise()); | ||
const record = new Record(childZoneName, DnssecRecordType.DS, DnsClass.IN, options.ttl ?? FIVE_MINUTES_IN_SECONDS, data.serialise()); | ||
const rrsig = this.generateRrsig(RRSet.init(record.makeQuestion(), [record]), dnskeyTag, options); | ||
@@ -63,3 +63,3 @@ return { data, message: rrsig.message, record, rrsig }; | ||
const data = RrsigData.generate(rrset, setMilliseconds(signatureExpiry, 0), setMilliseconds(signatureInception, 0), this.privateKey, this.zoneName, keyTag, this.algorithm); | ||
const record = new Record(rrset.name, DnssecRecordType.RRSIG, DNSClass.IN, rrset.ttl, data.serialise()); | ||
const record = new Record(rrset.name, DnssecRecordType.RRSIG, DnsClass.IN, rrset.ttl, data.serialise()); | ||
const message = new Message({ rcode: RCode.NoError }, [new Question(rrset.name, rrset.type, rrset.class_)], [...rrset.records, record]); | ||
@@ -66,0 +66,0 @@ return { data, message, record }; |
@@ -13,3 +13,6 @@ import { createPublicKey } from 'node:crypto'; | ||
case DnssecAlgorithm.ECDSAP384SHA384: | ||
return serialiseEcdsaPublicKey(publicKey); | ||
return serialiseEcDsaPublicKey(publicKey); | ||
case DnssecAlgorithm.ED25519: | ||
case DnssecAlgorithm.ED448: | ||
return serialiseEdDsaPublicKey(publicKey); | ||
default: | ||
@@ -46,3 +49,3 @@ throw new Error(`Unsupported DNSSEC algorithm (${dnssecAlgorithm})`); | ||
} | ||
function serialiseEcdsaPublicKey(publicKey) { | ||
function serialiseEcDsaPublicKey(publicKey) { | ||
const algorithm = publicKey.asymmetricKeyType; | ||
@@ -57,2 +60,10 @@ if (algorithm !== 'ec') { | ||
} | ||
function serialiseEdDsaPublicKey(publicKey) { | ||
const algorithm = publicKey.asymmetricKeyType; | ||
if (!['ed25519', 'ed448'].includes(algorithm)) { | ||
throw new Error(`Requested serialisation of EdDSA key but got ${algorithm} key`); | ||
} | ||
const keyJwt = publicKey.export({ format: 'jwk' }); | ||
return Buffer.from(keyJwt.x, 'base64url'); | ||
} | ||
export function deserialisePublicKey(serialisation, dnssecAlgorithm) { | ||
@@ -66,3 +77,6 @@ switch (dnssecAlgorithm) { | ||
case DnssecAlgorithm.ECDSAP384SHA384: | ||
return deserialiseEcdsaPublicKey(serialisation, dnssecAlgorithm); | ||
return deserialiseEcDsaPublicKey(serialisation, dnssecAlgorithm); | ||
case DnssecAlgorithm.ED25519: | ||
case DnssecAlgorithm.ED448: | ||
return deserialiseEdDsaPublicKey(serialisation, dnssecAlgorithm); | ||
default: | ||
@@ -94,3 +108,3 @@ throw new Error(`Unsupported DNSSEC algorithm (${dnssecAlgorithm})`); | ||
} | ||
function deserialiseEcdsaPublicKey(serialisation, algorithm) { | ||
function deserialiseEcDsaPublicKey(serialisation, algorithm) { | ||
const serialisationLength = serialisation.byteLength; | ||
@@ -112,2 +126,17 @@ if (algorithm === DnssecAlgorithm.ECDSAP256SHA256 && serialisationLength !== 64) { | ||
} | ||
function deserialiseEdDsaPublicKey(serialisation, algorithm) { | ||
const serialisationLength = serialisation.byteLength; | ||
if (algorithm === DnssecAlgorithm.ED25519 && serialisationLength !== 32) { | ||
throw new Error(`Ed25519 public key should span 32 octets (got ${serialisationLength})`); | ||
} | ||
if (algorithm === DnssecAlgorithm.ED448 && serialisationLength !== 57) { | ||
throw new Error(`Ed448 public key should span 57 octets (got ${serialisationLength})`); | ||
} | ||
const curveName = algorithm === DnssecAlgorithm.ED25519 ? 'Ed25519' : 'Ed448'; | ||
const publicKeyBase64 = serialisation.toString('base64url'); | ||
return createPublicKey({ | ||
key: { crv: curveName, kty: 'OKP', x: publicKeyBase64 }, | ||
format: 'jwk', | ||
}); | ||
} | ||
//# sourceMappingURL=keySerialisation.js.map |
@@ -6,4 +6,5 @@ import { Question } from '../dns/Question'; | ||
import { RRSet } from '../dns/RRSet'; | ||
import { Resolver } from './Resolver'; | ||
interface MessageByKey { | ||
readonly [name: string]: Message; | ||
readonly [key: string]: Message; | ||
} | ||
@@ -14,6 +15,7 @@ export declare class UnverifiedChain { | ||
readonly zoneMessageByKey: MessageByKey; | ||
static retrieve(question: Question, resolver: Resolver): Promise<UnverifiedChain>; | ||
static initFromMessages(query: Question, messages: readonly Message[]): UnverifiedChain; | ||
constructor(query: Question, response: Message, zoneMessageByKey: MessageByKey); | ||
protected constructor(query: Question, response: Message, zoneMessageByKey: MessageByKey); | ||
verify(options?: Partial<VerificationOptions>): VerificationResult<RRSet>; | ||
} | ||
export {}; |
@@ -0,1 +1,2 @@ | ||
import { Question } from '../dns/Question'; | ||
import { DnssecRecordType } from '../DnssecRecordType'; | ||
@@ -12,8 +13,11 @@ import { augmentFailureResult } from './results'; | ||
zoneMessageByKey; | ||
// public static async retrieve( | ||
// question: Omit<Question, 'class'>, | ||
// resolver: (q: Question) => Promise<Message>, | ||
// ): Promise<UnverifiedChain> { | ||
// throw new Error('' + question + resolver); | ||
// } | ||
static async retrieve(question, resolver) { | ||
const zoneNames = getZonesInChain(question.name); | ||
const dnskeyMessages = await retrieveZoneMessages(zoneNames, DnssecRecordType.DNSKEY, question.class_, resolver); | ||
const dsMessages = await retrieveZoneMessages(zoneNames.slice(1), // Skip the root DS | ||
DnssecRecordType.DS, question.class_, resolver); | ||
const zoneMessageByKey = { ...dnskeyMessages, ...dsMessages }; | ||
const response = await resolver(question); | ||
return new UnverifiedChain(question, response, zoneMessageByKey); | ||
} | ||
static initFromMessages(query, messages) { | ||
@@ -115,2 +119,9 @@ const allMessages = messages.reduce((acc, m) => { | ||
} | ||
async function retrieveZoneMessages(zoneNames, recordType, class_, resolver) { | ||
const question = new Question('.', recordType, class_); | ||
return zoneNames.reduce(async (messages, zoneName) => { | ||
const message = await resolver(question.shallowCopy({ name: zoneName })); | ||
return { ...(await messages), [`${zoneName}/${recordType}`]: message }; | ||
}, Promise.resolve({})); | ||
} | ||
//# sourceMappingURL=UnverifiedChain.js.map |
@@ -7,3 +7,3 @@ import { DsData } from '../rdata/DsData'; | ||
import { SignedRRSet } from './SignedRRSet'; | ||
import { DNSClass } from '../dns/DNSClass'; | ||
import { DnsClass } from '../dns/DnsClass'; | ||
import { Question } from '../dns/Question'; | ||
@@ -34,3 +34,3 @@ /** | ||
} | ||
const dnskeySignedRrset = SignedRRSet.initFromRecords(new Question(zoneName, DnssecRecordType.DNSKEY, DNSClass.IN), dnskeyMessage.answers); | ||
const dnskeySignedRrset = SignedRRSet.initFromRecords(new Question(zoneName, DnssecRecordType.DNSKEY, DnsClass.IN), dnskeyMessage.answers); | ||
let dnskeys; | ||
@@ -75,3 +75,3 @@ try { | ||
} | ||
const dsSignedRrset = SignedRRSet.initFromRecords(new Question(zoneName, DnssecRecordType.DS, DNSClass.IN), dsMessage.answers); | ||
const dsSignedRrset = SignedRRSet.initFromRecords(new Question(zoneName, DnssecRecordType.DS, DnsClass.IN), dsMessage.answers); | ||
if (!dsSignedRrset.verify(this.dnskeys, datePeriod, this.name)) { | ||
@@ -78,0 +78,0 @@ return { |
{ | ||
"name": "@relaycorp/dnssec", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"author": { | ||
@@ -5,0 +5,0 @@ "email": "no-reply@relaycorp.tech", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
124982
129
1726