[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_> 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--