Re: [Anima] Benjamin Kaduk's Discuss on draft-ietf-anima-bootstrapping-keyinfra-22: (with DISCUSS and COMMENT)

Michael Richardson <> Sun, 11 August 2019 08:13 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id 93B4B120AFB; Sun, 11 Aug 2019 01:13:05 -0700 (PDT)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -4.2
X-Spam-Status: No, score=-4.2 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001] autolearn=ham autolearn_force=no
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id mlV2Asi8OCTK; Sun, 11 Aug 2019 01:11:57 -0700 (PDT)
Received: from ( []) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by (Postfix) with ESMTPS id F1A82120954; Sat, 10 Aug 2019 21:06:08 -0700 (PDT)
Received: from (unknown [IPv6:2607:f0b0:f:2:56b2:3ff:fe0b:d84]) by (Postfix) with ESMTP id 8870C3818C; Sun, 11 Aug 2019 00:05:25 -0400 (EDT)
Received: from localhost (localhost [IPv6:::1]) by (Postfix) with ESMTP id 9702F266; Sun, 11 Aug 2019 00:06:07 -0400 (EDT)
From: Michael Richardson <>
To: Benjamin Kaduk <>
cc: The IESG <>,,,,
In-Reply-To: <>
References: <>
X-Mailer: MH-E 8.6; nmh 1.7+dev; GNU Emacs 24.5.1
X-Face: $\n1pF)h^`}$H>Hk{L"x@)JS7<%Az}5RyS@k9X%29-lHB$Ti.V>2bi.~ehC0; <'$9xN5Ub# z!G,p`nR&p7Fz@^UXIn156S8.~^@MJ*mMsD7=QFeq%AL4m<nPbLgmtKK-5dC@#:k
MIME-Version: 1.0
Content-Type: multipart/signed; boundary="=-=-="; micalg="pgp-sha256"; protocol="application/pgp-signature"
Date: Sun, 11 Aug 2019 00:06:07 -0400
Message-ID: <25503.1565496367@localhost>
Archived-At: <>
Subject: Re: [Anima] Benjamin Kaduk's Discuss on draft-ietf-anima-bootstrapping-keyinfra-22: (with DISCUSS and COMMENT)
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Autonomic Networking Integrated Model and Approach <>
List-Unsubscribe: <>, <>
List-Archive: <>
List-Post: <>
List-Help: <>
List-Subscribe: <>, <>
X-List-Received-Date: Sun, 11 Aug 2019 08:13:06 -0000 contains an updated diff against -24.

Benjamin Kaduk via Datatracker <> wrote:
    > Section 5.2

    > application/voucher-cms+json  The request is a "YANG-defined JSON
    > document that has been signed using a CMS structure" as described
    > in Section 3 using the JSON encoding described in [RFC7951].  This

    > Section 3 does not describe any "sign[ing] using a CMS structure"
    > operation.

Yes, I see, the sentence structure is wrong.  I have changed it:

-   application/voucher-cms+json  The request is a "YANG-defined JSON
-      document that has been signed using a CMS structure" as described
-      in Section 3 using the JSON encoding described in [RFC7951].  This
-      voucher media type is defined in [RFC8366] and is also used for
-      the pledge voucher-request.  The pledge SHOULD sign the request
-      using the Section 2.3 credential.

+   application/voucher-cms+json  [RFC8366] defines a "YANG-defined JSON
+      document that has been signed using a CMS structure", and the
+      voucher-request described in Section 3 is created in the same way.
+      The media type is the same as defined in [RFC8366].  and is also
+      used for the pledge voucher-request.  The pledge MUST sign the
+      request using the Section 2.3 credential.

    > To be clear, this is MUST sign, but SHOULD use IDevID (vs. some other
    > credential) to sign?

It was SHOULD, because we supported unsigned voucher requests, but we removed
that option.  It is now MUST.

    > constrained voucher formats are expected in the future.  Registrar's
    > and MASA's are expected to be flexible in what they accept.

    > nits: no apostrophes for plurals.


    > proximity-registrar-cert:  In a pledge voucher-request this is the
    > first certificate in the TLS server 'certificate_list' sequence
    > (see [RFC5246]) presented by the registrar to the pledge.  This
    > MUST be populated in a pledge voucher-request if the "proximity"
    > assertion is populated.

    > [same comment as above about "end-entity certificate"]


    > The registrar validates the client identity as described in EST
    > [RFC7030] section 3.3.2.  The registrar confirms that the 'proximity'
    > assertion and associated 'proximity-registrar-cert' are correct.

    > what 'proximity' assertion?
    > Does verifying proximity-registrar-cert just mean checking that it's the
    > same leaf certificate that the registrar presented?  What happens if the
    > validation fails?

Yes, it means confirming that the pinned certificate is one's own.
If it fails, then there is a MITM, and the connection should be closed.
{I will use "MITM" until someone tells if me we are using a different term}

I've split that paragraph up, as there are two thoughts, one is about the
ClientCertificate, and the other is about the pinned certificate.

    The registrar validates the client identity as described in EST
-   [RFC7030] section 3.3.2.  The registrar confirms that the 'proximity'
-   assertion and associated 'proximity-registrar-cert' are correct.
+   [RFC7030] section 3.3.2.
+   The registrar confirms that the assertion is 'proximity' and that
+   pinned 'proximity-registrar-cert' is the Registrar's certificate.  If
+   this validation fails, then there a On-Path Attacker (MITM), and the
+   connection MUST be closed after the returning an HTTP 401 error code.

    > Section 5.3

    doc> A Registrar accepts or declines a request to join the domain, based
    doc> on the authenticated identity presented.  Automated acceptance
    doc> criteria include:

    > I suggest "for different networks, examples of automated acceptance
    > criteria may include".

    doc> If these validations fail the registrar SHOULD respond with an
    doc> appropriate HTTP error code.

    > Similarly, "If validation fails".


    > Section 5.4

    doc> The BRSKI-MASA TLS connection is a 'normal' TLS connection
    doc> appropriate for HTTPS REST interfaces.  The registrar initiates the
    doc> connection and uses the MASA URL obtained as described in Section 2.8
    doc> for [RFC6125] authentication of the MASA.

    > I'd consider mentioning  the implicit trust anchor database as well as
    > the MASA URL.

edits for another review changed this to:
   The BRSKI-MASA TLS connection is a 'normal' TLS connection
   appropriate for HTTPS REST interfaces.  The registrar initiates the
   connection and uses the MASA URL obtained as described in
   Section 2.8.  The mechanisms in [RFC6125] SHOULD be used
   authentication of the MASA.  Some vendors will establish explicit (or
   private) trust anchors for validating their MASA; this will typically
   done as part of a sales channel integration.  Registars SHOULD permit
   trust anchors to be pre-configured on a per-vendor basis.

    doc> The MASA and the registrars SHOULD be prepared to support TLS client
    doc> certificate authentication and/or HTTP Basic or Digest authentication
    doc> as described in [RFC7030] for EST clients.  This connection MAY also
    doc> have no client authentication at all (Section 7.4)

    > I don't see discussion of skipping client authentication in Section 7.4.
    > It would be great to have some, there!

It's buried in point 2.
I moved text from 7.4 into a new 5.4.1, I created 7.4.1/7.4.2 so that it
could be forward referenced.  Diff too long here, see link above.

    doc> The authentication of the BRSKI-MASA connection does not affect the
    doc> voucher-request process, as voucher-requests are already signed by
    doc> the registrar.  Instead, this authentication provides access control
    doc> to the audit log.

    > I don't understand what "access control to the audit log" means.  Is the
    > idea that the TLS client identity in the BSRKI-MASA connection is only
    > used when processing requests to the requestauditlog endpoint and that
    > some clients might be denied access?

The audit log reveals who owns what.  Revealing it to strangers would be a problem.
So in order to get access to the audit log for device FOO, one presents a
voucher-request for FOO.  Since the request contains a serial-number and a
mapping to an owner, we use that as an access key to get the audit-log.
The identity that the MASA sees in the HTTPS request (ClientCertificate
preferred), says who is asking.

What can I fix here?

    > Section 5.5

    doc> created-on:  Registrars are RECOMMENDED to populate this field.  This
    doc> provides additional information to the MASA.

    > Earlier we said that this field would be propagated from the pledge
    > voucher-request; we should probably say something like "populate this
    > field; if it was present in the pledge voucher-request it is copied
    > unchanged to the registrar voucher-request; otherwise the current time
    > is used".

That create-on is the time on the Registrar, not on the pledge. It currently

   The registrar populates the voucher-request fields as follows:

   created-on:  The Registrars SHOULD populate this field with the
      current date and time when the Registrar formed this voucher
      request.  This field provides additional information to the MASA.

    > nonce:  This is the value from the pledge voucher-request.  The
    > registrar voucher-request MAY omit the nonce as per Section 3.1)

    > I'd suggest "value from the pledge voucher-request, if present" and
    > changing the second sentence to refer to the pledge voucher-request.

I've written:

   nonce:  This value, if present, is copied from the pledge voucher-
      request.  The registrar voucher-request MAY omit the nonce as per
      Section 3.1.

It's up to the Registrar whether to include the nonce.
A registrar may issue a voucher-request on it's own, if it is trying to get
an offline voucher.

    > idevid-issuer:  The idevid-issuer value from the pledge certificate
    > is included to ensure a statistically unique identity.

    > There is no "idevid-issuer" field in the pledge certificate; I assume
    > this is supposed to be the Issuer Name of the IDevID certificate.

Changed to:
   idevid-issuer:  The Issuer value from the value from the pledge
      IDevID certificate is included to ensure a uniqueness of the
      serial-number.  In the case of nonceless (offline) voucher-
      request, then an appropriate value needs to be configured from the
      same out-of-band source as the serial-number.

    > prior-signed-voucher-request:  The signed pledge voucher-request
    > SHOULD be included in the registrar voucher-request.  (NOTE: what
    > is included is the complete pledge voucher-request, inclusive of
    > the 'assertion', 'proximity-registrar-cert', etc wrapped by the
    > pledge's original signature).  If a signed voucher-request was not
    > recieved from the pledge then this leaf is omitted from the
    > registrar voucher request.

    > This is a good example of text that implies the signed voucher is
    > binary.  (And as such would be a good place to talk about the base64
    > encoding.)

okay, done.

    > All other fields MAY be omitted in the registrar voucher-request.

    > Should the proximity-registrar-cert field *not* be present?

Correct, it's from the pledge->registrar.

    > Section 5.5.2

    doc> The MASA MUST verify that the registrar voucher-request is signed by
    doc> a registrar.  This is confirmed by verifying that the id-kp-cmcRA
    doc> extended key usage extension field (as detailed in EST RFC7030
    doc> section 3.6.1) exists in the certificate of the entity that signed
    doc> the registrar voucher-request.  This verification is only a
    doc> consistency check that the unauthenticated domain CA intended the
    doc> voucher-request signer to be a registrar.  Performing this check
    doc> provides value to the domain PKI by assuring the domain administrator
    doc> that the MASA service will only respect claims from authorized
    doc> Registration Authorities of the domain.

    > If the MASA has no prior knowledge of the domain (certificate), this is
    > susceptible to anyone spinning up something that claims to be a domain
    > CA and issuing registrar certs with that extension.  We need to document
    > somewhere what other part of the system prevents that from causing an
    > unauthorized voucher to be used.  (Perhaps preventing one from being
    > issued is not feasible, but acceptable if the pledge will not accept
    > it, though there remains risk of DoS on the MASA.)

The ability for someone to spin up a domain is part one of the ways that the
MASA MAY operate in the absense of supply chain integration.  The audit-log
is the defense against this.  If the MASA does not want to do business with
such entities, then it just doesn't.

    > Section 5.5.3

    doc> If a nonceless voucher-request is submitted the MASA MUST
    doc> authenticate the registrar as described in either EST [RFC7030]
    doc> section 3.2, section 3.3, or by validating the registrar's

    > Subsubsection references might be more helpful.


    doc> In the nonced case, validation of the registrar MAY be omitted if the
    doc> device policy is to accept audit-only vouchers.

    > I don't see any (SHOULD?) guidance about validating the registrar in the
    > nonced case when other policy is used.  Even the previous section does
    > not really say much to indicate there is value in authenticating the
    > signature on the voucher request.

The signature on the pledge voucher-request is always validated.
The signature on the registrar voucher-request is also always validated.
What's optional is validating the TLS ClientCertificate/HTTP of the

I've added a few words to say this.

    > Section 5.5.4

    doc> authentication or voucher-request signature validation.  Similarly,
    doc> as noted in Section 5.5.2, the MASA performs normal PKIX revocation
    doc> checking during signature consistency checks (a signature by a
    doc> registrar certificate that has been revoked is an inconsistency).

    > I think this needs to be noted more clearly in Section 5.5.2.

I'll ask *** MAX *** to help here.

    > Section 5.5.5

    doc> The MASA MAY verify that the registrar voucher-request includes the
    doc> 'prior-signed-voucher-request' field.  If so the prior-signed-
    doc> voucher-request MUST include a 'proximity-registrar-cert' that is
    doc> consistent with the certificate used to sign the registrar voucher-
    doc> request.  Additionally the voucher-request serial-number leaf MUST

    > This seems kind of tautological ("if the MASA is checking X, X MUST have
    > happened").  Also, what does "consistent with"  mean?

If the MASA is configured to issue nonceless vouchers for this device, then
no prior-signed-voucher-request field is needed.  If it's there, then it must
be valid.

    doc> match the pledge serial-number that the MASA extracts from the
    doc> signing certificate of the prior-signed-voucher-request.  The MASA is
    doc> aware of which pledges support signing of their voucher requests and
    doc> can use this information to confirm proximity of the pledge with the
    doc> registrar, thus ensuring that the BRSKI-EST TLS connection has no
    doc> man-in-the-middle.

    > To be clear, this MITM detection is only for the case of pledges that
    > sign their voucher requests, right?  And it seems to only hold if
    > pledges that support signing actually do sign, every time.

Yes, and also we have removed unsigned, so this is another place we missed
a conditional on that.  I want to note that the manufacturer knows, by
construction, what the behaviour of the pledge is.
So I've removed the last sentence completely

    > Section 5.5.6

    doc> The registrar's certificate chain is extracted from the signature
    doc> method.  The chain includes the domain CA certificate as specified in
    doc> Section 5.5.  This certificate is used to populate the "pinned-

    > I don't think Section 5.5 is the right reference for "includes the
    > domain CA certificate" (both here and in 5.5.2).

It's referring to:
   The entire
   registrar certificate chain, up to and including the Domain CA, MUST
   be included in the CMS structure.

I think that 5.5.2 is the right pointer.

    doc> domain-cert" of the voucher being issued.  The domainID (e.g., hash
    doc> of the root public key) is determined from the pinned-domain-cert and
    doc> is used to update the audit log.

    > If the pinning takes the whole cert (per RFC 8366), then what do we need
    > the domainID for?  Just the audit log?  Surely in that case SHA-1 is
    > not a hard requirement...

I've changed the domainID definition such that it uses the
SubjectKeyIdentifier, if present.  That can be any algorithm that the CA
wants to use to identify the Entity certificate.  We need to have a
consistently calculated value if it's not present, and RFC5280 says SHA-1.

   domainID:  The domain IDentity is a unique hash based upon a
      Registrar's certificate.  If the certificate includes the
      SubjectKeyIdentifier (Section [RFC5280]), then it is to be
      used as the domainID.  If not, then the 160-bit SHA-1 hash as
      described in that section is to be used.  This value needs to be
      calculated by both MASA (to populate the audit log), and by the
      Registrar (to recognize itself).

Does this work?  We are only using SHA-1 (for identification, btw, not
for resistence to pre-image attacks) as a last resort.

I'm looking for a place where I could RECOMMEND that Registrar certificates
have SubjectKeyIdentifier added.  To 5.1, I have added:

              <xref target="RFC5280" /> section does not mandate that the
              SubjectKeyIdentifier extension be present in non-CA certificates.
              It is RECOMMENDED that Registrar certificates (even if
              self-signed), always include the SubjectKeyIdentifier to be
              used as a DomainID, and that a hash stronger than SHA-1 be

    > Section 5.5.7

    doc> The MASA MUST use the nonce from the registrar voucher-request for
    doc> the resulting voucher and audit log.  The prior-signed-voucher-
    doc> request nonce is ignored during this operation.

    > I don't understand this requirement.  They could only be different if
    > the MUST from the previous paragraph is ignored.

The Registrar may include no nonce. So I agree it looks weird at this point.
I will change this to:

   The MASA populates the audit-log with the nonce that was verified.
   If a nonceless voucher is issued, then the audit log is to be
   populated with the JSON value "null".

and I noticed that the audit log asked for the string "null", rather than a
JSON null.

    > Section 5.6

    doc> The MASA voucher response to the registrar is forwarded without
    doc> changes to the pledge; therefore this section applies to both the
    doc> MASA and the registrar.  The HTTP signaling described applies to both
    doc> the MASA and registrar responses.  A registrar either caches prior
    doc> MASA responses or dynamically requests a new voucher based on local
    doc> policy (it does not generate or sign a voucher).  [...]

    > Do we need to say how this local caching policy interacts with HTTP
    > cache control headers?

All of the requests are via POST. We are not permitting 201 returns for the
voucher-request (with GET to the Location:), so there can be no opportunity
to cache.

If the Registrar caches a voucher, it would be caching a nonceless one.

    > I got confused by "or dynamically requests a new voucher" the first
    > couple times I read it; I landed on something like "when a voucher
    > request arrives at the registrar, if it has a cached response from the
    > MASA for the corresponding registrar voucher-request, that cached
    > response can be used according to local policy; otherwise the registrar
    > constructs a new registrar voucher-request and sends it to the MASA".

I can use your words.

Perhaps implicit in this is that there are two ways to build a registrar.

The simplest is with a single monolithic application framework, it receives
the voucher-request, and then does a synchronous HTTPS request to the MASA.
(Perhaps doing 100-Continue).
The other way is for the pledge-facing part of the Registrar to put it all
into a database, return 202, and wait for another query.  Asynchronously some
other part sends requests to the MASA and stores the answers back in the
database.  Perhaps the only thing connecting the two parts is some
multi-master database replication... running over
UUCP^WDelay-Tolerant-Networking between planets for all we know.

    > type.  The registrar SHOULD use this response if it determines the
    > pledge is unacceptable due to inventory control, MASA audit logs, or
    > any other reason.

    > What does "unacceptable due to inventory control" mean?

Such as, device is not in the list of devices that were expected, assuming
supply chain integration.

    > A 415 (Unsupported Media Type) response is approriate for a request
    > that has a voucher-request or accept encoding that is not understood.

    > Isn't "Accept-Encoding:" a more typical spelling?

Actually, we meant Accept: .. encoding. I've removed the word encoding,
because I see that it's confusing.
          A 415 (Unsupported Media Type) response is appropriate
          for a request that has a voucher-request or Accept: value that is
          not understood.

    > vouchers are described in detail in [RFC8366].  For example, the
    > voucher consists of:

    > {
    > "ietf-voucher:voucher": {
    > "nonce": "62a2e7693d82fcda2624de58fb6722e5",
    > "assertion": "logging"
    > "pinned-domain-cert": "base64encodedvalue=="
    > "serial-number": "JADA123456789"
    > }
    > }

    > nit: I think "might consist of" is better than "consists of".

already fixed.

    > assertion:  The method used to verify assertion.  See Section 5.5.5.

    > The method used to verify itself?

Changed to:
        The method used to verify the relationship between pledge and registrar

    doc> The pledge MUST be prepared to parse and fail gracefully from a
    doc> voucher response that does not contain a 'pinned-domain-cert' field.

    > What would such a graceful failure look like?  Reverting back to the
    > discovery stage, since without a manufacturer-validated indication of
    > the trust anchor for the domain, the pledge cannot  consider itself to
    > be a part of a domain?

changed to:
          The pledge MUST be prepared to parse and fail gracefully from
          a voucher response that does not contain a 'pinned-domain-cert'
          field.  Such a thing indicates a failure to enroll in this domain,
          and the pledge MUST attempt joining with other available Join Proxy.
          The pledge MUST be prepared to ignore additional fields that it does not recognize.

    > Section 5.6.2

    doc> found.  It SHOULD return to the same proxy again after attempting
    doc> with other proxies.  Attempts should be attempted in the exponential

    > But only if those other proxies failed to produce a valid voucher?

yes, inserted "unsucccessful"

    doc> The pledge's PKIX path validation of a registrar certificate's
    doc> validity period information is as described in Section 2.6.1.  Once
    doc> the PKIX path validation is successful the TLS connection is no
    doc> longer provisional.

    > Section 2.6.1 doesn't actually say that the pledge has to check the five
    > listed timestamps in the case that it does have a realtime clock.

Noted, added text to 2.6.1.

    > Section 5.7

    doc> To indicate pledge status regarding the voucher, the pledge MUST post
    doc> a status message.

    > I think we've had other text that implies that providing telemetry is
    > optional; perhaps just "the pledge POSTs a status message"?

The 5.7 Pledge BRSKI Status Telemtry is mandatory.
The 5.9.4 Enrollment Status Telemtry is not, because enrollment is not mandatory.

    doc> The client HTTP POSTs the following to the server at the EST well
    doc> known URI "/voucher_status".  The Status field indicates if the

    > I think it's probably more clear to write out
    > ".well-known/est/voucher_status"; there's not a separate registry of EST
    > well-known URIs.


    > We don't actually have anything in  this section that declares "this is
    > the structure of the JSON object used as the POST body"; it's only
    > implicitly provided.

I believe that I have reworked this section as a result of other reviews already.

    doc> indicates why.  In the failure case this message may be sent to an
    doc> unauthenticated, potentially malicious registrar and therefore the
    doc> Reason string SHOULD NOT provide information beneficial to an
    doc> attacker.  The operational benefit of this telemetry information is

    > What sort of information might a pledge consider including that would be
    > beneficial to an attacker?

It's hard to say at this point.
We want things in the logs of the Registrar that will help avoid a truck
roll.  IBM (AIX and friends) was historically really good at having really
detailed, but often uninformative three digits codes, yet they told AIX
support people reams of useful info.

    > This still have some privacy considerations, though.

At this point, the attacking registrar has seen the entire IDevID
certificate.  I would think that putting the GPS coordinates of the device in
the telemetry message would be of course, make things even worse.
On the other hand, if a device has a GPS and can not be installed in some
places to due some kind of geofencing...

    > Section 5.8

    doc> is posted to the /requestauditlog URI instead.  The "idevid-issuer"
    doc> and "serial-number" informs the MASA which log is requested so the
    doc> appropriate log can be prepared for the response.  Using the same

    > Is the implicit point that the other fields are ignored?


    doc> A registrar MAY request logs at future times.  If the registrar
    doc> generates a new request then the MASA is forced to perform the
    doc> additional cryptographic operations to verify the new request.

    > Is this statement just supposed to be further justification for using
    > the original voucher-request as the POST body, or describing new
    > behavior?

Further justification.  The MASA can do a memcmp()/SELECT on a history of raw
voucher requests.  {that's what my code does}

    doc> A MASA that receives a request for a device that does not exist, or
    doc> for which the requesting owner was never an owner returns an HTTP 404
    doc> ("Not found") code.

    > What is a "requesting owner"?  I thought devices were owned by the
    > domain, not the specific registrar.

So, if Registrar A has stored a valid pledge-request (or perhaps a falsy
constructed one) for a pledge that has joined another network (B), then
registrar A can not get a history of the pledge if it was never an owner.

If the pledge was once owned by Registrar A (but sold), then there is a hole
that would permit Registrar A to ask for history.  But this is legitimate,
because perhaps it wasn't actually sold, but in fact stolen, and when
they can't get the device to respond, the operator could ask if the device
has become owned by another Registrar.

This interface will likely get future work: some kind of zero-knowledge proof
mechanism would be interesting, but we don't know what exactly are the
requirements yet.

    doc> In order to avoid enumeration of device audit logs, MASA that return
    doc> URLs SHOULD take care to make the returned URL unguessable.  For
    doc> instance, rather than returning URLs containing a database number
    doc> such as or the EUI of the device
    doc> such, the MASA SHOULD
    doc> return a randomly generated value (a "slug" in web parlance).  The
    doc> value is used to find the relevant database entry.

    > may also be a useful reference.

thanks, added.

That's all for today.

Will the Joker Get Away?  Will the document editor switch to Markdown?
Does the YIN/YANG circle converge ever? Can it be rendered in SVG?
Stay tuned for tomorrow's exciting episode.

Michael Richardson <>, Sandelman Software Works
 -= IPv6 IoT consulting =-