or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

dns-constants.mddns-exceptions.mddns-messages.mddns-names.mddns-queries.mddns-records.mddns-resolution.mddns-updates.mddns-utilities.mddns-zones.mddnssec.mdindex.mdtsig.md

dnssec.mddocs/

0

# DNSSEC

1

2

DNS Security Extensions (DNSSEC) functionality for validating DNS signatures, handling cryptographic keys, and performing security operations. Provides complete DNSSEC validation and key management capabilities.

3

4

## Capabilities

5

6

### Signature Validation

7

8

Validate DNSSEC signatures and verify resource record authenticity.

9

10

```python { .api }

11

def validate(rrset, rrsigset, keys, origin=None, now=None):

12

"""

13

Validate an RRset against its RRSIG records using provided keys.

14

15

Args:

16

rrset (dns.rrset.RRset): Resource record set to validate

17

rrsigset (dns.rrset.RRset): RRSIG records for validation

18

keys (dict): Mapping from key names to DNSKEY records

19

origin (dns.name.Name): Origin for relative names

20

now (float): Current time (default current time)

21

22

Raises:

23

dns.dnssec.ValidationFailure: If validation fails

24

dns.dnssec.UnsupportedAlgorithm: If algorithm not supported

25

"""

26

27

def validate_rrsig(rrset, rrsig, keys, origin=None, now=None):

28

"""

29

Validate an RRset against a single RRSIG record.

30

31

Args:

32

rrset (dns.rrset.RRset): Resource record set to validate

33

rrsig (dns.rdata.RRSIG): RRSIG record for validation

34

keys (dict): Mapping from key names to DNSKEY records

35

origin (dns.name.Name): Origin for relative names

36

now (float): Current time (default current time)

37

38

Raises:

39

dns.dnssec.ValidationFailure: If validation fails

40

dns.dnssec.UnsupportedAlgorithm: If algorithm not supported

41

"""

42

43

def _validate_rrsig(rrset, rrsig, keys, origin=None, now=None):

44

"""

45

Internal validation function with detailed error information.

46

47

Returns validation status and error details for diagnostic purposes.

48

"""

49

```

50

51

### Key Operations

52

53

Handle DNSKEY records and perform key-related cryptographic operations.

54

55

```python { .api }

56

def make_ds(name, key, algorithm, origin=None):

57

"""

58

Create a DS record from a DNSKEY record.

59

60

Args:

61

name (dns.name.Name): Key owner name

62

key (dns.rdata.DNSKEY): DNSKEY record

63

algorithm (int): Digest algorithm (1=SHA-1, 2=SHA-256, 4=SHA-384)

64

origin (dns.name.Name): Origin for relative names

65

66

Returns:

67

dns.rdata.DS: Generated DS record

68

"""

69

70

def key_id(key, origin=None):

71

"""

72

Calculate the key ID (key tag) for a DNSKEY record.

73

74

Args:

75

key (dns.rdata.DNSKEY): DNSKEY record

76

origin (dns.name.Name): Origin parameter (historical, not needed)

77

78

Returns:

79

int: Key tag (0-65535)

80

"""

81

82

def make_cds(name, key, algorithm, origin=None):

83

"""

84

Create a CDS record from a DNSKEY record.

85

86

Args:

87

name (dns.name.Name): Key owner name

88

key (dns.rdata.DNSKEY): DNSKEY record

89

algorithm (int): Digest algorithm

90

origin (dns.name.Name): Origin for relative names

91

92

Returns:

93

dns.rdata.CDS: Generated CDS record

94

"""

95

96

def make_cdnskey(key):

97

"""

98

Create a CDNSKEY record from a DNSKEY record.

99

100

Args:

101

key (dns.rdata.DNSKEY): DNSKEY record

102

103

Returns:

104

dns.rdata.CDNSKEY: Generated CDNSKEY record

105

"""

106

```

107

108

### Algorithm Support

109

110

DNSSEC algorithm constants and algorithm support functions.

111

112

```python { .api }

113

# DNSSEC algorithms

114

RSAMD5 = 1 # RSA/MD5 (deprecated)

115

DH = 2 # Diffie-Hellman

116

DSA = 3 # DSA/SHA-1

117

ECC = 4 # Elliptic curve cryptography

118

RSASHA1 = 5 # RSA/SHA-1

119

DSANSEC3SHA1 = 6 # DSA-NSEC3-SHA1

120

RSASHA1NSEC3SHA1 = 7 # RSASHA1-NSEC3-SHA1

121

RSASHA256 = 8 # RSA/SHA-256

122

RSASHA512 = 10 # RSA/SHA-512

123

ECCGOST = 12 # GOST R 34.10-2001

124

ECDSAP256SHA256 = 13 # ECDSA Curve P-256 with SHA-256

125

ECDSAP384SHA384 = 14 # ECDSA Curve P-384 with SHA-384

126

ED25519 = 15 # Ed25519

127

ED448 = 16 # Ed448

128

PRIVATEDNS = 253 # Private use DNS

129

PRIVATEOID = 254 # Private use OID

130

131

# Digest algorithms

132

SHA1 = 1 # SHA-1

133

SHA256 = 2 # SHA-256

134

GOST = 3 # GOST R 34.11-94

135

SHA384 = 4 # SHA-384

136

137

def algorithm_from_text(text):

138

"""

139

Convert algorithm name to number.

140

141

Args:

142

text (str): Algorithm name

143

144

Returns:

145

int: Algorithm number

146

"""

147

148

def algorithm_to_text(algorithm):

149

"""

150

Convert algorithm number to name.

151

152

Args:

153

algorithm (int): Algorithm number

154

155

Returns:

156

str: Algorithm name

157

"""

158

159

def _is_rsa(algorithm):

160

"""Check if algorithm is RSA-based."""

161

162

def _is_dsa(algorithm):

163

"""Check if algorithm is DSA-based."""

164

165

def _is_ecdsa(algorithm):

166

"""Check if algorithm is ECDSA-based."""

167

168

def _is_eddsa(algorithm):

169

"""Check if algorithm is EdDSA-based."""

170

```

171

172

### NSEC and NSEC3 Support

173

174

Functions for working with NSEC and NSEC3 records for authenticated denial of existence.

175

176

```python { .api }

177

def nsec_matches(name, nsec, origin=None):

178

"""

179

Check if a name matches an NSEC record's coverage.

180

181

Args:

182

name (dns.name.Name): Name to check

183

nsec (dns.rdata.NSEC): NSEC record

184

origin (dns.name.Name): Origin for relative names

185

186

Returns:

187

bool: True if name is covered by NSEC

188

"""

189

190

def nsec3_hash(domain, salt, iterations, algorithm):

191

"""

192

Calculate NSEC3 hash for a domain name.

193

194

Args:

195

domain (dns.name.Name): Domain name to hash

196

salt (bytes): Salt value

197

iterations (int): Number of iterations

198

algorithm (int): Hash algorithm (1=SHA-1)

199

200

Returns:

201

bytes: NSEC3 hash value

202

"""

203

204

def nsec3_matches(hash_value, nsec3, origin=None):

205

"""

206

Check if a hash value matches an NSEC3 record's coverage.

207

208

Args:

209

hash_value (bytes): Hash value to check

210

nsec3 (dns.rdata.NSEC3): NSEC3 record

211

origin (dns.name.Name): Origin for relative names

212

213

Returns:

214

bool: True if hash is covered by NSEC3

215

"""

216

```

217

218

### Signature Creation

219

220

Create DNSSEC signatures (requires private keys and cryptographic libraries).

221

222

```python { .api }

223

def sign(rrset, key, signer, inception=None, expiration=None, lifetime=None):

224

"""

225

Sign an RRset with a private key.

226

227

Args:

228

rrset (dns.rrset.RRset): RRset to sign

229

key (private key object): Private key for signing

230

signer (dns.name.Name): Signer name

231

inception (int): Signature inception time

232

expiration (int): Signature expiration time

233

lifetime (int): Signature lifetime (alternative to expiration)

234

235

Returns:

236

dns.rdata.RRSIG: Generated RRSIG record

237

238

Note:

239

Requires cryptographic library (cryptography package)

240

"""

241

```

242

243

## Usage Examples

244

245

### Basic DNSSEC Validation

246

247

```python

248

import dns.resolver

249

import dns.dnssec

250

import dns.rdatatype

251

252

# Query for a DNSSEC-signed domain

253

resolver = dns.resolver.Resolver()

254

resolver.use_edns(0, dns.flags.DO, 4096) # Enable DNSSEC

255

256

# Get the DNSKEY records

257

dnskey_answer = resolver.query('example.com', dns.rdatatype.DNSKEY)

258

dnskey_rrset = dnskey_answer.rrset

259

260

# Get A records and their signatures

261

a_answer = resolver.query('www.example.com', dns.rdatatype.A)

262

a_rrset = a_answer.rrset

263

264

# Try to get RRSIG records for the A records

265

try:

266

rrsig_answer = resolver.query('www.example.com', dns.rdatatype.RRSIG)

267

rrsig_rrset = rrsig_answer.rrset

268

269

# Create key dictionary

270

keys = {}

271

for key in dnskey_rrset:

272

key_id = dns.dnssec.key_id(key)

273

keys[(dnskey_rrset.name, key_id)] = key

274

275

# Validate the signature

276

try:

277

dns.dnssec.validate(a_rrset, rrsig_rrset, keys)

278

print("DNSSEC validation successful!")

279

except dns.dnssec.ValidationFailure as e:

280

print(f"DNSSEC validation failed: {e}")

281

282

except dns.resolver.NoAnswer:

283

print("No RRSIG records found")

284

```

285

286

### Creating DS Records

287

288

```python

289

import dns.dnssec

290

import dns.name

291

import dns.rdata

292

import dns.rdatatype

293

import dns.rdataclass

294

295

# Create a DNSKEY record (example)

296

dnskey_text = '256 3 8 AwEAAcX...base64-encoded-key...'

297

dnskey = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DNSKEY, dnskey_text)

298

299

# Create DS record with SHA-256

300

name = dns.name.from_text('example.com.')

301

ds_sha256 = dns.dnssec.make_ds(name, dnskey, dns.dnssec.SHA256)

302

303

print(f"DS record (SHA-256):")

304

print(f" Key tag: {ds_sha256.key_tag}")

305

print(f" Algorithm: {ds_sha256.algorithm}")

306

print(f" Digest type: {ds_sha256.digest_type}")

307

print(f" Digest: {ds_sha256.digest.hex().upper()}")

308

309

# Create DS record with SHA-1 (less secure, for compatibility)

310

ds_sha1 = dns.dnssec.make_ds(name, dnskey, dns.dnssec.SHA1)

311

print(f"\nDS record (SHA-1):")

312

print(f" Key tag: {ds_sha1.key_tag}")

313

print(f" Digest: {ds_sha1.digest.hex().upper()}")

314

315

# Calculate key ID

316

key_id = dns.dnssec.key_id(dnskey)

317

print(f"\nDNSKEY key tag: {key_id}")

318

```

319

320

### Algorithm Information

321

322

```python

323

import dns.dnssec

324

325

# Work with algorithm names and numbers

326

algorithms = [

327

dns.dnssec.RSASHA256,

328

dns.dnssec.RSASHA512,

329

dns.dnssec.ECDSAP256SHA256,

330

dns.dnssec.ECDSAP384SHA384,

331

dns.dnssec.ED25519

332

]

333

334

print("Supported DNSSEC algorithms:")

335

for alg in algorithms:

336

name = dns.dnssec.algorithm_to_text(alg)

337

print(f" {alg}: {name}")

338

339

# Convert algorithm names back to numbers

340

alg_name = 'RSASHA256'

341

alg_num = dns.dnssec.algorithm_from_text(alg_name)

342

print(f"\n{alg_name} = {alg_num}")

343

344

# Check algorithm types

345

print(f"\nRSASHA256 is RSA: {dns.dnssec._is_rsa(dns.dnssec.RSASHA256)}")

346

print(f"ECDSAP256SHA256 is ECDSA: {dns.dnssec._is_ecdsa(dns.dnssec.ECDSAP256SHA256)}")

347

print(f"ED25519 is EdDSA: {dns.dnssec._is_eddsa(dns.dnssec.ED25519)}")

348

```

349

350

### NSEC3 Operations

351

352

```python

353

import dns.dnssec

354

import dns.name

355

356

# Calculate NSEC3 hash

357

domain = dns.name.from_text('www.example.com.')

358

salt = b'\x12\x34\x56\x78'

359

iterations = 10

360

algorithm = 1 # SHA-1

361

362

hash_value = dns.dnssec.nsec3_hash(domain, salt, iterations, algorithm)

363

print(f"NSEC3 hash for {domain}: {hash_value.hex().upper()}")

364

365

# Base32 encode the hash (typical NSEC3 format)

366

import base64

367

b32_hash = base64.b32encode(hash_value).decode().rstrip('=').lower()

368

print(f"Base32 encoded: {b32_hash}")

369

```

370

371

### Comprehensive Validation Example

372

373

```python

374

import dns.message

375

import dns.query

376

import dns.dnssec

377

import dns.rdatatype

378

import dns.name

379

380

def validate_dnssec_chain(domain, nameserver):

381

"""Validate DNSSEC chain for a domain."""

382

383

# Create query with DNSSEC enabled

384

query = dns.message.make_query(domain, dns.rdatatype.A, want_dnssec=True)

385

386

# Send query

387

response = dns.query.udp(query, nameserver)

388

389

if not response.answer:

390

print("No answer section in response")

391

return False

392

393

# Extract RRsets

394

answer_rrset = None

395

rrsig_rrsets = []

396

397

for rrset in response.answer:

398

if rrset.rdtype == dns.rdatatype.A:

399

answer_rrset = rrset

400

elif rrset.rdtype == dns.rdatatype.RRSIG:

401

rrsig_rrsets.append(rrset)

402

403

if not answer_rrset or not rrsig_rrsets:

404

print("Missing required records for validation")

405

return False

406

407

# Get DNSKEY records for validation

408

dnskey_query = dns.message.make_query(domain, dns.rdatatype.DNSKEY, want_dnssec=True)

409

dnskey_response = dns.query.udp(dnskey_query, nameserver)

410

411

# Build key dictionary

412

keys = {}

413

for rrset in dnskey_response.answer:

414

if rrset.rdtype == dns.rdatatype.DNSKEY:

415

for key in rrset:

416

key_id = dns.dnssec.key_id(key)

417

keys[(rrset.name, key_id)] = key

418

419

# Validate signatures

420

for rrsig_rrset in rrsig_rrsets:

421

try:

422

dns.dnssec.validate(answer_rrset, rrsig_rrset, keys)

423

print(f"Successfully validated {domain}")

424

return True

425

except dns.dnssec.ValidationFailure as e:

426

print(f"Validation failed: {e}")

427

continue

428

429

return False

430

431

# Example usage

432

domain = dns.name.from_text('example.com.')

433

nameserver = '8.8.8.8'

434

validate_dnssec_chain(domain, nameserver)

435

```

436

437

## Constants

438

439

```python { .api }

440

# Key flags

441

SEP = 0x0001 # Secure Entry Point

442

REVOKE = 0x0080 # Revoke flag

443

ZONE = 0x0100 # Zone key flag

444

445

# NSEC3 flags

446

OPTOUT = 0x01 # Opt-out flag

447

448

# Default values

449

default_algorithm = RSASHA256

450

```

451

452

## Exceptions

453

454

```python { .api }

455

class DNSSECError(DNSException):

456

"""Base class for DNSSEC errors."""

457

458

class ValidationFailure(DNSSECError):

459

"""DNSSEC validation failed."""

460

461

class UnsupportedAlgorithm(DNSSECError):

462

"""Unsupported DNSSEC algorithm."""

463

464

class InvalidSignature(ValidationFailure):

465

"""RRSIG signature is invalid."""

466

467

class ExpiredSignature(ValidationFailure):

468

"""RRSIG signature has expired."""

469

470

class NotYetValidSignature(ValidationFailure):

471

"""RRSIG signature is not yet valid."""

472

473

class NoMatchingKey(ValidationFailure):

474

"""No matching DNSKEY found for RRSIG."""

475

```