<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rfc SYSTEM 'rfc2629.dtd' [
        <!ENTITY rfc2629 PUBLIC '' 'http://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.2629.xml'>
]>

<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?> <!-- used by XSLT processors -->

<?rfc toc="yes"?>         <!-- generate a table of contents -->
<?rfc symrefs="yes"?>     <!-- use anchors instead of numbers for references -->
<?rfc sortrefs="yes" ?>   <!-- alphabetize the references -->
<?rfc compact="yes" ?>    <!-- conserve vertical whitespace -->
<?rfc subcompact="no" ?>  <!-- but keep a blank line between list items -->

<rfc category="info" docName="draft-ietf-sidr-rpki-tree-validation-00" ipr="trust200902">
  <front>

    <title abbrev="RPKI Tree Validation">RPKI Certificate Tree Validation by a Relying Party Tool</title>

    <author fullname="Oleg Muravskiy" initials="O." surname="Muravskiy">
      <organization>RIPE NCC</organization>
      <address>
        <email>oleg@ripe.net</email>
      </address>
    </author>
    <author initials='T.' surname="Bruijnzeels" fullname='Tim Bruijnzeels'>
      <organization>RIPE NCC</organization>
      <address>
        <email>tim@ripe.net</email>
      </address>
    </author>

    <date year="2016" />
    <area>rtg</area>
    <workgroup>SIDR</workgroup>

    <keyword>RPKI</keyword>
    <keyword>validation</keyword>
    <keyword>RRDP</keyword>

    <abstract>
      <t>This document currently describes the approach to validate the content of the RPKI certificate tree, as used by
        the RIPE NCC RPKI Validator. This approach is independent of a particular object retrieval mechanism. This
        allows it to be used with repositories available over the rsync protocol, the RPKI Repository Delta Protocol,
        and repositories that use a mix of both.
      </t>
      <t>This algorithm does not rely on content of repository directories, but uses the Authority Key Identifier (AKI)
      field of a manifest and a certificate revocation list (CRL) objects to discover manifest and CRL objects issued
      by a particular Certificate Authority (CA). It further uses the hashes of manifest entries to discover other
      objects issued by the CA.</t>
      <t>If the working group finds that algorithm outlined here is useful for other implementations, we may either
      update future revisions of this document to be less specific to the RIPE NCC RPKI Validator implementation, or
      we may use this document as a starting point of a generic validation document and keep this as a detailed description
      of the actual RIPE NCC RPKI Validator implementation.</t>
    </abstract>
  </front>
  <middle>
    <section title="Introduction">
      <t>In order to use information published in RPKI repositories, Relying Parties (RP) need to retrieve and validate
        the content of certificates, CRLs, and other RPKI signed objects. To validate a particular object, one must
        ensure that all certificates in the certificate chain up to the Trust Anchor (TA) are valid. Therefore the
        validation of a certificate tree is usually performed top-down, starting from the TA certificate and descending
        down the certificate chain, validating every encountered certificate and its products. The result of this
        process is a list of all encountered RPKI objects with a validity status attached to each of them. These results
        may later be used by a Relying Party in taking routing decisions, etc.
      </t>
      <t>Traditionally RPKI data is made available to RPs through the repositories <xref target="RFC6481" /> accessible
        over rsync protocol. Relying parties are advised to keep a local copy of repository data, and perform regular
        updates of this copy from the repository (Section 5 of<xref target="RFC6481" />). The RPKI Repository Delta
        Protocol <xref target="I-D.ietf-sidr-delta-protocol" /> introduces another method to fetch repository
        data and keep the local copy up to date with the repository.
      </t>
      <t>This document describes how a Relying Party tool could discover RPKI objects to download, build certificate
        path, and validate RPKI objects, independently from what repository access protocol is used. To achieve this,
        it puts downloaded RPKI objects in an object store, where objects could be found by their URI, hash of their
        content, value of the object's AKI field, or combination of these. It also keeps track of download and
        validation time for every object, to perform cleanups of the local copy.
      </t>
    </section>

    <section title="Top-down Validation of a Single Trust Anchor Certificate Tree">

      <t>The validation of a Trust Anchor (TA) certificate tree starts from its TA certificate. To retrieve the TA
        certificate, a Trust Anchor Locator (TAL) object is used, as described in <xref target="ta-fetch" />.
      </t>
      <t>If the TA certificate is retrieved, it is validated according to the Section 7 of <xref target="RFC6487" />
        and Section 2.2 of <xref target="RFC7730" />.
      </t>
      <t>Then the TA certificate and all its subordinate objects are validated as described in
        <xref target="ca-cert-validation" />.
      </t>
      <t>For all repository objects that were validated during this validation run, their validation timestamp is
        updated in an object store (see <xref target="store-validation-time" />).
      </t>
      <t>Outdated objects are removed from the store as described in <xref target="store-cleanup" />. This completes the
        validation of the TA certificate tree.
      </t>

      <section anchor="ta-fetch" title="Fetching the Trust Anchor Certificate Using the Trust Anchor Locator">
        <t>The following steps are performed in order to fetch the Trust Anchor Certificate:
          <list style="symbols">
            <t>(Optional) If the Trust Anchor Locator contains a "prefetch.uris" field, pass the URIs contained there to
              the fetcher (see <xref target="fetch-repo" />). (This field is a non-standard extension to the TAL format
              supported by the RIPE NCC Validator. It helps fetching non-hierarchical rsync repositories more
              efficiently.)
            </t>
            <t>Extract the TA certificate URI from the TAL's URI section (see Section 2.1 of<xref target="RFC7730" />)
              and pass to the object fetcher (<xref target="fetch-object" />).
            </t>
            <t>Retrieve from the object store (see <xref target="store-get-cer-by-uri" />) all certificate objects, for
              which the URI matches the URI extracted from the TAL in the previous step, and the public key matches the
              subjectPublicKeyInfo field of the TAL (see Section 2.1 of <xref target="RFC7730" />).
            </t>
            <t>If no, or more than one such objects are found, issue an error and stop validation process. Otherwise,
              use that object as the Trust Anchor certificate.
            </t>
          </list>
        </t>
      </section>

      <section anchor="ca-cert-validation" title="Resource Certificate Validation">
        <t>The following steps describe the validation of a single resource certificate:
          <list style="symbols">
            <t>If both the caRepository (Section 4.8.8.1 of <xref target="RFC6487" />), and the id-ad-rpkiNotify (Section
              3.5 of <xref target="I-D.ietf-sidr-delta-protocol" />) SIA pointers are present in the given
              resource certificate, use a local policy to determine which pointer to use. Extract the URI from the
              selected pointer and pass it to the object fetcher (see <xref target="fetch-repo" />).
            </t>
            <t>For a given resource certificate, find its manifest and certificate revocation list (CRL), using the
              procedure described in <xref target="findRecentValidMftWithCrl" />. If no such manifest and CRL could be
              found, issue an error and stop processing current certificate.
            </t>
            <t>Compare the URI found in the given resource certificate's id-ad-rpkiManifest field (Section 4.8.8.1 of
              <xref target="RFC6487" />) with the URI of the manifest found in the previous step. If they are
              different, issue a warning.
            </t>
            <t>Perform manifest entries validation as described in <xref target="mft-entries-val" />.
            </t>
            <t>Validate all resource certificate objects found on the manifest, using the CRL object found on the
              manifest, according to Section 7 of <xref target="RFC6487" />.
            </t>
            <t>Validate all ROA objects found on the manifest, using the CRL object found on the manifest, according to
              the Section 4 of <xref target="RFC6482" />.
            </t>
            <t>Validate all Ghostbusters Record objects found on the manifest, using the CRL object found on the
              manifest, according to the Section 7 of <xref target="RFC6493" />.
            </t>
            <t>For every valid resource certificate object found on the manifest, apply the procedure described in
              <xref target="ca-cert-validation">this section</xref>, recursively, provided that this resource
              certificate (identified by its SKI) has not yet been validated during current repository validation run.
            </t>
          </list>
        </t>

        <section anchor="findRecentValidMftWithCrl" title="Finding most recent valid manifest and CRL">
          <t>Fetch from the store (see <xref target="store-get-mft-by-aki" />) all objects of type manifest, whose
            certificate's AKI field matches the SKI of the current CA certificate.
          </t>
          <t>Find the manifest object with the highest manifestNumber field (Section 4.2.1 of <xref target="RFC6486" />),
            for which all following conditions are met:
            <list style="symbols">
              <t>There is only one entry in the manifest for which the store contains exactly one object of type CRL,
                whose hash matches the hash of the entry.
              </t>
              <t>The manifest's certificate AKI equals the above CRL's AKI</t>
              <t>The above CRL is a valid object according to Section 6.3 of
                <xref target="RFC5280" />
              </t>
              <t>The manifest is a valid object according to Section 4.4 of <xref target="RFC6486" />, using the CRL
                found above
              </t>
            </list>
          </t>
          <t>Report an error for every invalid manifest with the number higher than the number of the valid manifest.
          </t>
        </section>

        <section anchor="mft-entries-val" title="Manifest entries validation">
          <t>
            For every entry in the manifest object:
            <list style="symbols">
              <t>Construct an entry's URI by appending the entry name to the current CA's publication point URI.</t>
              <t>Get all objects from the store whose hash attribute equals entry's hash (see
                <xref target="store-get-by-hash" />).
              </t>
              <t>If no such objects found, issue an error.</t>
              <t>For every found object, compare its URI with the URI of the manifest entry. If they do not match,
                issue a warning.
              </t>
              <t>If no objects with matching URI found, issue a warning.</t>
              <t>If some objects with non-matching URI found, issue a warning.</t>
            </list>
          </t>
        </section>
      </section>

      <section title="Object Store Cleanup" anchor="store-cleanup">
        <t>At the end of the TA tree validation the store cleanup is performed:
          <list style="symbols">
            <t>Given all objects that were validated during the current validation run, remove from the store (<xref
                target="store-delete-other" />) all objects whose URI attribute matches the URI of one of the validated
              objects, but the content's hash is different.
            </t>
            <t>Remove from the store all objects that were last validated more than 7 days ago.</t>
            <t>Remove from the store all objects that were downloaded more than 2 hours ago and have never been used in
              a validation process.
            </t>
          </list>
          The time intervals used in the steps above are a matter of local policy.
        </t>
      </section>
    </section>

    <section title="Remote Objects Fetcher" anchor="fetcher">

      <t>The fetcher is responsible for downloading objects from remote repositories (described in Section 3
        of <xref target="RFC6481"/>) using rsync protocol (<xref target="rsync" />), or RPKI Repository Delta
        Protocol (RRDP) (<xref target="I-D.ietf-sidr-delta-protocol"/>).
      </t>

      <section title="Fetcher Operations">

        <section title="Fetch repository objects" anchor="fetch-repo">

          <t>This operation receives one parameter – a URI. For rsync protocol this URI points to a directory in a
            remote repository. For RRDP repository it points to the repository's notification file.</t>
          <t>The fetcher performs following steps:
            <list style="symbols">
              <t>If the given URI has been downloaded recently (as specified by the local policy), skip all following
                steps.
              </t>
              <t>Download the remote objects using the URI provided (for an rsync repository use a recursive mode).</t>
              <t>For every new object that is downloaded, try to parse it as an object of specific RPKI type
                (certificate, manifest, CRL, ROA, Ghostbusters record), based on the object's filename extension (.cer,
                .mft, .crl, .roa, and .gbr, respectively), and perform basic RPKI object validation, as specified in
                <xref target="RFC6487" /> and <xref target="RFC6488" />.
              </t>
              <t>For every downloaded valid object, record it in the object store (<xref target="store-object" />),
                and set its last fetch time to the time it was downloaded (<xref target="store-fetch-time" />).
              </t>
            </list>
          </t>
        </section>

        <section title="Fetch single repository object" anchor="fetch-object">
          <t>This operation receives one parameter – a URI that points to an object in a remote repository.</t>
          <t>The fetcher performs following operations:
            <list style="symbols">
              <t>If the given URI has been downloaded recently (as specified by the local policy), skip all following
                steps.
              </t>
              <t>Download the remote object using the URI provided.</t>
              <t>Try to parse the downloaded object as an object of a specific RPKI type (certificate, manifest, CRL,
                ROA, Ghostbusters record), based on the object's filename extension (.cer, .mft, .crl, .roa, and .gbr,
                respectively), and perform basic RPKI object validation, as specified in <xref target="RFC6487" />
                and <xref target="RFC6488" />.
              </t>
              <t>If the downloaded object is not valid, issue an error and skip further steps.</t>
              <t>Delete objects from the object store (<xref target="store-delete-by-uri" />) whose URI matches
                the URI given.</t>
              <t>Put validated object in the object store (<xref target="store-object" />),
                and set its last fetch time to the time it was downloaded (<xref target="store-fetch-time" />).
              </t>
            </list>
          </t>
        </section>

      </section>

    </section>

    <section title="Local Object Store" anchor="store">

      <section title="Store Operations">

        <section title="Store Repository Object" anchor="store-object">
          <t>Put given object in the store, along with its type, URI, hash, and AKI,
            if there is no record with the same hash and URI fields.
          </t>
        </section>

        <section title="Update object's last fetch time" anchor="store-fetch-time">
          <t>For all objects in the store whose URI matches the given URI, set the last fetch time attribute to the
            given timestamp.
          </t>
        </section>

        <section title="Get objects by hash" anchor="store-get-by-hash">
          <t>Retrieve all objects from the store whose hash attribute matches the given hash.
          </t>
        </section>

        <section title="Get certificate objects by URI" anchor="store-get-cer-by-uri">
          <t>Retrieve from the store all objects of type certificate, whose URI attribute matches the given URI.
          </t>
        </section>

        <section title="Get manifest objects by AKI" anchor="store-get-mft-by-aki">
          <t>Retrieve from the store all objects of type manifest, whose AKI attribute matches the given AKI.
          </t>
        </section>

        <section title="Delete objects for URI" anchor="store-delete-by-uri">
          <t>For a given URI, delete all objects in the store with matching URI attribute.</t>
        </section>

        <section title="Delete outdated objects" anchor="store-delete-other">
          <t>For a given URI and a list of hashes, delete all objects in the store with matching URI, whose hash
            attribute is not in the given list of hashes.
          </t>
        </section>

        <section title="Update object's validation time" anchor="store-validation-time">
          <t>For all objects in the store whose hash attribute matches the given hash, set the last validation time
            attribute to the given timestamp.
          </t>
        </section>

      </section>
    </section>

    <section anchor="Acknowledgements" title="Acknowledgements">
      <t>This document describes the algorithm as it is implemented by the software development team at the RIPE NCC.
        The original idea behind it was outlined by Tim Bruijnzeels. The authors would also like to acknowledge
        contributions by Carlos Martinez, Andy Newton, and Rob Austein.
      </t>
    </section>

    <section anchor="IANA" title="IANA Considerations">
      <t>This document has no actions for IANA.</t>
    </section>

    <section anchor="Security" title="Security Considerations">

      <t>This algorithm uses the content of a manifest object to discover other objects issued by a particular CA. It
        verifies that the manifest is located in the publication point designated in the CA Certificate. However, if
        there are other (not enlisted in the manifest) objects located in that publication point directory, they will
        be ignored, even if their content is correct and they are issued by the same CA as the manifest.
      </t>
      <t>In contrast, objects whose content hash matches the hash listed in the manifest, but that are not located in
        the publication directory listed in their CA certificate, will be used in the validation process (although a
        warning will be issued in that case).
      </t>
      <t>The store cleanup procedure described in <xref target="store-cleanup" /> tries to minimise removal and
        subsequent re-fetch of objects that are published in some repository but not used in the validation. Once such
        objects are removed from the remote repository, they will be discarded from the local object store after a
        period of time specified by a local policy. By generating an excessive amount of syntactically valid RPKI
        objects, a man-in-the-middle attack rendered between a validating tool and a repository could force an
        implementation to fetch and store those objects in the object store before they are being validated and
        discarded, leading to an out-of-memory or out-of-disk-space conditions, and, subsequently, a denial of service.
      </t>

    </section>
  </middle>

  <back>
    <references title="Normative References">
      <?rfc include="reference.RFC.5280.xml"?>
      <?rfc include="reference.RFC.6481.xml"?>
      <?rfc include="reference.RFC.6482.xml"?>
      <?rfc include="reference.RFC.6486.xml"?>
      <?rfc include="reference.RFC.6487.xml"?>
      <?rfc include="reference.RFC.6488.xml"?>
      <?rfc include="reference.RFC.7730.xml"?>
      <?rfc include="reference.RFC.6493.xml"?>
    </references>

    <references title="Informative References">
      <?rfc include="reference.I-D.draft-ietf-sidr-delta-protocol-02.xml"?>
      <reference anchor="rsync" target="https://rsync.samba.org">
          <front>
            <title>Rsync home page</title>
            <author/>
            <date />
          </front>
      </reference>
    </references>
  </back>
</rfc>
