<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://trustification.io/blog</id>
    <title>Trustification Blog</title>
    <updated>2025-07-04T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://trustification.io/blog"/>
    <subtitle>Trustification Blog</subtitle>
    <icon>https://trustification.io/img/logo.svg</icon>
    <entry>
        <title type="html"><![CDATA[Trustify: Release 0.3.2]]></title>
        <id>https://trustification.io/blog/2025/07/04/release-0-3-2</id>
        <link href="https://trustification.io/blog/2025/07/04/release-0-3-2"/>
        <updated>2025-07-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Today we released Trustify 0.3.2, exactly one year after 0.1.0-alpha.10.]]></summary>
        <content type="html"><![CDATA[<p>Today we released Trustify <code>0.3.2</code>, exactly one year after <a class="" href="https://trustification.io/blog/2024/07/04/release-0-1-0-alpha-10"><code>0.1.0-alpha.10</code></a>.
Read on to learn what's new and what happened in the last year.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-past-year">The past year<a href="https://trustification.io/blog/2025/07/04/release-0-3-2#the-past-year" class="hash-link" aria-label="Direct link to The past year" title="Direct link to The past year" translate="no">​</a></h2>
<p>Time flies when you're having fun! It seems we've been so focused on development that we didn't pay much attention to the blog. During this time, we had the <code>0.2.z</code> release train, which served as the foundation for Red Hat Trusted Profile Analyzer 2.0. We also started working on the <code>0.3.z</code> stream, which brings us to today's release.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="new-and-noteworthy">New and noteworthy<a href="https://trustification.io/blog/2025/07/04/release-0-3-2#new-and-noteworthy" class="hash-link" aria-label="Direct link to New and noteworthy" title="Direct link to New and noteworthy" translate="no">​</a></h2>
<p>Since we didn't cover any previous <code>0.3.z</code> releases, let's focus on the <code>0.3</code> series in general. Here's what's new:</p>
<ul>
<li class=""><strong>Enhanced Analysis Endpoint</strong> - Provides a fast way to search SBOMs and their relationships, even across multiple SBOMs</li>
<li class=""><strong>Quay Integration</strong> - Added support for importing SBOMs from Quay instances</li>
<li class=""><strong>Improved Labels Experience</strong> - Enhanced labeling functionality for better organization and filtering</li>
<li class=""><strong>UI Modernization</strong> - Updated the user interface to PatternFly 6 for a more modern and consistent experience</li>
<li class=""><strong>OpenShift Data Foundation Compatibility</strong> - Ensured full compatibility with OpenShift Data Foundation</li>
<li class=""><strong>License Reports</strong> - New reporting capabilities for license information and compliance</li>
<li class=""><strong>Performance and Stability</strong> - The usual bug fixes and performance improvements to keep everything running smoothly</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What's next?<a href="https://trustification.io/blog/2025/07/04/release-0-3-2#whats-next" class="hash-link" aria-label="Direct link to What's next?" title="Direct link to What's next?" translate="no">​</a></h2>
<p>We recommend trying out the new version! In "<a class="" href="https://trustification.io/blog/2024/06/27/trying-out-trustify">Trying out Trustify, on a local machine</a>", we introduced a quick and easy way to get started within minutes.</p>
<p>And of course:</p>
<ul>
<li class="">Check out the <a href="https://github.com/trustification/trustify/releases/tag/v0.3.2" target="_blank" rel="noopener noreferrer" class="">release 0.3.2</a> on GitHub</li>
<li class="">Reach out to <a href="https://matrix.to/#/#trustification:matrix.org" target="_blank" rel="noopener noreferrer" class="">us on Matrix</a> and let us know what you think</li>
</ul>]]></content>
        <author>
            <name>Jens Reimann</name>
            <uri>https://github.com/ctron</uri>
        </author>
        <category label="trustify" term="trustify"/>
        <category label="release" term="release"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Trustify: Release 0.1.0-alpha.10]]></title>
        <id>https://trustification.io/blog/2024/07/04/release-0-1-0-alpha-10</id>
        <link href="https://trustification.io/blog/2024/07/04/release-0-1-0-alpha-10"/>
        <updated>2024-07-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Today we released Trustify 0.1.0-alpha.10. It's another alpha release as part of our weekly release cadence.]]></summary>
        <content type="html"><![CDATA[<p>Today we released Trustify <code>0.1.0-alpha.10</code>. It's another alpha release as part of our weekly release cadence.
Read on to learn what's new.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="new-and-noteworthy">New and noteworthy<a href="https://trustification.io/blog/2024/07/04/release-0-1-0-alpha-10#new-and-noteworthy" class="hash-link" aria-label="Direct link to New and noteworthy" title="Direct link to New and noteworthy" translate="no">​</a></h2>
<ul>
<li class="">
<p>There are more labels that get applied during the upload process. It also is possible to automatically add labels
using the importer configuration.</p>
</li>
<li class="">
<p>The system will now also record the SHA384 and SHA512 digests of uploaded documents.</p>
</li>
<li class="">
<p>The package API endpoint and corresponding UI have been renamed to "PURL".</p>
<p>The reason for that is pretty simple, the discussion was not. Right now, these "packages" actually had been "PURLs",
and not much more. That led to confusion about what arguments to pass in, and what information to expect back.</p>
<p>For the future, we still want to collect information about packages, outside the context of an SBOM. However today,
that model didn't work well.</p>
</li>
<li class="">
<p>In addition to titles, also descriptions will be returned now for advisories. As many advisories don't have a title,
this allows the UI to render a title, based on those descriptions instead.</p>
</li>
<li class="">
<p>Allow setting labels during the upload of a document.</p>
</li>
<li class="">
<p>There are some incompatible changes to the database migration. While our goal is to provide migrations as good as
possible, this change was simply too big. So, as we are still in an alpha cycle, the decision was made to simply
update the schema in a breaking way.</p>
</li>
<li class="">
<p>The UI can show the relationship between package and vulnerabilities for each entity</p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What's next?<a href="https://trustification.io/blog/2024/07/04/release-0-1-0-alpha-10#whats-next" class="hash-link" aria-label="Direct link to What's next?" title="Direct link to What's next?" translate="no">​</a></h2>
<p>Of course, we would recommend you try out the new version! In "<a class="" href="https://trustification.io/blog/2024/06/27/trying-out-trustify">Trying out Trustify, on a local machine</a>", we introduced a quick and easy way to get there within minutes.</p>
<p>And of course:</p>
<ul>
<li class="">Check out the <a href="https://github.com/trustification/trustify/releases/tag/v0.1.0-alpha.10" target="_blank" rel="noopener noreferrer" class="">release 0.1.0-alpha.10</a>.</li>
<li class="">Reach out to <a href="https://matrix.to/#/#trustification:matrix.org" target="_blank" rel="noopener noreferrer" class="">us on Matrix</a>, and let us know what you think.</li>
</ul>]]></content>
        <author>
            <name>Jens Reimann</name>
            <uri>https://github.com/ctron</uri>
        </author>
        <category label="trustify" term="trustify"/>
        <category label="release" term="release"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Trying out Trustify, on a local machine]]></title>
        <id>https://trustification.io/blog/2024/06/27/trying-out-trustify</id>
        <link href="https://trustification.io/blog/2024/06/27/trying-out-trustify"/>
        <updated>2024-06-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Trustify is a project for working with software supply chain information,]]></summary>
        <content type="html"><![CDATA[<p><a href="https://github.com/trustification/trustify" target="_blank" rel="noopener noreferrer" class="">Trustify</a> is a project for working with software supply chain information,
like SBOMs and advisories. Connect a few data sources with the system, and gather some insight in what you have.</p>
<p>Although Trustify is in its pretty early stages, it might be interesting to try it out and play a bit with it, do see
where this is heading. Read on to see how you can easily do that.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-to-expect">What to expect?<a href="https://trustification.io/blog/2024/06/27/trying-out-trustify#what-to-expect" class="hash-link" aria-label="Direct link to What to expect?" title="Direct link to What to expect?" translate="no">​</a></h2>
<p>First of all, we really want to emphasize that the project is pretty young. There are a lot of areas where work is
underway. However, in the sprit of "release early, release often", we try to release a version every week. In a
form that you can simply download and run it right away.</p>
<p>That, of course, is not the ideal deployment scenario. But it should enable you to get started within minutes and
see what's in the box.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-do-you-need">What do you need?<a href="https://trustification.io/blog/2024/06/27/trying-out-trustify#what-do-you-need" class="hash-link" aria-label="Direct link to What do you need?" title="Direct link to What do you need?" translate="no">​</a></h2>
<p>A computer (doesn't work on phones, sorry), internet access (we don't ship on floppies), and the ability to run some
code on your machine (yes, corporate IT rules might be an issue).</p>
<p>Linux, macOS, Windows. AMD or ARM. Doesn't make a difference.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="everything-everywhere-all-at-once">Everything, Everywhere, All at once<a href="https://trustification.io/blog/2024/06/27/trying-out-trustify#everything-everywhere-all-at-once" class="hash-link" aria-label="Direct link to Everything, Everywhere, All at once" title="Direct link to Everything, Everywhere, All at once" translate="no">​</a></h2>
<p>Head over to the <a href="https://github.com/trustification/trustify/releases" target="_blank" rel="noopener noreferrer" class="">release page</a>, and pick a binary for your OS and
architecture with the name starting with <code>trustd-pm</code>. That's a binary which includes just everything: the application
itself, the UI, the database, and an embedded OIDC server.</p>
<p>Download that archive, extract it, and run the binary inside it. That's it!</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="now-what">Now what?<a href="https://trustification.io/blog/2024/06/27/trying-out-trustify#now-what" class="hash-link" aria-label="Direct link to Now what?" title="Direct link to Now what?" translate="no">​</a></h2>
<p>Take your favorite web browser and navigate to: <a href="http://localhost:8080/" target="_blank" rel="noopener noreferrer" class="">http://localhost:8080</a>. That will automatically
log you in with a demo user, and show you the user interface.</p>
<p>You might notice that the system looks quite empty. That is because we did not connect any datasource yet. Navigate
to the "Importer" section and enable the following pre-configured importers:</p>
<ul>
<li class=""><code>cve-from-2024</code></li>
<li class=""><code>redhat-csaf-vex-2024</code></li>
<li class=""><code>redhat-sbom</code></li>
</ul>
<p>After that, you might want to take a break. Ingesting those sources for the first time might take a bit. Future runs,
however, will be much faster, as only the diff will be processed.</p>
<p>Maybe click a bit around in the UI to get an idea. Again, don't expect too much yet. It's'a work in progress.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="so">So?<a href="https://trustification.io/blog/2024/06/27/trying-out-trustify#so" class="hash-link" aria-label="Direct link to So?" title="Direct link to So?" translate="no">​</a></h2>
<p>Being a work in progress also has its advantages. If you managed to get the system up and running in a few minutes,
you might want to reach out and check what we're up to. Or you might have some ideas yourself, or questions. Or, in
case you had not been able to start up the demo, we would kindly as to reach out to use and let us know.</p>
<p>Everything is on GitHub: <a href="https://github.com/trustification/trustify" target="_blank" rel="noopener noreferrer" class="">https://github.com/trustification/trustify</a>.
If you have some feedback or run into problems, just raise an issue. If you have some ideas, please let us know as well.
And of course, PRs are also always welcome.</p>
<p>If you're looking for a direct chat, you're also welcome to join our Matrix channel: <a href="https://matrix.to/#/#trustification:matrix.org" target="_blank" rel="noopener noreferrer" class="">#trustification<!-- -->:matrix<!-- -->.org</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What's next?<a href="https://trustification.io/blog/2024/06/27/trying-out-trustify#whats-next" class="hash-link" aria-label="Direct link to What's next?" title="Direct link to What's next?" translate="no">​</a></h2>
<p>Our goal is to push out a new pre-release every week around Thursday. So maybe come back in a bit and check out the
improvements.</p>]]></content>
        <author>
            <name>Jens Reimann</name>
            <uri>https://github.com/ctron</uri>
        </author>
        <category label="trustify" term="trustify"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The CycloneDX Maven Aggregate SBOM and why you shouldn't trust it (yet)]]></title>
        <id>https://trustification.io/blog/2023/03/20/cyclonedx-maven-aggregate-bom-why-not-to-trust</id>
        <link href="https://trustification.io/blog/2023/03/20/cyclonedx-maven-aggregate-bom-why-not-to-trust"/>
        <updated>2023-03-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Over the last few months I've spent a lot of time with the CycloneDX Maven Plugin, trying to prove it is suitable for us to use as part of securing the Software Supply Chain. I've discovered and fixed a number of issues, related to the generation of an SBOM for each project using the makeBom goal, and have now turned my focus to aggregates and the makeAggregateBom goal.]]></summary>
        <content type="html"><![CDATA[<p>Over the last few months I've spent a lot of time with the <a href="https://github.com/CycloneDX/cyclonedx-maven-plugin" target="_blank" rel="noopener noreferrer" title="The CycloneDX Maven Plugin GitHub repository" class="">CycloneDX Maven Plugin</a>, trying to prove it is suitable for us to use as part of securing the Software Supply Chain. I've discovered and fixed a number of issues, related to the generation of an SBOM for each project using the <code>makeBom</code> goal, and have now turned my focus to aggregates and the <code>makeAggregateBom</code> goal.</p>
<p>I'll start this post with a description of what I believe an aggregate SBOM should contain. This may be different to what you are looking for, if so I would like to hear about your expectations and tailor my fix to address your needs. In any case I believe the issues I am about to describe will likely impact yourselves and create enough doubt in the accuracy of the aggregate SBOM for you to decide not to trust it.</p>
<p>Generating an SBOM for an individual project is fairly straight forward, you run the <code>makeBom</code> goal and create an SBOM representing the <code>build time</code> dependency graph for your component. You can choose to filter certain artifacts and/or scopes from the SBOM, however the dependency resolution will still be impacted by all the dependencies within the project.</p>
<p>When generating SBOMs for a multi-module project you have two choices</p>
<ul>
<li class="">generate an SBOM for each individual project</li>
<li class="">generate an aggregate SBOM which represents all projects within your multi-module project</li>
</ul>
<p>My expectation is the aggregate SBOM would be an aggregate of all the individual SBOMs, in other words each component present in the individual SBOMs should be present in the aggregate SBOM and each dependency tree represented in the individual SBOMs should also be present in the aggregate SBOM.</p>
<h1>What do we get from the current aggregate SBOM?</h1>
<p>Before we describe what happens it is important to understand the CyloneDX specification requires a component to specify a <code>bom-ref</code> attribute if the component is to be referenced elsewhere in the SBOM, with the <code>bom-ref</code> being unique across the set of components. The CycloneDX maven plugin will always generate a <code>bom-ref</code> for each component, currently the same as the component purl, and will use this reference when creating the dependency hierarchy.</p>
<p>Now to the details.</p>
<p>When generating an aggregate SBOM the plugin will iterate over all the projects within the multi-module build (the reactor), generate an SBOM for each project and combining this with the previous SBOMs. It will continue until each project within the reactor has been processed, resulting in an aggregate SBOM. On the surface this appears to be the right thing to do, all components and all dependencies should be included in the SBOM and this is what we want ..... only the details are more subtle.</p>
<p>What actually happens when we combine the components and dependencies from a project is the plugin will iterate over each component, adding it to the set of known components if it has not previously encountered its <code>bom-ref</code>, and in the case of dependencies it will add all project dependencies to the set of known dependencies within the aggregate. Now I know what you are thinking! This still appears to be correct, so where is it going wrong? To understand that we need to look at the <code>Dependency</code> class.</p>
<p>The <code>Dependency</code> class defines equality only on the content of its ref attribute, so when adding dependencies to a <code>Set</code> the following are considered to be the same.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.dependency_trees/dependency_B@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.dependency_trees/dependency_C@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span></code></pre></div></div>
<p>and</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.dependency_trees/dependency_B@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.dependency_trees/dependency_C@2.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span></code></pre></div></div>
<p>What this means is the first dependency added to the set of all dependencies will be the winner, will be part of the generated SBOM, and all subsequent dependency hierarchies will be lost. But wait, shouldn't a component always have the same dependencies on other components? This is certainly the assumption made in the plugin, unfortunately it is not a valid assumption for many reasons and for this we need to look more at how maven handles dependency resolution. Scenarios where this assumption is invalid include</p>
<ul>
<li class="">the component is included in a project with a different set of dependencies</li>
<li class="">the component is included in a project which specifies dependencies in a different order</li>
<li class="">the component includes dependencies on artifacts with <code>test</code> or <code>provided</code> scope, or includes dependencies on artifacts marked as <code>optional</code></li>
<li class="">there is a dependency management section overriding the version of an artifact</li>
<li class="">there is a dependency management section excluding dependencies from an artifact</li>
</ul>
<p>There are likely more scenarios, however the above are reasonably common and sufficient to demonstrate the problem. In the next sections we will go through examples for each of the top three, ignoring version management, so we can demonstrate how easy it is to fall into this trap and explore the impact on the generated aggregate SBOM.</p>
<h1>Differing Sets of Dependencies</h1>
<p>In this scenario we will take a look at a multi-module project where an external project is consumed within the context of differing sets of dependencies. Project <code>dependency_A</code> will consume the artifact we are interested in, <code>dependency_C</code>, alongside a second dependency, <code>dependency_E</code>, which will cause a version conflict which needs to be resolved by the maven conflict resolution mechanism. Project <code>dependency_B</code> will simply consume <code>dependency_C</code> as is, without there being any conflict needing to be resolved.</p>
<p>Let us now take a look at the dependency hierarchy for both projects, as visualized through the dependency<!-- -->:tree<!-- --> plugin. For <code>dependency_A</code> we see</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example.example1:dependency_A:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.example.external:dependency_C:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  \- com.example.external:dependency_D:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|     \- (com.example.external:dependency_E:jar:1.0.0:compile - omitted for conflict with 2.0.0)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example.external:dependency_E:jar:2.0.0:compile (scope not updated to compile)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example.external:dependency_F:jar:2.0.0:compile</span><br></span></code></pre></div></div>
<p>and for <code>dependency_B</code> we see</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example.example1:dependency_B:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example.external:dependency_C:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example.external:dependency_D:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      \- com.example.external:dependency_E:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         \- com.example.external:dependency_F:jar:1.0.0:compile</span><br></span></code></pre></div></div>
<p>In the first project we see the maven dependency resolution mechanism has aligned the version of <code>dependency_E</code> referenced in the tree to version <code>2.0.0</code>, this was chosen because this dependency is closer to the root of the tree.</p>
<p>Let's now take a look at what we see in the aggregate SBOM.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.example1/dependency_A@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_C@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_E@2.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_C@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_D@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_D@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_E@2.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_E@2.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_F@2.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_F@2.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.example1/dependency_B@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_C@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_E@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_F@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_F@1.0.0?type=jar"/&gt;</span><br></span></code></pre></div></div>
<p>From the above we see there is a flow matching <code>A1-&gt;C1-&gt;D1-&gt;E2-&gt;F2</code> and <code>A1-&gt;E2-&gt;F2</code>, so the aggregated SBOM correctly represents the dependency hierarchy for <code>dependency_A</code>.</p>
<p>If we now look at how the dependency tree for <code>dependency_B</code> is represented we see a problem. The representation for <code>dependency_B</code> is a flow from <code>B1-&gt;C1-&gt;D1-&gt;E2-F2</code> which does not match the dependency hierarchy for <code>dependency_B</code>; it should be <code>B1-&gt;C1-&gt;D1-&gt;E1-&gt;F1</code>! Where has the flow <code>E1-&gt;F1</code> gone? Unfortunately this flow is now orphaned with <code>E1</code> being its own root in the SBOM!</p>
<h1>Differing Order of Dependencies</h1>
<p>In this scenario we will take a look at a multi-module project where we have two projects consuming the same sets of dependencies, but specifying those dependencies in opposite order within their respective <code>pom.xml</code> files. The first will declare a dependency on <code>dependency_C</code> followed by <code>deependency_D</code> whereas the second will declare a dependency on <code>dependency_D</code> followed by <code>dependency_C</code>. Both <code>dependency_C</code> and <code>dependency_D</code> will consume <code>dependency_E</code> but with different versions, causing a conflict which needs to be resolved.</p>
<p>Let us now take a look at the dependency hierarchy for both projects, as visualized through the dependency<!-- -->:tree<!-- --> plugin. For <code>dependency_A</code> we see</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example.example2:dependency_A:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.example.external:dependency_C:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  \- com.example.external:dependency_E:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|     \- com.example.external:dependency_F:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example.external:dependency_D:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- (com.example.external:dependency_E:jar:2.0.0:compile - omitted for conflict with 1.0.0)</span><br></span></code></pre></div></div>
<p>and for <code>dependency_B</code> we see</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example.example2:dependency_B:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.example.external:dependency_D:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  \- com.example.external:dependency_E:jar:2.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|     \- com.example.external:dependency_F:jar:2.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example.external:dependency_C:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- (com.example.external:dependency_E:jar:1.0.0:compile - omitted for conflict with 2.0.0)</span><br></span></code></pre></div></div>
<p>In the first project we see the maven dependency resolution mechanism has aligned <code>dependency_E</code> with version <code>1.0.0</code> while in the second project the resolution mechanism has aligned <code>dependency_E</code> with version <code>2.0.0</code>. Since both versions of <code>dependency_E</code> appear at the same depth it is the one which is first included in the dependency tree which will win.</p>
<p>Let's now take a look at what we see in the aggregate SBOM.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.example2/dependency_A@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_C@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_D@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_C@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_E@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_E@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_F@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_F@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_D@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_E@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.example2/dependency_B@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_D@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_C@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_E@2.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_F@2.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_F@2.0.0?type=jar"/&gt;</span><br></span></code></pre></div></div>
<p>From the above we see there is a flow matching <code>A1-&gt;C1-&gt;E1-&gt;F1</code> and <code>A1-&gt;D1-&gt;E1-&gt;F1</code>, so the aggregated SBOM correctly represents the dependency hierarchy for <code>dependency_A</code>.</p>
<p>If we now look at how the dependency tree for <code>dependency_B</code> is represented we can again see a problem. The representation for <code>dependency_B</code> has flows from <code>B1-&gt;D1-&gt;E1-F1</code> and <code>B1-&gt;C1-&gt;E1-&gt;F1</code> which do not match the dependency hierarchy for <code>dependency_B</code> since it does not include <code>E1-&gt;F1</code> in its hierarchy! Where has the flow <code>E2-&gt;F2</code> gone? Unfortunately this flow is now orphaned with <code>E2</code> being its own root in the SBOM!</p>
<h1>Non Transitive Dependencies</h1>
<p>In this scenario we will take a look at how non-Transitive dependencies can impact the normal resolution process, and therefore the derived dependency trees. The non-Transitive dependencies could be those dependencies with scopes of either <code>provided</code> or <code>test</code>, or could be dependencies which are marked as being <code>optional</code>.</p>
<p>Project <code>dependency_A</code> will declare a dependency on <code>dependency_C</code> alongside an optional dependency on <code>dependency_E</code>, which causes a conflict which needs to be resolved. Project <code>dependency_B</code> will have a single dependency on <code>dependency_A</code>, consuming it as is.</p>
<p>Let us now take a look at the dependency hierarchy for both projects, as visualized through the dependency<!-- -->:tree<!-- --> plugin. For <code>dependency_A</code> we see</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example.example3:dependency_A:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.example.external:dependency_C:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  \- com.example.external:dependency_D:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|     \- (com.example.external:dependency_E:jar:1.0.0:compile - omitted for conflict with 2.0.0)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example.external:dependency_E:jar:2.0.0:compile (scope not updated to compile)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example.external:dependency_F:jar:2.0.0:compile</span><br></span></code></pre></div></div>
<p>and for <code>dependency_B</code> we see</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example.example3:dependency_B:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example.example3:dependency_A:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example.external:dependency_C:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      \- com.example.external:dependency_D:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         \- com.example.external:dependency_E:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            \- com.example.external:dependency_F:jar:1.0.0:compile</span><br></span></code></pre></div></div>
<p>In the first project we see the maven dependency resolution mechanism has aligned <code>dependency_E</code> with version <code>2.0.0</code> through the transitive dependency inherited via the <code>optional</code> dependency. In the second project the maven dependency resolution mechanism has ignored the optional dependency leaving the original dependency on <code>dependency_E:1.0.0</code>.</p>
<hr>
<p><strong>Note:</strong> While this example is making use of an optional dependency, the same tree would be generated if this dependency was of scope <code>test</code> or <code>provided</code>.</p>
<hr>
<p>Let's now take a look at what we see in the aggregate SBOM.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.example3/dependency_A@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_C@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_E@2.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_C@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_D@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_D@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_E@2.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_E@2.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_F@2.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_F@2.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.example3/dependency_B@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.example3/dependency_A@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_E@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example.external/dependency_F@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.example.external/dependency_F@1.0.0?type=jar"/&gt;</span><br></span></code></pre></div></div>
<p>From the above we see there is a flow matching <code>A1-&gt;C1-&gt;D1-&gt;E2-&gt;F2</code> and <code>A1-&gt;E2-&gt;F2</code>, so the aggregated SBOM correctly represents the dependency hierarchy for <code>dependency_A</code>.</p>
<p>If we now look at how the dependency tree for <code>dependency_B</code> is represented we see a problem. The representation for <code>dependency_B</code> includes flows from <code>B1-&gt;A1-&gt;C1-&gt;D1-&gt;E2-&gt;F2</code> and <code>B1-&gt;A1-&gt;E2-&gt;F2</code>, neither of which match the dependency hierarchy for B; the hierarchy for <code>dependency_B</code> should be a flow of <code>B1-&gt;A1-&gt;C1-&gt;D1-&gt;E1-&gt;F1</code>! Not only has the flow <code>E1-&gt;F1</code> been orphaned from the <code>dependency_B</code> dependency tree, and now its own root, but the SBOM claims <code>dependency_B</code> has multiple dependency flows when it should only be a single flow.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summarising-the-issue">Summarising the issue<a href="https://trustification.io/blog/2023/03/20/cyclonedx-maven-aggregate-bom-why-not-to-trust#summarising-the-issue" class="hash-link" aria-label="Direct link to Summarising the issue" title="Direct link to Summarising the issue" translate="no">​</a></h2>
<p>We see from the above scenarios it is reasonably easy to end up with a multi-module project which results in an invalid expression of the project dependency trees within the aggregated SBOM, and we have still to look at exclusions and version management through the maven <code>dependencyManagement</code> declarations. To make matters worse we have no easy way of identifying whether the aggregated SBOM contains an invalid dependency graph. While it is possible the aggregated SBOM could contain orphaned dependency trees it is also possible those dependency trees would be consumed by other components within the SBOM.</p>
<p>Given the aggregate SBOM is no longer reliable the only safe approach is to rely on the individual SBOMs for each project, at least for now.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-can-we-solve-this">How can we solve this?<a href="https://trustification.io/blog/2023/03/20/cyclonedx-maven-aggregate-bom-why-not-to-trust#how-can-we-solve-this" class="hash-link" aria-label="Direct link to How can we solve this?" title="Direct link to How can we solve this?" translate="no">​</a></h2>
<p>There is a solution for this, however the solution comes with implications which <em>may</em> break some tools which work with SBOMs. These tools will already be making invalid assumptions, and we will have to work with their authors to identify and fix any occurrences we find.</p>
<p>What is really lacking in the CycloneDX specification is a way in which we can easily describe alternative dependency hierarchies for a component, since as we have shown this is something which happens within the java space and likely other areas.</p>
<p>The CyloneDX specification defines the component dependency hierarchies by referring to the <code>components</code> themselves, through their references, however this reference also defines the unique hierarchy within the <code>dependencies</code> section. For example</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.owasp.webgoat.lesson/auth-bypass@v8.0.0.M15?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.owasp.encoder/encoder@1.2?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.thoughtworks.xstream/xstream@1.4.7?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.apache.commons/commons-exec@1.3?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span></code></pre></div></div>
<p>The <code>ref</code> attribute <code>pkg:maven/org.owasp.webgoat.lesson/auth-bypass@v8.0.0.M15?type=jar</code> represents not only the specific component, tied through the component <code>bom-ref</code> attribute, but also a unique dependency hierarchy within the <code>dependencies</code> section. Given this how can we also represent the following hierarchy within the same aggregate SBOM?</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.owasp.webgoat.lesson/auth-bypass@v8.0.0.M15?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.owasp.webgoat/webgoat-container@v8.0.0.M15?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.owasp.encoder/encoder@1.2?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.thoughtworks.xstream/xstream@1.4.7?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.projectlombok/lombok@1.16.20?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.apache.commons/commons-exec@1.3?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span></code></pre></div></div>
<p>In order to achieve this we need to have some way of enriching the <code>ref</code> attribute value so it represents not only the specific component but also the direct dependencies in its particular location within the dependency graph, for example including a hash which would be derived from each set of dependencies. This hash would need to be calculated from the leaves back to the root, with every deviation in the dependency tree propagating its way up to the root.</p>
<p>We could then have a representation similar to the following</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ref="pkg:maven/org.owasp.webgoat.lesson/auth-bypass@v8.0.0.M15?hash=&lt;hash1&gt;&amp;amp;type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.owasp.encoder/encoder@1.2?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.thoughtworks.xstream/xstream@1.4.7?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.apache.commons/commons-exec@1.3?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ref="pkg:maven/org.owasp.webgoat.lesson/auth-bypass@v8.0.0.M15?hash=&lt;hash2&gt;&amp;amp;type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.owasp.webgoat/webgoat-container@v8.0.0.M15?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.owasp.encoder/encoder@1.2?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.thoughtworks.xstream/xstream@1.4.7?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.projectlombok/lombok@1.16.20?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.apache.commons/commons-exec@1.3?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span></code></pre></div></div>
<hr>
<p><strong>Note:</strong> The child dependencies in the example above should also have a hash, however these have been omitted for brevity.</p>
<hr>
<p>The above would allow us to represent different hierarchies, but now we have another problem. Each reference used in the <code>dependencies</code> section <em>must</em> refer to an existing <code>component</code> within the <code>components</code> section and, therefore, we now need the <code>component</code> to be defined for each reference in use, e.g.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;component type="library"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    bom-ref="pkg:maven/org.owasp.webgoat.lesson/auth-bypass@v8.0.0.M15?hash=&lt;hash1&gt;&amp;amp;type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;publisher&gt;OWASP&lt;/publisher&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;group&gt;org.owasp.webgoat.lesson&lt;/group&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;name&gt;auth-bypass&lt;/name&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;version&gt;v8.0.0.M15&lt;/version&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;description&gt;Parent Pom for the WebGoat Project. A deliberately insecure Web Application&lt;/description&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;purl&gt;pkg:maven/org.owasp.webgoat.lesson/auth-bypass@v8.0.0.M15?type=jar&lt;/purl&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/component&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;component type="library"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    bom-ref="pkg:maven/org.owasp.webgoat.lesson/auth-bypass@v8.0.0.M15?hash=&lt;hash2&gt;&amp;amp;type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;publisher&gt;OWASP&lt;/publisher&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;group&gt;org.owasp.webgoat.lesson&lt;/group&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;name&gt;auth-bypass&lt;/name&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;version&gt;v8.0.0.M15&lt;/version&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;description&gt;Parent Pom for the WebGoat Project. A deliberately insecure Web Application&lt;/description&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;purl&gt;pkg:maven/org.owasp.webgoat.lesson/auth-bypass@v8.0.0.M15?type=jar&lt;/purl&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/component&gt;</span><br></span></code></pre></div></div>
<p>It is this change which, while not invalid according to the specification schema, will likely cause problems for tools which have made the assumption the component can only exist once.</p>
<h1>Conclusions</h1>
<p>There is a <a href="https://github.com/CycloneDX/cyclonedx-maven-plugin/pull/306" target="_blank" rel="noopener noreferrer" class="">CycloneDX maven plugin PR</a> open to modify the plugin's behaviour and generate an aggregate SBOM using the above hashing scheme, representing all the dependency hierarchies within a multi-module project. There is also an associated <a href="https://github.com/CycloneDX/cyclonedx-maven-plugin/issues/310" target="_blank" rel="noopener noreferrer" class="">CycloneDX maven plugin issue</a> where the reasons for this change are still being discussed, as well as a number of discussions on how the specification can evolve to address this issue in a cleaner way.</p>
<p>I am hopeful we can come up with a suitable resolution to these discussions and deliver a solution to the issue, however until this is achieved the <code>dependencies</code> section of the aggregate SBOMs generated by the CycloneDX maven plugin is unreliable and should not be trusted. The only reliable source of dependency hierarchy information is to be found within the individual SBOMs of each project.</p>]]></content>
        <author>
            <name>Kevin Conner</name>
            <uri>https://github.com/knrc</uri>
        </author>
        <category label="cyclonedx" term="cyclonedx"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[in-toto attestations]]></title>
        <id>https://trustification.io/blog/2023/03/13/in-toto-attestations</id>
        <link href="https://trustification.io/blog/2023/03/13/in-toto-attestations"/>
        <updated>2023-03-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[When we sign an artifact, like a blob, the signature proves that we were in]]></summary>
        <content type="html"><![CDATA[<p>When we sign an artifact, like a blob, the signature proves that we were in
possesion of the private key. When we verify, we use the signature, the public
key, and the blob, and we are verifying that this was in fact the case. But it
does not say anything else about the artifact, we don't know <code>what</code> was actually
signed.</p>
<p>By providing, and signing a document specifying <code>statements</code> about the artifact
we can say things about the artifact as well. Statements could be anything which
we will address later in this document. A signed Statement is called an
Attestation.</p>
<p>An attestation is authenticated metadata about software artifacts and follows
the <a href="https://slsa.dev/attestation-model" target="_blank" rel="noopener noreferrer" class="">Software-chain Levels for Software Artifacts attestation model</a>.</p>
<p>An attestation can be json object, and the outer-most element is the <code>Envelope</code>:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"payloadType"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"application/vnd.in-toto+json"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"payload"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&lt;Base64(Statement)&gt;"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"signatures"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"sig"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&lt;Base64(Signature)&gt;"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>Notice that the <code>payload</code> is a base64 encoded <code>Statement</code>. This format follows
the <a href="https://github.com/secure-systems-lab/dsse" target="_blank" rel="noopener noreferrer" class="">DSSE</a> format.</p>
<p>The <code>payloadType</code> could be JSON, CBOR, or ProtoBuf.</p>
<p>The structure of the <code>Statement</code>, in payload element above, looks something
like this (before it is base64 encoded):</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"_type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"https://in-toto.io/Statement/v0.1"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"subject"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&lt;NAME&gt;"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"digest"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"&lt;ALGORITHM&gt;"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&lt;HEX_VALUE&gt;"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"predicateType"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&lt;URI&gt;"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"predicate"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>The subjects bind this attestation to a set of software artifacts, notice that
this is an array of objects.</p>
<p>Each software artifact is given a name and a digest. The digest contains the
name of the hashing algorithm used, and the digest (the outcome of the hash
function).
The name could be a file name but it can also be left unspecified using <code>_</code>.</p>
<p>This leads us to the <code>predicate</code> fields, which like shown above has one field
for the type of the predicate (predicateType), and an object as the content of
the predicate.</p>
<p>The predicate can contain pretty much any metadata related to the Statement
object's subjects. The <code>predicateType</code> provides a way of knowing how to
interpret the <code>predicate</code> field.</p>
<p>Examples of predicate types are
<a href="https://slsa.dev/provenance/v0.1#example" target="_blank" rel="noopener noreferrer" class="">SLSA Provenance</a>,
<a href="https://github.com/in-toto/attestation/blob/main/spec/predicates/link.md" target="_blank" rel="noopener noreferrer" class="">in-toto Link</a>
, <a href="https://github.com/in-toto/attestation/blob/main/spec/predicates/spdx.md" target="_blank" rel="noopener noreferrer" class="">SPDX</a>
, <a href="https://github.com/in-toto/attestation/blob/main/spec/predicates/scai.md" target="_blank" rel="noopener noreferrer" class="">Software Supply Chain Attribute Integrity (SCAI)</a>.</p>
<p>NPM also uses this for it to publish <a href="https://github.com/npm/rfcs/blob/main/accepted/0049-link-packages-to-source-and-build.md#slsa-provenance-schema" target="_blank" rel="noopener noreferrer" class="">attestations</a>:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"_type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"https://in-toto.io/Statement/v0.1"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"subject"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"pkg:npm/@scope/package-foo@1.4.3"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"digest"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token property" style="color:#36acaa">"sha512"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"41o0P/CEffYGDqvo2pHQXRBOfFOxvYY3WkwkQTy..."</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"predicateType"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"https://github.com/npm/attestation/tree/main/specs/publish/v0.1"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"predicate"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@scope/package-foo"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"1.4.3"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"registry"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"https://registry.npmjs.org"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>The <code>digest</code> in this case is the sha512sum of the published tar file.</p>
<p>So, we mentioned that the predicate type is used by the consumer of the
predicate so it knows how to interpret the contents of the predicate. But who
is the consumer?<br>
<!-- -->Most often this would be a Policy Engine. The Policy engine would be passed
the contents of the Statement related to the predicate, and rules written in
the Policy Engine's language would process the predicate as input. The outcome
would be a true/false result (remember that a predicate is a statement/function
that returns true or false).</p>
<p>To try to make this a little more concrete lets take a look at an example
that creates an attestation.</p>
<p>For this example I'm going to use a GitHub Action named
<a href="https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/generic/README.md" target="_blank" rel="noopener noreferrer" class="">slsa-github-generator</a> which can generate SLSA provenance attestations for
github native projects. This generator can generate SLSA provenance for SLSA
level 3.</p>
<p>The example project I'm going to use is <a href="https://github.com/danbev/tuf-keyid" target="_blank" rel="noopener noreferrer" class="">tuf-keyid</a>
but the actual project is not important in this case, any Rust project could
have been used.</p>
<p>So we need to set up a GitHub Action which can been seen in
<a href="https://github.com/danbev/tuf-keyid/blob/main/.github/workflows/provenance.yaml" target="_blank" rel="noopener noreferrer" class="">provenance.yaml</a>.</p>
<p>After that workflow has run it will produce an attestation and a binary which
we will use to verify.</p>
<p>First, we need to download the binary from the <a href="https://github.com/danbev/tuf-keyid/actions/runs/4015220869" target="_blank" rel="noopener noreferrer" class="">workflow run</a> (we should really
be able to be download this from the releases page too, but I've not been able
to get that to work just yet):</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ unzip tuf-keyid.zip</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ file tuf-keyid</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">tuf-keyid: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=ceaa62d49b024798ebd7fe7d021f3ade5925b1f9, for GNU/Linux 3.2.0, with debug_info, not stripped</span><br></span></code></pre></div></div>
<p>And then we need to download the attestation file:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ curl -L https://github.com/danbev/tuf-keyid/releases/download/v0.2.0/tuf-keyid.intoto.jsonl --output tuf-keyid.intoto.jsonl</span><br></span></code></pre></div></div>
<p>Lets inspect the attestation file:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat tuf-keyid.intoto.jsonl | jq</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "payloadType": "application/vnd.in-toto+json",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "payload": "...",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "signatures": [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "keyid": "",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "sig": "MEUCIHwmJopmrXWqi+rKIeTlWW0r027hLL1nO7xEj0mW8czsAiEAhdc6SDlhWo3m0YOtsUSoIYSlvw3Xu7ts3S8btHzdMpw=",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "cert": "-----BEGIN CERTIFICATE-----\nMIIDtjCCAzygAwIBAgIUCeak2sfkfZbS0IMRSbK4+BHcUzAwCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjMwMTI2MTAxMzQxWhcNMjMwMTI2MTAyMzQxWjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAEZMurC3H80wzo+Xn7uifeTDV/AAFnye8uFwEj\n5VmxJb30VzuEw8gD8/Dj4V79bIW9sePcZjvREhFWak+PhUZVMqOCAlswggJXMA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUncOT\nSyRyKgylBYlUHwPF+EyemfkwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wgYQGA1UdEQEB/wR6MHiGdmh0dHBzOi8vZ2l0aHViLmNvbS9zbHNhLWZyYW1l\nd29yay9zbHNhLWdpdGh1Yi1nZW5lcmF0b3IvLmdpdGh1Yi93b3JrZmxvd3MvZ2Vu\nZXJhdG9yX2dlbmVyaWNfc2xzYTMueW1sQHJlZnMvdGFncy92MS40LjAwOQYKKwYB\nBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50\nLmNvbTASBgorBgEEAYO/MAECBARwdXNoMDYGCisGAQQBg78wAQMEKDUxM2IwZTA2\nMGM3NmExZGVkN2IxYTQxNzMxNjUxMDM4MzhmOGRkZTcwFQYKKwYBBAGDvzABBAQH\nUHVibGlzaDAeBgorBgEEAYO/MAEFBBBkYW5iZXYvdHVmLWtleWlkMB4GCisGAQQB\ng78wAQYEEHJlZnMvdGFncy92MC4yLjAwgYoGCisGAQQB1nkCBAIEfAR6AHgAdgDd\nPTBqxscRMmMZHhyZZzcCokpeuN48rf+HinKALynujgAAAYXtkZ+vAAAEAwBHMEUC\nIQDgO+S94sXq3wcfg344IV8FRhynvsJsVFEfHmwOHGqAVgIgArfX+7pnaLrplJ0u\nXB6tlWaCxQJ7GAo9YByqXCa0b2gwCgYIKoZIzj0EAwMDaAAwZQIxAOYkXbpLbSqC\njdORW6lWGWB/Ts2aOhK7VAHaQCRgRHQGiZx4Pe/LCwqkQF/1W2BAEQIwLB9Ic2jt\nIiEjtw8xKFDQAfnUleNUtZ51LXgXEkdpIX9cnj4UdR6k4gu/wul16Bd8\n-----END CERTIFICATE-----\n"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>If we look back at the beginning of this document we will see that this format
matches the <code>Envelope</code> of the attestation, and we have the <code>payloadType</code>,
a <code>payload</code>, and <code>signatures</code>.</p>
<p>The certificate can be inspected using:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat tuf-keyid.intoto.jsonl | jq -r '.signatures[].cert' | openssl x509 --text</span><br></span></code></pre></div></div>
<p>Recall that the payload is a base64 encoded <code>Statement</code>. Let's decode the
<code>Statement</code> and take a closer a look at it:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat tuf-keyid.intoto.jsonl | jq -r '.payload' | base64 -d | jq</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "_type": "https://in-toto.io/Statement/v0.1",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "predicateType": "https://slsa.dev/provenance/v0.2",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "subject": [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "name": "tuf-keyid",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "digest": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "sha256": "470c549740f98fe1b1977d48e014031ed5183785fd459df7e04605daefe8e293"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "predicate": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "builder": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "id": "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.4.0"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "buildType": "https://github.com/slsa-framework/slsa-github-generator/generic@v1",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "invocation": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "configSource": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "uri": "git+https://github.com/danbev/tuf-keyid@refs/tags/v0.2.0",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "digest": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "sha1": "513b0e060c76a1ded7b1a4173165103838f8dde7"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "entryPoint": ".github/workflows/provenance.yaml"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "parameters": {},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "environment": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "github_actor": "danbev",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "github_actor_id": "432351",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "github_base_ref": "",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "github_event_name": "push",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "github_event_payload": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "after": "13c69c54cbd04d1920cc5e42441f0a693a371494",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "base_ref": null,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "before": "0000000000000000000000000000000000000000",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "commits": [],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "compare": "https://github.com/danbev/tuf-keyid/compare/v0.2.0",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "created": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "deleted": false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "forced": false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "head_commit": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "author": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "email": "daniel.bevenius@gmail.com",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "name": "Daniel Bevenius",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "username": "danbev"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "committer": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "email": "daniel.bevenius@gmail.com",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "name": "Daniel Bevenius",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "username": "danbev"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "distinct": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "id": "513b0e060c76a1ded7b1a4173165103838f8dde7",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "message": "Add content(releases) write permission\n\nSigned-off-by: Daniel Bevenius &lt;daniel.bevenius@gmail.com&gt;",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "timestamp": "2023-01-26T11:09:02+01:00",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "tree_id": "5030177fa47fc8b8252c26e8556083b4abc5df71",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "url": "https://github.com/danbev/tuf-keyid/commit/513b0e060c76a1ded7b1a4173165103838f8dde7"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "pusher": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "email": "daniel.bevenius@gmail.com",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "name": "danbev"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "ref": "refs/tags/v0.2.0",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "repository": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "allow_forking": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "archive_url": "https://api.github.com/repos/danbev/tuf-keyid/{archive_format}{/ref}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "archived": false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "assignees_url": "https://api.github.com/repos/danbev/tuf-keyid/assignees{/user}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "blobs_url": "https://api.github.com/repos/danbev/tuf-keyid/git/blobs{/sha}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "branches_url": "https://api.github.com/repos/danbev/tuf-keyid/branches{/branch}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "clone_url": "https://github.com/danbev/tuf-keyid.git",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "collaborators_url": "https://api.github.com/repos/danbev/tuf-keyid/collaborators{/collaborator}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "comments_url": "https://api.github.com/repos/danbev/tuf-keyid/comments{/number}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "commits_url": "https://api.github.com/repos/danbev/tuf-keyid/commits{/sha}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "compare_url": "https://api.github.com/repos/danbev/tuf-keyid/compare/{base}...{head}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "contents_url": "https://api.github.com/repos/danbev/tuf-keyid/contents/{+path}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "contributors_url": "https://api.github.com/repos/danbev/tuf-keyid/contributors",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "created_at": 1674117641,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "default_branch": "main",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "deployments_url": "https://api.github.com/repos/danbev/tuf-keyid/deployments",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "description": "A command line tool to print the key id for a TUF public key in JSON format.",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "disabled": false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "downloads_url": "https://api.github.com/repos/danbev/tuf-keyid/downloads",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "events_url": "https://api.github.com/repos/danbev/tuf-keyid/events",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "fork": false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "forks": 0,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "forks_count": 0,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "forks_url": "https://api.github.com/repos/danbev/tuf-keyid/forks",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "full_name": "danbev/tuf-keyid",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "git_commits_url": "https://api.github.com/repos/danbev/tuf-keyid/git/commits{/sha}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "git_refs_url": "https://api.github.com/repos/danbev/tuf-keyid/git/refs{/sha}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "git_tags_url": "https://api.github.com/repos/danbev/tuf-keyid/git/tags{/sha}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "git_url": "git://github.com/danbev/tuf-keyid.git",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "has_discussions": false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "has_downloads": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "has_issues": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "has_pages": false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "has_projects": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "has_wiki": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "homepage": null,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "hooks_url": "https://api.github.com/repos/danbev/tuf-keyid/hooks",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "html_url": "https://github.com/danbev/tuf-keyid",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "id": 590801502,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "is_template": false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "issue_comment_url": "https://api.github.com/repos/danbev/tuf-keyid/issues/comments{/number}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "issue_events_url": "https://api.github.com/repos/danbev/tuf-keyid/issues/events{/number}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "issues_url": "https://api.github.com/repos/danbev/tuf-keyid/issues{/number}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "keys_url": "https://api.github.com/repos/danbev/tuf-keyid/keys{/key_id}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "labels_url": "https://api.github.com/repos/danbev/tuf-keyid/labels{/name}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "language": "Rust",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "languages_url": "https://api.github.com/repos/danbev/tuf-keyid/languages",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "license": null,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "master_branch": "main",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "merges_url": "https://api.github.com/repos/danbev/tuf-keyid/merges",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "milestones_url": "https://api.github.com/repos/danbev/tuf-keyid/milestones{/number}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "mirror_url": null,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "name": "tuf-keyid",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "node_id": "R_kgDOIzbqXg",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "notifications_url": "https://api.github.com/repos/danbev/tuf-keyid/notifications{?since,all,participating}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "open_issues": 0,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "open_issues_count": 0,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "owner": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "avatar_url": "https://avatars.githubusercontent.com/u/432351?v=4",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "email": "daniel.bevenius@gmail.com",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "events_url": "https://api.github.com/users/danbev/events{/privacy}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "followers_url": "https://api.github.com/users/danbev/followers",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "following_url": "https://api.github.com/users/danbev/following{/other_user}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "gists_url": "https://api.github.com/users/danbev/gists{/gist_id}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "gravatar_id": "",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "html_url": "https://github.com/danbev",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "id": 432351,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "login": "danbev",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "name": "danbev",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "node_id": "MDQ6VXNlcjQzMjM1MQ==",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "organizations_url": "https://api.github.com/users/danbev/orgs",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "received_events_url": "https://api.github.com/users/danbev/received_events",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "repos_url": "https://api.github.com/users/danbev/repos",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "site_admin": false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "starred_url": "https://api.github.com/users/danbev/starred{/owner}{/repo}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "subscriptions_url": "https://api.github.com/users/danbev/subscriptions",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "type": "User",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "url": "https://api.github.com/users/danbev"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "private": false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "pulls_url": "https://api.github.com/repos/danbev/tuf-keyid/pulls{/number}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "pushed_at": 1674727856,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "releases_url": "https://api.github.com/repos/danbev/tuf-keyid/releases{/id}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "size": 21,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "ssh_url": "git@github.com:danbev/tuf-keyid.git",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "stargazers": 1,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "stargazers_count": 1,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "stargazers_url": "https://api.github.com/repos/danbev/tuf-keyid/stargazers",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "statuses_url": "https://api.github.com/repos/danbev/tuf-keyid/statuses/{sha}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "subscribers_url": "https://api.github.com/repos/danbev/tuf-keyid/subscribers",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "subscription_url": "https://api.github.com/repos/danbev/tuf-keyid/subscription",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "svn_url": "https://github.com/danbev/tuf-keyid",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "tags_url": "https://api.github.com/repos/danbev/tuf-keyid/tags",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "teams_url": "https://api.github.com/repos/danbev/tuf-keyid/teams",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "topics": [],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "trees_url": "https://api.github.com/repos/danbev/tuf-keyid/git/trees{/sha}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "updated_at": "2023-01-19T10:26:19Z",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "url": "https://github.com/danbev/tuf-keyid",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "visibility": "public",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "watchers": 1,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "watchers_count": 1,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "web_commit_signoff_required": false</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "sender": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "avatar_url": "https://avatars.githubusercontent.com/u/432351?v=4",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "events_url": "https://api.github.com/users/danbev/events{/privacy}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "followers_url": "https://api.github.com/users/danbev/followers",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "following_url": "https://api.github.com/users/danbev/following{/other_user}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "gists_url": "https://api.github.com/users/danbev/gists{/gist_id}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "gravatar_id": "",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "html_url": "https://github.com/danbev",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "id": 432351,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "login": "danbev",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "node_id": "MDQ6VXNlcjQzMjM1MQ==",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "organizations_url": "https://api.github.com/users/danbev/orgs",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "received_events_url": "https://api.github.com/users/danbev/received_events",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "repos_url": "https://api.github.com/users/danbev/repos",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "site_admin": false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "starred_url": "https://api.github.com/users/danbev/starred{/owner}{/repo}",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "subscriptions_url": "https://api.github.com/users/danbev/subscriptions",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "type": "User",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "url": "https://api.github.com/users/danbev"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "github_head_ref": "",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "github_ref": "refs/tags/v0.2.0",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "github_ref_type": "tag",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "github_repository_id": "590801502",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "github_repository_owner": "danbev",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "github_repository_owner_id": "432351",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "github_run_attempt": "1",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "github_run_id": "4014167952",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "github_run_number": "13",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "github_sha1": "513b0e060c76a1ded7b1a4173165103838f8dde7"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "metadata": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "buildInvocationID": "4014167952-1",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "completeness": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "parameters": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "environment": false,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "materials": false</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "reproducible": false</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "materials": [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "uri": "git+https://github.com/danbev/tuf-keyid@refs/tags/v0.2.0",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "digest": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "sha1": "513b0e060c76a1ded7b1a4173165103838f8dde7"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>So that gives us a concrete example of an attestation and in this case it is
a <a href="https://slsa.dev/provenance/v0.1" target="_blank" rel="noopener noreferrer" class="">SLSA Provenance</a>.</p>
<p>Notice that the <code>digest</code> in the subject array is the sha256sum of the tuf-keyid
binary:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat tuf-keyid.intoto.jsonl | jq -r '.payload' | base64 -d | jq -r '.subject[].digest.sha256'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">470c549740f98fe1b1977d48e014031ed5183785fd459df7e04605daefe8e293</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ sha256sum tuf-keyid</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">470c549740f98fe1b1977d48e014031ed5183785fd459df7e04605daefe8e293  tuf-keyid</span><br></span></code></pre></div></div>
<p>Alright, so next step if to verify the binary that we produced, using the
attestation.</p>
<p>There is project named <a href="https://github.com/slsa-framework/slsa-verifier#example" target="_blank" rel="noopener noreferrer" class="">slsa-verifier</a> which can be used to verify the artifact.
Installing <code>slsa-verifier</code>:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@v2.0.1</span><br></span></code></pre></div></div>
<p>Let's try verifying the attestation using <code>slsa-verifier</code> and using a local
build of the binary, that is, a local build on my laptop:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ slsa-verifier verify-artifact --provenance-path tuf-keyid.intoto.jsonl \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --source-uri github.com/danbev/tuf-keyid \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   ~/work/rust/tuf-keyid/target/release/tuf-keyid</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Verified signature against tlog entry index 11978552 at URL: https://rekor.sigstore.dev/api/v1/log/entries/24296fb24b8ad77a217b8f07bccab3dc8caa1c7badf65f104a762647e5e355db23ccc13a22e275dd</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">FAILED: SLSA verification failed: expected hash '32dcff46ec4be5462a66aeb5d82366da3b870d36796f3d1fe6fec6245f21ce6f' not found: artifact hash does not match provenance subject</span><br></span></code></pre></div></div>
<p>And now let's see what happens when we try with the binary that was produced by
the GitHub action:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ slsa-verifier verify-artifact --provenance-path tuf-keyid.intoto.jsonl \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --source-uri github.com/danbev/tuf-keyid \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   tuf-keyid</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Verified signature against tlog entry index 11978552 at URL: https://rekor.sigstore.dev/api/v1/log/entries/24296fb24b8ad77a217b8f07bccab3dc8caa1c7badf65f104a762647e5e355db23ccc13a22e275dd</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Verified build using builder https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.4.0 at commit 513b0e060c76a1ded7b1a4173165103838f8dde7</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">PASSED: Verified SLSA provenance</span><br></span></code></pre></div></div>
<p><code>slsa-verifier</code> can also print out the predicate information after validation
, using <code>--print-provenance</code>, which could then be passed to a Policy Engine:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ slsa-verifier verify-artifact --provenance-path tuf-keyid.intoto.jsonl \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --source-uri github.com/danbev/tuf-keyid \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --print-provenance \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  tuf-keyid</span><br></span></code></pre></div></div>]]></content>
        <author>
            <name>Daniel Bevenius</name>
            <uri>https://github.com/danbev</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Signing elf binaries, or not?! Lessons learned.]]></title>
        <id>https://trustification.io/blog/2023/02/13/elfsign</id>
        <link href="https://trustification.io/blog/2023/02/13/elfsign"/>
        <updated>2023-02-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Trying to figure out what went into a binary can be a tricky thing. And once you figured it out, how do you]]></summary>
        <content type="html"><![CDATA[<p>Trying to figure out what went into a binary can be a tricky thing. And once you figured it out, how do you
transport this information? True, it all starts simple: Java, NodeJS, Go, or Rust, all languages<sup><a href="https://trustification.io/blog/2023/02/13/elfsign#user-content-fn-1-84d680" id="user-content-fnref-1-84d680" data-footnote-ref="true" aria-describedby="footnote-label" class="anchorTargetStickyNavbar_Vzrq">1</a></sup> bring their
dependency management, which defines what the final command line tool you create is made of. Or, does it?</p>
<p>But let's take a step back: A typical use-case today is to download a command line application from the internet.
Take <code>helm</code> for example. You navigate to their GitHub releases page, download the binary, unzip it into a local
folder and run it. But, what exactly is inside the binary?</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sboms">SBOMs<a href="https://trustification.io/blog/2023/02/13/elfsign#sboms" class="hash-link" aria-label="Direct link to SBOMs" title="Direct link to SBOMs" translate="no">​</a></h2>
<p><em>Software Bills of Material</em> (SBOMs) are a thing which already exist. Yet, someone needs to create them,
and creating an accurate SBOM can be tricky.</p>
<p>There are tools to create SBOMs from the source code of a project, but that doesn't tell the whole story in
most cases. Those tools simply analyze the dependency information declared in e.g. a <code>package.lock</code> file, or a Maven <code>pom.xml</code>. Should be enough, right? Well, no. Maven projects for example have "profiles", and you
need to exactly generate the SBOM for the profile that gets enabled when creating the final artifact. Also,
with Maven mirrors and proxies, it's not always 100% clear what gets into a "binary" and where it comes from.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-really-goes-in">What really goes in<a href="https://trustification.io/blog/2023/02/13/elfsign#what-really-goes-in" class="hash-link" aria-label="Direct link to What really goes in" title="Direct link to What really goes in" translate="no">​</a></h2>
<p>Then again, JAR files aren't real binaries are they. They are ZIP files, which contain compiled <code>.class</code> files. So
it actually is pretty simple to understand what is in there. Assuming you trust your build process
(which is a topic of its own). Even if you create a "fat", or "shaded" JAR, it is possible to understand what
really ended up in your "binary".</p>
<p>And, others can do the same. Rust for example allows one use <code>cargo auditable</code>, to tap into the compilation process,
and record the actual dependencies which go into a binary. On Linux, the binary will be an ELF file, which then
contains the dependency information from the compilation process. And Go can do the same.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="null-and-void">Null and void<a href="https://trustification.io/blog/2023/02/13/elfsign#null-and-void" class="hash-link" aria-label="Direct link to Null and void" title="Direct link to Null and void" translate="no">​</a></h2>
<p>But, if someone can write dependency information into a binary, then someone else can also overwrite it. So
unless you protect the binary against modifications, this information isn't really trustworthy. Taking a look at
the Helm release page, you will find SHA based checksums. Isn't that enough?</p>
<p>No, not really. Because if someone can alter the binary on the download page, the attacker can also swap out the
SHA checksum file. The checksum, or digest, really isn't more than a checksum. By its own, it doesn't protect much.</p>
<p>If however, you encrypt the digest with a private key that only the author knows, and you publish the public key
part, then this becomes a "signature". And this is good enough to prove, that only the person how knew the private
key, could have signed the binary. And if we can trust this person to create the correct SBOM and binary, and keep
the private key secure, we are good.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="usability">Usability<a href="https://trustification.io/blog/2023/02/13/elfsign#usability" class="hash-link" aria-label="Direct link to Usability" title="Direct link to Usability" translate="no">​</a></h2>
<p>Or, not! In the Maven world JARs have been signed for quite a while. Everyone uploading JARs to Maven Central needs
to sign their JAR with GPG. And I guess most people never validated a JAR during a build.</p>
<p>On the other side, the Eclipse IDE (as well as some other Java applications), did JAR file validation for quite a
while. Whenever you install a plugin, it cryptographically validates the JAR. And it's easy, as the JAR file itself
is signed, and the signature is part of the JAR file. As part of the build process in the Eclipse Foundation
build system, JARs which got created by the build, can automatically get signed. No additional files needed,
and only the actual build output is considered, no guessing of dependencies.</p>
<p>From a user perspective, the IDE automatically checks signatures, and only bothers the user if an issue was found.
The user can override, because the idea is to give the final authority to the user.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="back-to-binaries">Back to binaries<a href="https://trustification.io/blog/2023/02/13/elfsign#back-to-binaries" class="hash-link" aria-label="Direct link to Back to binaries" title="Direct link to Back to binaries" translate="no">​</a></h2>
<p>Now, just assume we could do the same with (ELF) binaries. In fact this was possible a while back, Solaris had some
tools to sign ELF binaries. That doesn't help on modern Linux systems. But with a bit of Rust code, it was possible
to create <a href="https://github.com/ctron/elfsign" target="_blank" rel="noopener noreferrer" class="">elfsign</a>. The idea is simple:</p>
<ul>
<li class="">Create a digest of all relevant ELF sections and headers</li>
<li class="">Sign this digest</li>
<li class="">Add the signature to the ELF binary as a new section</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="solvable-downsides">Solvable downsides<a href="https://trustification.io/blog/2023/02/13/elfsign#solvable-downsides" class="hash-link" aria-label="Direct link to Solvable downsides" title="Direct link to Solvable downsides" translate="no">​</a></h2>
<p>The first downside might be that people are afraid of signed binaries. Windows and macOS have been doing this for a
while, and it happens that signatures get in the way of the user running a binary. Well, actually it is the operating
system which gets into the user's way. To protect the user, that's the argument. And that might be true, but it also
is true that some users indeed know better than the operating system and want to have the final word in what they
can run.</p>
<p>This problem can easily be addressed. Checking a signature, and making a decision if a binary can be run or not,
actually are two different things. Even if a system brings a default rule/policy set which would reject invalid
signatures, it could still be possible to let the user customize the behavior and override, just like the
Eclipse IDE does.</p>
<p>Another issue the handling of keys and certificates. Prices for code signing certificates can be quite high.
Especially when we are talking about open source projects, this can become a truly limiting factor. It also takes a
bit of care, handling a private key properly.</p>
<p>Luckily, we now have <a href="https://www.sigstore.dev/" target="_blank" rel="noopener noreferrer" class="">sigstore</a>. Sigstore can help us with two things, creating
short-lived private keys (Fulcio), and a tamper-resistant log (Rekor). We already talked a bit about both in
the context of [gitsign]({% post_url 2022-12-02-sign-commits-with-sigstore %}).</p>
<p>Adding Fulcio and Rekor to <code>elfsign</code>, we gain a bunch of cool things:</p>
<ul>
<li class="">Short-lived, disposable private keys: You don't need to store them, they are only valid for a few minutes.</li>
<li class="">X.509 certificates: Alongside the key, we get an X.509 certificates, with our identity, which we can use for signing.</li>
<li class="">An attestation that we provided the valid certificate and signature to Rekor, at a time the key was valid</li>
</ul>
<p>And with that, we can easily implement <code>elfsign sign</code> to sign a binary, and <code>elfsign verify</code> to validate one. We
could also create something like <code>elfsign execute</code> to verify and execute, but that's just a variant of <code>verify</code>.</p>
<p>As we can prove, using Rekor, that we did own the private key during the time the certificate was valid, and we
provided the signature/digest at the same time, we now only need to decide if we want to trust the issuer and the
subject the certificate was issued for. And by storing [the Rekor bundle]({% post_url 2023-01-13-sigstore-bundle-format %}), we can do this offline too.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="too-good-to-be-true">Too good to be true?<a href="https://trustification.io/blog/2023/02/13/elfsign#too-good-to-be-true" class="hash-link" aria-label="Direct link to Too good to be true?" title="Direct link to Too good to be true?" translate="no">​</a></h2>
<p>So where's the catch?</p>
<p>Signing elf binaries adds a bit of extra complexity. Creating a digest of an ELF binary isn't as trivial as
just running <code>sha256sum</code> on a file. Storing an additional "signature section" in the ELF binary, will actually
alter it. So it is necessary have a normalized view on the ELF binary, which creates a reproducible digest, one that
does include all important information, but excludes the signature information itself, and still is a valid ELF
binary format.</p>
<p>It works, but is a bit complex. And more complexity might lead to more bugs, which isn't a good thing when
it comes to cryptography. But if this allows one to drop handling additional files (like SBOMs or checksum files),
and increase the usability, it may actually be worth it.</p>
<p>The problem is, that the tooling which creates the dependency information for the ELF binaries, isn't
accurate enough.</p>
<p>In many cases it works, but as soon as you include a C library, add some JavaScript for an embedded frontend, or
deviate from "standard artifact repositories", many of those tools just fall short. And I am not even talking
about all those little hacks in build systems, or the mess called "vendor" folder in Go.</p>
<p>SBOM formats like <a href="https://cyclonedx.org/" target="_blank" rel="noopener noreferrer" class="">CycloneDX</a> allow you to compensate and fix up generated SBOMs.
But, that's another step in the build process, and the output doesn't go into the ELF binary. As Go only cares
about Go dependencies, and Cargo only about Cargo.</p>
<p>So adding all the complexity isn't good enough in the end. You still need to handle an extra file, and validate it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="happy-end">Happy end?<a href="https://trustification.io/blog/2023/02/13/elfsign#happy-end" class="hash-link" aria-label="Direct link to Happy end?" title="Direct link to Happy end?" translate="no">​</a></h2>
<p>The truth is, <code>cosign</code>, which is intended to sign containers, can actually sign any BLOB. Just the same way,
using Fulcio to get a short-lived private key and certificate, and storing the signature in Rekor. So if we can make
our peace with handling an extra file, we can just use <code>cosign sign-blob</code> and <code>cosign verify-blob</code> to sign
anything we want. Using <code>cosign attest-blob</code>, we can even "attach" an SBOM to the Rekor log entry.</p>
<p>Yes, we need to handle the extra "bundle" and "signature" files. Or we can accept the fact that we need rely on the
uptime of the Rekor instance (or our ISP). But it definitely improves the situation over the status quo.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="so-what">So what?<a href="https://trustification.io/blog/2023/02/13/elfsign#so-what" class="hash-link" aria-label="Direct link to So what?" title="Direct link to So what?" translate="no">​</a></h2>
<p><code>elfsign</code> was a nice experiment. And while it didn't work out, I still learned a lot. I also still believe that
the idea works out in general. It just needs more work for a more specialized solution. So the approach of
"cosign blob" is a more generic one. However, through that, also less user-friendly one.</p>
<p>But this situation could also be improved. Just assume someone would create a more convenient version of
cosign, which "downloads and verifies" or "verifies and executes". That would definitely lead to a similar
user experience, and help with adoption.</p>
<p>And, having a policy engine like Seedwing, you could actually define checks like: Only run this binary if it is signed, and does not contain a dependency which has an active CVE.</p>
<p>If you are interested in things like this, maybe this blog post gave you a few insights and ideas.</p>
<!-- -->
<section data-footnotes="true" class="footnotes"><h2 class="anchor anchorTargetStickyNavbar_Vzrq sr-only" id="footnote-label">Footnotes<a href="https://trustification.io/blog/2023/02/13/elfsign#footnote-label" class="hash-link" aria-label="Direct link to Footnotes" title="Direct link to Footnotes" translate="no">​</a></h2>
<ol>
<li class="anchorTargetStickyNavbar_Vzrq" id="user-content-fn-1-84d680">
<p>Yes, C/C++ is missing here. Let's not talk about build systems and dependency management for C/C++ 😉 <a href="https://trustification.io/blog/2023/02/13/elfsign#user-content-fnref-1-84d680" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content>
        <author>
            <name>Jens Reimann</name>
            <uri>https://github.com/ctron</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Continuing the Adventure with the CycloneDX Maven Plugin]]></title>
        <id>https://trustification.io/blog/2023/02/10/cyclonedx-maven-plugin-adventure-continues</id>
        <link href="https://trustification.io/blog/2023/02/10/cyclonedx-maven-plugin-adventure-continues"/>
        <updated>2023-02-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[My investigation into the CycloneDX Maven Plugin began back in November/December 2022 with the intent of integrating the plugin into the Quarkus build process to generate Software Bill of Materials (SBOMs) for the project. I quickly discovered issues in the plugin and raised these with the maintainer early in December, writing a blog post (An Adventure with the CycloneDX Maven Plugin) to help clarify each issue. I finally opened a pull request in early January to move the conversation forward and this is where our story continues .....]]></summary>
        <content type="html"><![CDATA[<p>My investigation into the <a href="https://github.com/CycloneDX/cyclonedx-maven-plugin" target="_blank" rel="noopener noreferrer" title="The CycloneDX Maven Plugin GitHub repository" class="">CycloneDX Maven Plugin</a> began back in November/December 2022 with the intent of integrating the plugin into the <a href="https://github.com/quarkusio/quarkus" target="_blank" rel="noopener noreferrer" title="The Quarkus GitHub repository" class="">Quarkus</a> build process to generate Software Bill of Materials (SBOMs) for the project. I quickly discovered issues in the plugin and raised these with the maintainer early in December, writing a blog post (<a class="" href="https://trustification.io/blog/2022/12/09/cyclonedx-maven-plugin-adventure">An Adventure with the CycloneDX Maven Plugin</a>) to help clarify each issue. I finally opened a pull request in early January to move the conversation forward and this is where our story continues .....</p>
<p>Two weeks ago I received some feedback on the pull request from Steve Springett, he ran my version of the CycloneDX plugin and hit some problems. Steve was running the plugin against the <a href="https://github.com/WebGoat/WebGoat/tree/v8.0.0" target="_blank" rel="noopener noreferrer" class="">WebGoat 8.0.0</a> codebase and noticed some dependencies were not present in the components section! This was intriguing as I had been running the plugin against a complex codebase (<a href="https://github.com/quarkusio/quarkus" target="_blank" rel="noopener noreferrer" title="The Quarkus GitHub repository" class="">Quarkus</a>) without seeing the issue, and had also included a BOM validation step in my pull request which would emit <strong>WARNING</strong> log messages if this situation occurred. I took a look at the WebGoat codebase and could not get this specific version to build, however a build of a different version did succeed without displaying the problem. Curiouser and curiouser .......</p>
<p>We now jump forward to this Monday (4 days ago) when I'm trying to arrange a call with Steve to discuss the differences in our environments and help move this forward. Steve suggested we include Hervé Boutemy in the call, the new maintainer of the upstream codebase, however he offered instead to review my pull request as-is. It's at this point I realised the pull request now had conflicts with the base branch, so I quickly rebased and fixed the conflicts. I also decided to give the WebGoat codebase another try.</p>
<p>I spent time investigating the failures I had seen with the WebGoat build and eventually realised I needed to be running on an older version of Java, I needed to install JDK8 in order to make progress. I was now able to build the same version of the code Steve had been using, although with errors, but could now see missing components. Even better, I could also see the expected <strong>WARNING</strong> messages were present!</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">[WARNING] CycloneDX: Dependency missing component entry: pkg:maven/org.webjars/jquery@1.11.1?type=jar</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[WARNING] CycloneDX: Dependency missing component entry: pkg:maven/commons-io/commons-io@LATEST?type=jar</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[WARNING] CycloneDX: Dependency missing component entry: pkg:maven/com.google.guava/guava@18.0?type=jar</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[WARNING] CycloneDX: Dependency missing component entry: pkg:maven/org.apache.commons/commons-lang3@3.4?type=jar</span><br></span></code></pre></div></div>
<p>This was great, I now had something to work with.</p>
<h1>Comparing Upstream Output with my pull request</h1>
<p>Before investigating I decided to first understand the differences in output between the current upstream codebase and what was being generated by my pull request. This may provide some insight into the new issue and could possibly hint at a direction to follow.</p>
<p>With regard to <strong>components</strong> I discovered three were missing from my version of the bom, however in each case the component was never referenced in the dependencies section. These components were</p>
<ul>
<li class="">pkg<!-- -->:maven<!-- -->/com.google.guava/guava@20.0?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/commons-io/commons-io@2.11.0?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.apache.commons/commons-lang3@3.6?type=jar</li>
</ul>
<p>These are three of the components we were warned about, but suspiciously each has a different version.</p>
<p>I also found we were now including two additional <strong>components</strong>, these are</p>
<ul>
<li class="">pkg<!-- -->:maven<!-- -->/junit/junit@4.12?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.hamcrest/hamcrest-core@1.3?type=jar</li>
</ul>
<p>With regard to <strong>dependencies</strong> we were expanding the dependency tree to include transitive dependencies for the following</p>
<ul>
<li class="">pkg<!-- -->:maven<!-- -->/com.fasterxml.jackson.core/jackson-databind@2.8.11.1?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.springframework.boot/spring-<a href="mailto:boot-autoconfigure@1.5.12.RELEASE" target="_blank" rel="noopener noreferrer" class="">boot-autoconfigure@1.5.12.RELEASE</a>?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.springframework.boot/spring-<a href="mailto:boot@1.5.12.RELEASE" target="_blank" rel="noopener noreferrer" class="">boot@1.5.12.RELEASE</a>?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.springframework.security/spring-<a href="mailto:security-core@4.2.5.RELEASE" target="_blank" rel="noopener noreferrer" class="">security-core@4.2.5.RELEASE</a>?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.springframework.security/spring-<a href="mailto:security-web@4.2.5.RELEASE" target="_blank" rel="noopener noreferrer" class="">security-web@4.2.5.RELEASE</a>?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.springframework/spring-<a href="mailto:aop@4.3.16.RELEASE" target="_blank" rel="noopener noreferrer" class="">aop@4.3.16.RELEASE</a>?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.springframework/spring-<a href="mailto:beans@4.3.16.RELEASE" target="_blank" rel="noopener noreferrer" class="">beans@4.3.16.RELEASE</a>?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.springframework/spring-<a href="mailto:context@4.3.16.RELEASE" target="_blank" rel="noopener noreferrer" class="">context@4.3.16.RELEASE</a>?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.springframework/spring-<a href="mailto:expression@4.3.16.RELEASE" target="_blank" rel="noopener noreferrer" class="">expression@4.3.16.RELEASE</a>?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.springframework/spring-<a href="mailto:test@4.3.16.RELEASE" target="_blank" rel="noopener noreferrer" class="">test@4.3.16.RELEASE</a>?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.springframework/spring-<a href="mailto:web@4.3.16.RELEASE" target="_blank" rel="noopener noreferrer" class="">web@4.3.16.RELEASE</a>?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.webjars/bootstrap@3.3.7?type=jar</li>
</ul>
<p>as well as adding new <strong>dependencies</strong> into the tree</p>
<ul>
<li class="">pkg<!-- -->:maven<!-- -->/aopalliance/aopalliance@1.0?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.hamcrest/hamcrest-core@1.3?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/junit/junit@4.12?type=jar</li>
</ul>
<p>however, we are also seeing the following <strong>dependencies</strong> without any mention in the <strong>component</strong> section</p>
<ul>
<li class="">pkg<!-- -->:maven<!-- -->/com.google.guava/guava@18.0?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/commons-io/commons-io@LATEST?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.apache.commons/commons-lang3@3.4?type=jar</li>
<li class="">pkg<!-- -->:maven<!-- -->/org.webjars/jquery@1.11.1?type=jar</li>
</ul>
<p>These match the list of <strong>dependencies</strong> reported as <strong>WARNING</strong>s in the log, confirming the issue.</p>
<p>We now know the pull request codebase is having a beneficial effect and providing a more detailed dependency graph. What is left to work out is why we are seeing these four dependencies in the tree with no associated component.</p>
<h1>Identity, Does it Matter?</h1>
<p>Before we take a look at each of the problematic dependencies let us quickly cover how components are identified in the upstream CycloneDX codebase and in my pull request.</p>
<p>The upstream codebase discovers its components by asking maven for those artifacts which it has resolved to be the definitive set for the build. These artifacts are then filtered based on their scope, however as we discovered in the previous post this does not follow the transitive scoping rules applied by maven, and then used to create the set of components included in the bom file. It is also important to realise that when resolving the dependency tree the upstream codebase will not include any dependencies which do not exist in the set of known components. No components will be removed, even if they do not take part in the dependency tree.</p>
<p>In my pull request we take a slightly different approach. To discover the set of possible components we still ask maven for the definitive set of artifacts, but rely instead on maven to handle the filtering when collecting the dependency graph. At the end of the process we check the set of components and remove any which do not appear in the dependency tree. No dependencies will be removed, even if they do not have an associated component, however a warning is emitted on the console. This is the warning we are now seeing.</p>
<p>These approaches are, essentially, tackling the discovery from opposite directions.</p>
<p>With the above in mind let us now take a look at the problematic artifacts and return to our trusty dependency tree graph. We can see from the <strong>WARNING</strong>s that we should focus on two of the projects</p>
<ul>
<li class=""><strong>xxe</strong> for <strong>guava</strong> and <strong>commons-lang3</strong></li>
<li class=""><strong>webwolf</strong> for <strong>jquery</strong> and <strong>commons-io</strong></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-look-at-guava">A look at Guava<a href="https://trustification.io/blog/2023/02/10/cyclonedx-maven-plugin-adventure-continues#a-look-at-guava" class="hash-link" aria-label="Direct link to A look at Guava" title="Direct link to A look at Guava" translate="no">​</a></h2>
<p>The parts of the <strong>xxe</strong> dependency tree which are of interest are</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">org.owasp.webgoat.lesson:xxe:jar:v8.0.0.M15</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.github.tomakehurst:wiremock:jar:2.8.0:test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  +- com.google.guava:guava:jar:20.0:provided</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  +- com.flipkart.zjsonpatch:zjsonpatch:jar:0.3.0:test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  |  +- (com.google.guava:guava:jar:18.0:test - omitted for conflict with 20.0)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- org.owasp.webgoat:webgoat-container:jar:v8.0.0.M15:provided</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  +- (com.google.guava:guava:jar:18.0:provided - omitted for conflict with 20.0)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- org.owasp.webgoat:webgoat-container:jar:tests:v8.0.0.M15:test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  +- (com.google.guava:guava:jar:18.0:test - omitted for conflict with 20.0)</span><br></span></code></pre></div></div>
<p>From this we can see <strong>guava:20.0</strong> has been resolved as the winner by maven, however the winning artifact is hidden beneath a <strong>test</strong> scoped artifact (we saw this in our previous issues). We can also see the artifact discovered through the transitive <strong>compile</strong> scope is being reported as <strong>guava:18.0</strong>, so while version <strong>20.0</strong> has been declared the winner we are still seeing the marker nodes report the original version of <strong>18.0</strong>. How does each version of the plugin handle this scenario?</p>
<p>The upstream code discovers <strong>guava:20.0</strong> in the set of resolved artifacts, including it in its set of known components. When creating the dependency tree it discovers <strong>guava:18.0</strong>, however decides not to include it as this version is not in the set of known components. This results in a bom which includes the <strong>guava:20.0</strong> component and a dependency graph which does not reference the <strong>guava</strong> dependency, losing the dependency relationship between <strong>webgoat-container</strong> and <strong>guava</strong>. The bom looks as follows</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;component type="library" bom-ref="pkg:maven/com.google.guava/guava@20.0?type=jar"&gt;</span><br></span></code></pre></div></div>
<p>In my pull request we discover <strong>guava:20.0</strong> in the set of resolved artifacts, including it as a known component. When creating the dependency tree we discover the <strong>guava:18.0</strong> dependency and include it in the tree. At the end of the process we drop components which are not mentioned in the dependency tree, in this instance the <strong>guava:20.0</strong> component, but keep the dependency relationship between <strong>webgoat-container</strong> and <strong>guava:18.0</strong>, which is a missing component. The bom looks as follows</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.owasp.webgoat/webgoat-container@v8.0.0.M15?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.google.guava/guava@18.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.google.guava/guava@18.0?type=jar"/&gt;</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-look-at-commons-lang3">A look at commons-lang3<a href="https://trustification.io/blog/2023/02/10/cyclonedx-maven-plugin-adventure-continues#a-look-at-commons-lang3" class="hash-link" aria-label="Direct link to A look at commons-lang3" title="Direct link to A look at commons-lang3" translate="no">​</a></h2>
<p>The parts of the <strong>xxe</strong> dependency tree which are of interest are</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">org.owasp.webgoat.lesson:xxe:jar:v8.0.0.M15</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.github.tomakehurst:wiremock:jar:2.8.0:test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  +- org.apache.commons:commons-lang3:jar:3.6:provided</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  \- com.github.jknack:handlebars:jar:4.0.6:test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|     +- (org.apache.commons:commons-lang3:jar:3.1:test - omitted for conflict with 3.6)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- org.owasp.webgoat:webgoat-container:jar:v8.0.0.M15:provided</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  +- (org.apache.commons:commons-lang3:jar:3.4:provided - omitted for conflict with 3.6)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- org.owasp.webgoat:webgoat-container:jar:tests:v8.0.0.M15:test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  +- (org.apache.commons:commons-lang3:jar:3.4:test - omitted for conflict with 3.6)</span><br></span></code></pre></div></div>
<p>We can see from the above that the <strong>commons-lang3</strong> artifact suffers from the same problem as the <strong>guava</strong> artifact, with the artifact identified through the transitive <strong>compile</strong> scope having a version of <strong>3.4</strong> while the resolved winner has a version of <strong>3.6</strong> but is hidden beneath a <strong>test</strong> scoped artifact. We can also see there is a third version being referenced beneath the <strong>test</strong> scoped artifact, <strong>commons-lang3:3.1</strong>.</p>
<p>The upstream bom looks as follows</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;component type="library" bom-ref="pkg:maven/org.apache.commons/commons-lang3@3.6?type=jar"&gt;</span><br></span></code></pre></div></div>
<p>The bom from my pull request looks as follows</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.owasp.webgoat/webgoat-container@v8.0.0.M15?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.apache.commons/commons-lang3@3.4?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.apache.commons/commons-lang3@3.4?type=jar"/&gt;</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-look-at-jquery">A look at jquery<a href="https://trustification.io/blog/2023/02/10/cyclonedx-maven-plugin-adventure-continues#a-look-at-jquery" class="hash-link" aria-label="Direct link to A look at jquery" title="Direct link to A look at jquery" translate="no">​</a></h2>
<p>The parts of the <strong>webwolf</strong> dependency tree which are of interest are</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">org.owasp.webgoat:webwolf:jar:v8.0.0.M15</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- org.webjars:bootstrap:jar:3.3.7:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  \- (org.webjars:jquery:jar:1.11.1:compile - omitted for conflict with 3.2.1)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- org.webjars:jquery:jar:3.2.1:compile</span><br></span></code></pre></div></div>
<p>This scenario is slightly different from the previous ones in that the resolved component is not hidden behind a <strong>test</strong> scoped artifact. We can see from the above that we have two artifacts being discovered within the transitive <strong>compile</strong> scope, <strong>jquery:3.2.1</strong> and <strong>jquery:1.11.1</strong>. Version <strong>3.2.1</strong> is the resolved winner and version <strong>1.11.1</strong> is the marker node for an artifact which lost the resolution process. How does each version of the plugin handle this scenario?</p>
<p>The upstream code discovers <strong>jquery:3.2.1</strong> in the set of resolved artifacts, including it in its set of known components. When creating the dependency tree it discovers both <strong>jquery:3.2.1</strong> and <strong>jquery:1.11.1</strong>, including <strong>3.2.1</strong> in the tree but deciding not to include <strong>1.11.1</strong> as this does not match a known component. This results in a bom which includes the <strong>jquery:3.2.1</strong> component and the dependency relationship between <strong>webwolf</strong> and <strong>jquery</strong> but loses the dependency relationship between <strong>bootstrap</strong> and <strong>jquery</strong>. The bom looks as follows</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;component type="library" bom-ref="pkg:maven/org.webjars/jquery@3.2.1?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.owasp.webgoat/webwolf@v8.0.0.M15?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.webjars/jquery@3.2.1?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.webjars/jquery@3.2.1?type=jar"/&gt;</span><br></span></code></pre></div></div>
<p>In my pull request we discover <strong>jquery:3.2.1</strong> in the set of resolved artifacts, including it as a known component. When creating the dependency tree we discover both <strong>jquery:3.2.1</strong> and <strong>jquery:1.11.1</strong>, including both in the tree. This results in a bom which includes the <strong>jquery:3.2.1</strong> component and the dependency relationship between <strong>webwolf</strong> and <strong>jquery</strong>. The bom also keeps the dependency relationship between <strong>bootstrap</strong> and <strong>jquery:1.11.1</strong>, which is a missing component. The bom looks as follows</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;component type="library" bom-ref="pkg:maven/org.webjars/jquery@3.2.1?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.owasp.webgoat/webwolf@v8.0.0.M15?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.webjars/jquery@3.2.1?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.webjars/bootstrap@3.3.7?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.webjars/jquery@1.11.1?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.webjars/jquery@1.11.1?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.webjars/jquery@3.2.1?type=jar"/&gt;</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-look-at-commons-io">A look at commons-io<a href="https://trustification.io/blog/2023/02/10/cyclonedx-maven-plugin-adventure-continues#a-look-at-commons-io" class="hash-link" aria-label="Direct link to A look at commons-io" title="Direct link to A look at commons-io" translate="no">​</a></h2>
<p>The parts of the <strong>webwolf</strong> dependency tree which are of interest are</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">org.owasp.webgoat:webwolf:jar:v8.0.0.M15</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- commons-io:commons-io:jar:LATEST:compile</span><br></span></code></pre></div></div>
<p>Now this scenario is very different from the previous ones. In each of the previous scenarios the dependency tree included marker nodes with versions which did not match the version resolved by maven, the first two with the resolved artifact hidden behind a <strong>test</strong> scoped artifact and the third with both artifacts discovered through the transitive <strong>compile</strong> scope. So what is going on here? It's time for a quick dive under the covers of maven!</p>
<p>Maven includes support for two <em>metaversions</em> which can be used when specifying the version of an artifact, these are <strong>RELEASE</strong> and <strong>LATEST</strong>. These <em>metaversions</em> have specific meanings when resolving artifacts within a pom, these are</p>
<ul>
<li class=""><strong>RELEASE</strong>: represents the latest non-snapshot version of the artifact within a repository</li>
<li class=""><strong>LATEST</strong>: represents the latest version of the artifact within a repository, which includes both released and snapshot versions</li>
</ul>
<hr>
<p><strong>Note:</strong> Using either <strong>RELEASE</strong> or <strong>LATEST</strong> in a build breaks reproducibility. Thankfully maven is now issuing the following deprecation <strong>WARNING</strong> when encountering these <em>metaversions</em>, which means support for these versions should be removed at some point in the future.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">[WARNING] 'dependencies.dependency.version' for commons-io:commons-io:jar is either LATEST or RELEASE (both of them are being deprecated)</span><br></span></code></pre></div></div>
<hr>
<p>When maven encounters either of these <em>metaversions</em> it will resolve the artifact to a specific version based on the above meanings. In our case, at least as of today, maven will resolve <strong>commons-io<!-- -->:LATEST</strong> to <strong>commons-io:2.11.0</strong>. How does each version of the plugin handle this scenario?</p>
<p>The upstream code discovers <strong>commons-io:2.11.0</strong> in the set of resolved artifacts, including it in its set of known components. When creating the dependency tree it discovers <strong>commons-io<!-- -->:LATEST</strong>, however decides not to include it as this version is not in the set of known components. This results in a bom which includes the <strong>commons-io:2.11.0</strong> component and a dependency graph which does not reference the <strong>common-io</strong> dependency, losing the dependency relationship between <strong>webwolf</strong> and <strong>commons-io</strong>. The bom looks as follows</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;component type="library" bom-ref="pkg:maven/commons-io/commons-io@2.11.0?type=jar"&gt;</span><br></span></code></pre></div></div>
<p>In my pull request we discover <strong>commons-io:2.11.0</strong> in the set of resolved artifacts, including it as a known component. When creating the dependency tree we discover the <strong>commons-io<!-- -->:LATEST</strong> dependency and include it in the tree. At the end of the process we drop components which are not mentioned in the dependency tree, in this instance the <strong>commons-io:2.11.0</strong> component, but keep the dependency relationship between <strong>webwolf</strong> and <strong>commons-io<!-- -->:LATEST</strong>, which is a missing component. The bom looks as follows</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.owasp.webgoat/webwolf@v8.0.0.M15?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/commons-io/commons-io@LATEST?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/commons-io/commons-io@LATEST?type=jar"/&gt;</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summarising-the-issues">Summarising the issues<a href="https://trustification.io/blog/2023/02/10/cyclonedx-maven-plugin-adventure-continues#summarising-the-issues" class="hash-link" aria-label="Direct link to Summarising the issues" title="Direct link to Summarising the issues" translate="no">​</a></h2>
<p>We have three different scenarios here, however each has the same root cause. Maven is returning a dependency graph which includes marker nodes referencing the original artifact versions and not the versions resolved within the context of the build. These marker nodes have a different identity to the resolved dependencies and are, therefore, treated separately. As we would expect, identity does matter!</p>
<p>With the upstream codebase we see the resolved components being included in the bom, but with certain dependency relationships missing from the dependency tree.</p>
<p>With my pull request we see some missing components from the bom, but with all dependency relationships included in the dependency tree. The problem is that some of these relationships reference dependencies with their original version and not the version resolved by maven.</p>
<hr>
<p><strong>Note:</strong> The issues we are seeing do not happen with dependencies which have their version managed, if we look at the node for a managed dependency we can see the version of the marker has been updated</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">org.slf4j:slf4j-api:1.7.25:compile    (org.slf4j:slf4j-api:jar:1.7.25:compile - version managed from 1.6.6; omitted for duplicate)</span><br></span></code></pre></div></div>
<p>In this case the version of the marker node has been updated from <strong>1.6.6</strong> to <strong>1.7.25</strong>.</p>
<p>Unfortunately this additional information is not available to us other than through the <strong>toNodeString</strong> method on the <strong>VerboseDependencyNode</strong> class, that is unless we delve under the covers and work on the internal <em><a href="https://wiki.eclipse.org/Aether" target="_blank" rel="noopener noreferrer" title="Eclipse Aether website" class="">aether</a></em> dependency tree which does contain a data map including this information.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="now-for-the-solution">Now for the solution<a href="https://trustification.io/blog/2023/02/10/cyclonedx-maven-plugin-adventure-continues#now-for-the-solution" class="hash-link" aria-label="Direct link to Now for the solution" title="Direct link to Now for the solution" translate="no">​</a></h2>
<p>Now we have identified a root cause there is an obvious solution. We know maven is not updating the versions for some marker nodes, leaving them with their original version, so we need to handle this aspect. We need to track the versions of the resolved artifacts and, when creating the dependency graph, ensure all dependency versions reference the resolved version of the artifact. Thankfully this is a straight forward update to the codebase.</p>
<p>Now that we have a working solution how does this look for each component?</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="recap-and-solution-for-guava">Recap and Solution for guava<a href="https://trustification.io/blog/2023/02/10/cyclonedx-maven-plugin-adventure-continues#recap-and-solution-for-guava" class="hash-link" aria-label="Direct link to Recap and Solution for guava" title="Direct link to Recap and Solution for guava" translate="no">​</a></h3>
<p>From our earlier discussion we saw the upstream plugin had identified the correct guava version for the component, but had lost all dependency relationships, and my pull request had kept the dependency relationships but had lost the component as it was referring to the original version of the artifact. What do we see now in the bom file?</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;component type="library" bom-ref="pkg:maven/com.google.guava/guava@20.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.owasp.webgoat/webgoat-container@v8.0.0.M15?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.google.guava/guava@20.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/com.google.guava/guava@20.0?type=jar"/&gt;</span><br></span></code></pre></div></div>
<p>Fantastic, we now see a component with the version resolved by maven and all the dependency relationships we were expecting!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="recap-and-solution-for-commons-lang3">Recap and Solution for commons-lang3<a href="https://trustification.io/blog/2023/02/10/cyclonedx-maven-plugin-adventure-continues#recap-and-solution-for-commons-lang3" class="hash-link" aria-label="Direct link to Recap and Solution for commons-lang3" title="Direct link to Recap and Solution for commons-lang3" translate="no">​</a></h3>
<p>From our earlier discussion we saw a similar issue with commons-lang3. The upstream plugin had identified the correct commons-lang3 version for the component, but had lost all dependency relationships, and my pull request had kept the dependency relationships but had lost the component as it was using the original version of the artifact. What do we see now in the bom file?</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;component type="library" bom-ref="pkg:maven/org.apache.commons/commons-lang3@3.6?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.owasp.webgoat/webgoat-container@v8.0.0.M15?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.apache.commons/commons-lang3@3.6?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.apache.commons/commons-lang3@3.6?type=jar"/&gt;</span><br></span></code></pre></div></div>
<p>We are now two for two, we again see the component with the resolved version and also see all the dependency relationships!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="recap-and-solution-for-jquery">Recap and Solution for jquery<a href="https://trustification.io/blog/2023/02/10/cyclonedx-maven-plugin-adventure-continues#recap-and-solution-for-jquery" class="hash-link" aria-label="Direct link to Recap and Solution for jquery" title="Direct link to Recap and Solution for jquery" translate="no">​</a></h3>
<p>In our earlier discussion we had identified a slightly different scenario with jquery, as the <strong>compile</strong> scoped artifacts included both the resolved version (3.2.1) and an older version (1.11.1). Both plugins had identified the component and included the dependency relationship between <strong>webwolf</strong> and <strong>jquery</strong>, however the upstream plugin had lost the dependency relationship between <strong>bootstrap</strong> and <strong>jquery</strong> whereas my pull request included the dependency but referenced the original version. What do we now see in the bom file?</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;component type="library" bom-ref="pkg:maven/org.webjars/jquery@3.2.1?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.owasp.webgoat/webwolf@v8.0.0.M15?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.webjars/jquery@3.2.1?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.webjars/bootstrap@3.3.7?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/org.webjars/jquery@3.2.1?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.webjars/jquery@3.2.1?type=jar"/&gt;</span><br></span></code></pre></div></div>
<p>We are on a roll, and are now three for three. We can see all the expected dependency relationships are present with all the relationships referencing the resolved version!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="recap-and-solution-for-commons-io">Recap and Solution for commons-io<a href="https://trustification.io/blog/2023/02/10/cyclonedx-maven-plugin-adventure-continues#recap-and-solution-for-commons-io" class="hash-link" aria-label="Direct link to Recap and Solution for commons-io" title="Direct link to Recap and Solution for commons-io" translate="no">​</a></h3>
<p>Now we come to our final scenario and the use of <em>metaversions</em>, can we make it four for four?</p>
<p>In our earlier discussion we covered the use and meaning of <em>metaversions</em> within maven dependencies and saw the upstream plugin had correctly identified the resolved component, but had no dependency relationships, whereas my pull request identified the dependency relationships using the <strong>LATEST</strong> <em>metaversion</em> but did not identify the component. What do we now see in the bom file?</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;component type="library" bom-ref="pkg:maven/commons-io/commons-io@2.11.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/org.owasp.webgoat/webwolf@v8.0.0.M15?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/commons-io/commons-io@2.11.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependency ref="pkg:maven/commons-io/commons-io@2.11.0?type=jar"/&gt;</span><br></span></code></pre></div></div>
<p>Brilliant, the component and all expected dependency relationships are present, with each referencing the resolved version and not the <em>metaversion</em>!</p>
<p>We have done it, we are now four for four!</p>
<h1>Conclusions</h1>
<p>With this latest issue now resolved I feel we have a much better solution for generating SBOMs for maven projects. We know these bom files will contain all dependency relationships returned via maven, and now this version mismatch issue has been addressed we can be confident we will only include entries for resolved artifacts.</p>
<p>My original pull request has been updated to include the fix for these issues, in addition to the issues covered in the previous post (<a class="" href="https://trustification.io/blog/2022/12/09/cyclonedx-maven-plugin-adventure">An Adventure with the CycloneDX Maven Plugin</a>), and has now been merged into the upstream codebase with help from Hervé. I'm looking forward to having this released in the next <a href="https://github.com/CycloneDX/cyclonedx-maven-plugin" target="_blank" rel="noopener noreferrer" title="The CycloneDX Maven Plugin GitHub repository" class="">CycloneDX Maven Plugin</a> release and being able to use this in earnest as part of our effort to secure our Software Supply Chain. With any luck this can also be of benefit to your efforts, at least I hope that proves to be the case.</p>]]></content>
        <author>
            <name>Kevin Conner</name>
            <uri>https://github.com/knrc</uri>
        </author>
        <category label="cyclonedx" term="cyclonedx"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The Update Framework (TUF)]]></title>
        <id>https://trustification.io/blog/2023/01/31/tuf</id>
        <link href="https://trustification.io/blog/2023/01/31/tuf"/>
        <updated>2023-01-31T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[TUF seems to pop again and again when learning about Secure Supply-Chain]]></summary>
        <content type="html"><![CDATA[<p>TUF seems to pop again and again when learning about Secure Supply-Chain
Security (SSCS). The goal of this post is to get some hands-on experience
with TUF, showing examples that will hopefully clarify TUF concepts, and
the reason for using it in projects like Sigstore.</p>
<p>As the name "The Update Framework" implies this is a framework for update
systems, and doing so in a secure way. What is getting updated could be
anything, it could be software packages, source files, certificates, public
keys, etc. And by following this "framework", updates can be performed in a
secure way.</p>
<p>Producers want the things they produce to be available to consumers, and they
want to make sure that consumers are getting updates for these things. I'm using
"things" just to make it clear that this does not have to be software packages
which might be what first comes to mind.</p>
<p>Lets take a look what this might look like without TUF:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+     +---------------------+                      +----------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Producer  |     | Distribution server |                      | Consumer |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  |-----------+     |---------------------+                      |----------|</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | thing_v1  | --&gt; | thing_v1            | -------------------&gt; | thing_v1 |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+     +---------------------+                      +----------+</span><br></span></code></pre></div></div>
<p>So we have a producer that has something that it makes available to consumer's
via a distribution server. The consumer uses this thing by downloading it from
the distribution server in some manner. If the distribution server just allows
the consumer to poll and download the thing/artifact, then it will be up to the
consumer code to decide when it should poll to check for updates and update if
needed.</p>
<p>For example, lets say that a man in the middle (MITM) attack is put in place
and the consumer is no longer talking to the distribution server but instead
to server controlled by an attacker which provides the consumer with a malicious
artifacts:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+     +---------------------+     +----------+     +----------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Producer  |     | Distribution server |     | MITM     |     | Consumer |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  |-----------+     |---------------------+     |          |     |----------|</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | thing_v1  | --&gt; | thing_v1            |     | evil_v1  | --&gt; | thing_v1 |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+     +---------------------+     +----------+     +----------+</span><br></span></code></pre></div></div>
<p>An attacker may also target the distribution server itself and modify the
artifacts that the consumers download:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+     +---------------------+                      +----------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Producer  |     | Distribution server |                      | Consumer |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  |-----------+     |---------------------+                      |----------|</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | thing_v1  | --&gt; | thing_v1 (evil_v1)  | ------------------&gt;  | thing_v1 |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+     +---------------------+                      +----------+</span><br></span></code></pre></div></div>
<p>This type of attack is refered to as <code>Arbitary software installation</code>.</p>
<p>Another attack against the distribution server is where the attacker prevents
the consumer from getting updates, and instead provides the consumer with an
older version which might contain a known vulnerabilty.</p>
<p>This would be the current state where the correct/latest version is being used:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+     +---------------------+                      +----------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Producer  |     | Distribution server |                      | Consumer |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  |-----------+     |---------------------+                      |----------|</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | thing_v3  | --&gt; | thing_v3            | ------------------&gt;  | thing_v3 |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+     +---------------------+                      +----------+</span><br></span></code></pre></div></div>
<p>The attacker then changes the version on the distribution server to an older
version, causing the consumer to downgrade, or rollback to that version:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+     +---------------------+                      +----------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Producer  |     | Distribution server |                      | Consumer |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  |-----------+     |---------------------+                      |----------|</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | thing_v3  | --&gt; | thing_v2 (evil_v2)  | ------------------&gt;  | thing_v2 |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+     +---------------------+                      +----------+</span><br></span></code></pre></div></div>
<p>This type of attack is refered to as <code>Rollback attack</code>.</p>
<p>There are other <a href="https://theupdateframework.io/security/" target="_blank" rel="noopener noreferrer" class="">attacks</a> but these
I found helped me better understand the metadata that is provided by TUF.</p>
<p>A simplified overview of this can be seen below and I'm going into more
details later in the document.</p>
<p>What I'd like to convey with this is that the producer will update the TUF
repository by creating <code>metadata</code> about the artifact(s) that are going to be
made available. This metadata is signed by one or more keys.
The motivation for signing is that we want to prevent the situation above where
an attacker is able to replace an artifact with an older version, or a modified
version. Having the metadata signed for each version means that it would not be
possible for an attacker to do this as the TUF client framework will verify
signatures.</p>
<p>In TUF, the "distribution server" in the above scenarios will have a TUF
repository integrated into it. This repository will be updated by the producer,
and the consumer in the above scenarios will be replaced by a TUF client:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         +---------------------+               +------------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Producer  |         | TUF Repository      | &lt;-----------  | TUF Client       |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  |-----------+ update  |---------------------+               |------------------|</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | thing_v1  | ------&gt; | Metadata (signed)   | ------------&gt; | Metadata (signed)|</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         +---------------------+               +------------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                                ------------&gt; | thing_v1         |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                                              +------------------+</span><br></span></code></pre></div></div>
<p>Notice that in addition to the metadata that exists on the TUF repository there
is also metadata on the TUF consumer/client side. This metadata is downloaded
and frequently resigned, and it has an short expiration date. This is how the
TUF framework enforces updates actually take place. Because the TUF client
framework checks the expiration and the signature of the metadata file, it
can detect if the expiration date has passed. If there has not been any updates
and the expiration date has passed, perhaps a certain number of times, it can
take action to notify the client side software about this situation. This is how
TUF can enforce that updates actually get applied to the consumer.</p>
<p>This metadata is also signed as we don't want an attacker to be able to serve
the client with a metadata file they crafted themselves, which might have
enabled the attacker to trick the consumer into thinking that there are no
updates and force the consumer to be stuck on an older version.</p>
<p>Hopefully this has provided an overview and some idea about the metadata and
the signing in TUF. Later we will see a concrete example of the metadata files
to get "feel" for what they look like.</p>
<p>So, we have mentioned metadata files and signing. The following is an attempt
to visualize where the metadata files exist.</p>
<p>Initially, we would have the following metadata files:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         +---------------------+               +---------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Producer  |         | TUF Repository      |               | TUF Consumer  |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  |-----------+ update  |---------------------+               |---------------|</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Keys      | ------&gt; | Metadata            |               | Metadata      |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         | 1.root.json         |               | root.json     |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Metadata  |         | 1.targets.json      |               +---------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | root.json |         | 1.snapshot.json     |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         | timestamp.json      |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | thing_v1  |         +---------------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         | thing_v1            |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        +---------------------+</span><br></span></code></pre></div></div>
<p>Initially, before the client has interacted with the TUF repository, the client
has a trusted root.json metadata file. This file is shipped with the client and
it does not matter if it's expire date has passed, as it will get updated once
the client interacts with the TUF reporitory which is part of the client
<a href="https://theupdateframework.github.io/specification/latest/index.html#detailed-client-workflow" target="_blank" rel="noopener noreferrer" class="">workflow</a>
of TUF's specification.</p>
<p>The client starts by <a href="https://theupdateframework.github.io/specification/latest/index.html#load-trusted-root" target="_blank" rel="noopener noreferrer" class="">loading</a> this trusted root file.</p>
<p>Next, client proceeds to the <a href="https://theupdateframework.github.io/specification/latest/index.html#update-root" target="_blank" rel="noopener noreferrer" class="">download</a> &lt;version&gt;.root.json files from the TUF repository until it has
reached the latest:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         +---------------------+               +---------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Producer  |         | TUF Repository      | &lt;-----------  | TUF Consumer  |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  |-----------+ update  |---------------------+               |---------------|</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Keys      | ------&gt; | Metadata            | ------------&gt; | Metadata      |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         | 1.root.json         |               | root.json     |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Metadata  |         | 1.targets.json      |               +---------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | root.json |         | 1.snapshot.json     |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         | timestamp.json      |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | thing_v1  |         +---------------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         | thing_v1            |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        +---------------------+</span><br></span></code></pre></div></div>
<p>Notice that the root.json is written on the client side without the version
prefix. This will be used to verify the files that are download later.</p>
<p>Next, the client will <a href="https://theupdateframework.github.io/specification/latest/index.html#update-timestamp" target="_blank" rel="noopener noreferrer" class="">download</a> the timestamp metadata file:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         +---------------------+               +---------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Producer  |         | TUF Repository      | &lt;-----------  | TUF Consumer  |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  |-----------+ update  |---------------------+               |---------------|</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Keys      | ------&gt; | Metadata            | ------------&gt; | Metadata      |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         | 1.root.json         |               | root.json     |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Metadata  |         | 1.targets.json      |               | timestamp.json|</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | root.json |         | 1.snapshot.json     |               +---------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         | timestamp.json      |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | thing_v1  |         +---------------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         | thing_v1            |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        +---------------------+</span><br></span></code></pre></div></div>
<p>And there will number of verifications performed on timestamp.json.</p>
<p>Next, the client will <a href="https://theupdateframework.github.io/specification/latest/index.html#update-snapshot" target="_blank" rel="noopener noreferrer" class="">download</a> the snapshot metadata file:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         +---------------------+               +---------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Producer  |         | TUF Repository      | &lt;-----------  | TUF Consumer  |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  |-----------+ update  |---------------------+               |---------------|</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Keys      | ------&gt; | Metadata            | ------------&gt; | Metadata      |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         | 1.root.json         |               | root.json     |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Metadata  |         | 1.targets.json      |               | timestamp.json|</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | root.json |         | 1.snapshot.json     |               | snapshot.json |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         | timestamp.json      |               +---------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | thing_v1  |         +---------------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         | thing_v1            |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        +---------------------+</span><br></span></code></pre></div></div>
<p>And there will number of verifications performed on snapshot.json.</p>
<p>Next, the client will <a href="https://theupdateframework.github.io/specification/latest/index.html#update-targets" target="_blank" rel="noopener noreferrer" class="">download</a> the targets.json metadata file:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         +---------------------+               +---------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Producer  |         | TUF Repository      | &lt;-----------  | TUF Consumer  |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  |-----------+ update  |---------------------+               |---------------|</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Keys      | ------&gt; | Metadata            | ------------&gt; | Metadata      |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         | 1.root.json         |               | root.json     |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | Metadata  |         | 1.targets.json      |               | timestamp.json|</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | root.json |         | 1.snapshot.json     |               | snapshot.json |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         | timestamp.json      |               | targets.json  |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | thing_v1  |         +---------------------+               +---------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  +-----------+         | thing_v1            |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                        +---------------------+</span><br></span></code></pre></div></div>
<p>And there will number of verifications performed on targets.json.</p>
<p>Finally, the client will <a href="https://theupdateframework.github.io/specification/latest/index.html#fetch-target" target="_blank" rel="noopener noreferrer" class="">fetch</a> the actual target files, these are the actual artifacts.</p>
<p>The names of the metadata files are named after the four top level roles in TUF:</p>
<ul>
<li class=""><code>Root</code> Delegates trust to specific keys for all the other top level roles</li>
<li class=""><code>Target</code> Signs metadata for the target files</li>
<li class=""><code>Snapshot</code> Signs metadata about the latest version of targets metadata</li>
<li class=""><code>Timestamp</code> Signs metadata about the latest version of the snapshot metadata</li>
</ul>
<p>The following sections will take a closer look at these metadata files.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="root-metadata">Root Metadata<a href="https://trustification.io/blog/2023/01/31/tuf#root-metadata" class="hash-link" aria-label="Direct link to Root Metadata" title="Direct link to Root Metadata" translate="no">​</a></h4>
<p>Instead of having a single root key, there will often be multiple root keys
which are stored in different offline locations, meaning that they are not
accessible remotely. These are often hardware keys, like Yubikeys.</p>
<p>Root keys are often used together to sign other keys. These non-root keys can
then be re-signed/revoked/rotated if/when needed.</p>
<p>Each role has metadata associated with it, and the specification defines a
canonical json format for them. So there would be a root.json, a targets.json,
a, timestamps.json, and a snapshot.json.</p>
<p>So what do these file look like?</p>
<p>Lets try this out by using a tool called
<a href="https://github.com/awslabs/tough/tree/develop/tuftool" target="_blank" rel="noopener noreferrer" class="">tuftool</a>:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cargo install --force tuftool</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="root-metadata-1">Root metadata<a href="https://trustification.io/blog/2023/01/31/tuf#root-metadata-1" class="hash-link" aria-label="Direct link to Root metadata" title="Direct link to Root metadata" translate="no">​</a></h4>
<p>Next we initiate a new <code>root.json</code> file using the following command:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ tuftool root init root/root.json</span><br></span></code></pre></div></div>
<p>This command will generate a file named <code>root/root.json</code>:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat root/root.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "signed": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "_type": "root",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "spec_version": "1.0.0",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "consistent_snapshot": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "version": 1,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "expires": "2023-01-17T07:48:23Z",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "keys": {},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "roles": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "timestamp": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "keyids": [],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "threshold": 1507</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "root": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "keyids": [],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "threshold": 1507</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "snapshot": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "keyids": [],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "threshold": 1507</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "targets": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "keyids": [],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "threshold": 1507</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "signatures": []</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>These are just the default values, and we can see that there are no root keys,
that field is just an empty object, and notice that the roles are mainly empty
apart from the <code>threshold</code> values which is 1507. The threshold value specifies
the minimum number of keys required to sign that roles metadata. 1507 is a large
number of keys and we can change this to just requiring one key:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ tuftool root set-threshold root/root.json snapshot 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ tuftool root set-threshold root/root.json root 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ tuftool root set-threshold root/root.json timestamp 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ tuftool root set-threshold root/root.json targets 1</span><br></span></code></pre></div></div>
<p>And we can see that <code>root/root.json</code> has been updated:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat root/root.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "signed": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "_type": "root",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "spec_version": "1.0.0",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "consistent_snapshot": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "version": 1,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "expires": "2023-02-27T14:05:04Z",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "keys": {},</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "roles": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "root": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "keyids": [],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "threshold": 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "targets": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "keyids": [],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "threshold": 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "snapshot": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "keyids": [],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "threshold": 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "timestamp": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "keyids": [],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "threshold": 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "signatures": []</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>We can also set the expire time for the root using the following command:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ tuftool root expire root/root.json 'in 6 weeks'</span><br></span></code></pre></div></div>
<p>Now, to sign anything we will need a private key to create the signatures and
a matching public key to be used to verify signatures.</p>
<p>We can generate a root key and one can be generated using
<code>tuftool root gen-rsa-key</code>:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ tuftool root gen-rsa-key root/root.json ./keys/root.pem --role root</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">6e99ec437323f2c7334c8b16fd7a7a197829ba89ff50d07aa4b50fc9634dad9f</span><br></span></code></pre></div></div>
<p>This will generate keys/root.pem which is a private key in pkcs8 format. The
hex value printed above is the <code>key_id</code> which will be used later to reference
this key in metadata files.</p>
<p>Now, if we again inspect <code>root.json</code> we find that a key has been added:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat root/root.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "signed": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "_type": "root",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "spec_version": "1.0.0",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "consistent_snapshot": true,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "version": 1,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "expires": "2023-02-28T08:30:48Z",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "keys": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "6e99ec437323f2c7334c8b16fd7a7a197829ba89ff50d07aa4b50fc9634dad9f": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "keytype": "rsa",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "keyval": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5ZiWzak3CBJkRrCfw5GO\nSUtYjIK2jLozyaZ44FePW/KYEhM8LyHcNz9lwx45tZ8gId4AsxGBj9fhsOgjpN7l\nMPXpaKsV/5f37HzQLCrbldz3ei9LkMWG5La4Cwil0qPDpTxfzI7IWDKk6l4/epgi\nOrAJDaQ/mKhH5OZ485JYuDIE7a0jplU/GvsNeCdZVMEQ8dko/CA4Di8lPkDRRdSw\naC/8g3K6mF+87ADdGOmZ+LFodLEPvqIVljece2JlX2z44Io3N7Y5FH63Az4H3MFL\nDPZJH5lFs7Lb/fHx25rWSE2/GHcUUTs4oScPp2X0hAnblOsmCFSCjf8Kb0R7dLUb\nnQIDAQAB\n-----END PUBLIC KEY-----"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "scheme": "rsassa-pss-sha256"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "roles": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "timestamp": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "keyids": [],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "threshold": 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "targets": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "keyids": [],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "threshold": 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "root": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "keyids": [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "6e99ec437323f2c7334c8b16fd7a7a197829ba89ff50d07aa4b50fc9634dad9f"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "threshold": 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "snapshot": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "keyids": [],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "threshold": 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "signatures": []</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>Notice that the <code>keys</code> object has a field which is named after the <code>key_id</code> and
that the <code>root</code> role has this <code>key_id</code> in its <code>keyids</code> array. This <code>key_id</code> is
created from the json value of the fields <code>keytype</code>, <code>keyval</code>, and <code>scheme</code>,
which is then canonicalized before hashed using sha256. We can inspect/verify
this using a tool named <a href="https://github.com/danbev/tuf-keyid" target="_blank" rel="noopener noreferrer" class="">tuf-keyid</a>, and
passing in the above json field of the public key:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ tuf-keyid --json='{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "keytype": "rsa",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "keyval": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">              "public": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5ZiWzak3CBJkRrCfw5GO\nSUtYjIK2jLozyaZ44FePW/KYEhM8LyHcNz9lwx45tZ8gId4AsxGBj9fhsOgjpN7l\nMPXpaKsV/5f37HzQLCrbldz3ei9LkMWG5La4Cwil0qPDpTxfzI7IWDKk6l4/epgi\nOrAJDaQ/mKhH5OZ485JYuDIE7a0jplU/GvsNeCdZVMEQ8dko/CA4Di8lPkDRRdSw\naC/8g3K6mF+87ADdGOmZ+LFodLEPvqIVljece2JlX2z44Io3N7Y5FH63Az4H3MFL\nDPZJH5lFs7Lb/fHx25rWSE2/GHcUUTs4oScPp2X0hAnblOsmCFSCjf8Kb0R7dLUb\nnQIDAQAB\n-----END PUBLIC KEY-----"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            "scheme": "rsassa-pss-sha256"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">key_id: SHA256:6e99ec437323f2c7334c8b16fd7a7a197829ba89ff50d07aa4b50fc9634dad9f</span><br></span></code></pre></div></div>
<p>And we can see that the <code>key_id</code>'s produced are the same. This may be obvious
but just to be clear, <code>keys</code> only includes the public key.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="targets-metadata">Targets metadata<a href="https://trustification.io/blog/2023/01/31/tuf#targets-metadata" class="hash-link" aria-label="Direct link to Targets metadata" title="Direct link to Targets metadata" translate="no">​</a></h4>
<p>The Target role is a role that signs metadata files that describe the
project artifacts, like software packages, source code, or whatever artifacts
that are to be consumed by TUF clients/consumers.</p>
<p>So lets add a target key, and we will use the same private key as before:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ tuftool root add-key root/root.json ./keys/root.pem --role targets</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">6e99ec437323f2c7334c8b16fd7a7a197829ba89ff50d07aa4b50fc9634dad9f</span><br></span></code></pre></div></div>
<p>This will update the <code>targets</code> role in <code>root.json</code>:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ jq '.signed.roles.targets' &lt; root/root.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "keyids": [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "6e99ec437323f2c7334c8b16fd7a7a197829ba89ff50d07aa4b50fc9634dad9f"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "threshold": 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="snapshot-metadata">Snapshot metadata<a href="https://trustification.io/blog/2023/01/31/tuf#snapshot-metadata" class="hash-link" aria-label="Direct link to Snapshot metadata" title="Direct link to Snapshot metadata" translate="no">​</a></h4>
<p>The Snapshot roles signs a metadata file which contains information about the
latest version of the targets metadata. This is used to identify which versions
of a target are in a repository at a certain time. This is used to know if there
is an update available (remember it's call The Update Framework).</p>
<p>So, lets add a key to the snapshot role:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ tuftool root add-key root/root.json ./keys/root.pem --role snapshot</span><br></span></code></pre></div></div>
<p>And we can see that following change to <code>root.json</code>:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ jq '.signed.roles.snapshot' &lt; root/root.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "keyids": [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "6e99ec437323f2c7334c8b16fd7a7a197829ba89ff50d07aa4b50fc9634dad9f"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "threshold": 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="timestamp-metadata">Timestamp metadata<a href="https://trustification.io/blog/2023/01/31/tuf#timestamp-metadata" class="hash-link" aria-label="Direct link to Timestamp metadata" title="Direct link to Timestamp metadata" translate="no">​</a></h4>
<p>Finally, we have the timestamp role which tells if there is an update.</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ tuftool root add-key root/root.json ./keys/root.pem --role timestamp</span><br></span></code></pre></div></div>
<p>And we can see that following change to <code>root.json</code>:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ jq '.signed.roles.timestamp' &lt; root/root.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "keyids": [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "6e99ec437323f2c7334c8b16fd7a7a197829ba89ff50d07aa4b50fc9634dad9f"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "threshold": 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="signing-rootjson">Signing root.json<a href="https://trustification.io/blog/2023/01/31/tuf#signing-rootjson" class="hash-link" aria-label="Direct link to Signing root.json" title="Direct link to Signing root.json" translate="no">​</a></h4>
<p>So we have configured which keys to be used for each of the roles but we have
not signed this metadata file. We need to sign it to prevent tampering of it
as it will be sent to the TUF repository, usually on server but for this
example everything will be on the local file system.</p>
<p>We can now sign root.json using the following command:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ tuftool root sign ./root/root.json -k ./keys/root.pem</span><br></span></code></pre></div></div>
<p>And we can check <code>root.json</code> that the signatures field has been updated with
a keyid and a signature.</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain"> jq '.signatures' &lt; root/root.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "keyid": "6e99ec437323f2c7334c8b16fd7a7a197829ba89ff50d07aa4b50fc9634dad9f",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "sig": "8e7c7ca88e242ff360af30ba83e0ccfd9de2a9dee774166abe508ad2757620d6439bc7a5163c55867e069812a21ba31b7097d9ded3590f03f8bdc7106755a9ae840efbfe9b6c7d69e047230c59f3bd682e83f0b5b9c271d6db60943f7fa57d565790de58687560b50951a363725471c3a8f64c3980385eb214876bb1fe87d4aefc5cdd557bd022ddd794a52368f8502c1944185c75827ca97bba8fd5cdd5bb41b7ad76f0105072fbee980d3dbbf9889ec223ea1399228560fd747bc03a378d3ba93990560b000d02a59aab04844ec70662f8baaee33f8591f5bbe3126fb057f9b3055d498005220d1715c92166506995e89f2e8e62d1032452d51ba6579eb0e2"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">]</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="generate-the-tuf-repository">Generate the TUF repository<a href="https://trustification.io/blog/2023/01/31/tuf#generate-the-tuf-repository" class="hash-link" aria-label="Direct link to Generate the TUF repository" title="Direct link to Generate the TUF repository" translate="no">​</a></h4>
<p>With <code>root.json</code> and the private key we can generate a tuf repository using the
following command:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ tuftool create \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --root root/root.json \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --key keys/root.pem \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --add-targets artifacts \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --targets-expires 'in 3 weeks' \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --targets-version 1 \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --snapshot-expires 'in 3 weeks' \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --snapshot-version 1 \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --timestamp-expires 'in 1 week' \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --timestamp-version 1 \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  --outdir repo</span><br></span></code></pre></div></div>
<p>That command will create a directory named <code>repo</code> which contains two
directories, <code>metadata</code> and <code>targets</code>.</p>
<p>Let start by looking at the <code>targets</code> directory:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ ls -l repo/targets/01ab0faaf41a4543df1fa218b8e9f283d07536339cf11d2afae9d116a257700c.artifact_1.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">lrwxrwxrwx. 1 danielbevenius danielbevenius 79 Jan 17 12:50 repo/targets/01ab0faaf41a4543df1fa218b8e9f283d07536339cf11d2afae9d116a257700c.artifact_1.txt -&gt; artifacts/artifact_1.txt</span><br></span></code></pre></div></div>
<p>Notice that the name of this link is the sha256sum of the contents of
artifact_1.txt file:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ sha256sum  artifacts/artifact_1.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">01ab0faaf41a4543df1fa218b8e9f283d07536339cf11d2afae9d116a257700c  artifacts/artifact_1.txt</span><br></span></code></pre></div></div>
<p>And we can check the size of this file using:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ stat -c "%s" artifact_1.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">24</span><br></span></code></pre></div></div>
<p>The reason for showing this values is that they are referred to in the next
section.</p>
<p>Now, lets take a look at the <code>metadata</code> directory.</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ ls repo/metadata/</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">1.root.json  1.snapshot.json  1.targets.json  timestamp.json</span><br></span></code></pre></div></div>
<p>The number prefix is the version, to 1.targets.json is for version 1 for
example.</p>
<p>Lets start by looking at <code>targets.json</code>:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"signed"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"_type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"targets"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"spec_version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"1.0.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"expires"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"2023-02-07T11:50:00.608598188Z"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"targets"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"artifact_1.txt"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"length"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">24</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"hashes"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token property" style="color:#36acaa">"sha256"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"01ab0faaf41a4543df1fa218b8e9f283d07536339cf11d2afae9d116a257700c"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"delegations"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"keys"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"roles"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"signatures"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"keyid"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"6e99ec437323f2c7334c8b16fd7a7a197829ba89ff50d07aa4b50fc9634dad9f"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"sig"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"48b9810f275e16acb2d093c5487da4107f2312e0c9e084f6974aa836661a0e87d341be37fe84a4afd6ba82e8e54301e01a7431a0e69d3bef95ce3e34d90badff3c4a19ed7a6cea2a4ec69c6dc7392fde1f20b1246f3113ace85a223bfc54203a9254e82c8cd9686b8b973bfc41cdda657ff707a41c3db125b61dfc41c8937896f7fcc0ea17429a934b9c0fee912ca4df4a3b1dac6811968aa34bbf2d3327bbeab9cad1dadc1f8134c0add4267bf8ff285c066d24ea39b24d9bca197bf9762025133205612d41b167ee1232adf8c122320d77b70b936817ddf2cc93732228f772078b663f3fc896ec8873873414ba44fd3e28772589f69af06ee3e1297e0b2b37"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>Notice that the <code>hashes</code> object has a single field which is the sha256sum of
the file <code>artifacts_1.txt</code>, and that <code>length</code> matches the size which we showed
in the previous section.</p>
<p>We have information about the targets, in this case on a single file named
artifact_1.txt, and this is the file that a client wants to consume. This
metadata file is signed and the signature in the <code>sig</code> field of the
<code>signatures</code> array.</p>
<p>Again, this needs to be signed to prevent an attacker from modifying the targets
and modifying the <code>length</code>, and <code>sha256</code> fields which would otherwise allow them
to replace the target artifact with a potentially malicious version.</p>
<p>Next, lets take a look at the <code>snapshots.json</code> metadata file:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat repo/metadata/1.snapshot.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "signed": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "_type": "snapshot",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "spec_version": "1.0.0",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "version": 1,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "expires": "2023-02-07T11:50:00.608597347Z",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "meta": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "targets.json": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "length": 1048,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "hashes": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "sha256": "896781ff1260ed4ad5b05a004b034279219dc92b64068a2cc376604e8a6821c9"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "version": 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "signatures": [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "keyid": "6e99ec437323f2c7334c8b16fd7a7a197829ba89ff50d07aa4b50fc9634dad9f",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "sig": "5a8d9597329183c52547591d1abc8e36c1535d81c0e51ed51d95d2ddf1ec2076f2412ba8e631f039c7bf9e5a14cdd44eb7a5c7dae5dcc84e6aa2ebd51049ee791cf3c3dc486af26731fc06ba39e449ef85b102247c4254cb48784e4a95b54943df9e668470a6def79c7c3d532a68e93d18f1d59f1636455dddec0b5960afeb5a9ac38c38c6891e6f819f22aed7996a7f9964d655d634a940e1234f2015caa8f4f710570443bc0bc3ec04117c3dc97c8d564f42489cc499593f6232b7f5062646644aecafaf50dc9a4005a000f6720b0b9c455e5b92d7a1bcfb96f14a6a9da162e9b091497b0eb24283a837ba1d15ff67f12d104b1c5e1d83c36ae49400bb326e"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>So looking at the above <code>meta</code> field, we can see that there is a <code>targets.json</code>
"meta path". If we search for this file we won't be able to find it. The actual
file is prefixed with the version from the <code>version</code> field. So the file in
question is <code>repo/metadata/1.targets.json</code>, and we can check the size of this
file using:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ stat -c "%s" repo/metadata/1.targets.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">1048</span><br></span></code></pre></div></div>
<p>And that matches the <code>length</code> field above.</p>
<p>And we also can check the hash using:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ sha256sum repo/metadata/1.targets.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">896781ff1260ed4ad5b05a004b034279219dc92b64068a2cc376604e8a6821c9  repo/metadata/1.targets.json</span><br></span></code></pre></div></div>
<p>The snapshot metadata file tells us which versions of metadata files
existed for a specific version. Even though we only have one version currently
in our example, a real world repositories would have multiple versions of
metadata files. The purpose of the snapshot.json file is to prevent an attacker
from including metadata files from another version in some version:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">       TUF Repository              TUF Client</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     +----------------+           +----------------+</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     | timestamp.json | --------&gt; | timestamp.json |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     | 1.targets.json | version 3 | - version 3    |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     | 2.targets.json | &lt;-------  |                |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     | 3.targets.json | version 2 |                |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     |                | --------&gt; |                |</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     +----------------+           +----------------+kk</span><br></span></code></pre></div></div>
<p>The above is trying to show that the client has received a timestamp.json,
which we will discuss shortly, with a version number of 3. The client proceeds
to retrieve this version update from the TUF server. Now if an attacker was able
to include other metadata files, which are available in the TUF repository only
they are not part of the request version, it would be possible for them those
targets to be sent to the client.Having the <code>snapshot.json</code> prevents this as
it specifies which metadata files are included in a specific version and no
other additional metadata files that may exist in the TUF repository are
included.</p>
<p>So that leaves us with <code>timestamp.json</code>. This is a file that is downloaded by
the client and usually has a short expiration date. As mentioned before this is
the part that allows the system to enforce that updates are actually reaching
consumers, and if they are not they allow the consumer to take action.</p>
<p>The metadata looks like this:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat repo/metadata/timestamp.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "signed": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "_type": "timestamp",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "spec_version": "1.0.0",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "version": 1,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "expires": "2023-01-24T11:50:00.608598985Z",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "meta": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "snapshot.json": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "length": 1004,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "hashes": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          "sha256": "b92c443c21b6bc15d4f3991491e8bcb201f66a26ab289fb8cc9af7f851530872"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "version": 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "signatures": [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "keyid": "6e99ec437323f2c7334c8b16fd7a7a197829ba89ff50d07aa4b50fc9634dad9f",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "sig": "3708f055fe58b2c70e92cbc46bd9cc0f3149900bf25b3e924ff666eb8b45187df8d1f064b249cd790c170b5e97b322866d298d527ff950d2fbcbf508097868afca34ebaa159890799155c6bb615bab9a8bcfc34a39574584716d9a89b531fce97d876884fad2db69dc8f3569870dee280e87c9d506b5b08698e7c23e7dbbf4a3209fbc91ec764b54bf87367145cbb7bc9d7edaf47f709355284315fac9167312833d990e9e064852bb4fa905ec4edb5fe051480e70d505694528c5e9b47fefc3b78f6e54623f93344511326bdeec392a5eac31e7299bf9f602036d9f9524810eb03c4720370250f3e9f503e8d5bee94a6e6539ca9f988a27272d47612fd03436"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>Notice that <code>snapshot.json</code> is refering to the file <code>1.timestamp.json</code> in the
TUF repository.</p>
<p>Finally, we have repo/metadata/1.root.json which is identical to root/root.json
which we saw previously as this is the only version we have in our repository.</p>
<p>What we have been doing is setting up a repository which would be most often
exist on on a server somewhere.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="tuf-clientconsumer">TUF client/consumer<a href="https://trustification.io/blog/2023/01/31/tuf#tuf-clientconsumer" class="hash-link" aria-label="Direct link to TUF client/consumer" title="Direct link to TUF client/consumer" translate="no">​</a></h3>
<p>A consumer of the artifact would use a TUF client library to download the
artifacts, and would specify the metadata and targets to download.</p>
<p>To make this more concrete we have created a very basic <a href="https://github.com/danbev/tuf-client#readme" target="_blank" rel="noopener noreferrer" class="">example</a>
which is intended to show how one such client library, in this case
<a href="https://crates.io/crates/tough" target="_blank" rel="noopener noreferrer" class="">tough</a>, might be used. Please refer to the
example's README.md for details.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="tuf-usage-in-sigstore">TUF usage in Sigstore<a href="https://trustification.io/blog/2023/01/31/tuf#tuf-usage-in-sigstore" class="hash-link" aria-label="Direct link to TUF usage in Sigstore" title="Direct link to TUF usage in Sigstore" translate="no">​</a></h3>
<p>Armed with the above knowledge, lets take a look at how Sigstore uses TUF.</p>
<p>The <a href="https://github.com/sigstore/root-signing/tree/main/repository" target="_blank" rel="noopener noreferrer" class="">root-signing</a>
repository has a directory which contains the TUF repository metadata.</p>
<p>Sigstore uses TUF to protect their public keys and certificates, which was one
reason for trying to say "things" instead of software updates in the text above.
So the artifacts that are updated are public keys and certificates. As of this
writing these are the current <a href="https://github.com/sigstore/root-signing/blob/0ce4aa6c45c3ee709766d90e34c6b1372ad4b29a/repository/repository/targets.json" target="_blank" rel="noopener noreferrer" class="">targets</a>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">fulcio.crt.pem  Fulico (CA) certificate.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">rekor.pub       Rekor public key.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ctfe.pub        Certificate Transparency log public key used to verify</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                signed certificate timestamps.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">artifact.pub    Public key which is used to verify Sigstore releases, like</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                Cosign, Rekor, and Fulcio releases.</span><br></span></code></pre></div></div>
<p>There are more than four in the actual file but they are different versions. The
four listed here just explain the usage of these keys. In the case of
sigstore-rs only the Fulio certificate, and Rekor's public key are used. We will
focus on these in this post.</p>
<p>The <a href="https://github.com/sigstore/root-signing/blob/main/repository/repository/root.json" target="_blank" rel="noopener noreferrer" class="">root.json</a>
can also be found in the same directory and hopefully this should look familar
after seeing the root.json earlier.</p>
<p>We also learned earlier that the initial trusted <code>root.json</code> is shipped with the
software in some manner. In sigstore-rs, <code>root.json</code> is a constant named
<a href="https://github.com/sigstore/sigstore-rs/blob/8d22a6d23a6771688c8206850524a2b1076bbdb0/src/tuf/constants.rs#L30-L173" target="_blank" rel="noopener noreferrer" class="">SIGSTORE_ROOT</a> in the crate itself.</p>
<p>sigstore-rs uses the <code>tough</code> crate just like the example we saw earlier, and
similar to the <a href="https://github.com/danbev/tuf-client/blob/3adca52130c69f242ef24c5845c91ee1612fc64c/src/main.rs#L61" target="_blank" rel="noopener noreferrer" class="">example</a>, creates a tough <a href="https://github.com/sigstore/sigstore-rs/blob/cef673776548c9b268e0ce8ecc3a4fe2da504658/src/tuf/repository_helper.rs#L43" target="_blank" rel="noopener noreferrer" class="">RepositoryLoader</a> in a RepositoryHelper
struct. A RepositoryHelper is created in SigstoreRepository's
<a href="https://github.com/sigstore/sigstore-rs/blob/cef673776548c9b268e0ce8ecc3a4fe2da504658/src/tuf/mod.rs#L123" target="_blank" rel="noopener noreferrer" class="">fetch</a> method, and the <code>Fulcio certificate</code>, and <code>Rekor's public key</code> are read from
the repository, similar to how <code>artifact.txt</code> was read in the example:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> repository_helper </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">RepositoryHelper</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token constant" style="color:#36acaa">SIGSTORE_ROOT</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">as_bytes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        metadata_base</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        target_base</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        checkout_dir</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> fulcio_certs </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> repository_helper</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">fulcio_certs</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> rekor_pub_key </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> repository_helper</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">rekor_pub_key</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token closure-params">data</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">from_utf8</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map_err</span><span class="token punctuation" style="color:#393A34">(</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token closure-params">e</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">SigstoreError</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">UnexpectedError</span><span class="token punctuation" style="color:#393A34">(</span><span class="token macro property" style="color:#36acaa">format!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"Cannot parse Rekor's public key obtained from TUF repository: {}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                e</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>There is a caching layer in-between the call to <code>fulcio_certs</code> but after
that, and if there is a cache miss, the actual call the TUF repository can
be found in <a href="https://github.com/sigstore/sigstore-rs/blob/cef673776548c9b268e0ce8ecc3a4fe2da504658/src/tuf/repository_helper.rs#L158" target="_blank" rel="noopener noreferrer" class="">fetch_target</a>:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">/// Download a file from a TUF repository</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">fetch_target</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">repository</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token namespace" style="opacity:0.7">tough</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">Repository</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> target_name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">TargetName</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Result</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Vec</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">u8</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> data</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Vec</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">u8</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">match</span><span class="token plain"> repository</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">read_target</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">target_name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">None</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token class-name">Err</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">SigstoreError</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">TufTargetNotFoundError</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            target_name</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">raw</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">to_string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">Some</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">reader</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            data </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">read_to_end</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">reader</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name">Ok</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>And this is simliar to how in the example above we <a href="https://github.com/danbev/tuf-client/blob/3adca52130c69f242ef24c5845c91ee1612fc64c/src/main.rs#L69-L71" target="_blank" rel="noopener noreferrer" class="">downloaded</a> <code>artifact.txt</code> like this:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> artifact </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> repository</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">read_target</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token class-name">TargetName</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">from_str</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"artifact.txt"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">unwrap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">unwrap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>By using the TUF framework for Fulcio's certificate, and Rekor's public keys
these can be updated in a secure manner like described previously in this post.</p>]]></content>
        <author>
            <name>Daniel Bevenius</name>
            <uri>https://github.com/danbev</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Is this a cryptographic key which I see before me?]]></title>
        <id>https://trustification.io/blog/2023/01/25/keys</id>
        <link href="https://trustification.io/blog/2023/01/25/keys"/>
        <updated>2023-01-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Yes, it is. Really? Then what format is it in and how can I tell?]]></summary>
        <content type="html"><![CDATA[<p>Yes, it is. Really? Then what format is it in and how can I tell?</p>
<p>I've found myself in this situation a number of times and this post tries to
provide some guidelines for figuring out the type and format of keys without
having to go off and read some project's documentation.</p>
<p>To start off we can try to determine if the key is in a PEM format, or in
DER format.</p>
<p>Keys in PEM format are in ascii and can be inspected from the
command line using <code>cat</code>, or opened in any text editor. For example:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat pubkey.pem</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-----BEGIN PUBLIC KEY-----</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDTvL0PRsxoxMXfSaXu+7w0ovVNzZ</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">k/BAIoz2GL2cPY3qZENU/+YrR92AuZFXn0jSmmvOktpAzGhnDhtidonkyA==</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-----END PUBLIC KEY-----</span><br></span></code></pre></div></div>
<p>If we try the same with DER format then we will get a bunch of strange
characters printed. For example:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat pubkey.der</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">;���lƌL]��^��J/T�ٓ�@"����=��dCT��+G݀��W�HҚkΒ�@�hgv���$</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pem-formatted-keys">PEM formatted keys<a href="https://trustification.io/blog/2023/01/25/keys#pem-formatted-keys" class="hash-link" aria-label="Direct link to PEM formatted keys" title="Direct link to PEM formatted keys" translate="no">​</a></h2>
<p>So we have determined that the key we have in front of us is in PEM format.
Now, if we take a look at the PEM output above again:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">-----BEGIN PUBLIC KEY-----</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDTvL0PRsxoxMXfSaXu+7w0ovVNzZ</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">k/BAIoz2GL2cPY3qZENU/+YrR92AuZFXn0jSmmvOktpAzGhnDhtidonkyA==</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-----END PUBLIC KEY-----</span><br></span></code></pre></div></div>
<p>We can see that it has a header and the footer. Notice that there is no
information about the type of public key that this file contains. This means
that the information about the type of key in baked in there somewhere. So how
can we find out what the type of the key?<br>
<!-- -->One option is to use the <code>openssl asn1parse</code> command:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ openssl asn1parse -i  -in pubkey.pem</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    0:d=0  hl=2 l=  89 cons: SEQUENCE</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    2:d=1  hl=2 l=  19 cons:  SEQUENCE</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    4:d=2  hl=2 l=   7 prim:   OBJECT            :id-ecPublicKey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   13:d=2  hl=2 l=   8 prim:   OBJECT            :prime256v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   23:d=1  hl=2 l=  66 prim:  BIT STRING</span><br></span></code></pre></div></div>
<p>And we can see, that there is an id here which is <code>ecPublicKey</code>.</p>
<p>As a rule of thumb, if there is no key type in the PEM header, then
the format of the key is most probably in Subject Public Key Info (SPKI) if it
is a public key, and in Public-Key Cryptography Standard 8 (pkcs8) format if it
is a private key.</p>
<p>With the knowledge that the key is an Elliptic Curve (EC) public key we can use
the following openssl command to inspect it:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ openssl ec -pubin -in pubkey.pem --text --noout</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">read EC key</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Public-Key: (256 bit)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">pub:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    04:0d:3b:cb:d0:f4:6c:c6:8c:4c:5d:f4:9a:5e:ef:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    bb:c3:4a:2f:54:dc:d9:93:f0:40:22:8c:f6:18:bd:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    9c:3d:8d:ea:64:43:54:ff:e6:2b:47:dd:80:b9:91:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    57:9f:48:d2:9a:6b:ce:92:da:40:cc:68:67:0e:1b:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    62:76:89:e4:c8</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ASN1 OID: prime256v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">NIST CURVE: P-256</span><br></span></code></pre></div></div>
<p>Some PEM keys can also be in a specific key format, in which case the type is
in the header of the pem, for example:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">-----BEGIN RSA PUBLIC KEY-----</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-----END RSA PUBLIC KEY-----</span><br></span></code></pre></div></div>
<p>And if needed we can use the <code>openssl rsa</code> command to inspect them further.</p>
<p>The same reasoning can be applied to private keys as well with regards to the
PEM header/footer information, and in the case of private keys the <code>-pubin</code>
argument to the openssl commands should left out.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="der-formatted-keys">DER formatted keys<a href="https://trustification.io/blog/2023/01/25/keys#der-formatted-keys" class="hash-link" aria-label="Direct link to DER formatted keys" title="Direct link to DER formatted keys" translate="no">​</a></h2>
<p>As mentioned before we can't just print DER files as they are in binary format,
but we can still use <code>openssl asn1parse</code>:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ openssl asn1parse -i -inform der  -in pubkey.der</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    0:d=0  hl=2 l=  89 cons: SEQUENCE</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    2:d=1  hl=2 l=  19 cons:  SEQUENCE</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    4:d=2  hl=2 l=   7 prim:   OBJECT            :id-ecPublicKey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   13:d=2  hl=2 l=   8 prim:   OBJECT            :prime256v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   23:d=1  hl=2 l=  66 prim:  BIT STRING</span><br></span></code></pre></div></div>
<p>And just like with the PEM example we can use other openssl tools to inspect the
key.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="when-the-guidelines-fail">When the guidelines fail<a href="https://trustification.io/blog/2023/01/25/keys#when-the-guidelines-fail" class="hash-link" aria-label="Direct link to When the guidelines fail" title="Direct link to When the guidelines fail" translate="no">​</a></h2>
<p>The above seems to work for most situations, but it can fail.</p>
<p>One example of this is when openssl cannot parse the key at all. I ran into this
recently with <a href="https://github.com/in-toto/in-toto-rs" target="_blank" rel="noopener noreferrer" class="">in-toto-rs</a>, which uses
the Rust <a href="https://crates.io/crates/ring" target="_blank" rel="noopener noreferrer" class="">ring</a> crate to handle Ed25519 keys.</p>
<p>The issue here is that <code>ring</code> supports pkcs8 version 2
(<a href="https://www.rfc-editor.org/rfc/rfc5958" target="_blank" rel="noopener noreferrer" class="">RFC-5958</a>), and OpenSSL currently only
supports pkcs8 version 1 (<a href="https://www.rfc-editor.org/rfc/rfc5208" target="_blank" rel="noopener noreferrer" class="">RFC-5208</a>),
so the openssl tools will not be able to parse keys in the version 2 format.</p>
<p>Below is an example of trying to use a version 2 formatted Ed25519 key with
openssl:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ openssl pkey -inform der -in ed25519-1 -pubout</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Could not read key from ed25519-1</span><br></span></code></pre></div></div>
<p>There is an open <a href="https://github.com/openssl/openssl/issues/10468" target="_blank" rel="noopener noreferrer" class="">openssl issue</a>
for this.</p>
<p>Hopefully there will not be many cases like this, and we hope that the
guidelines provided in this post are helpful.</p>]]></content>
        <author>
            <name>Daniel Bevenius</name>
            <uri>https://github.com/danbev</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Sigstore bundle format]]></title>
        <id>https://trustification.io/blog/2023/01/13/sigstore-bundle-format</id>
        <link href="https://trustification.io/blog/2023/01/13/sigstore-bundle-format"/>
        <updated>2023-01-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[This post takes a look at Sigstore's bundle format which is the format of]]></summary>
        <content type="html"><![CDATA[<p>This post takes a look at Sigstore's bundle format which is the format of
Sigstore's offline verification data.</p>
<p>Offline verification is described like this in
<a href="https://www.chainguard.dev/unchained/busting-5-sigstore-myths" target="_blank" rel="noopener noreferrer" class="">busting-5-sigstore-myths</a>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Another common use case is that organizations need to run systems in air-gapped</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">environments with no outside network access. That means it’s not possible to</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">look up a signature in the transparency log, Rekor, right? Wrong! We use what’s</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">called "stapled inclusion proofs" by default, meaning you can verify an object</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">is present in the transparency log without needing to contact the transparency</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">log! The signer is responsible for gathering this evidence from the log and</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">presenting it alongside the artifact and signature. We store this in an OCI</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">image automatically, but you can treat it like a normal file and copy it around</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">for verification as well.</span><br></span></code></pre></div></div>
<p>So, lets create a bundle and inspect the contents. First, we need to sign an
artifact and in this case we are going to use a simple text file:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ echo "some data" &gt; artifact.txt</span><br></span></code></pre></div></div>
<p>As mentioned, Sigstore can create a <code>bundle</code>, which contains all the information
required for "stapled inclusion proofs". A bundle can be generated using the
following command:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ COSIGN_EXPERIMENTAL=1 cosign sign-blob --bundle=artifact.bundle artifact.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Using payload from: artifact.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Generating ephemeral keys...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Retrieving signed certificate...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Note that there may be personally identifiable information associated with this signed artifact.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        This may include the email address associated with the account with which you authenticate.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        This information will be used for signing this artifact and will be stored in public transparency logs and cannot be removed later.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        By typing 'y', you attest that you grant (or have permission to grant) and agree to have this information stored permanently in transparency logs.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Are you sure you want to continue? (y/[N]): y</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Your browser will now be opened to:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">https://oauth2.sigstore.dev/auth/auth?access_type=online&amp;client_id=sigstore&amp;code_challenge=gGdRPWHb4ZNnBjRIEs9wbBhI3bqVriOCyq2W98YuqQ0&amp;code_challenge_method=S256&amp;nonce=2KGHDNf4CZ4gXINF9A12quVVxHl&amp;redirect_uri=http%3A%2F%2Flocalhost%3A41711%2Fauth%2Fcallback&amp;response_type=code&amp;scope=openid+email&amp;state=2KGHDOhtlyDhCegsNy1qPuKAWbd</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Successfully verified SCT...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">using ephemeral certificate:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-----BEGIN CERTIFICATE-----</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">MIICpzCCAi6gAwIBAgIUb6LDCNlvHnUGD55dbYuRq9BEB7gwCgYIKoZIzj0EAwMw</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">NzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">cm1lZGlhdGUwHhcNMjMwMTEzMDcxMTIyWhcNMjMwMTEzMDcyMTIyWjAAMFkwEwYH</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">KoZIzj0CAQYIKoZIzj0DAQcDQgAEDTvL0PRsxoxMXfSaXu+7w0ovVNzZk/BAIoz2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">GL2cPY3qZENU/+YrR92AuZFXn0jSmmvOktpAzGhnDhtidonkyKOCAU0wggFJMA4G</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUdZPv</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Pd5abMkW8mcBgb3umAmHTcUwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ZD8wJwYDVR0RAQH/BB0wG4EZZGFuaWVsLmJldmVuaXVzQGdtYWlsLmNvbTAsBgor</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">BgEEAYO/MAEBBB5odHRwczovL2dpdGh1Yi5jb20vbG9naW4vb2F1dGgwgYoGCisG</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">AQQB1nkCBAIEfAR6AHgAdgDdPTBqxscRMmMZHhyZZzcCokpeuN48rf+HinKALynu</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">jgAAAYWp+AiYAAAEAwBHMEUCIAlfL870WJta7pD97Yiw0JbvY7YGg604cGxXEXtQ</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">tzoaAiEA+VWQiz+JPEsLBLbtclfhXFhn/C4kTyaS2Fj12+voTt4wCgYIKoZIzj0E</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">AwMDZwAwZAIwUtBB+1H6177KW3nfTpK9unSGgwIPEuNqQviJyeZRjkK85pnfk0p5</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">lwQVbfekXYq+AjBgJA/xjX5+UqRh+O1LqxBIun1gYhIwK+UUZq49SH0uP2sQL5un</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ILHOPrBw0f00Q68=</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-----END CERTIFICATE-----</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">tlog entry created with index: 11074687</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Bundle wrote in the file artifact.bundle</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">MEUCIBbfVr0rREgk2yXfENMzTduXnSRc2GkJEUOb5tBncFgSAiEAtC4f1CA4Yio9N3wjdMAbY6hCerCKwyM+hn8L1kn33GE=</span><br></span></code></pre></div></div>
<p>After this there will be an file named <code>artifact.bundle</code> in the directory where
the above command was executed.</p>
<p>So lets take a look at the bundle:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat artifact.bundle | jq</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "base64Signature": "MEUCIBbfVr0rREgk2yXfENMzTduXnSRc2GkJEUOb5tBncFgSAiEAtC4f1CA4Yio9N3wjdMAbY6hCerCKwyM+hn8L1kn33GE=",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "cert": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNwekNDQWk2Z0F3SUJBZ0lVYjZMRENObHZIblVHRDU1ZGJZdVJxOUJFQjdnd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpNd01URXpNRGN4TVRJeVdoY05Nak13TVRFek1EY3lNVEl5V2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVEVHZMMFBSc3hveE1YZlNhWHUrN3cwb3ZWTnpaay9CQUlvejIKR0wyY1BZM3FaRU5VLytZclI5MkF1WkZYbjBqU21tdk9rdHBBekdobkRodGlkb25reUtPQ0FVMHdnZ0ZKTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWRCZ05WSFE0RUZnUVVkWlB2ClBkNWFiTWtXOG1jQmdiM3VtQW1IVGNVd0h3WURWUjBqQkJnd0ZvQVUzOVBwejFZa0VaYjVxTmpwS0ZXaXhpNFkKWkQ4d0p3WURWUjBSQVFIL0JCMHdHNEVaWkdGdWFXVnNMbUpsZG1WdWFYVnpRR2R0WVdsc0xtTnZiVEFzQmdvcgpCZ0VFQVlPL01BRUJCQjVvZEhSd2N6b3ZMMmRwZEdoMVlpNWpiMjB2Ykc5bmFXNHZiMkYxZEdnd2dZb0dDaXNHCkFRUUIxbmtDQkFJRWZBUjZBSGdBZGdEZFBUQnF4c2NSTW1NWkhoeVpaemNDb2twZXVONDhyZitIaW5LQUx5bnUKamdBQUFZV3ArQWlZQUFBRUF3QkhNRVVDSUFsZkw4NzBXSnRhN3BEOTdZaXcwSmJ2WTdZR2c2MDRjR3hYRVh0UQp0em9hQWlFQStWV1FpeitKUEVzTEJMYnRjbGZoWEZobi9DNGtUeWFTMkZqMTIrdm9UdDR3Q2dZSUtvWkl6ajBFCkF3TURad0F3WkFJd1V0QkIrMUg2MTc3S1czbmZUcEs5dW5TR2d3SVBFdU5xUXZpSnllWlJqa0s4NXBuZmswcDUKbHdRVmJmZWtYWXErQWpCZ0pBL3hqWDUrVXFSaCtPMUxxeEJJdW4xZ1loSXdLK1VVWnE0OVNIMHVQMnNRTDV1bgpJTEhPUHJCdzBmMDBRNjg9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "rekorBundle": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "SignedEntryTimestamp": "MEUCIQDYiu9WHR4eCJ2JGPCfwWYg/lILIM+9IvDEb3Nq2MYIUAIgK2tRLSYDLuU0uaywKy8C+3ETUBKfw1lds4Q4Bw4l8jQ=",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "Payload": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI1YWEwM2Y5NmM3NzUzNjU3OTE2NmZiYTE0NzkyOTYyNmNjM2E5Nzk2MGU5OTQwNTdhOWQ4MDI3MWE3MzZkMTBmIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJQmJmVnIwclJFZ2syeVhmRU5NelRkdVhuU1JjMkdrSkVVT2I1dEJuY0ZnU0FpRUF0QzRmMUNBNFlpbzlOM3dqZE1BYlk2aENlckNLd3lNK2huOEwxa24zM0dFPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVTndla05EUVdrMlowRjNTVUpCWjBsVllqWk1SRU5PYkhaSWJsVkhSRFUxWkdKWmRWSnhPVUpGUWpkbmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcE5kMDFVUlhwTlJHTjRUVlJKZVZkb1kwNU5hazEzVFZSRmVrMUVZM2xOVkVsNVYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZFVkhaTU1GQlNjM2h2ZUUxWVpsTmhXSFVyTjNjd2IzWldUbnBhYXk5Q1FVbHZlaklLUjB3eVkxQlpNM0ZhUlU1Vkx5dFpjbEk1TWtGMVdrWlliakJxVTIxdGRrOXJkSEJCZWtkb2JrUm9kR2xrYjI1cmVVdFBRMEZWTUhkblowWktUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlZrV2xCMkNsQmtOV0ZpVFd0WE9HMWpRbWRpTTNWdFFXMUlWR05WZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDBwM1dVUldVakJTUVZGSUwwSkNNSGRITkVWYVdrZEdkV0ZYVm5OTWJVcHNaRzFXZFdGWVZucFJSMlIwV1Zkc2MweHRUblppVkVGelFtZHZjZ3BDWjBWRlFWbFBMMDFCUlVKQ1FqVnZaRWhTZDJONmIzWk1NbVJ3WkVkb01WbHBOV3BpTWpCMllrYzVibUZYTkhaaU1rWXhaRWRuZDJkWmIwZERhWE5IQ2tGUlVVSXhibXREUWtGSlJXWkJValpCU0dkQlpHZEVaRkJVUW5GNGMyTlNUVzFOV2tob2VWcGFlbU5EYjJ0d1pYVk9ORGh5Wml0SWFXNUxRVXg1Ym5VS2FtZEJRVUZaVjNBclFXbFpRVUZCUlVGM1FraE5SVlZEU1VGc1prdzROekJYU25SaE4zQkVPVGRaYVhjd1NtSjJXVGRaUjJjMk1EUmpSM2hZUlZoMFVRcDBlbTloUVdsRlFTdFdWMUZwZWl0S1VFVnpURUpNWW5SamJHWm9XRVpvYmk5RE5HdFVlV0ZUTWtacU1USXJkbTlVZERSM1EyZFpTVXR2V2tsNmFqQkZDa0YzVFVSYWQwRjNXa0ZKZDFWMFFrSXJNVWcyTVRjM1MxY3pibVpVY0VzNWRXNVRSMmQzU1ZCRmRVNXhVWFpwU25sbFdsSnFhMHM0TlhCdVptc3djRFVLYkhkUlZtSm1aV3RZV1hFclFXcENaMHBCTDNocVdEVXJWWEZTYUN0UE1VeHhlRUpKZFc0eFoxbG9TWGRMSzFWVlduRTBPVk5JTUhWUU1uTlJURFYxYmdwSlRFaFBVSEpDZHpCbU1EQlJOamc5Q2kwdExTMHRSVTVFSUVORlVsUkpSa2xEUVZSRkxTMHRMUzBLIn19fX0=",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "integratedTime": 1673593883,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "logIndex": 11074687,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "logID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>So we have a json object with three fields, a <code>base64Signature</code>, a <code>cert</code>, and
a <code>rekorBundle</code> field.</p>
<p>Lets start with <code>base64Signature</code> field:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat artifact.bundle | jq '.base64Signature'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">"MEUCIBbfVr0rREgk2yXfENMzTduXnSRc2GkJEUOb5tBncFgSAiEAtC4f1CA4Yio9N3wjdMAbY6hCerCKwyM+hn8L1kn33GE="</span><br></span></code></pre></div></div>
<p>As the name of this field implies it contains a base64 encoded signature.</p>
<p>Lets be decode the signature and store it in a file:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat artifact.bundle | jq -r '.base64Signature' | base64 -d - &gt; signature</span><br></span></code></pre></div></div>
<p>We will use this file shortly.</p>
<p>The <code>cert</code> field contains a base64 encoded certificate in pem format:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat artifact.bundle | jq -r '.rekorBundle.Payload.body' | base64 -d - | jq -r '.spec.signature.publicKey.content' | base64 -d -</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-----BEGIN CERTIFICATE-----</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">MIICpzCCAi6gAwIBAgIUb6LDCNlvHnUGD55dbYuRq9BEB7gwCgYIKoZIzj0EAwMw</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">NzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">cm1lZGlhdGUwHhcNMjMwMTEzMDcxMTIyWhcNMjMwMTEzMDcyMTIyWjAAMFkwEwYH</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">KoZIzj0CAQYIKoZIzj0DAQcDQgAEDTvL0PRsxoxMXfSaXu+7w0ovVNzZk/BAIoz2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">GL2cPY3qZENU/+YrR92AuZFXn0jSmmvOktpAzGhnDhtidonkyKOCAU0wggFJMA4G</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUdZPv</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Pd5abMkW8mcBgb3umAmHTcUwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ZD8wJwYDVR0RAQH/BB0wG4EZZGFuaWVsLmJldmVuaXVzQGdtYWlsLmNvbTAsBgor</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">BgEEAYO/MAEBBB5odHRwczovL2dpdGh1Yi5jb20vbG9naW4vb2F1dGgwgYoGCisG</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">AQQB1nkCBAIEfAR6AHgAdgDdPTBqxscRMmMZHhyZZzcCokpeuN48rf+HinKALynu</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">jgAAAYWp+AiYAAAEAwBHMEUCIAlfL870WJta7pD97Yiw0JbvY7YGg604cGxXEXtQ</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">tzoaAiEA+VWQiz+JPEsLBLbtclfhXFhn/C4kTyaS2Fj12+voTt4wCgYIKoZIzj0E</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">AwMDZwAwZAIwUtBB+1H6177KW3nfTpK9unSGgwIPEuNqQviJyeZRjkK85pnfk0p5</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">lwQVbfekXYq+AjBgJA/xjX5+UqRh+O1LqxBIun1gYhIwK+UUZq49SH0uP2sQL5un</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ILHOPrBw0f00Q68=</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-----END CERTIFICATE-----</span><br></span></code></pre></div></div>
<p>We can inspect this certificate using openssl:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat artifact.bundle | jq -r '.rekorBundle.Payload.body' | base64 -d - | jq -r '.spec.signature.publicKey.content' | base64 -d - | openssl x509 -text</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Certificate:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Data:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Version: 3 (0x2)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Serial Number:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            6f:a2:c3:08:d9:6f:1e:75:06:0f:9e:5d:6d:8b:91:ab:d0:44:07:b8</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Signature Algorithm: ecdsa-with-SHA384</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Issuer: O = sigstore.dev, CN = sigstore-intermediate</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Validity</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            Not Before: Jan 13 07:11:22 2023 GMT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            Not After : Jan 13 07:21:22 2023 GMT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Subject:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        Subject Public Key Info:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            Public Key Algorithm: id-ecPublicKey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                Public-Key: (256 bit)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                pub:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    04:0d:3b:cb:d0:f4:6c:c6:8c:4c:5d:f4:9a:5e:ef:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    bb:c3:4a:2f:54:dc:d9:93:f0:40:22:8c:f6:18:bd:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    9c:3d:8d:ea:64:43:54:ff:e6:2b:47:dd:80:b9:91:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    57:9f:48:d2:9a:6b:ce:92:da:40:cc:68:67:0e:1b:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    62:76:89:e4:c8</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                ASN1 OID: prime256v1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                NIST CURVE: P-256</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        X509v3 extensions:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            X509v3 Key Usage: critical</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                Digital Signature</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            X509v3 Extended Key Usage:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                Code Signing</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            X509v3 Subject Key Identifier:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                75:93:EF:3D:DE:5A:6C:C9:16:F2:67:01:81:BD:EE:98:09:87:4D:C5</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            X509v3 Authority Key Identifier:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                keyid:DF:D3:E9:CF:56:24:11:96:F9:A8:D8:E9:28:55:A2:C6:2E:18:64:3F</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            X509v3 Subject Alternative Name: critical</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                email:daniel.bevenius@gmail.com</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            1.3.6.1.4.1.57264.1.1:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                https://github.com/login/oauth</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            CT Precertificate SCTs:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                Signed Certificate Timestamp:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    Version   : v1 (0x0)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    Log ID    : DD:3D:30:6A:C6:C7:11:32:63:19:1E:1C:99:67:37:02:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                A2:4A:5E:B8:DE:3C:AD:FF:87:8A:72:80:2F:29:EE:8E</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    Timestamp : Jan 13 07:11:22.776 2023 GMT</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    Extensions: none</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                    Signature : ecdsa-with-SHA256</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                30:45:02:20:09:5F:2F:CE:F4:58:9B:5A:EE:90:FD:ED:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                88:B0:D0:96:EF:63:B6:06:83:AD:38:70:6C:57:11:7B:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                50:B7:3A:1A:02:21:00:F9:55:90:8B:3F:89:3C:4B:0B:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                04:B6:ED:72:57:E1:5C:58:67:FC:2E:24:4F:26:92:D8:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                                58:F5:DB:EB:E8:4E:DE</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Signature Algorithm: ecdsa-with-SHA384</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         30:64:02:30:52:d0:41:fb:51:fa:d7:be:ca:5b:79:df:4e:92:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         bd:ba:74:86:83:02:0f:12:e3:6a:42:f8:89:c9:e6:51:8e:42:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         bc:e6:99:df:93:4a:79:97:04:15:6d:f7:a4:5d:8a:be:02:30:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         60:24:0f:f1:8d:7e:7e:52:a4:61:f8:ed:4b:ab:10:48:ba:7d:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         60:62:12:30:2b:e5:14:66:ae:3d:48:7d:2e:3f:6b:10:2f:9b:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         a7:20:b1:ce:3e:b0:70:d1:fd:34:43:af</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-----BEGIN CERTIFICATE-----</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">MIICpzCCAi6gAwIBAgIUb6LDCNlvHnUGD55dbYuRq9BEB7gwCgYIKoZIzj0EAwMw</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">NzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">cm1lZGlhdGUwHhcNMjMwMTEzMDcxMTIyWhcNMjMwMTEzMDcyMTIyWjAAMFkwEwYH</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">KoZIzj0CAQYIKoZIzj0DAQcDQgAEDTvL0PRsxoxMXfSaXu+7w0ovVNzZk/BAIoz2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">GL2cPY3qZENU/+YrR92AuZFXn0jSmmvOktpAzGhnDhtidonkyKOCAU0wggFJMA4G</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUdZPv</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Pd5abMkW8mcBgb3umAmHTcUwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ZD8wJwYDVR0RAQH/BB0wG4EZZGFuaWVsLmJldmVuaXVzQGdtYWlsLmNvbTAsBgor</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">BgEEAYO/MAEBBB5odHRwczovL2dpdGh1Yi5jb20vbG9naW4vb2F1dGgwgYoGCisG</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">AQQB1nkCBAIEfAR6AHgAdgDdPTBqxscRMmMZHhyZZzcCokpeuN48rf+HinKALynu</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">jgAAAYWp+AiYAAAEAwBHMEUCIAlfL870WJta7pD97Yiw0JbvY7YGg604cGxXEXtQ</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">tzoaAiEA+VWQiz+JPEsLBLbtclfhXFhn/C4kTyaS2Fj12+voTt4wCgYIKoZIzj0E</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">AwMDZwAwZAIwUtBB+1H6177KW3nfTpK9unSGgwIPEuNqQviJyeZRjkK85pnfk0p5</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">lwQVbfekXYq+AjBgJA/xjX5+UqRh+O1LqxBIun1gYhIwK+UUZq49SH0uP2sQL5un</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ILHOPrBw0f00Q68=</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-----END CERTIFICATE-----</span><br></span></code></pre></div></div>
<p>Lets store the certificate in a file, and extract the public key:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat artifact.bundle | jq -r '.rekorBundle.Payload.body' | base64 -d - | jq -r '.spec.signature.publicKey.content' | base64 -d -  &gt; cert.pem</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ openssl x509 -pubkey -noout -in cert.pem  &gt; pub.pem</span><br></span></code></pre></div></div>
<p>With those files, the <code>signature</code>, the <code>public key</code>, and the <code>blob</code> we should be
able to verify the signature from the <code>base64Signature</code> field using the
following command:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ openssl dgst -verify pub.pem -keyform PEM -sha256 -signature signature -binary artifact.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Verified OK</span><br></span></code></pre></div></div>
<p>The motivation of doing that was to show that the <code>base64Signature</code> is just the
signature of the blob.</p>
<p>Next, lets take a look at the <code>rekorBundle</code> field:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat artifact.bundle | jq -r '.rekorBundle' |  jq '.'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "SignedEntryTimestamp": "MEUCIQDYiu9WHR4eCJ2JGPCfwWYg/lILIM+9IvDEb3Nq2MYIUAIgK2tRLSYDLuU0uaywKy8C+3ETUBKfw1lds4Q4Bw4l8jQ=",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "Payload": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI1YWEwM2Y5NmM3NzUzNjU3OTE2NmZiYTE0NzkyOTYyNmNjM2E5Nzk2MGU5OTQwNTdhOWQ4MDI3MWE3MzZkMTBmIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJQmJmVnIwclJFZ2syeVhmRU5NelRkdVhuU1JjMkdrSkVVT2I1dEJuY0ZnU0FpRUF0QzRmMUNBNFlpbzlOM3dqZE1BYlk2aENlckNLd3lNK2huOEwxa24zM0dFPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVTndla05EUVdrMlowRjNTVUpCWjBsVllqWk1SRU5PYkhaSWJsVkhSRFUxWkdKWmRWSnhPVUpGUWpkbmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcE5kMDFVUlhwTlJHTjRUVlJKZVZkb1kwNU5hazEzVFZSRmVrMUVZM2xOVkVsNVYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZFVkhaTU1GQlNjM2h2ZUUxWVpsTmhXSFVyTjNjd2IzWldUbnBhYXk5Q1FVbHZlaklLUjB3eVkxQlpNM0ZhUlU1Vkx5dFpjbEk1TWtGMVdrWlliakJxVTIxdGRrOXJkSEJCZWtkb2JrUm9kR2xrYjI1cmVVdFBRMEZWTUhkblowWktUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlZrV2xCMkNsQmtOV0ZpVFd0WE9HMWpRbWRpTTNWdFFXMUlWR05WZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDBwM1dVUldVakJTUVZGSUwwSkNNSGRITkVWYVdrZEdkV0ZYVm5OTWJVcHNaRzFXZFdGWVZucFJSMlIwV1Zkc2MweHRUblppVkVGelFtZHZjZ3BDWjBWRlFWbFBMMDFCUlVKQ1FqVnZaRWhTZDJONmIzWk1NbVJ3WkVkb01WbHBOV3BpTWpCMllrYzVibUZYTkhaaU1rWXhaRWRuZDJkWmIwZERhWE5IQ2tGUlVVSXhibXREUWtGSlJXWkJValpCU0dkQlpHZEVaRkJVUW5GNGMyTlNUVzFOV2tob2VWcGFlbU5EYjJ0d1pYVk9ORGh5Wml0SWFXNUxRVXg1Ym5VS2FtZEJRVUZaVjNBclFXbFpRVUZCUlVGM1FraE5SVlZEU1VGc1prdzROekJYU25SaE4zQkVPVGRaYVhjd1NtSjJXVGRaUjJjMk1EUmpSM2hZUlZoMFVRcDBlbTloUVdsRlFTdFdWMUZwZWl0S1VFVnpURUpNWW5SamJHWm9XRVpvYmk5RE5HdFVlV0ZUTWtacU1USXJkbTlVZERSM1EyZFpTVXR2V2tsNmFqQkZDa0YzVFVSYWQwRjNXa0ZKZDFWMFFrSXJNVWcyTVRjM1MxY3pibVpVY0VzNWRXNVRSMmQzU1ZCRmRVNXhVWFpwU25sbFdsSnFhMHM0TlhCdVptc3djRFVLYkhkUlZtSm1aV3RZV1hFclFXcENaMHBCTDNocVdEVXJWWEZTYUN0UE1VeHhlRUpKZFc0eFoxbG9TWGRMSzFWVlduRTBPVk5JTUhWUU1uTlJURFYxYmdwSlRFaFBVSEpDZHpCbU1EQlJOamc5Q2kwdExTMHRSVTVFSUVORlVsUkpSa2xEUVZSRkxTMHRMUzBLIn19fX0=",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "integratedTime": 1673593883,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "logIndex": 11074687,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "logID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p><code>SignedEntryTimestamp</code> is a signature of the <code>logIndex</code>, the <code>body</code>, and the
<code>integratedTime</code> time fields created by Rekor. We can inspect the Rekor log
entry to verify:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ curl --silent https://rekor.sigstore.dev/api/v1/log/entries?logIndex=11074687 | jq -r '.[]'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI1YWEwM2Y5NmM3NzUzNjU3OTE2NmZiYTE0NzkyOTYyNmNjM2E5Nzk2MGU5OTQwNTdhOWQ4MDI3MWE3MzZkMTBmIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJQmJmVnIwclJFZ2syeVhmRU5NelRkdVhuU1JjMkdrSkVVT2I1dEJuY0ZnU0FpRUF0QzRmMUNBNFlpbzlOM3dqZE1BYlk2aENlckNLd3lNK2huOEwxa24zM0dFPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVTndla05EUVdrMlowRjNTVUpCWjBsVllqWk1SRU5PYkhaSWJsVkhSRFUxWkdKWmRWSnhPVUpGUWpkbmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcE5kMDFVUlhwTlJHTjRUVlJKZVZkb1kwNU5hazEzVFZSRmVrMUVZM2xOVkVsNVYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZFVkhaTU1GQlNjM2h2ZUUxWVpsTmhXSFVyTjNjd2IzWldUbnBhYXk5Q1FVbHZlaklLUjB3eVkxQlpNM0ZhUlU1Vkx5dFpjbEk1TWtGMVdrWlliakJxVTIxdGRrOXJkSEJCZWtkb2JrUm9kR2xrYjI1cmVVdFBRMEZWTUhkblowWktUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlZrV2xCMkNsQmtOV0ZpVFd0WE9HMWpRbWRpTTNWdFFXMUlWR05WZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDBwM1dVUldVakJTUVZGSUwwSkNNSGRITkVWYVdrZEdkV0ZYVm5OTWJVcHNaRzFXZFdGWVZucFJSMlIwV1Zkc2MweHRUblppVkVGelFtZHZjZ3BDWjBWRlFWbFBMMDFCUlVKQ1FqVnZaRWhTZDJONmIzWk1NbVJ3WkVkb01WbHBOV3BpTWpCMllrYzVibUZYTkhaaU1rWXhaRWRuZDJkWmIwZERhWE5IQ2tGUlVVSXhibXREUWtGSlJXWkJValpCU0dkQlpHZEVaRkJVUW5GNGMyTlNUVzFOV2tob2VWcGFlbU5EYjJ0d1pYVk9ORGh5Wml0SWFXNUxRVXg1Ym5VS2FtZEJRVUZaVjNBclFXbFpRVUZCUlVGM1FraE5SVlZEU1VGc1prdzROekJYU25SaE4zQkVPVGRaYVhjd1NtSjJXVGRaUjJjMk1EUmpSM2hZUlZoMFVRcDBlbTloUVdsRlFTdFdWMUZwZWl0S1VFVnpURUpNWW5SamJHWm9XRVpvYmk5RE5HdFVlV0ZUTWtacU1USXJkbTlVZERSM1EyZFpTVXR2V2tsNmFqQkZDa0YzVFVSYWQwRjNXa0ZKZDFWMFFrSXJNVWcyTVRjM1MxY3pibVpVY0VzNWRXNVRSMmQzU1ZCRmRVNXhVWFpwU25sbFdsSnFhMHM0TlhCdVptc3djRFVLYkhkUlZtSm1aV3RZV1hFclFXcENaMHBCTDNocVdEVXJWWEZTYUN0UE1VeHhlRUpKZFc0eFoxbG9TWGRMSzFWVlduRTBPVk5JTUhWUU1uTlJURFYxYmdwSlRFaFBVSEpDZHpCbU1EQlJOamc5Q2kwdExTMHRSVTVFSUVORlVsUkpSa2xEUVZSRkxTMHRMUzBLIn19fX0=",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "integratedTime": 1673593883,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "logID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "logIndex": 11074687,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "verification": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "inclusionProof": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "checkpoint": "rekor.sigstore.dev - 2605736670972794746\n6915767\nIDKYzW3/yaZoFrPpz2HKEReyArFz47FmWC3Z9REfsCY=\nTimestamp: 1673599771028600100\n\n— rekor.sigstore.dev wNI9ajBFAiBcmpywRj3UZCOMIzwlHzd5eNYEG1rQgX5VKhHAqM49iQIhAPxul/hYfn7wHRCh8/LTXFpLbB3vieU4mqLEPZSUdX4L\n",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "hashes": [</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "e5871beb5d6ffc577b31f4b0f14763adb1a231d52f2f15dd8c44f4925e402d1d",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "1d2962738aaebe76a8497de8615fadb0b8a52db957ccfb37b87719131abb53bd",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "62c6f1d6610f123395faffd632dc853f682a7f1bd93e36c08e53f8591b2b50d7",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "c1bb29369643451e47467ce1293a981ee4bd00a019a0a5bf77dacfd0aa15eff7",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "fec4c3b5bfb7783f8eee0e83af6e781f49825efb515bd70b2745b4d15b0b56f5",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "aaee4f535cb2dca6853ab13d2f2eda182dd72aa708824d6281182009763e753e",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "22430b589e10029a924c4ec50a96b51fa0aff8b461b205dc9e02d3eb588bcd98",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "067da42bda7c3c476cbd160a7df567266e3c4788d38d214b44774907a1e1bd27",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "2269e80ae081e893a5e7a6350826b29bdf890afa397110c632910acf895e7a26",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "7c4a791951a23906049a3060ac3f29e571df225f0d7eadeb5417dff7631c8cec",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "3648d28ef4842a998b3f22755750e99a81a74d6567166831e325f044cde6162b",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "0cd1da2cb04f7956568f32c500bad03be8a022faa50f393c185ac5ac201f3339",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "a14a3e23a363f496dc96a3061d454e1f0629ea94c0664991d4e5eab4d29306cb",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "4c00279b889607cf1f98294f05dc3f10ffecd2a87df4af3e4360a039ff3421c9",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "35da85b3d8a823b9040af497f298dc7c517236e78a98b1b426251b9ecde33628",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "9d57b977c2a8ebeb68d127df7be605c849c732275a0b05db00264a59f4ca0834",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "9eb0417210c64dcc971f58268b5aaa968ce2c2d200c41b346f50a100728ebc72",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "e7d67f5102ddeda58eda651dcba76876d01955a4eca9fce4caaf9e0ba7521cdd",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "616429db6c7d20c5b0eff1a6e512ea57a0734b94ae0bc7c914679463e01a7fba",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "5a4ad1534b1e770f02bfde0de15008a6971cf1ffbfa963fc9c2a644973a8d2d1"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      ],</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "logIndex": 6911256,</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "rootHash": "203298cd6dffc9a66816b3e9cf61ca1117b202b173e3b166582dd9f5111fb026",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "treeSize": 6915767</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "signedEntryTimestamp": "MEUCIGicHWGa0XI3perd9LM64+tdneXvvVsOrWxn7pCoUbuNAiEAjmgWIxOH8itbqYjAgkiilYmNVR/hewmfatviQZf3Wr8="</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>The Rekor log can also be accessed using https:
<a href="https://rekor.tlog.dev/?logIndex=11074687" target="_blank" rel="noopener noreferrer" class="">https://rekor.tlog.dev/?logIndex=11074687</a></p>
<p>Now, lets inspect the <code>body</code> field of the bundle:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat artifact.bundle | jq -r '.rekorBundle.Payload.body' | base64 -d - | jq</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "apiVersion": "0.0.1",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "kind": "hashedrekord",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "spec": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "data": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "hash": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "algorithm": "sha256",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "value": "5aa03f96c77536579166fba147929626cc3a97960e994057a9d80271a736d10f"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "signature": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "content": "MEUCIBbfVr0rREgk2yXfENMzTduXnSRc2GkJEUOb5tBncFgSAiEAtC4f1CA4Yio9N3wjdMAbY6hCerCKwyM+hn8L1kn33GE=",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "publicKey": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "content": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNwekNDQWk2Z0F3SUJBZ0lVYjZMRENObHZIblVHRDU1ZGJZdVJxOUJFQjdnd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpNd01URXpNRGN4TVRJeVdoY05Nak13TVRFek1EY3lNVEl5V2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVEVHZMMFBSc3hveE1YZlNhWHUrN3cwb3ZWTnpaay9CQUlvejIKR0wyY1BZM3FaRU5VLytZclI5MkF1WkZYbjBqU21tdk9rdHBBekdobkRodGlkb25reUtPQ0FVMHdnZ0ZKTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWRCZ05WSFE0RUZnUVVkWlB2ClBkNWFiTWtXOG1jQmdiM3VtQW1IVGNVd0h3WURWUjBqQkJnd0ZvQVUzOVBwejFZa0VaYjVxTmpwS0ZXaXhpNFkKWkQ4d0p3WURWUjBSQVFIL0JCMHdHNEVaWkdGdWFXVnNMbUpsZG1WdWFYVnpRR2R0WVdsc0xtTnZiVEFzQmdvcgpCZ0VFQVlPL01BRUJCQjVvZEhSd2N6b3ZMMmRwZEdoMVlpNWpiMjB2Ykc5bmFXNHZiMkYxZEdnd2dZb0dDaXNHCkFRUUIxbmtDQkFJRWZBUjZBSGdBZGdEZFBUQnF4c2NSTW1NWkhoeVpaemNDb2twZXVONDhyZitIaW5LQUx5bnUKamdBQUFZV3ArQWlZQUFBRUF3QkhNRVVDSUFsZkw4NzBXSnRhN3BEOTdZaXcwSmJ2WTdZR2c2MDRjR3hYRVh0UQp0em9hQWlFQStWV1FpeitKUEVzTEJMYnRjbGZoWEZobi9DNGtUeWFTMkZqMTIrdm9UdDR3Q2dZSUtvWkl6ajBFCkF3TURad0F3WkFJd1V0QkIrMUg2MTc3S1czbmZUcEs5dW5TR2d3SVBFdU5xUXZpSnllWlJqa0s4NXBuZmswcDUKbHdRVmJmZWtYWXErQWpCZ0pBL3hqWDUrVXFSaCtPMUxxeEJJdW4xZ1loSXdLK1VVWnE0OVNIMHVQMnNRTDV1bgpJTEhPUHJCdzBmMDBRNjg9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>Now, when an online verification is done, that is when the bundle is not
specified on the command line, the Rekor bundle is looked up in the transparency
log. Notice for example that the same information is also available in the
Rekor log:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ curl --silent https://rekor.sigstore.dev/api/v1/log/entries?logIndex=11074687 | jq -r '.[].body' | base64 -d | jq</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">{</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "apiVersion": "0.0.1",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "kind": "hashedrekord",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  "spec": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "data": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "hash": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "algorithm": "sha256",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "value": "5aa03f96c77536579166fba147929626cc3a97960e994057a9d80271a736d10f"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    "signature": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "content": "MEUCIBbfVr0rREgk2yXfENMzTduXnSRc2GkJEUOb5tBncFgSAiEAtC4f1CA4Yio9N3wjdMAbY6hCerCKwyM+hn8L1kn33GE=",</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      "publicKey": {</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        "content": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNwekNDQWk2Z0F3SUJBZ0lVYjZMRENObHZIblVHRDU1ZGJZdVJxOUJFQjdnd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpNd01URXpNRGN4TVRJeVdoY05Nak13TVRFek1EY3lNVEl5V2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVEVHZMMFBSc3hveE1YZlNhWHUrN3cwb3ZWTnpaay9CQUlvejIKR0wyY1BZM3FaRU5VLytZclI5MkF1WkZYbjBqU21tdk9rdHBBekdobkRodGlkb25reUtPQ0FVMHdnZ0ZKTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWRCZ05WSFE0RUZnUVVkWlB2ClBkNWFiTWtXOG1jQmdiM3VtQW1IVGNVd0h3WURWUjBqQkJnd0ZvQVUzOVBwejFZa0VaYjVxTmpwS0ZXaXhpNFkKWkQ4d0p3WURWUjBSQVFIL0JCMHdHNEVaWkdGdWFXVnNMbUpsZG1WdWFYVnpRR2R0WVdsc0xtTnZiVEFzQmdvcgpCZ0VFQVlPL01BRUJCQjVvZEhSd2N6b3ZMMmRwZEdoMVlpNWpiMjB2Ykc5bmFXNHZiMkYxZEdnd2dZb0dDaXNHCkFRUUIxbmtDQkFJRWZBUjZBSGdBZGdEZFBUQnF4c2NSTW1NWkhoeVpaemNDb2twZXVONDhyZitIaW5LQUx5bnUKamdBQUFZV3ArQWlZQUFBRUF3QkhNRVVDSUFsZkw4NzBXSnRhN3BEOTdZaXcwSmJ2WTdZR2c2MDRjR3hYRVh0UQp0em9hQWlFQStWV1FpeitKUEVzTEJMYnRjbGZoWEZobi9DNGtUeWFTMkZqMTIrdm9UdDR3Q2dZSUtvWkl6ajBFCkF3TURad0F3WkFJd1V0QkIrMUg2MTc3S1czbmZUcEs5dW5TR2d3SVBFdU5xUXZpSnllWlJqa0s4NXBuZmswcDUKbHdRVmJmZWtYWXErQWpCZ0pBL3hqWDUrVXFSaCtPMUxxeEJJdW4xZ1loSXdLK1VVWnE0OVNIMHVQMnNRTDV1bgpJTEhPUHJCdzBmMDBRNjg9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>Now, let first look at the <code>spec.data.hash</code> field which contains a hash
algorithm that was used, and a value. The value is the hash of our blob, the
<code>artifact.txt</code>file:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ sha256sum artifact.txt</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">5aa03f96c77536579166fba147929626cc3a97960e994057a9d80271a736d10f  artifact.txt</span><br></span></code></pre></div></div>
<p>And we can compare this with the value in the <code>spec.data.hash.value</code> field and
check that they indeed are the same:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat artifact.bundle | jq -r '.rekorBundle.Payload.body' | base64 -d - | jq -r '.spec.data.hash.value'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">5aa03f96c77536579166fba147929626cc3a97960e994057a9d80271a736d10f</span><br></span></code></pre></div></div>
<p>Next we have signature field:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat artifact.bundle | jq -r '.rekorBundle.Payload.body' | base64 -d - | jq -r '.spec.signature.content'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">MEUCIBbfVr0rREgk2yXfENMzTduXnSRc2GkJEUOb5tBncFgSAiEAtC4f1CA4Yio9N3wjdMAbY6hCerCKwyM+hn8L1kn33GE=</span><br></span></code></pre></div></div>
<p>Notice that this is the same value as the toplevel <code>base64Signature</code> field:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat artifact.bundle | jq -r '.base64Signature'</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">MEUCIBbfVr0rREgk2yXfENMzTduXnSRc2GkJEUOb5tBncFgSAiEAtC4f1CA4Yio9N3wjdMAbY6hCerCKwyM+hn8L1kn33GE=</span><br></span></code></pre></div></div>
<p>And there is also a <code>publicKey</code> field in the body which contains:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ cat artifact.bundle | jq -r '.rekorBundle.Payload.body' | base64 -d - | jq -r '.spec.signature.publicKey.content' | base64 -d</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-----BEGIN CERTIFICATE-----</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">MIICpzCCAi6gAwIBAgIUb6LDCNlvHnUGD55dbYuRq9BEB7gwCgYIKoZIzj0EAwMw</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">NzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">cm1lZGlhdGUwHhcNMjMwMTEzMDcxMTIyWhcNMjMwMTEzMDcyMTIyWjAAMFkwEwYH</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">KoZIzj0CAQYIKoZIzj0DAQcDQgAEDTvL0PRsxoxMXfSaXu+7w0ovVNzZk/BAIoz2</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">GL2cPY3qZENU/+YrR92AuZFXn0jSmmvOktpAzGhnDhtidonkyKOCAU0wggFJMA4G</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUdZPv</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Pd5abMkW8mcBgb3umAmHTcUwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ZD8wJwYDVR0RAQH/BB0wG4EZZGFuaWVsLmJldmVuaXVzQGdtYWlsLmNvbTAsBgor</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">BgEEAYO/MAEBBB5odHRwczovL2dpdGh1Yi5jb20vbG9naW4vb2F1dGgwgYoGCisG</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">AQQB1nkCBAIEfAR6AHgAdgDdPTBqxscRMmMZHhyZZzcCokpeuN48rf+HinKALynu</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">jgAAAYWp+AiYAAAEAwBHMEUCIAlfL870WJta7pD97Yiw0JbvY7YGg604cGxXEXtQ</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">tzoaAiEA+VWQiz+JPEsLBLbtclfhXFhn/C4kTyaS2Fj12+voTt4wCgYIKoZIzj0E</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">AwMDZwAwZAIwUtBB+1H6177KW3nfTpK9unSGgwIPEuNqQviJyeZRjkK85pnfk0p5</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">lwQVbfekXYq+AjBgJA/xjX5+UqRh+O1LqxBIun1gYhIwK+UUZq49SH0uP2sQL5un</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ILHOPrBw0f00Q68=</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">-----END CERTIFICATE-----</span><br></span></code></pre></div></div>
<p>Notice that this is the same certificate as the toplevel <code>cert</code> field. Using
the <code>base64Signature</code> field, and the <code>cert</code> field we are able to verify a blob
which we saw an example of previously.</p>
<p>Hopefully this has given some insight into the bundle format and given some
example of how one can inspect the fields.</p>]]></content>
        <author>
            <name>Daniel Bevenius</name>
            <uri>https://github.com/danbev</uri>
        </author>
        <category label="sigstore" term="sigstore"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Sigstore, in-toto, OPA, orientation]]></title>
        <id>https://trustification.io/blog/2023/01/11/sigstore-in-toto-opa</id>
        <link href="https://trustification.io/blog/2023/01/11/sigstore-in-toto-opa"/>
        <updated>2023-01-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[As someone who was completly new to secure supply chain security (sscs) there]]></summary>
        <content type="html"><![CDATA[<p>As someone who was completly new to secure supply chain security (sscs) there
were a lot of new projects that I learned the names of but did not really
understand exactly what they did or how they complement each other. This post
hopes to clarify a few of these projects, and others will be addressed in future
posts.</p>
<p>Lets say we have a software project that we want to distribute. We want to sign
the artifact that we produce, and lets say it's distributed as a tar file. It
is possible to do this signing manually, but it involves some work like managing
keys and using tools to perform the signing tasks. Using
<a href="https://www.sigstore.dev/" target="_blank" rel="noopener noreferrer" class="">sigstore</a> simplfies this process, similar to how
Let's Encrypt made it simpler to get certificates to be used with web sites.
Sigstore also provides tools to verify signatures and a transparency log to
store signatures. So that allows us to sign our end product, and publish the
signatures to the transparency log, and consumers/clients can verify our
artifact.</p>
<p>But how can we trust what was built? For example, if I built this tar on my
local laptop I could replace a source code file with a backdoor and still be
able to produce a valid signature, and it could still be verified. This is also
the case if a build server is used and it gets compromised, so we need something
more.</p>
<p>This is where another project named <a href="https://in-toto.io/" target="_blank" rel="noopener noreferrer" class="">in-toto</a> comes into
play. It contains tools to define the steps of a build process, and assign
someone that is responsible for each step. This person also signs the artifact
produced by that step. So each step is signed by the person responsible for that
step, called the funtionary, and then all the steps are signed by a product
owner. This will produce a document which lists the steps that were followed to
produce the software, with signatures for each step.</p>
<p>For example, one step might have been checking out a specific version from git,
and this could be verified that it was indeed that version that was used, and
the source files that were used. This gives the end user insight into the
product that they are about to install and the ability to verify it.</p>
<p>So we now have our built artifact, signed it, and we have attestations, in
this case json files that contain metadata about how it was built. And we can
use in-toto-verify to verify that all that information is correct.</p>
<p>Now, lets say that another company, or another project, wants to include our
software in their project, as a thirdparty dependency. Ours might be one of many
dependencies that they include in their product and they might have
requirements/restrictions on what they are allowed to use. For example, they
might require that only certain licences are used. The license information is
hopefully available in the project, like a license file or field in Cargo.toml,
but there is nothing available to say that only certain licenses are allowed.
This is where a policy engine like
<a href="https://www.openpolicyagent.org/" target="_blank" rel="noopener noreferrer" class="">Open Policy Agent (OPA)</a> comes into play. OPA
gives us the ability to write policy rules that take in-toto json files as
input, and verify that there are licences for all thirdparty dependencies and
that they are of the type(s) that are allowed. Rules can be written to handle
other types of restrictions/requirements as well, which are the policies that
the company has.</p>
<p>So they could include a step in their build process that execute enforces the
policy rules they have defined. Policy rules can also be useful when deploying
applications in container images where one might want to make sure that only
supported base images are used etc.</p>
<p>Hopefully this post gives some insight into how Sigstore, in-toto, and OPA may
be used, and how they complement each other.</p>]]></content>
        <author>
            <name>Daniel Bevenius</name>
            <uri>https://github.com/danbev</uri>
        </author>
        <category label="sigstore" term="sigstore"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[An Adventure with the CycloneDX Maven Plugin]]></title>
        <id>https://trustification.io/blog/2022/12/09/cyclonedx-maven-plugin-adventure</id>
        <link href="https://trustification.io/blog/2022/12/09/cyclonedx-maven-plugin-adventure"/>
        <updated>2022-12-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The CycloneDX Maven Plugin can be used to generate CycloneDX Software Bill of Materials (SBOM) for your maven projects as part of your build process. The plugin is easy to integrate, however does have some issues due mostly to idiosyncrasies and shortcomings with the maven resolution mechanism. In this post I attempt to provide some background, examples and explanations for the issues I've discovered as well as context for the solutions I'm proposing.]]></summary>
        <content type="html"><![CDATA[<p>The CycloneDX Maven Plugin can be used to generate CycloneDX Software Bill of Materials (SBOM) for your maven projects as part of your build process. The plugin is easy to integrate, however does have some issues due mostly to idiosyncrasies and shortcomings with the maven resolution mechanism. In this post I attempt to provide some background, examples and explanations for the issues I've discovered as well as context for the solutions I'm proposing.</p>
<p>Three weeks ago I started an adventure with the <a href="https://github.com/CycloneDX/cyclonedx-maven-plugin" target="_blank" rel="noopener noreferrer" title="The CycloneDX Maven Plugin GitHub repository" class="">CycloneDX Maven Plugin</a>, investigating how we could make use of this plugin to generate Software Bill of Materials (SBOMs) for the <a href="https://github.com/quarkusio/quarkus" target="_blank" rel="noopener noreferrer" title="The Quarkus GitHub repository" class="">Quarkus</a> project. At first this goal appeared easy to achieve, simply enable the plugin for all projects within the <strong>Quarkus</strong> build (hello parent pom.xml) and verify the generated <em>bom</em> contents were accurate.</p>
<p>As I had expected, enabling the plugin was very straight forward. I created a profile in the top level <em>pom.xml</em> to capture the information required at compile time, incorporating all artifacts using <em>compile</em>, <em>provided</em> and <em>system</em> maven scopes. I chose not to include any <em>test</em> or <em>runtime</em> artifacts.</p>
<p>Once the BOM files were created I looked for a way to verify the output was reasonable. I turned to the <a href="https://github.com/apache/maven-dependency-plugin" target="_blank" rel="noopener noreferrer" title="The Maven Dependency Plugin GitHub repository" class="">maven dependency plugin</a> and its <em>tree</em> goal, along with a fairly straight forward script to compare the information in the generated dependency tree with that in the <em>bom</em> file and highlight any discrepancies. This is where the fun began 😁</p>
<p>The remainder of those three weeks involved many hours with a debugger, walking through the internals of maven as well as the CycloneDX plugin, identifying the causes of these discrepancies and working through fixes to generate the output I believed should have been included in the <em>bom</em> files.</p>
<hr>
<p><strong>Note:</strong> At this time these changes have neither been discussed nor reviewed by the CycloneDX community, I've reached out to them via slack and am hoping we can find time to go through this in detail over the next few weeks or so. In the meantime treat this article as my opinions of what I believe should be done.</p>
<hr>
<h1>Part Two - The Case of the Missing Dependency</h1>
<p>Before we talk about missing dependencies we first need to take a quick refresher for how maven resolves artifacts within a project.</p>
<p>One of the benefits of maven is its ability to automatically derive the dependency tree for your project using the information in your <em>pom.xml</em> combined with the information in the <em>pom.xml</em> for each of your transitive dependencies. Maven will take this information and create a dependency tree where each artifact exists once (not always the case, but we will come on to that), will favour artifacts which are closer to the root of the tree than those farther away, reconcile their versions based on the defined constraints and derive an appropriate scope.</p>
<p>The example used in the maven documentation is as follows</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">A</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ├── B</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  │   └── C</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  │       └── D 2.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  └── E</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      └── D 1.0</span><br></span></code></pre></div></div>
<p>As the shortest path to <strong>D</strong> is via E, the generated dependency tree will look like</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">A</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ├── B</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  │   └── C</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  └── E</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      └── D 1.0</span><br></span></code></pre></div></div>
<p>With the above refresher out of the way let's move on to the issue of missing dependencies and consider the following example</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example:trustification:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.example:dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  \- com.example:dependency2:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|     \- com.example:shared_dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|       \- com.example:shared_dependency2:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example:test_dependency:jar:1.0.0:test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example:shared_dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      \- com.example:shared_dependency2:jar:1.0.0:compile</span><br></span></code></pre></div></div>
<p>In this graph we can see that <strong>com.example<!-- -->:dependency2</strong> and <strong>com.example<!-- -->:test_dependency</strong> both depend on <strong>com.example<!-- -->:shared_dependency1</strong>, with <strong>dependency2</strong> having a scope of <em>compile</em> and <strong>test_dependency</strong> having a scope of <em>test</em>. When this graph is processed by maven we end up with a dependency tree which is close to the example given in the maven documentation.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example:trustification:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.example:dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  \- com.example:dependency2:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example:test_dependency:jar:1.0.0:test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example:shared_dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      \- com.example:shared_dependency2:jar:1.0.0:compile</span><br></span></code></pre></div></div>
<p>Each artifact exists once and the <strong>shared_dependency1</strong> artifact is now seen only under the <strong>test_dependency</strong> artifact.</p>
<p>Only this isn't the full picture.</p>
<p>What is actually taking place under the covers is that each set of conflicts within the graph is being evaluated in order to decide which one is chosen (the winning artifact), with all losing artifacts then being updated and turned into a marker artifact without child dependencies. We can see a visualisation of this by enabling the <em>verbose</em> flag on the <em>dependency:tree</em> goal (use version 3.4.0), which displays the underlying dependency tree and not the clean version.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example:trustification:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.example:dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  \- com.example:dependency2:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|     \- (com.example:shared_dependency1:jar:1.0.0:compile - omitted for duplicate)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example:test_dependency:jar:1.0.0:test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example:shared_dependency1:jar:1.0.0:compile (scope not updated to compile)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      \- com.example:shared_dependency2:jar:1.0.0:compile</span><br></span></code></pre></div></div>
<p>We can now see that the <strong>shared_dependency1</strong> artifact exists multiple times and that the dependency under <strong>dependency2</strong> lost the conflict resolution to the dependency under <strong>test_dependency</strong>.</p>
<p>How do we end up with missing dependencies? This happens when we filter the graph using scopes, which in my case includes <em>compile</em>, <em>provided</em> and <em>system</em>. Let's take a look at what happens under those circumstances.</p>
<p>Maven's DependencyCollectorBuilder works by first generating the dependency tree, with conflicts resolved as above, then pruning the result to remove subtrees which are not accepted by the filter. In my case this means any artifacts which do not have the right scope, along with their dependent children, will be removed. The tree returned to the CycloneDX plugin will be as follows</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example:trustification:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example:dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example:dependency2:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      \- (com.example:shared_dependency1:jar:1.0.0:compile - omitted for duplicate)</span><br></span></code></pre></div></div>
<p>The CycloneDX plugin will process this tree and create the following dependency graph within the <em>bom</em> file</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependencies&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example/trustification@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;dependency ref="pkg:maven/com.example/dependency1@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example/dependency1@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;dependency ref="pkg:maven/com.example/dependency2@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example/dependency2@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;dependency ref="pkg:maven/com.example/shared_dependency1@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example/shared_dependency1@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependencies&gt;</span><br></span></code></pre></div></div>
<p>This is notable for two reasons</p>
<ol>
<li class="">The bom contains the <em>shared_dependency1</em> artifact even though this entry came from the marker entry (we can make use of this)</li>
<li class="">We have lost the <em>shared_dependency2</em> artifact since it is only present under the pruned <em>test</em> scoped subtree.</li>
</ol>
<p>In order to see a representation of the graph I would like in the <em>bom</em> we simply need to comment out the <em>test</em> dependency in the top level <em>pom.xml</em>, which would result in the following dependency tree</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example:trustification:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example:dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example:dependency2:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      \- com.example:shared_dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         \- com.example:shared_dependency2:jar:1.0.0:compile</span><br></span></code></pre></div></div>
<p>and the following dependency graph in the <em>bom</em></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependencies&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example/trustification@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;dependency ref="pkg:maven/com.example/dependency1@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example/dependency1@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;dependency ref="pkg:maven/com.example/dependency2@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example/dependency2@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;dependency ref="pkg:maven/com.example/shared_dependency1@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example/shared_dependency1@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;dependency ref="pkg:maven/com.example/shared_dependency2@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example/shared_dependency2@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependencies&gt;</span><br></span></code></pre></div></div>
<p>How can we fix this while including the test artifact as a dependency? We can rely on the following information</p>
<ul>
<li class="">the marker artifact has been included in the filtered result tree, however it is without children</li>
<li class="">the full dependency tree contains a <em>winner</em> artifact which contains any dependent children</li>
</ul>
<p>We can then follow this process</p>
<ul>
<li class="">retrieve the full dependency tree</li>
<li class="">collect all children from top level <em>test</em> scoped dependencies</li>
<li class="">search the original tree looking for potential marker artifacts, i.e. those without children, then<!-- -->
<ul>
<li class="">check the set of hidden artifacts to see if the potential marker artifact is also hidden</li>
<li class="">if the hidden artifact does exist then transplant its dependencies to the marker artifact</li>
</ul>
</li>
</ul>
<p>The above will allow us to reconstruct the missing parts of the SBOM dependency graph and create my desired <em>bom</em> content.</p>
<hr>
<p><strong>Note:</strong> The same issue will occur with <em>runtime</em> scoped artifacts within the graph, these can also conceal <em>compile</em> scoped artifacts if closer to the root. The difference between <em>test</em> scoped artifacts and those with <em>runtime</em> scope is that the <em>runtime</em> scoped artifacts can exist anywhere in the dependency tree whereas the <em>test</em> artifacts will only be found at the top level. The <em>runtime</em> artifacts can be handled by following a similar process to the one above, extended to the full dependency tree.</p>
<hr>
<h1>Part Three - Should Consistency Matter?</h1>
<p>In going through the <em>bom</em> file we can see that the information is split into two major types, <strong>Components</strong> and <strong>Dependencies</strong>. My expectation was that this information would be consistent, with these elements being related as follows</p>
<ul>
<li class="">each <strong>Dependency</strong> being associated with a <strong>Component</strong></li>
<li class="">each nested <strong>Dependency</strong> referencing an existing top level <strong>Dependency</strong> element</li>
<li class="">each <strong>Component</strong> being associated with a top level <strong>Dependency</strong></li>
</ul>
<p>One of the verification tests I ran on the <em>bom</em> files was to test these expectations, and while I did not discover any issues with the <strong>Dependencies</strong> I did discover numerous examples of <strong>Components</strong> existing without any associated dependency information.</p>
<p>We can revisit the example from earlier to explain why this happens. The CycloneDX code decides which components to include based on the set of resolved artifacts derived from the full dependency tree, and it does this separately from determining the filtered dependency graph. The only connection between the two is that, when generating the dependency graph, the existing process will check whether the dependency has an associated <em>Component</em> before adding it to the graph. If the <em>Component</em> has not been created then the dependency will be ignored.</p>
<p>As a reminder, here's the example we covered earlier as seen by CycloneDX when processing the dependency graph.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example:trustification:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.example:dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  \- com.example:dependency2:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|     \- (com.example:shared_dependency1:jar:1.0.0:compile - omitted for duplicate)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example:test_dependency:jar:1.0.0:test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example:shared_dependency1:jar:1.0.0:compile (scope not updated to compile)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      \- com.example:shared_dependency2:jar:1.0.0:compile</span><br></span></code></pre></div></div>
<p>And the following represents the set of resolved artifacts used to determine which <em>Components</em> and <em>Dependencies</em> are included in the SBOM dependency graph, assuming we are generating the <em>bom</em> based on the <em>compile</em> scope.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example:trustification:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.example:dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  \- com.example:dependency2:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- &lt;test artifact ignored&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example:shared_dependency1:jar:1.0.0:compile (scope not updated to compile)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      \- com.example:shared_dependency2:jar:1.0.0:compile</span><br></span></code></pre></div></div>
<p>There are two issues with this that I can see</p>
<ul>
<li class="">this will generate <em>Components</em> for all <em>compile</em> scope artifacts in the tree, including <strong>shared_dependency2</strong> from the test subtree</li>
<li class="">this ignores the cumulative scopes used by maven when filtering the artifacts to create the dependency tree, relying instead on an explicit test of equality</li>
</ul>
<p>All of the instances I have discovered so far have been related to the missing dependency issue from <a href="https://trustification.io/blog/2022/12/09/cyclonedx-maven-plugin-adventure#part-two---the-case-of-the-missing-dependency" class="">Part Two</a>, and are addressed by ensuring concealed artifacts are included in the SBOM dependency graph, however I am not yet convinced this is the only circumstance under which this would occur with the current codebase.</p>
<hr>
<p><strong>Note:</strong> The Maven cumulative scopes are as follows</p>
<ul>
<li class="">compile -&gt; system, provided and compile</li>
<li class="">runtime -&gt; compile and runtime</li>
<li class="">test -&gt; system, provided, compile, runtime and test</li>
</ul>
<hr>
<p>Another related issue, coupled with the processing of excluded types, is the possibility of creating split dependency graphs within the same SBOM.</p>
<p>Consider the following dependency tree</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example:trustification:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.example:dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  \- com.example:dependency2:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example:type_dependency:test-jar:tests:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example:shared_type_dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      \- com.example:shared_type_dependency2:jar:1.0.0:compile</span><br></span></code></pre></div></div>
<p>If we create the SBOM for the above tree, and choose to exclude artifacts of type <em>test-jar</em> from the graph, the current approach will result in two dependency graphs being generated. The first would be rooted at <strong>com.example<!-- -->:trustification</strong> and the second would be rooted at <strong>com.example<!-- -->:shared_type_dependency1</strong>. This is another consequence of the <em>Component</em> creation process, since only the specific <strong>com.example:type_dependency<!-- -->:test-jar</strong> artifact will be removed from the graph and not its dependencies. This results in the following dependency section within the <em>bom</em>.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">&lt;dependencies&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;!-- the first dependency graph is rooted here --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example/trustification@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;dependency ref="pkg:maven/com.example/dependency1@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example/dependency1@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;dependency ref="pkg:maven/com.example/dependency2@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example/dependency2@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;!-- the second dependency graph is rooted here --&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example/shared_type_dependency1@1.0.0?type=jar"&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    &lt;dependency ref="pkg:maven/com.example/shared_type_dependency2@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;/dependency&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  &lt;dependency ref="pkg:maven/com.example/shared_type_dependency2@1.0.0?type=jar"/&gt;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">&lt;/dependencies&gt;</span><br></span></code></pre></div></div>
<p>If we move the processing of the excluded types to the creation of the SBOM dependency graph we could address this issue and create only a single dependency graph for the root artifact, however without also addressing how we determine which <em>Components</em> are included in the <em>bom</em> we would be creating another source for inconsistencies and those now excluded artifacts would still exist in the <em>Components</em> section.</p>
<p>I believe a better approach would be to start with the assumption that all artifacts are included as <em>Components</em>, generate the dependency graph with type exclusion, and then prune all unreferenced components from the generated <em>bom</em>. Please remember this for now, it will come up again in the next part.</p>
<h1>Part Four - The Return of the Missing Dependency</h1>
<p>In <a href="https://trustification.io/blog/2022/12/09/cyclonedx-maven-plugin-adventure#part-two---the-case-of-the-missing-dependency" class="">Part Two</a> we discussed what happened when the dependency resolution led to parts of the dependency tree being concealed by artifacts with <em>test</em> or <em>runtime</em> scopes, however one edge case we did not cover is when the dependency is itself the <em>test</em> scoped artifact. In the current CycloneDX implementation this will cause the <em>test</em> artifact, and its children, to be ignored because of the mechanism used to determine which <em>Components</em> are included in the <em>bom</em>. Recall from <a href="https://trustification.io/blog/2022/12/09/cyclonedx-maven-plugin-adventure#part-three---should-consistency-matter" class="">Part Three</a> that dependencies will not be included in the dependency graph unless they already have an associated <em>Component</em>.</p>
<p>We can show this in action by looking at a modified version of the earlier example, depicted by <em>dependency:tree</em> as follows</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example:trustification:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.example:dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  \- (com.example:test_dependency:jar:1.0.0:compile - omitted for duplicate)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example:test_dependency:jar:1.0.0:test (scope not updated to compile)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example:shared_dependency1:jar:1.0.0:test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      \- com.example:shared_dependency2:jar:1.0.0:test</span><br></span></code></pre></div></div>
<p>One fact we should be aware of is that the only real <em>test</em> scoped artifacts in the tree will be at the top level, Maven will ignore lower level <em>test</em> scoped artifacts when determining the transitive graph. In this case <strong>test_dependency</strong> is the only true <em>test</em> scoped artifact, and as neither <strong>shared_dependency1</strong> not <strong>shared_dependency2</strong> are referenced from a <em>compile</em> scope they only have a scope of <em>test</em> by inheriting it from the parent. Compare this with the example we used previously, when <strong>shared_dependency1</strong> was referenced from a <em>compile</em> scope.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example:trustification:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.example:dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  \- com.example:dependency2:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|     \- (com.example:shared_dependency1:jar:1.0.0:compile - omitted for duplicate)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example:test_dependency:jar:1.0.0:test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example:shared_dependency1:jar:1.0.0:compile (scope not updated to compile)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      \- com.example:shared_dependency2:jar:1.0.0:compile</span><br></span></code></pre></div></div>
<p>What I would like to see is the SBOM dependency graph represented as follows</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example:trustification:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.example:dependency1:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example:test_dependency:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      \- com.example:shared_dependency1:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         \- com.example:shared_dependency2:jar:1.0.0</span><br></span></code></pre></div></div>
<p>This can be fixed by following a similar process to that discussed in <a href="https://trustification.io/blog/2022/12/09/cyclonedx-maven-plugin-adventure#part-two---the-case-of-the-missing-dependency" class="">Part Two</a>, however it will also require us to move away from the current mechanism of identifying <em>Components</em> and relying on those references to restrict which <em>Artifacts</em> can be included in the dependency graph. Instead of the existing mechanism we would start from the assumption that all Artifacts will be included, determine the actual dependency graph, and then use this to prune the set of <em>Components</em> down to the required set.</p>
<p>Once this switch is made we can finally include those remaining missing dependencies in the graph and address the issues from <a href="https://trustification.io/blog/2022/12/09/cyclonedx-maven-plugin-adventure#part-three---should-consistency-matter" class="">Part Three</a>, we certainly have a number of reasons for doing so.</p>
<p>There are a few implementation details we do need to be aware of when switching approaches</p>
<ul>
<li class="">we need to consider excluded types, as moving their processing to the creation of the dependency graph will allow us to correctly handle their subtrees, however they can now also conceal parts of the dependency graph</li>
<li class="">we need to ensure we do not inadvertently pull in <em>runtime</em> scoped artifacts when reconstructing the graph from concealed dependencies</li>
</ul>
<h1>Conclusions</h1>
<p>This has been an interesting journey, and through it I've learned a lot about CycloneDX and more than I had likely wanted to know about the implementation of Maven. I have addressed all of the issues I believe to be present with the current approach, with the exception of one. While it is true that we can reconstruct the dependency tree to include concealed artifacts, the information provided directly by maven is insufficient to resolve all cases. The edge case identified in <a href="https://trustification.io/blog/2022/12/09/cyclonedx-maven-plugin-adventure#part-four---the-return-of-the-missing-dependency" class="">Part Four</a> covers the inclusion of <em>compile</em> scoped artifacts which are referenced through a top level <em>test</em> artifact, however there is also the case of <em>runtime</em> artifacts being included which, unfortunately, also have their scopes modified to a <em>test</em> scope.</p>
<p>By way of example, if we were to change the scope of the <strong>shared_dependency1</strong> dependency within the <strong>test_dependency</strong> pom.xml to a scope of <strong>runtime</strong> we would still see the following returned by maven</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">com.example:trustification:jar:1.0.0</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">+- com.example:dependency1:jar:1.0.0:compile</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">|  \- (com.example:test_dependency:jar:1.0.0:compile - omitted for duplicate)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">\- com.example:test_dependency:jar:1.0.0:test (scope not updated to compile)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   \- com.example:shared_dependency1:jar:1.0.0:test</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      \- com.example:shared_dependency2:jar:1.0.0:test</span><br></span></code></pre></div></div>
<p>As things currently stand we now have a <em>bom</em> file which is no longer missing dependencies, although it may include the occasional <em>runtime</em> scoped artifact when it really shouldn't. In order to fix this edge case we will need to go deeper into the maven level and look at the underlying graph generated by <a href="https://wiki.eclipse.org/Aether" target="_blank" rel="noopener noreferrer" title="Eclipse Aether website" class="">Eclipse Aether</a> as this contains more useful information.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">Node: com.example:trustification:1.0.0    {}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  Node: com.example:dependency1:1.0.0    {conflict.originalScope=compile, conflict.originalOptionality=false}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Node: com.example:test_dependency:1.0.0    {conflict.winner=com.example:test_dependency:jar:1.0.0 (test), conflict.originalScope=compile, conflict.originalOptionality=false}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  Node: com.example:test_dependency:1.0.0    {REDUCED_SCOPE=compile, conflict.originalScope=test, conflict.originalOptionality=false}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    Node: com.example:shared_dependency1:1.0.0    {conflict.originalScope=runtime, conflict.originalOptionality=false}</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      Node: com.example:shared_dependency2:1.0.0    {conflict.originalScope=compile, conflict.originalOptionality=false}</span><br></span></code></pre></div></div>
<p>The above information contains the original scope of the dependencies, the optionality and also a reference to the winning dependency in the case of conflict.</p>
<p>Switching over to using this tree would likely be intrusive, and not something I would like to do without building up the existing test cases within the project. This is definitely a task for another day 😁</p>]]></content>
        <author>
            <name>Kevin Conner</name>
            <uri>https://github.com/knrc</uri>
        </author>
        <category label="cyclonedx" term="cyclonedx"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[How to Configure a Gitsign Cache]]></title>
        <id>https://trustification.io/blog/2022/12/05/gitsign-cache</id>
        <link href="https://trustification.io/blog/2022/12/05/gitsign-cache"/>
        <updated>2022-12-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[This post contains the steps for setting up]]></summary>
        <content type="html"><![CDATA[<p>This post contains the steps for setting up
<a href="https://github.com/sigstore/gitsign/tree/main/cmd/gitsign-credential-cache" target="_blank" rel="noopener noreferrer" class="">gitsign-credential-cache</a>.
which is useful if one has to perform multiple commits in short succession, or
when doing a rebase.</p>
<p>It can be somewhat frustrating to have the browser open for every single
commit. For these situations a cache can be enabled using the instructions in
this post.</p>
<p>First install <code>gitsign-credential-cache</code> if it is not already installed:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ go install github.com/sigstore/gitsign/cmd/gitsign-credential-cache@latest</span><br></span></code></pre></div></div>
<p>Create a file named <code>~/.config/systemd/user/gitsign.service</code>:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">[Unit]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Description=Gitsign Credentials Cache</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Documentation=https://github.com/sigstore/gitsign</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[Service]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Type=simple</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ExecStart=%h/go/bin/gitsign-credential-cache</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Restart=on-failure</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[Install]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">WantedBy=default.target</span><br></span></code></pre></div></div>
<p>This service can then be enabled using:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ systemctl --user daemon-reload</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">$ systemctl --user enable gitsign.service</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Created symlink /home/danielbevenius/.config/systemd/user/default.target.wants/gitsign.service → /home/danielbevenius/.config/systemd/user/gitsign.service.</span><br></span></code></pre></div></div>
<p>And we can start it manually using:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ systemctl --user start gitsign.service</span><br></span></code></pre></div></div>
<p>Check that it has started successfully:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ systemctl --user status gitsign.service</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">● gitsign.service - Gitsign Credentials Cache</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     Loaded: loaded (/home/danielbevenius/.config/systemd/user/gitsign.service; enabled; vendor preset: disabled)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     Active: active (running) since Mon 2022-11-28 11:27:47 CET; 2min 35s ago</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">       Docs: https://github.com/sigstore/gitsign</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   Main PID: 177444 (gitsign-credent)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/gitsign.service</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">             └─ 177444 /home/danielbevenius/go/bin/gitsign-credential-cache</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Nov 28 11:27:47 localhost.localdomain systemd[1295]: Started Gitsign Credentials Cache.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Nov 28 11:27:47 localhost.localdomain gitsign-credential-cache[177444]: /home/danielbevenius/.cache/.sigstore/gitsig&gt;</span><br></span></code></pre></div></div>
<p>And we then need to add the following environment variable:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ export GITSIGN_CREDENTIAL_CACHE=~/.cache/.sigstore/gitsign/cache.sock</span><br></span></code></pre></div></div>
<p>After this we should be able to commit a first time and have our credentials
stored. Subsequent commits will then be made without a browser "popup".</p>]]></content>
        <author>
            <name>Daniel Bevenius</name>
            <uri>https://github.com/danbev</uri>
        </author>
        <category label="sigstore" term="sigstore"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Keyless Git Signing with Sigstore]]></title>
        <id>https://trustification.io/blog/2022/12/02/sign-commits-with-sigstore</id>
        <link href="https://trustification.io/blog/2022/12/02/sign-commits-with-sigstore"/>
        <updated>2022-12-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[This post contains the steps for setting up]]></summary>
        <content type="html"><![CDATA[<p>This post contains the steps for setting up
<a href="https://github.com/sigstore/gitsign" target="_blank" rel="noopener noreferrer" class="">gitsign</a> to sign your git
commits using <a href="https://www.sigstore.dev/" target="_blank" rel="noopener noreferrer" class="">sigstore</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="install-gitsign">Install gitsign<a href="https://trustification.io/blog/2022/12/02/sign-commits-with-sigstore#install-gitsign" class="hash-link" aria-label="Direct link to Install gitsign" title="Direct link to Install gitsign" translate="no">​</a></h3>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ go install github.com/sigstore/gitsign@latest</span><br></span></code></pre></div></div>
<p>Or using brew:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ brew install sigstore/tap/gitsign</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-git">Configure git<a href="https://trustification.io/blog/2022/12/02/sign-commits-with-sigstore#configure-git" class="hash-link" aria-label="Direct link to Configure git" title="Direct link to Configure git" translate="no">​</a></h3>
<p>The collowing will configure signing for the current project:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">#!/bin/bash</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Sign all commits</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">git config --local commit.gpgsign true</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Sign all tags</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">git config --local tag.gpgsign true</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Use gitsign for signing</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">git config --local gpg.x509.program gitsign</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># gitsign expects x509 args</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">git config --local gpg.format x509</span><br></span></code></pre></div></div>
<p>To configure for all projects, use:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">#!/bin/bash</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Sign all commits</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">git config --global commit.gpgsign true</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Sign all tags</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">git config --global tag.gpgsign true</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># Use gitsign for signing</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">git config --global gpg.x509.program gitsign</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"># gitsign expects x509 args</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">git config --global gpg.format x509</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="commit">Commit<a href="https://trustification.io/blog/2022/12/02/sign-commits-with-sigstore#commit" class="hash-link" aria-label="Direct link to Commit" title="Direct link to Commit" translate="no">​</a></h3>
<p>Now when you commit, <code>gitsign</code> will be used to start an Open ID
Connect (OIDC) flow. This will allow you to choose an OIDC provider:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ git commit -v</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Your browser will now be opened to:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">https://oauth2.sigstore.dev/auth/auth?access_type=online&amp;client_id=sigstore&amp;code_challenge=eQvdw56pTgXnkj76Cab-4ZWaKk8XFM6UFFBdayKQX1Y&amp;code_challenge_method=S256&amp;nonce=2GmBDq86TMNuz8VhMUixMxiPSe2&amp;redirect_uri=http%3A%2F%2Flocalhost%3A39617%2Fauth%2Fcallback&amp;response_type=code&amp;scope=openid+email&amp;state=2GmBDlYDps5Ywd8dX4Ebwo4VnQL</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">[master 4292869] Add initial Oniro notes</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> 1 file changed, 10 insertions(+)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"> create mode 100644 notes/oniro.md</span><br></span></code></pre></div></div>
<p>Note that on github this commit will be marked as <code>Unverified</code> because
the sigstore Certificate Authority root is not part of Github's trust
root. Further, validation needs to be done using Rekor to verify that
the certificate was valid at the time this commit was signed.</p>
<p>To avoid having to choose an auth provider each time, set the following environment variable. For example:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ export GITSIGN_CONNECTOR_ID=https://github.com/login/oauth</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="verifying-a-commit">Verifying a commit<a href="https://trustification.io/blog/2022/12/02/sign-commits-with-sigstore#verifying-a-commit" class="hash-link" aria-label="Direct link to Verifying a commit" title="Direct link to Verifying a commit" translate="no">​</a></h3>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ git verify-commit HEAD</span><br></span></code></pre></div></div>
<p>If verified, you'll see output similar to this:</p>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">tlog index: 6058402</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">gitsign: Signature made using certificate ID 0xb073e00bfabd4fb9988b9e1e0896dcfc1527fcdb | CN=sigstore-intermediate,O=sigstore.dev</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">gitsign: Good signature from [daniel.bevenius@gmail.com]</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Validated Git signature: true</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">Validated Rekor entry: true</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="inspect-commit-signature">Inspect commit signature<a href="https://trustification.io/blog/2022/12/02/sign-commits-with-sigstore#inspect-commit-signature" class="hash-link" aria-label="Direct link to Inspect commit signature" title="Direct link to Inspect commit signature" translate="no">​</a></h3>
<div class="language-console codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-console codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">$ git cat-file commit HEAD \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | sed -n '/BEGIN/, /END/p' \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | sed 's/^ //g' \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | sed 's/gpgsig //g' \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | sed 's/SIGNED MESSAGE/PKCS7/g' \</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  | openssl pkcs7 -print -print_certs -text</span><br></span></code></pre></div></div>]]></content>
        <author>
            <name>Daniel Bevenius</name>
            <uri>https://github.com/danbev</uri>
        </author>
        <category label="sigstore" term="sigstore"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Welcome]]></title>
        <id>https://trustification.io/blog/welcome</id>
        <link href="https://trustification.io/blog/welcome"/>
        <updated>2022-11-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Today, we're excited to announce the launch of Trustification, a new]]></summary>
        <content type="html"><![CDATA[<p>Today, we're excited to announce the launch of Trustification, a new
community dedicated to improving software supply-chain security.</p>
<p><img decoding="async" loading="lazy" alt="ChatGPT&amp;#39;s welcome" src="https://trustification.io/assets/images/ai-intro-30ce0a1b3d6bfab2c30428ff70fec055.png" width="822" height="717" class="img_ev3q"></p>]]></content>
        <author>
            <name>Jim Crossley</name>
            <uri>https://github.com/jcrossley3</uri>
        </author>
    </entry>
</feed>