1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
# Known issues with GSSAPI
GSSAPI on Linux is typically provided by either the [MIT krb5](http://web.mit.edu/kerberos/) library or by
[Heimdal](https://github.com/heimdal/heimdal). While the behaviour of both are largely the same there can be some
differences in some edge cases. Pyspnego tries to iron out those differences where it can and make them the same but
in some cases that isn't possible. This document aims to outline all those behaviour differences and what pyspnego
tries to do about them.
_Note: The majority of the tests are done with MIT krb5 so that's the implementation that will work the best with pysnego._
# Scenarios
Each scenario below should outline
* The distribution/GSSAPI version that are known to be affected
* A description of the scenario
* The problem and known workarounds
* Python code that can be used to test out the scenario in the future
This is an evolving document and I'm trying to keep this updated as I figure out problems going forward.
* [Channel bindings on MIT Negotiate](#channel-bindings-on-mit-negotiate)
* [Delegation with explicit credentials](#delegation-with-explicit-credentials)
* [Explicit Kerberos pass is stored in the credential cache](#explicit-kerberos-pass-is-stored-in-the-credential-cache)
* [RC4 unwrapping on Heimdal](#rc4-unwrapping-on-heimdal)
## Channel bindings on MIT Negotiate
### Versions affects
| Distribution | MIT Version | Heimdal Version |
|-|-|-|
| Centos 8 | <=1.18.2 | N/A |
### Description
When using pure `SPNEGO` through MIT KRB5 it will fail to pass the channel bindings token along to the underlying
mech causing failures if CB were required by the acceptor. This has been fixed in a
[recent commit](https://github.com/krb5/krb5/commit/d16325a24c34ec9a5f6fb4910987f162e0d4d9cd) but not into any releases
as of yet. MIT KRB5's `SPNEGO` provider is only used when both Kerberos and NTLM are available, if it is not then
`pyspnego` will automatically use it's own Negotiate provider which handles this scenario just fine.
The workaround is to either set `options=spnego.NegotiateOptions.use_negotiate` to force the use of `pyspnego's`
Negotiate provider or set the protocol to either `ntlm` or `kerberos` explicitly.
_Note: Some distributions, like Fedora, have backported this to the 1.18.x releases on those distributions._
### Code
This problem is already fixed and is just waiting on a new MIT KRB5 release, no need for code to test this.
## Delegation with explicit credentials
### Versions affected
| Distribution | MIT Version | Heimdal Version |
|-|-|-|
| Centos 8 | N/A | 7.7.0 |
### Description
When explicit credentials are used for Kerberos authentication there is no way to pass in desired flags into
`gss_acquire_cred_with_password`. For MIT we use a temporary `krb5.conf` file with the lines below to ensure that the
retrieved ticket is forwardable for delegation purposes:
```text
[libdefaults]
forwardable = true
```
Heimdal does not seem to use any of the `forwardable` flags in the `krb5.conf` so any credential that is retrieved
cannot be used in a delegation scenario. The only workaround is to call `kinit`, optionally with the `-f` flag, to
explicitly state that the credential can be forwarded/delegated. In pyspnego this means that no password should be set
when creating the context.
This problem has been fixed by [this PR](https://github.com/heimdal/heimdal/pull/738) and looks like it will be
backported to the 7 series of releases so I expect this to no longer be an issue once Heimdal 7.8 comes out.
### Code
Before running this you must initialise the credential store by running `kinit -f username@REALM.COM`. You should also
make sure `[libdefaults]\nforwardable = true` is set in `/etc/krb5.conf`
```python
import gssapi
kerberos = gssapi.OID.from_int_seq('1.2.840.113554.1.2.2')
username = gssapi.Name(base='username@REALM.COM', name_type=gssapi.NameType.user)
cred = gssapi.raw.acquire_cred_with_password(username, b'Password', usage='initiate', mechs=[kerberos]).creds
gssapi.raw.store_cred(cred, usage='initiate', mech=kerberos, overwrite=True)
```
Once that is complete run `klist -f` to view the cred store
```text
[vagrant@CENTOS8-HEIMDAL ~]$ klist -f
Credentials cache: FILE:/tmp/krb5cc_1000
Principal: spnego@SPNEGO.TEST
Issued Expires Flags Principal
Jul 10 01:54:48 2020 Jul 10 11:54:48 2020 IA krbtgt/SPNEGO.TEST@SPNEGO.TEST
```
The flags should contain `F` to indicate the credential is forwardable.
## Explicit Kerberos pass is stored in the credential cache
### Versions affected
| Distribution | MIT Version | Heimdal Version |
|-|-|-|
| N/A | <1.14 | N/A |
### Description
When using an explicit credential with Kerberos authentication the system call `gss_acquire_cred_with_password` is
used. On MIT versions less than `1.14`, it will store those credentials in the system cache which is available to other
processes for that user. This can be considered an issue as it exposes the Kerberos ticket to other processes allowing
it to use the credentials provided by the script. Newer versions store this in a memory specific cache for that
process.
While this problem has been fixed since 1.14 older hosts are still affected by this problem. What they can do to
workaround this problem and have the credentials be "private" is
* Update the MIT krb5 version to at least 1.14
* Set the env var `KRB5CCNAME` to a temp file accessible only by that user and delete once finished
The latter env var is used to specify a custom credential cache when MIT goes to store the credential. By having it as
a process specific temp file it will stop it from storing it in the default credential cache.
## RC4 unwrapping on Heimdal
### Versions affected
| Distribution | MIT Version | Heimdal Version |
|-|-|-|
| Centos 8 | N/A | 7.7.0 |
### Description
Heimdal's unwrapping code does not work the same way as MIT or SSPI. While the `unwrap_winrm()` function is designed
to paper over this problem as best as it can it doesn't fix the problem where RC4 wrapped data cannot be unwrapped when
using Heimdal. This shouldn't be an issue for most people but I am documenting it here in case someone comes across it
in the future.
There are 2 problems here;
* Heimdal mandates the presence of a `PADDING` IOV buffer in the call to `gss_unwrap_iov()`
* A bug in the RC4 decryption code which results in an erroneous validation error of the header
These 2 bugs have been fixed in [this PR](https://github.com/heimdal/heimdal/pull/740), the PR has also been tested and
confirmed to work using the same IOV buffer setup as both MIT and SSPI. Unfortunately using those IOV buffers fails
in existing Heimdal versions so the current code just calls `gss_unwrap()` which works only for AES. This unfortunately
means RC4 will never work until the code has changed to the IOV variant but that can only be done once the newer
Heimdal versions have a wider distribution.
### Code
This problem is being fixed in [the PR](https://github.com/heimdal/heimdal/pull/740) and this is extremely hard to
test. See [test_integration.py::test_winrm_rc4_wrapping](../tests/integration/templates/test_integration.py.tmpl) for
the integration test that covers this scenario. Currently it is disabled on the Heimdal tests.
|