[OpenAFS] RFC: Altering the processing of IPv4 (aka Host) ACLs to enforce negative rights

Jeffrey E Altman jaltman@auristor.com
Mon, 20 Mar 2023 16:21:12 -0400


This is a cryptographically signed message in MIME format.

--------------ms030103050000060704070406
Content-Type: multipart/alternative;
 boundary="------------rpa2zPXIS9rUZK3bC6GvCdEs"

--------------rpa2zPXIS9rUZK3bC6GvCdEs
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit

On 7 March Andrew Deason submitted a patch to OpenAFS documenting the 
existing behavior of the OpenAFS fileserver when computing Anonymous and 
Caller Access Rights if the IPv4 address from which the RXAFS RPC was 
received matches a PTS host entry and that PTS entry matches an Access 
Control Entry (ACE).

https://gerrit.openafs.org/#/c/15340/

Quoting Andrew's submission to the fs_setacl man page:

    "Combining _Negative rights_ granted from machine entries (IP
    addresses) and _Normal rights_ granted from non-machine entries (or
    vice versa) will generally not work as expected. Permissions granted
    by machine entries and by non-machine entries are calculated
    separately, and both sets of permissions are given to an accessing
    user. For example, if permissions are granted to an authenticated
    user or group (or _system:anyuser_), you cannot remove those
    permissions from specific hosts by adding machine entries to a group
    in an ACL in the _Negative rights_> section."

The IBM AFS Administrator's Guide "Protecting Data in AFS" section states:

    "When determining what type of access to grant to a user, theFile
    Server first compiles a set of permissions by examiningall of the
    entries in the Normal rights section of the ACL. Itthen subtracts
    any permissions associated with the user (orwith groups to which the
    user belongs) on the Negative rightssection of the ACL. Therefore,
    negative permissions alwayscancel out normal permissions."

IBM/Transarc AFS 3.2 introduced the granting of permissions based upon 
the host's IPv4 address in addition to those granted to the caller. The 
implementation evaluates the caller's rights independently of the host's 
rights and then ORs the results. This approach violates the statement 
that negative permissions always cancel out normal (aka positive) 
permissions. If a caller is granted "read" but there is a matching 
negative "read" ACE (aka permission) for the host, the negative "read" 
ACE is ignored. Likewise if "lookup" is granted to the host but the 
caller matches a negative "lookup" ACE, then the caller's negative 
"lookup" ACE is ignored.

The problem can be demonstrated with a couple of examples.   First, lets 
define some PTS entities and membership relations:

  * user: jane = 1000
      o member: system:authusers
      o member: system:anyuser
      o member: no-admin
  * user: 128.66.0.130 = 2000
      o member: local-hosts
  * group: no-admin = -100
      o member: jane
  * group: local-hosts = -500
      o member: 128.66.0.130

Example 1:  RXAFS RPC received from a host that is not a member of 
local-hosts

ACL

  * system:anyuser: l; -none
  * system:authuser: lrk; -none
  * jane: none; -r
  * local-hosts: r; -none

Rights:

  * system:anyuser: lookup
  * system:authuser: lookup, read, lock
  * jane: lookup, lock

When "jane" accesses a file with this ACL the granted rights will be 
"lk" because the negative read permission cancels the positive read 
permission granted by the membership in the system:authuser group.


Example 2: RXAFS RPC received from a host that is a member of local-hosts

ACL

  * system:anyuser: l; -none
  * system:authuser: lrk; -none
  * jane: none; -r
  * local-hosts: r; -none

Rights:

  * system:anyuser: lookup, read
  * system:authuser: lookup, read, lock
  * jane: lookup, read, lock

In this case, even though "jane" is denied the "read" permission granted 
to members of "system:authuser" because of the negative "read" in the 
"jane" ACE she is granted the permission because of the positive read 
permission granted to "local-hosts" members. The granting of "read" 
permission to "jane" is an unexpected result!


Example 3: RXAFS RPC received from a host that is not a member of 
local-hosts

ACL

  * system:anyuser: l; -none
  * system:authuser: lrk; -none
  * jane: lrkwid; -none
  * local-hosts: none; -wida

Rights:

  * system:anyuser: lookup
  * system:authuser: lookup, read, lock
  * jane: lookup, read, lock, write, insert, delete

In this case, "jane" is granted all of the permissions other than "admin".


Example 4: RXAFS RPC received from a host that is a member of local-hosts

ACL

  * system:anyuser: l; -none
  * system:authuser: lrk; -none
  * jane: lrkwid; -none
  * local-hosts: none; -wida

Rights:

  * system:anyuser: lookup
  * system:authuser: lookup, read, lock
  * jane: lookup, read, lock, write, insert, delete

In this case, "jane" is granted all of the permissions other than 
"admin".   However, because the RPC was issued from a host that is a 
member of "local-hosts" the expected result would be "jane" receiving 
only the "lookup, read, lock" rights.    The granting of "write, insert 
and delete" permission is an unexpected outcome!


In examples 2 and 4 rights are granted to the caller that would appear 
to be contrary to the explicit use of negative rights in the access 
control entries.  The example 4 use case might represent client systems 
which are intended to be read-only consumers of the /afs content but 
which might be vulnerable to exploitation.   Example 2 is intended to 
always deny read privileges to "jane" but if she can gain access to the 
host with IPv4 address 128.66.0.130 she can bypass those restrictions.

This behavior feels like a bug to me. A bug that has been present since 
the release of AFS 3.2 more than thirty years ago but a bug 
nevertheless.  I propose that OpenAFS fix the broken behavior so that 
ACL interpretation is consistent with the documentation inherited from IBM.

Two commits submitted to Gerrit will enforce negative access rights.

https://gerrit.openafs.org/#/c/15344/
https://gerrit.openafs.org/#/c/15345/


History:

AFS 3.1 and earlier did not have a concept of IP or Host ACLs.   That 
functionality was introduced in AFS 3.2.  However, the implementation 
that is present in the release version of AFS 3.2 and in use to this day 
might not have been the original implementation.    Today's fileserver 
issues separate calls to the protection service to obtain the caller's 
Current Protection Set (CPS) and the host's CPS.   The fileserver then 
computes the caller rights by comparing the caller's CPS to the object's 
ACL; and it computes the host's rights by comparing the host's CPS to 
the object's ACL.   The fileserver then grants the caller all rights 
granted to both the caller and the host.

The host's CPS is obtained by the fileserver by issuing the 
PR_GetHostCPS RPC.  PR_GetHostCPS differs from PR_GetCPS in that it 
matches the host's IPv4 address using wildcard pattern matching when 
searching for a matching PTS ID.  It also does not treat the PTS entity 
as a member of the system:anyuser group.

Before PR_GetHostCPS was added to the protection service another RPC was 
introduced, PR_GetCPS2 which obtained the CPS for the combination of a 
caller and a host. An implementation of IP ACLs that used PR_GetCPS2 
would have behaved as expected because the all of the positive rights 
would have been computed and from those all of the negative rights would 
have been removed.  I do not have access to the source code for a 
version of the fileserver that used the PR_GetCPS2 RPC but I can imagine 
that a likely implementation would have issued a PR_GetCPS2 call for 
(anonymous, host) and (caller, host).   The additional load these RPCs 
placed on the protection service might have been deemed too expensive.  
As a result, the alternative approach using the PR_GetHostCPS was 
introduced.

Whatever the motivation for PR_GetHostCPS in preference to PR_GetCPS2, 
the existing implementation does not interpret ACLs in a manner that 
permits negative rights to be superior to positive rights.   Perhaps it 
didn't occur to the implementer that there was a problem; and it didn't 
occur to anyone that a simple change to acl_checkRights() and the 
fileserver GetRights() function would permit computing the expected results.


Proposal:

I propose that OpenAFS treat the current behavior as a bug.  The use of 
negative rights is discouraged because they are hard to analyze.  It is 
hoped that their use is rare.  If negative rights are not in use, then 
changing the behavior when IP ACLs exist will not alter the computed 
outcome.  However, if negative rights are in use, they are likely being 
used because it wasn't easy to limit the access any other way.  In which 
case, granting more access then was specified is problematic.   A CVE 
can be published to document the existing behavior and the behavior as 
it will appear beginning with a specific version of the fileserver.

If required, a configuration option can be provided to enable the AFS 
3.2 behavior until all of the fileservers within a cell have been 
updated.   I discourage using a configuration option to enable the 
stricter interpretation of ACLs as that will result in some sites being 
vulnerable when they did not intend to be.


Jeffrey Altman

P.S. I am writing this letter publicly as opposed to sending it to the 
openafs-security queue because the behavior in question is public and 
Andrew's proposed patch to the OpenAFS man pages is public.


--------------rpa2zPXIS9rUZK3bC6GvCdEs
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: 8bit

<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p><font face="Gill Sans MT">On 7 March Andrew Deason submitted a
        patch to OpenAFS documenting the existing behavior of the
        OpenAFS fileserver when computing Anonymous and Caller Access
        Rights if the IPv4 address from which the RXAFS RPC was received
        matches a PTS host entry and that PTS entry matches an Access
        Control Entry (ACE).<br>
      </font></p>
    <p><font face="Gill Sans MT">  <a class="moz-txt-link-freetext" href="https://gerrit.openafs.org/#/c/15340/">https://gerrit.openafs.org/#/c/15340/</a></font></p>
    <p><font face="Gill Sans MT">Quoting Andrew's submission to the
        fs_setacl man page:<br>
      </font></p>
    <blockquote>
      <p><font face="Gill Sans MT">"Combining _Negative rights_ granted
          from machine entries (IP addresses) and _Normal rights_
          granted from non-machine entries (or vice versa) will
          generally not work as expected. Permissions granted by machine
          entries and by non-machine entries are calculated separately,
          and both sets of permissions are given to an accessing user.
          For example, if permissions are granted to an authenticated
          user or group (or _system:anyuser_), you cannot remove those
          permissions from specific hosts by adding machine entries to a
          group in an ACL in the _Negative rights_&gt; section."</font></p>
    </blockquote>
    <p><font face="Gill Sans MT">The IBM AFS Administrator's Guide
        "Protecting Data in AFS" section states:</font></p>
    <blockquote>
      <p><span
          class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">
          <font face="Gill Sans MT">"When determining what type of
            access to grant to a user, the</font></span><font face="Gill
          Sans MT"><span
            class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">
            File Server first compiles a set of permissions by examining</span><span
class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">
            all of the entries in the Normal rights section of the ACL.
            It</span><span
            class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">
            then subtracts any permissions associated with the user (or</span><span
class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">
            with groups to which the user belongs) on the Negative
            rights</span><span
            class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">
            section of the ACL. Therefore, negative permissions always</span><span
class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">
            cancel out normal permissions."</span></font></p>
    </blockquote>
    <p><font face="Gill Sans MT"><span
          class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">IBM/Transarc
          AFS 3.2 introduced the granting of permissions </span><span
          class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">based
          upon the host's IPv4 address in addition to those granted</span>
        <span
          class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">to
          the caller. The implementation evaluates the caller's rights</span>
        <span
          class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">independently
          of the host's rights and then ORs the results.  </span><span
class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">This
          approach violates the statement that negative permissions</span>
        <span
          class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">always
          cancel out normal (aka positive) permissions. If a caller</span>
        <span
          class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">is
          granted "read" but there is a matching negative "read" ACE
          (aka</span> <span
          class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">permission)
          for the host, the negative "read" ACE is ignored.  </span><span
class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">Likewise
          if "lookup" is granted to the host but the caller matches</span>
        <span
          class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">a
          negative "lookup" ACE, then the caller's negative "lookup" ACE</span>
        <span
          class="com-google-gwtexpui-safehtml-client-SafeHtmlCss-wikiPreFormat">is
          ignored.</span></font></p>
    <p><font face="Gill Sans MT">The problem can be demonstrated with a
        couple of examples.   First, lets define some PTS entities and
        membership relations:<br>
      </font></p>
    <ul>
      <li><font face="Gill Sans MT">user: jane = 1000</font></li>
      <ul>
        <li><font face="Gill Sans MT">member: system:authusers</font></li>
        <li><font face="Gill Sans MT">member: system:anyuser</font></li>
        <li><font face="Gill Sans MT">member: no-admin<br>
          </font></li>
      </ul>
      <li><font face="Gill Sans MT">user: 128.66.0.130 = 2000</font></li>
      <ul>
        <li><font face="Gill Sans MT">member: local-hosts<br>
          </font></li>
      </ul>
      <li>group: no-admin = -100</li>
      <ul>
        <li>member: jane<br>
        </li>
      </ul>
      <li><font face="Gill Sans MT">group: local-hosts = -500</font></li>
      <ul>
        <li><font face="Gill Sans MT">member: 128.66.0.130</font></li>
      </ul>
    </ul>
    <p><font face="Gill Sans MT">Example 1:  RXAFS RPC received from a
        host that is not a member of local-hosts<br>
      </font></p>
    <p><font face="Gill Sans MT">ACL<br>
      </font></p>
    <ul>
      <li><font face="Gill Sans MT">system:anyuser: l; -none</font></li>
      <li><font face="Gill Sans MT">system:authuser: lrk; -none<br>
        </font></li>
      <li><font face="Gill Sans MT">jane: none; -r</font></li>
      <li><font face="Gill Sans MT">local-hosts: r; -none</font><font
          face="Gill Sans MT"></font></li>
    </ul>
    <p><font face="Gill Sans MT">Rights: <br>
      </font></p>
    <ul>
      <li><font face="Gill Sans MT">system:anyuser: lookup</font></li>
      <li><font face="Gill Sans MT">system:authuser: lookup, read, lock</font></li>
      <li><font face="Gill Sans MT">jane: lookup, lock</font><br>
      </li>
    </ul>
    <p><font face="Gill Sans MT">When "jane" accesses a file with this
        ACL the granted rights will be "lk" because the negative read
        permission cancels the positive read permission granted by the
        membership in the system:authuser group.</font></p>
    <p><font face="Gill Sans MT"><br>
      </font></p>
    <p><font face="Gill Sans MT">Example 2: RXAFS RPC received from a
        host that is a member of local-hosts<br>
      </font></p>
    <p><font face="Gill Sans MT">ACL<br>
      </font></p>
    <ul>
      <li><font face="Gill Sans MT">system:anyuser: l; -none</font></li>
      <li><font face="Gill Sans MT">system:authuser: lrk; -none<br>
        </font></li>
      <li><font face="Gill Sans MT">jane: none; -r</font></li>
      <li><font face="Gill Sans MT">local-hosts: r; -none</font></li>
    </ul>
    <p>Rights:</p>
    <ul>
      <li><font face="Gill Sans MT">system:anyuser: lookup, read<br>
        </font></li>
      <li><font face="Gill Sans MT">system:authuser: lookup, read, lock<br>
        </font></li>
      <li><font face="Gill Sans MT">jane: lookup, read, lock<br>
        </font></li>
    </ul>
    <p></p>
    <p>In this case, even though "jane" is denied the "read" permission
      granted to members of "system:authuser" because of the negative
      "read" in the "jane" ACE she is granted the permission because of
      the positive read permission granted to "local-hosts" members.  
      The granting of "read" permission to "jane" is an unexpected
      result!</p>
    <p><br>
    </p>
    <p>Example 3: RXAFS RPC received from a host that is not a member of
      local-hosts</p>
    <p><font face="Gill Sans MT">ACL<br>
      </font></p>
    <ul>
      <li><font face="Gill Sans MT">system:anyuser: l; -none</font></li>
      <li><font face="Gill Sans MT">system:authuser: lrk; -none<br>
        </font></li>
      <li><font face="Gill Sans MT">jane: lrkwid; -none</font></li>
      <li><font face="Gill Sans MT">local-hosts: none; -wida</font></li>
    </ul>
    <p>Rights:</p>
    <ul>
      <li><font face="Gill Sans MT">system:anyuser: lookup<br>
        </font></li>
      <li><font face="Gill Sans MT">system:authuser: lookup, read, lock<br>
        </font></li>
      <li><font face="Gill Sans MT">jane: lookup, read, lock, write,
          insert, delete<br>
        </font></li>
    </ul>
    <p><font face="Gill Sans MT">In this case, "jane" is granted all of
        the permissions other than "admin".</font></p>
    <p><br>
    </p>
    <p></p>
    <p>Example 4: RXAFS RPC received from a host that is a member of
      local-hosts</p>
    <font face="Gill Sans MT">ACL<br>
    </font>
    <ul>
      <li>
        <font face="Gill Sans MT">system:anyuser: l; -none</font></li>
      <li><font face="Gill Sans MT">system:authuser: lrk; -none<br>
        </font></li>
      <li><font face="Gill Sans MT">jane: lrkwid; -none</font></li>
      <li><font face="Gill Sans MT">local-hosts: none; -wida</font></li>
    </ul>
    <p>Rights:</p>
    <ul>
      <li><font face="Gill Sans MT">system:anyuser: lookup<br>
        </font></li>
      <li><font face="Gill Sans MT">system:authuser: lookup, read, lock<br>
        </font></li>
      <li><font face="Gill Sans MT">jane: lookup, read, lock, write,
          insert, delete<br>
        </font></li>
    </ul>
    <p><font face="Gill Sans MT">In this case, "jane" is granted all of
        the permissions other than "admin".   However, because the RPC
        was issued from a host that is a member of "local-hosts" the
        expected result would be "jane" receiving only the "lookup,
        read, lock" rights.    The granting of "write, insert and
        delete" permission is an unexpected outcome!<br>
      </font></p>
    <p><br>
    </p>
    <p><font face="Gill Sans MT">In examples 2 and 4 rights are granted
        to the caller that would appear to be contrary to the explicit
        use of negative rights in the access control entries.  The
        example 4 use case might represent client systems which are
        intended to be read-only consumers of the /afs content but which
        might be vulnerable to exploitation.   Example 2 is intended to
        always deny read privileges to "jane" but if she can gain access
        to the host with IPv4 address </font><font face="Gill Sans MT">128.66.0.130
        she can bypass those restrictions.</font></p>
    <p><font face="Gill Sans MT">This behavior feels like a bug to me.  
        A bug that has been present since the release of AFS 3.2 more
        than thirty years ago but a bug nevertheless.  I propose that
        OpenAFS fix the broken behavior so that ACL interpretation is
        consistent with the documentation inherited from IBM.</font></p>
    <p><font face="Gill Sans MT">Two commits submitted to Gerrit will
        enforce negative access rights.</font></p>
    <p><font face="Gill Sans MT">   
        <a class="moz-txt-link-freetext" href="https://gerrit.openafs.org/#/c/15344/">https://gerrit.openafs.org/#/c/15344/</a><br>
            <a class="moz-txt-link-freetext" href="https://gerrit.openafs.org/#/c/15345/">https://gerrit.openafs.org/#/c/15345/</a><br>
      </font></p>
    <p><font face="Gill Sans MT"><br>
      </font></p>
    <p><font face="Gill Sans MT">History:</font></p>
    <p><font face="Gill Sans MT">AFS 3.1 and earlier did not have a
        concept of IP or Host ACLs.   That functionality was introduced
        in AFS 3.2.  However, the implementation that is present in the
        release version of AFS 3.2 and in use to this day might not have
        been the original implementation.    Today's fileserver issues
        separate calls to the protection service to obtain the caller's
        Current Protection Set (CPS) and the host's CPS.   The
        fileserver then computes the caller rights by comparing the
        caller's CPS to the object's ACL; and it computes the host's
        rights by comparing the host's CPS to the object's ACL.   The
        fileserver then grants the caller all rights granted to both the
        caller and the host.</font></p>
    <p><font face="Gill Sans MT">The host's CPS is obtained by the
        fileserver by issuing the PR_GetHostCPS RPC.  PR_GetHostCPS
        differs from PR_GetCPS in that it matches the host's IPv4
        address using wildcard pattern matching when searching for a
        matching PTS ID.  It also does not treat the PTS entity as a
        member of the system:anyuser group.</font></p>
    <p><font face="Gill Sans MT">Before PR_GetHostCPS was added to the
        protection service another RPC was introduced, PR_GetCPS2 which
        obtained the CPS for the combination of a caller and a host.  
        An implementation of IP ACLs that used PR_GetCPS2 would have
        behaved as expected because the all of the positive rights would
        have been computed and from those all of the negative rights
        would have been removed.  I do not have access to the source
        code for a version of the fileserver that used the PR_GetCPS2
        RPC but I can imagine that a likely implementation would have
        issued a PR_GetCPS2 call for (anonymous, host) and (caller,
        host).   The additional load these RPCs placed on the protection
        service might have been deemed too expensive.  As a result, the
        alternative approach using the PR_GetHostCPS was introduced.</font></p>
    <p><font face="Gill Sans MT">Whatever the motivation for
        PR_GetHostCPS in preference to PR_GetCPS2, the existing
        implementation does not interpret ACLs in a manner that permits
        negative rights to be superior to positive rights.   Perhaps it
        didn't occur to the implementer that there was a problem; and it
        didn't occur to anyone that a simple change to acl_checkRights()
        and the fileserver GetRights() function would permit computing
        the expected results.</font></p>
    <p><font face="Gill Sans MT"><br>
      </font></p>
    <p><font face="Gill Sans MT">Proposal:</font></p>
    <p><font face="Gill Sans MT">I propose that OpenAFS treat the
        current behavior as a bug.  The use of negative rights is
        discouraged because they are hard to analyze.  It is hoped that
        their use is rare.  If negative rights are not in use, then
        changing the behavior when IP ACLs exist will not alter the
        computed outcome.  However, if negative rights are in use, they
        are likely being used because it wasn't easy to limit the access
        any other way.  In which case, granting more access then was
        specified is problematic.   A CVE can be published to document
        the existing behavior and the behavior as it will appear
        beginning with a specific version of the fileserver.   <br>
      </font></p>
    <p><font face="Gill Sans MT">If required, a configuration option can
        be provided to enable the AFS 3.2 behavior until all of the
        fileservers within a cell have been updated.   I discourage
        using a configuration option to enable the stricter
        interpretation of ACLs as that will result in some sites being
        vulnerable when they did not intend to be.</font></p>
    <p><font face="Gill Sans MT"><br>
      </font></p>
    <p><font face="Gill Sans MT">Jeffrey Altman</font></p>
    <p><font face="Gill Sans MT">P.S. I am writing this letter publicly
        as opposed to sending it to the openafs-security queue because
        the behavior in question is public and Andrew's proposed patch
        to the OpenAFS man pages is public.</font></p>
    <p><br>
    </p>
  </body>
</html>

--------------rpa2zPXIS9rUZK3bC6GvCdEs--

--------------ms030103050000060704070406
Content-Type: application/pkcs7-signature; name="smime.p7s"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.p7s"
Content-Description: S/MIME Cryptographic Signature

MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCC
DHEwggXSMIIEuqADAgECAhBAAYJpmi/rPn/F0fJyDlzMMA0GCSqGSIb3DQEBCwUAMDoxCzAJ
BgNVBAYTAlVTMRIwEAYDVQQKEwlJZGVuVHJ1c3QxFzAVBgNVBAMTDlRydXN0SUQgQ0EgQTEz
MB4XDTIyMDgwNDE2MDQ0OFoXDTI1MTAzMTE2MDM0OFowcDEvMC0GCgmSJomT8ixkAQETH0Ew
MTQxMEQwMDAwMDE4MjY5OUEyRkQyMDAwMjMzQ0QxGTAXBgNVBAMTEEplZmZyZXkgRSBBbHRt
YW4xFTATBgNVBAoTDEF1cmlTdG9yIEluYzELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQCkC7PKBBZnQqDKPtZPMLAy77zo2DPvwtGnd1hNjPvbXrpGxUb3
xHZRtv179LHKAOcsY2jIctzieMxf82OMyhpBziMPsFAG/ukihBMFj3/xEeZVso3K27pSAyyN
fO/wJ0rX7G+ges22Dd7goZul8rPaTJBIxbZDuaykJMGpNq4PQ8VPcnYZx+6b+nJwJJoJ46kI
EEfNh3UKvB/vM0qtxS690iAdgmQIhTl+qfXq4IxWB6b+3NeQxgR6KLU4P7v88/tvJTpxIKkg
9xj89ruzeThyRFd2DSe3vfdnq9+g4qJSHRXyTft6W3Lkp7UWTM4kMqOcc4VSRdufVKBQNXjG
IcnhAgMBAAGjggKcMIICmDAOBgNVHQ8BAf8EBAMCBPAwgYQGCCsGAQUFBwEBBHgwdjAwBggr
BgEFBQcwAYYkaHR0cDovL2NvbW1lcmNpYWwub2NzcC5pZGVudHJ1c3QuY29tMEIGCCsGAQUF
BzAChjZodHRwOi8vdmFsaWRhdGlvbi5pZGVudHJ1c3QuY29tL2NlcnRzL3RydXN0aWRjYWEx
My5wN2MwHwYDVR0jBBgwFoAULbfeG1l+KpguzeHUG+PFEBJe6RQwCQYDVR0TBAIwADCCASsG
A1UdIASCASIwggEeMIIBGgYLYIZIAYb5LwAGAgEwggEJMEoGCCsGAQUFBwIBFj5odHRwczov
L3NlY3VyZS5pZGVudHJ1c3QuY29tL2NlcnRpZmljYXRlcy9wb2xpY3kvdHMvaW5kZXguaHRt
bDCBugYIKwYBBQUHAgIwga0MgapUaGlzIFRydXN0SUQgQ2VydGlmaWNhdGUgaGFzIGJlZW4g
aXNzdWVkIGluIGFjY29yZGFuY2Ugd2l0aCBJZGVuVHJ1c3QncyBUcnVzdElEIENlcnRpZmlj
YXRlIFBvbGljeSBmb3VuZCBhdCBodHRwczovL3NlY3VyZS5pZGVudHJ1c3QuY29tL2NlcnRp
ZmljYXRlcy9wb2xpY3kvdHMvaW5kZXguaHRtbDBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8v
dmFsaWRhdGlvbi5pZGVudHJ1c3QuY29tL2NybC90cnVzdGlkY2FhMTMuY3JsMB8GA1UdEQQY
MBaBFGphbHRtYW5AYXVyaXN0b3IuY29tMB0GA1UdDgQWBBQB+nzqgljLocLTsiUn2yWqEc2s
gjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwDQYJKoZIhvcNAQELBQADggEBAJwV
eycprp8Ox1npiTyfwc5QaVaqtoe8Dcg2JXZc0h4DmYGW2rRLHp8YL43snEV93rPJVk6B2v4c
WLeQfaMrnyNeEuvHx/2CT44cdLtaEk5zyqo3GYJYlLcRVz6EcSGHv1qPXgDT0xB/25etwGYq
utYF4Chkxu4KzIpq90eDMw5ajkexw+8ARQz4N5+d6NRbmMCovd7wTGi8th/BZvz8hgKUiUJo
Qle4wDxrdXdnIhCP7g87InXKefWgZBF4VX21t2+hkc04qrhIJlHrocPG9mRSnnk2WpsY0MXt
a8ivbVKtfpY7uSNDZSKTDi1izEFH5oeQdYRkgIGb319a7FjslV8wggaXMIIEf6ADAgECAhBA
AXA7OrqBjMk8rp4OuNQSMA0GCSqGSIb3DQEBCwUAMEoxCzAJBgNVBAYTAlVTMRIwEAYDVQQK
EwlJZGVuVHJ1c3QxJzAlBgNVBAMTHklkZW5UcnVzdCBDb21tZXJjaWFsIFJvb3QgQ0EgMTAe
Fw0yMDAyMTIyMTA3NDlaFw0zMDAyMTIyMTA3NDlaMDoxCzAJBgNVBAYTAlVTMRIwEAYDVQQK
EwlJZGVuVHJ1c3QxFzAVBgNVBAMTDlRydXN0SUQgQ0EgQTEzMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAu6sUO01SDD99PM+QdZkNxKxJNt0NgQE+Zt6ixaNP0JKSjTd+SG5L
wqxBWjnOgI/3dlwgtSNeN77AgSs+rA4bK4GJ75cUZZANUXRKw/et8pf9Qn6iqgB63OdHxBN/
15KbM3HR+PyiHXQoUVIevCKW8nnlWnnZabT1FejOhRRKVUg5HACGOTfnCOONrlxlg+m1Vjgn
o1uNqNuLM/jkD1z6phNZ/G9IfZGI0ppHX5AA/bViWceX248VmefNhSR14ADZJtlAAWOi2un0
3bqrBPHA9nDyXxI8rgWLfUP5rDy8jx2hEItg95+ORF5wfkGUq787HBjspE86CcaduLka/Bk2
VwIDAQABo4IChzCCAoMwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwgYkG
CCsGAQUFBwEBBH0wezAwBggrBgEFBQcwAYYkaHR0cDovL2NvbW1lcmNpYWwub2NzcC5pZGVu
dHJ1c3QuY29tMEcGCCsGAQUFBzAChjtodHRwOi8vdmFsaWRhdGlvbi5pZGVudHJ1c3QuY29t
L3Jvb3RzL2NvbW1lcmNpYWxyb290Y2ExLnA3YzAfBgNVHSMEGDAWgBTtRBnA0/AGi+6ke75C
5yZUyI42djCCASQGA1UdIASCARswggEXMIIBEwYEVR0gADCCAQkwSgYIKwYBBQUHAgEWPmh0
dHBzOi8vc2VjdXJlLmlkZW50cnVzdC5jb20vY2VydGlmaWNhdGVzL3BvbGljeS90cy9pbmRl
eC5odG1sMIG6BggrBgEFBQcCAjCBrQyBqlRoaXMgVHJ1c3RJRCBDZXJ0aWZpY2F0ZSBoYXMg
YmVlbiBpc3N1ZWQgaW4gYWNjb3JkYW5jZSB3aXRoIElkZW5UcnVzdCdzIFRydXN0SUQgQ2Vy
dGlmaWNhdGUgUG9saWN5IGZvdW5kIGF0IGh0dHBzOi8vc2VjdXJlLmlkZW50cnVzdC5jb20v
Y2VydGlmaWNhdGVzL3BvbGljeS90cy9pbmRleC5odG1sMEoGA1UdHwRDMEEwP6A9oDuGOWh0
dHA6Ly92YWxpZGF0aW9uLmlkZW50cnVzdC5jb20vY3JsL2NvbW1lcmNpYWxyb290Y2ExLmNy
bDAdBgNVHQ4EFgQULbfeG1l+KpguzeHUG+PFEBJe6RQwHQYDVR0lBBYwFAYIKwYBBQUHAwIG
CCsGAQUFBwMEMA0GCSqGSIb3DQEBCwUAA4ICAQB/7BKcygLX6Nl4a03cDHt7TLdPxCzFvDF2
bkVYCFTRX47UfeomF1gBPFDee3H/IPlLRmuTPoNt0qjdpfQzmDWN95jUXLdLPRToNxyaoB5s
0hOhcV6H08u3FHACBif55i0DTDzVSaBv0AZ9h1XeuGx4Fih1Vm3Xxz24GBqqVudvPRLyMJ7u
6hvBqTIKJ53uCs3dyQLZT9DXnp+kJv8y7ZSAY+QVrI/dysT8avtn8d7k7azNBkfnbRq+0e88
QoBnel6u+fpwbd5NLRHywXeH+phbzULCa+bLPRMqJaW2lbhvSWrMHRDy3/d8HvgnLCBFK2s4
Spns4YCN4xVcbqlGWzgolHCKUH39vpcsDo1ymZFrJ8QR6ihIn8FmJ5oKwAnnd/G6ADXFC9bu
db9+532phSAXOZrrecIQn+vtP366PC+aClAPsIIDJDsotS5z4X2JUFsNIuEgXGqhiKE7SuZb
rFG9sdcLprSlJN7TsRDc0W2b9nqwD+rj/5MN0C+eKwha+8ydv0+qzTyxPP90KRgaegGowC4d
UsZyTk2n4Z3MuAHX5nAZL/Vh/SyDj/ajorV44yqZBzQ3ChKhXbfUSwe2xMmygA2Z5DRwMRJn
p/BscizYdNk2WXJMTnH+wVLN8sLEwEtQR4eTLoFmQvrK2AMBS9kW5sBkMzINt/ZbbcZ3F+eA
MDGCAxQwggMQAgEBME4wOjELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUlkZW5UcnVzdDEXMBUG
A1UEAxMOVHJ1c3RJRCBDQSBBMTMCEEABgmmaL+s+f8XR8nIOXMwwDQYJYIZIAWUDBAIBBQCg
ggGXMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTIzMDMyMDIw
MjExMlowLwYJKoZIhvcNAQkEMSIEIFlJvLztiKaPrY8ALU3cRc1Lkd3wPq8ld4suQTRJjxlc
MF0GCSsGAQQBgjcQBDFQME4wOjELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUlkZW5UcnVzdDEX
MBUGA1UEAxMOVHJ1c3RJRCBDQSBBMTMCEEABgmmaL+s+f8XR8nIOXMwwXwYLKoZIhvcNAQkQ
AgsxUKBOMDoxCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlJZGVuVHJ1c3QxFzAVBgNVBAMTDlRy
dXN0SUQgQ0EgQTEzAhBAAYJpmi/rPn/F0fJyDlzMMGwGCSqGSIb3DQEJDzFfMF0wCwYJYIZI
AWUDBAEqMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG9w0DAgICAIAwDQYIKoZI
hvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwDQYJKoZIhvcNAQEBBQAEggEAK/AN
lkOWCfDJxuEl2sVcwjYki8hMCn3Eauj6KDnFCYyz1f6wrl2x4djYpAJsXgmtFX7lTm5MbnTG
FUJAl7BoHY83tYAXv8kD5TSDuNzrUM+LML63liVPtuWn9gqiR+Wmh8tYST2reiCHOWHaxbsN
tcqaKgwxc0eWCy4EEH3QwX/U0Bkrz99D1qAGduBCuAgWmTo4T44RK3lLKWjpUkHJ+x1YA+lf
QV7s9+c9w5nuFRnJasrpeyD46/S3rdbTlJBpZeDH3rZSaOPbnxFiTerofH/uI3qlc+Nwyfgz
flCeTdSDAN4+U6Uxlv1lXrWQsrtOAYxd49EsH8oGXKVfpxXCTgAAAAAAAA==
--------------ms030103050000060704070406--