Re: [netconf] built-in trust anchors

Kent Watsen <> Wed, 20 January 2021 02:18 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id 1CA223A0C38 for <>; Tue, 19 Jan 2021 18:18:35 -0800 (PST)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -1.899
X-Spam-Status: No, score=-1.899 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_NONE=0.001] autolearn=ham autolearn_force=no
Authentication-Results: (amavisd-new); dkim=pass (1024-bit key)
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id NBuF4yKtWWdY for <>; Tue, 19 Jan 2021 18:18:33 -0800 (PST)
Received: from ( []) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) by (Postfix) with ESMTPS id 1D9143A0C37 for <>; Tue, 19 Jan 2021 18:18:32 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=224i4yxa5dv7c2xz3womw6peuasteono;; t=1611109111; h=Content-Type:Mime-Version:Subject:From:In-Reply-To:Date:Cc:Content-Transfer-Encoding:Message-Id:References:To:Feedback-ID; bh=YhtNYdbHQ4ap11yhp5sisi5JKlv6yMrEPM4llDIYcCg=; b=C4ZCJUm2hZVK/qs4mgqm/w6SK3wT9g/T7YfSDXbSse9ADLV9Ef5kELd3ximLzOc/ lVatU5ohJjPtrnnlgiYuUFGKEdMpp9QEHzPNtfmkEJu2ZwyifvtHg1pEtZxmYDuyqBF ITZNMVBrOGOFJRWOqJbQ74R1WiLzyF4KzpVOmKK8=
Content-Type: text/plain; charset="utf-8"
Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.\))
From: Kent Watsen <>
In-Reply-To: <>
Date: Wed, 20 Jan 2021 02:18:31 +0000
Cc: "" <>
Content-Transfer-Encoding: quoted-printable
Message-ID: <>
References: <> <> <> <>
To: Martin Björklund <>
X-Mailer: Apple Mail (2.3608.
X-SES-Outgoing: 2021.01.20-
Archived-At: <>
Subject: Re: [netconf] built-in trust anchors
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: NETCONF WG list <>
List-Unsubscribe: <>, <>
List-Archive: <>
List-Post: <>
List-Help: <>
List-Subscribe: <>, <>
X-List-Received-Date: Wed, 20 Jan 2021 02:18:35 -0000

Hi Martin,

>>>>>> Hiding all the descendent nodes except “name” for built-in keys/certs
>>>>>> doesn’t work because the pubkey/cert is needed in order to encrypt
>>>>>> data that only a device can decrypt
>>>>> I don't understand this.  The descendent nodes would not be present in
>>>>> 'running', but they would be present in <operational> (b/c they are
>>>>> present in the firmware).
>>>> I think that there is a misunderstanding somewhere.  It might be
>>>> helpful for me to clarify that, at a high-level: 1) the drafts only
>>>> present a *configuration* model, and that 2) it’s possible that some
>>>> “config” only shows up in <operational>, when the values are
>>>> “built-in”.
>>>> For the “config” that only shows in <operational>, it’s necessary to
>>>> promote them to <running> in order for leafrefs to resolve.  I agree
>>>> that only the “name” is needed, but we lack a mechanism to just
>>>> configure a name as otherwise 1) validation would fail because
>>>> "mandatory true” descendants would fail validation and 2) there’s no
>>>> way to tell “apply config” process to not-delete the missing values.
>>> It can be done by doing something similar to "hidden", here's a sketch
>>> of the idea:
>>> list certificate-bag {
>>>   key name;
>>>   leaf name { ... }
>>>   choice type {
>>>     case inline {
>>>       list certificate { ... }
>>>     }
>>>     case built-in {
>>>       leaf built-in { type empty; }
>>>     }
>>>   }
>>> }
>> Thank you for the example.  It's infinitely easier to understand what
>> folks intend when examples are provided.
>> Yes, your model enables just the “name” node to appear, but I’m
>> confused/concerned by its implications...
>> In particular, what would be in <operational> in a device as shipped
>> from Manufacturing?  It can’t be “built-in” because the certificate
>> data must be accessible.  But, assuming it’s “inline”, then we’d
>> expect “inline” in <running> too, right?  If not, then we're devising
>> yet other special case rules that are no better than those described
>> in the truststore draft.
> No I don't agree that all nodes in <running> must exactly match what's
> in <operational>.  This is not a special case.  <operational> is
> designed to reflect reality, so things may not match what's in
> <running>.


>> Worse, how to reference specific certs (not
>> the bag), as is needed in some cases (not a TLS-client), becomes even
>> more complicated.
> So then we need to adjust the data model to allow this.  Perhaps not
> use a choice like I did above, but simply a leaf that indicates that
> the bag is builtin, and then allow certs to be set in <running> as
> well.

First we should decide if operators should be allowed to add certificates to built-in bags (i.e. #2 in my message to Tom).

>>>> Looking at the keystore draft's Change Log, I see that the
>>>> “require-instance false” idea was added in -05 (June 2018) and removed
>>>> in -07 (April 2019).
>>>> As for “hidden”, the current approach arrived in crypto-types-08.
>>>> Previously, the node was a ‘union’ with "permanently-hidden” being an
>>>> enumerated value.  This idea was moved into crypto-types-01 from
>>>> keystore-06.  It was called "hardware-protected” in keystore 03-05,
>>>> and “INACCESSIBLE” in keystore 01-02.
>>>> We also explored letting the private-key value be "mandatory false”
>>>> somewhere along the line.  Without digging for dates, I’m sure the
>>>> reason we backed out of it is because, again, it didn’t make sense to
>>>> do it for a 1% use case.
>>> I much prefer Jürgen's proposal than haveing special rules for some
>>> nodes in <running>.  Especially if it falls into this "1%" bucket.
>> Do you mean that built-in values should be in <factory-default>, not
>> <operational>?
> Yes, but if they are added via <factory-defaults> or not is imo
> important.  If the device doesn't have <factory-defaults>, a client
> can simply add them to <running>.

I’m unable to parse fully what you mean.  In any case, built-in stuff being in <factory-default> is a convenience, to have it in <running> at first boot, assuming that is necessary (I don’t think it is).  The draft says built-in certs/keys are in <operational>, just like built-in interfaces (e.g., loopback) in RFC 8342.

>> 1) there would still be a need for special-case rules ensuring that
>> descendent nodes of “built-in” (read-only) keys/certs are never
>> changed. E.g., consider a built-in (TPM-protected) key having an
>> associated IDevID cert, nothing about it can vary.
> I don't think special rules are needed.

True, servers can already ignore/override <intended> to reflect reality.  

>> 2) how do vendor-updates for the built-in public CA certs get picked
>> up?  Do we suggest that operators re-merge that part of
>> <factory-default> into their <running> after each OS update?  (And
>> what if the update occurs via ZTP and somehow that new cert is needed
>> then?)
> I think this problem is present with your proposed solution as well.

Yes and No.  

The only problem is that the intention of the words in the “Support for Built-in Trust Anchors” section isn’t completely realized by the model.  This section talks about what needs to be done in order to reference “certificates”, which is still true, sans it should be that servers must ignore (not “reject") attempts to modify built-ins.  

What’s missing is what needs to be done to reference a built-in *bag* that has not had any operator-specified certs added to it (i.e., an “empty” bag, in <running> only).  Your "case built-in” above addresses that case, as well could an empty list, which is even simpler.

>> 3) looking to my response to Tom, the proposal supports #3 - is this
>> what we want?  I personally think that deleting built-in public CA
>> certs is a questionably bad idea (too many things can break).  #2 is
>> “okay” (at least nothing breaks), but some may question if it’s ever
>> needed (i.e., rather than merge a new cert into the existing bag, it
>> may be better to put it in its own bag and have the TLS-client point
>> that bag instead).  #1 is the most conservative, perhaps to a fault,
>> but in the world of security, sometimes that is what’s needed.
> If the system can handle the case that a cert that is marked as
> built-in in running doesn't exist (see thread w/ Jürgen), then #3 is
> ok.

Regarding “then #3 is ok”, regardless if #3 is possible, I don’t think we want to support it.   #1 is safe, #2 is okay, #3 is potentially dangerous and the use case is weak.

>> 4) it seems that it may be possible to use alternate cert-data for a
>> “built-in” cert.  E.g., consider a built-in public CA cert called
>> “Verisign Root CA 2009-2”, it would be possible to configure a cert
>> having that name/key but with a different base64 value, potentially
>> opening up an attack vector.  My intention for #3 was “all or
>> nothing”, that is, certs can be present or deleted in their entirety,
>> nothing in-between.
> I'm not sure I follow you, but nothing prevents the system to ignore
> unwanted data in <running> for built-in certs, and use the
> system-provided values instead.

Yes (same realization as above)

>> 5) The entire contents of the built-in public CA certs bag would have
>> to be copied into <running>, cluttering it up unnecessarily with a
>> bunch of base64 strings representing the contents of, e.g.,
>> /etc/ssl/certs/.  Maybe this is okay, but it would likely be
>> unwelcomed by many.
> I don't understand why this is needed.

Maybe I misunderstood what you or Jürgen were trying to say before.  So long as we agree that it would be a usability-fail, then I’m fine.

>> It seems that the currently documented approach (tweaked per my email
>> to Tom) is still the simplest, agreed?  Yes, there are special case
>> rules, but they’re simple (“treat built-in values as read-only”).
> They may look innocent, but this is a slippery slope.  The proposal in
> the draft goes against the NMDA architure, see section 5 of RFC 8342.
> "system configuration" goes into <operational>, NOT into <running>.

The draft is completely in line with NMDA, sans the s/reject/ignore/ bit mentioned above.  Where do you see otherwise?