メインコンテンツまでスキップ

Appendix B. Pseudocode for Using TLSA

This appendix describes, in pseudocode format, the interactions given earlier in this specification. If the steps below disagree with the text earlier in the document, the steps earlier in the document ought to be considered correct and this text incorrect.

Note that this pseudocode is more strict than the normative text. For instance, it forces an order on the evaluation of criteria, which is not mandatory from the normative text.

B.1. Helper Functions​

// implement the function for exiting
function Finish (F) = {
if (F == ABORT_TLS) {
abort the TLS handshake or prevent TLS from starting
exit
}

if (F == NO_TLSA) {
fall back to non-TLSA certificate validation
exit
}

if (F == ACCEPT) {
accept the TLS connection
exit
}

// unreachable
}

// implement the selector function
function Select (S, X) = {
// Full certificate
if (S == 0) {
return X in DER encoding
}

// SubjectPublicKeyInfo
if (S == 1) {
return X.SubjectPublicKeyInfo in DER encoding
}

// unreachable
}
// implement the matching function
function Match (M, X, Y) {
// Exact match on selected content
if (M == 0) {
return (X == Y)
}

// SHA-256 hash of selected content
if (M == 1) {
return (SHA-256(X) == Y)
}

// SHA-512 hash of selected content
if (M == 2) {
return (SHA-512(X) == Y)
}

// unreachable
}

B.2. Main TLSA Pseudocode​

TLS connect using [transport] to [name] on [port] and receiving end
entity cert C for the TLS server:

(TLSArecords, ValState) = DNSSECValidatedLookup(
  domainname=_[port]._[transport].[name], RRtype=TLSA)

// check for states that would change processing
if (ValState == BOGUS) {
  Finish(ABORT_TLS)
}
if ((ValState == INDETERMINATE) or (ValState == INSECURE)) {
  Finish(NO_TLSA)
}
// if here, ValState must be SECURE

for each R in TLSArecords {
  // unusable records include unknown certUsage, unknown
  // selectorType, unknown matchingType, erroneous RDATA, and
  // prohibited by local policy
  if (R is unusable) {
    remove R from TLSArecords
  }
}
if (length(TLSArecords) == 0) {
  Finish(NO_TLSA)
}
// A TLS client might have multiple trust anchors that it might use
//    when validating the TLS server's end entity (EE) certificate.
//    Also, there can be multiple PKIX certification paths for the
//    certificates given by the server in TLS.  Thus, there are
//    possibly many chains that might need to be tested during
//    PKIX path validation.

for each R in TLSArecords {

  // pass PKIX certificate validation and chain through a CA cert
  //    that comes from TLSA
  if (R.certUsage == 0) {
    for each PKIX certification path H {
      if (C passes PKIX certification path validation in H) {
        for each D in H {
          if ((D is a CA certificate) and
              Match(R.matchingType, Select(R.selectorType, D),
                    R.cert)) {
            Finish(ACCEPT)
          }
        }
      }
    }
  }

  // pass PKIX certificate validation and match EE cert from TLSA
  if (R.certUsage == 1) {
    for each PKIX certification path H {
      if ((C passes PKIX certificate validation in H) and
              Match(R.matchingType, Select(R.selectorType, C),
              R.cert)) {
          Finish(ACCEPT)
      }
    }
  }

  // pass PKIX certification validation using TLSA record as the
  //    trust anchor
  if (R.certUsage == 2) {
    // the following assert() is merely a formalization of the
    // "trust anchor" condition for a certificate D matching R
    assert(Match(R.matchingType, Select(R.selectorType, D), R.cert))
    for each PKIX certification path H that has certificate D
        matching R as the trust anchor {
      if (C passes PKIX validation in H) {
        Finish(ACCEPT);
      }
    }
  }

  // match the TLSA record and the TLS certificate
  if (R.certUsage == 3) {
    if Match(R.matchingType, Select(R.selectorType, C), R.cert)
      Finish(ACCEPT)
    }
  }

}

// if here, then none of the TLSA records ended in "Finish(ACCEPT)"
//   so abort TLS
Finish(ABORT_TLS)