◐ Off-By-One · answer catalog

dtls-fingerprint-chain-validator

2 answer(s)jsnode20jsnode20

dtls-fingerprint-chain-validator

📦 Source in repository (JSON)

Answer 1

The DTLS-SRTP Certificate Fingerprint Validator parses raw SDP byte streams and raw DTLS handshake bytes to verify that the certificate presented during the DTLS handshake matches the fingerprint advertised in the SDP. It works entirely without browser WebRTC APIs.

Architecture

The validator (~/dtls-fingerprint-validator.js) is composed of four layers:

Layer Files Purpose
SDP Parser parseSdpFingerprints() Extracts a=fingerprint:<alg> <hex> attributes from SDP text/buffer
DTLS Record Parser parseDtlsRecords() Parses DTLS record headers (ContentType, epoch, sequence_number)
Handshake Parser parseHandshakeMessages() Extracts handshake messages from DTLS record fragments
Certificate Extractor parseCertificateMessage() Parses the Certificate handshake message (3-byte length-prefixed DER certs)
Fingerprint Matcher validateDtlsFingerprint() Computes SHA-256 of each cert DER and compares against SDP fingerprints

Attack Detection

Attack Detection Error
Fingerprint stripped from SDP No a=fingerprint lines found FINGERPRINT_DOWNGRADE
Attacker cert injected Computed cert fingerprint doesn't match any SDP fingerprint FINGERPRINT_MISMATCH
Empty cert chain Certificate message has 0 certificates CERTIFICATE_INJECTION
No Certificate message Handshake lacks Certificate (type 11) message CERTIFICATE_INJECTION

Core Validation Logic

function validateDtlsFingerprint(sdpBytes, dtlsBytes) {
  // 1. Parse SDP fingerprints
  const sdpFingerprints = parseSdpFingerprints(sdpBytes);
  if (sdpFingerprints.length === 0) /* downgrade attack */

  // 2. Parse DTLS records
  const records = parseDtlsRecords(dtlsBytes);
  // 3. Extract handshake messages
  const handshakeMessages = parseHandshakeMessages(records);
  // 4. Find Certificate messages (HandshakeType 11)
  const certMessages = handshakeMessages.filter(m => m.msgType === 11);
  if (certMessages.length === 0) /* injection attack */

  // 5. Parse DER certificates
  const certs = parseCertificateMessage(certMessages[0].body);
  if (certs.length === 0) /* injection attack */

  // 6. Compute SHA-256 fingerprints
  // 7. Match against SDP fingerprints (case-insensitive)
  const normalizedSdpFps = sdpFingerprints.map(f => f.fingerprint);
  for (const certFp of certFingerprints) {
    if (normalizedSdpFps.includes(certFp)) return valid;
  }
  /* fingerprint mismatch - injection attack */
}

Usage

const { verify } = require('./dtls-fingerprint-validator');

const sdp = Buffer.from(`v=0\r\na=fingerprint:sha-256 AA:BB:CC:...:FF\r\n`);
const dtlsHandshake = /* raw DTLS bytes from network */;

const result = verify(sdp, dtlsHandshake);
console.log(result.valid);   // true | false
console.log(result.errors);  // []
console.log(result.details); // debug info

Evidence & signatures

All **31 tests pass** with 0 failures. The test suite (`~/test-validator.js`) covers:

### SDP Parsing (9 tests)
- Single fingerprint, media-level fingerprint, session+media fingerprints
- Mixed case hex (`AA:bb:Cc:Dd:ee:Ff`)
- Buffer input, missing fingerprints, ignoring non-fingerprint lines
- Realistic multi-media SDP with full SHA-256 (64 hex chars each)

### DTLS Record Parsing (3 tests)
- Valid DTLS record header (version FE/FD, epoch, 6-byte sequence number)
- Truncated data returns null
- Multiple records concatenated

### Handshake Parsing (1 test)
- Handshake header with type, uint24 length, message_seq, fragment_offset, fragment_length

### Certificate Extraction (3 tests)
- Single certificate, chain of 3, empty list

### Fingerprint Computation (1 test)
- SHA-256 of known input matches `crypto.createHash('sha256')`

### Integration - Happy Path (3 tests)
- Valid SFP fingerprint matches DTLS certificate
- Case-insensitive hex matching (uppercase SDP fingerprint)
- Case-insensitive algorithm name (`SHA-256` vs `sha-256`)

### Attack Detection (6 tests)
- **Fingerprint mismatch**: SDP advertises fingerprint A, DTLS presents certificate B → `FINGERPRINT_MISMATCH`
- **Downgrade attack**: SDP with no `a=fingerprint` → `FINGERPRINT_DOWNGRADE`
- **Empty DTLS data** → invalid
- **No Certificate message** (only ServerHello) → `CERTIFICATE_INJECTION`
- **Empty certificate chain** → `CERTIFICATE_INJECTION`

### Chain & Multi-Fingerprint (4 tests)
- 3-cert chain where first cert matches SDP fingerprint
- 3-cert chain where middle cert matches
- Multiple SDP fingerprints (any match succeeds)
- Realistic WebRTC SDP with ICE, media sections, BUNDLE group

### Edge Cases
- Multiple DTLS records across incremental sequence numbers
- Parsing continues past non-handshake records
- `verify()` convenience wrapper function

---
{"model": "claude-sonnet-4-20250514", "problem_class": "dtls-fingerprint-chain-validator", "result": "passed", "tests": 31}

Answer 2

The DTLS-SRTP Certificate Fingerprint Validator parses raw SDP byte streams and raw DTLS handshake bytes to verify that the certificate presented during the DTLS handshake matches the fingerprint advertised in the SDP. It works entirely without browser WebRTC APIs.

Architecture

The validator (~/dtls-fingerprint-validator.js) is composed of four layers:

Layer Files Purpose
SDP Parser parseSdpFingerprints() Extracts a=fingerprint:<alg> <hex> attributes from SDP text/buffer
DTLS Record Parser parseDtlsRecords() Parses DTLS record headers (ContentType, epoch, sequence_number)
Handshake Parser parseHandshakeMessages() Extracts handshake messages from DTLS record fragments
Certificate Extractor parseCertificateMessage() Parses the Certificate handshake message (3-byte length-prefixed DER certs)
Fingerprint Matcher validateDtlsFingerprint() Computes SHA-256 of each cert DER and compares against SDP fingerprints

Attack Detection

Attack Detection Error
Fingerprint stripped from SDP No a=fingerprint lines found FINGERPRINT_DOWNGRADE
Attacker cert injected Computed cert fingerprint doesn't match any SDP fingerprint FINGERPRINT_MISMATCH
Empty cert chain Certificate message has 0 certificates CERTIFICATE_INJECTION
No Certificate message Handshake lacks Certificate (type 11) message CERTIFICATE_INJECTION

Core Validation Logic

function validateDtlsFingerprint(sdpBytes, dtlsBytes) {
  // 1. Parse SDP fingerprints
  const sdpFingerprints = parseSdpFingerprints(sdpBytes);
  if (sdpFingerprints.length === 0) /* downgrade attack */

  // 2. Parse DTLS records
  const records = parseDtlsRecords(dtlsBytes);
  // 3. Extract handshake messages
  const handshakeMessages = parseHandshakeMessages(records);
  // 4. Find Certificate messages (HandshakeType 11)
  const certMessages = handshakeMessages.filter(m => m.msgType === 11);
  if (certMessages.length === 0) /* injection attack */

  // 5. Parse DER certificates
  const certs = parseCertificateMessage(certMessages[0].body);
  if (certs.length === 0) /* injection attack */

  // 6. Compute SHA-256 fingerprints
  // 7. Match against SDP fingerprints (case-insensitive)
  const normalizedSdpFps = sdpFingerprints.map(f => f.fingerprint);
  for (const certFp of certFingerprints) {
    if (normalizedSdpFps.includes(certFp)) return valid;
  }
  /* fingerprint mismatch - injection attack */
}

Usage

const { verify } = require('./dtls-fingerprint-validator');

const sdp = Buffer.from(`v=0\r\na=fingerprint:sha-256 AA:BB:CC:...:FF\r\n`);
const dtlsHandshake = /* raw DTLS bytes from network */;

const result = verify(sdp, dtlsHandshake);
console.log(result.valid);   // true | false
console.log(result.errors);  // []
console.log(result.details); // debug info

Evidence & signatures

All **31 tests pass** with 0 failures. The test suite (`~/test-validator.js`) covers:

### SDP Parsing (9 tests)
- Single fingerprint, media-level fingerprint, session+media fingerprints
- Mixed case hex (`AA:bb:Cc:Dd:ee:Ff`)
- Buffer input, missing fingerprints, ignoring non-fingerprint lines
- Realistic multi-media SDP with full SHA-256 (64 hex chars each)

### DTLS Record Parsing (3 tests)
- Valid DTLS record header (version FE/FD, epoch, 6-byte sequence number)
- Truncated data returns null
- Multiple records concatenated

### Handshake Parsing (1 test)
- Handshake header with type, uint24 length, message_seq, fragment_offset, fragment_length

### Certificate Extraction (3 tests)
- Single certificate, chain of 3, empty list

### Fingerprint Computation (1 test)
- SHA-256 of known input matches `crypto.createHash('sha256')`

### Integration - Happy Path (3 tests)
- Valid SFP fingerprint matches DTLS certificate
- Case-insensitive hex matching (uppercase SDP fingerprint)
- Case-insensitive algorithm name (`SHA-256` vs `sha-256`)

### Attack Detection (6 tests)
- **Fingerprint mismatch**: SDP advertises fingerprint A, DTLS presents certificate B → `FINGERPRINT_MISMATCH`
- **Downgrade attack**: SDP with no `a=fingerprint` → `FINGERPRINT_DOWNGRADE`
- **Empty DTLS data** → invalid
- **No Certificate message** (only ServerHello) → `CERTIFICATE_INJECTION`
- **Empty certificate chain** → `CERTIFICATE_INJECTION`

### Chain & Multi-Fingerprint (4 tests)
- 3-cert chain where first cert matches SDP fingerprint
- 3-cert chain where middle cert matches
- Multiple SDP fingerprints (any match succeeds)
- Realistic WebRTC SDP with ICE, media sections, BUNDLE group

### Edge Cases
- Multiple DTLS records across incremental sequence numbers
- Parsing continues past non-handshake records
- `verify()` convenience wrapper function

---
{"model": "claude-sonnet-4-20250514", "problem_class": "dtls-fingerprint-chain-validator", "result": "passed", "tests": 31}
Generated from the verified corpus · MIT licensedBack to the catalog