cloud-foundations / keymaster Goto Github PK
View Code? Open in Web Editor NEWShort term certificate based identity system (ssh/x509 ca + openidc)
License: Apache License 2.0
Short term certificate based identity system (ssh/x509 ca + openidc)
License: Apache License 2.0
High Risk
Missing authentication occurs when a system does not require authentication, allowing a user to escalate privileges in the system.
The security team discovered the keymaster application exposed an administrative interface at https://keymaster.example.com:6920/ that did not require authentication. By browsing to the URL, an attacker can view logs containing sensitive information such as, who is authenticating, what keys the user has registered, and the challenges used during new key registration, as shown in the attached screenshot.
An attacker can use this information to perform more sophisticated attacks.
Currently, if someone types in a username which passes primary authentication (i.e. Okta is used for primary auth) and the user did not drop the @company.com
part of their username, they cannot pass the 2FA step because there is no U2F token registered to [email protected]
. The user is now in limbo, unable to retry with just username
because they have a cookie which causes the primary authentication flow to be bypassed.
If there was a logout button during the 2FA phase, the user could recover more easily.
Occasionally, when I first auth with keymaster
, I get an error like this:
computer:~ jayson$ keymaster
Password for jayson:
attempting to target 'https://keymaster.example.net' for 'jayson'
top of doU2fAuthenticate
manufacturer = "Yubico", product = "YubiKey FIDO+CCID", vid = 0x0406, pid = 0x1050
version: U2F_V2
authenticating, provide user presence
hid: general error
Oddly, if I retry immediately, it always works. Often times, it works without me even pressing the key again, too.
I don't think this is exactly the same as #2. It seems to be related to an initial error accessing the hid
subsystem or something. If we did a single retry on that specific error, I suspect it would be a decent workaround.
Running newest version of Firefox (85.0.2) on MacOS Catalina (10.15.7). Using a Yubikey 5C Nano, I recently had a great deal of trouble getting a replacement registered.
Firstly, I was getting delayed notifications when I attempted to go through the registration workflow. While this wasn't Keymaster's fault, it didn't do a good job of indicating that the e-mail I was looking at had an old code on it. Not entirely sure what to do here, but perhaps something involving a clear timestamp or fingerprint that should match between the e-mail and the OTP code form would be helpful. Or perhaps some way to resend a recent code and reuse it. The pathology of going through the registration cycle but never quite telling that you're one e-mail behind is very real and a pretty poor UX.
Once I got that right, I could never get Firefox to prompt when I attempted to register the key. I'd click the "Register" button but it would never pop up to read the U2F key. I was able to verify the key was installed using ykman
and I was also able to register the key with Firefox on GitHub and Okta. I eventually got it working with Chrome (88.0.4324.150), so it seems to be something with Firefox specifically.
Issue
The /users/ endpoint displays a list of all the Keymaster users to any logged in user. Also, there is no cleanup of this list in the backend.
Steps to reproduce
Login to keymaster (web) Go to the /users/ endpoint. One can see the names of all the users here.
Impact
There is no cleanup of users on keymaster backend. It would be great to add some mechanism to deactivate users on keymaster backend. Additionally, any logged in user can see a list of all keymaster users.
Remediation
Cleanup the user list so that only valid users are maintained in the database. Additionally, this list should ideally not be visible to non-admin users.
The admin panel on port 6920 is by default bound to all interfaces. Instead, bind the address to localhost only to provide for defense in depth and use a proxy or iptables to expose the port to the outside world if desired.
The last few days the Keymaster instances were not able to fetch the U2F token database from RDS and fell back to their cached versions. The effect on logins is a slight delay (a few seconds) but this would block people registering new U2F tokens. Restarting the daemons fixed the problem, but investigation is needed to understand why this failed and implement a permanent fix.
For reference, the instances first logged problems with fetching from RDS: GOT a timeout
The first error times were several hours apart. The timeout errors were immediately preceded by this error:
Error Preparing statement LoadUsers primary DB: write tcp XXXXX: write: broken pipe
Add a privileged API call to add an expiring One Time Password for a user if the user has no active 2nd factors registered. The OTP should be added to a database. When a user completes primary (username+password) authentication, the 2nd factor check will fall back to checking the database for the expiring OTP when there are no active 2nd factors registered for the user.
This may be used to streamline/automate the bootstrapping of users when they are first on-boarded and have no 2nd factor registered yet, when combined with issue #15.
This depends on issue #21.
Currently when okta 2fa is enabled the push notification is sent, but no message is given to the user. This leads to confusion as users assume that they need to enter the code, and that the push notification is not sufficient.
1.15.x is more strict on its handling of certificates. We need to construct certificates for testing that include localhost in their SAN fields
Running make get-deps
ends with
go: module github.com/duo-labs/webauthn is deprecated: use github.com/go-webauthn/webauthn instead
Issue
The content security policy allows unsafe-inline for style.
Steps to reproduce
Login to keymaster (web). We will notice that the response returns the CSP header which allows unsafe inline for style.
Impact
Allowing inline styles makes one susceptible to a the "other XSS". Cross Site Styling attacks that could end up defacing the website. Unless the other CSP rules never allow any kind of request to go to a untrusted or wildcard domain, then using a carefully crafted style rules attackers could send any information included on the page to external domains and expose or otherwise use that data maliciously against users.
Remediation
Don’t allow unsafe-inline option.
Code/Lines affected
keymaster/cmd/keymasterd/app.go
Line 545 in 8311025
High Risk
Insecure input validation occurs when an application does not perform input validation before using untrusted input in a downstream component.
The keymaster application validates redirect URLs using a regular expression that does not take into account URL metacharacters such as ?
and @
. By using a ?
character in a redirect URL, an attacker can force a victim to send their authentication credentials to an attacker controlled site. For example, this redirect_uri will send a user's credentials to rooted.systems
instead of the intended target example.com
/idp/oauth2/authorize?client_id=Vpih48hsRwUv5oqpYYNg7f8u34RI1N2D%2F%2FknlziteYo%3D&redirect_uri=https%3a//rooted.systems%3f.example.com/
Upon authenticating with a malicious URL, the victim's credentials are sent to the attacker controlled site:
/?.example.com/?code=eyJhbGciOiJSUzI1NiIsImtpZCI6IiIsInR5cCI6IkpXVCJ9.[REDACTED].pBlnR6pIJxKFDiqoxz4FVmvchEDP4ubZKRQ3wk28Uu0 HTTP/1.1
Host: rooted.systems
...omitted for brevity...
As shown above, after authenticating with the malicious URL, the victm's authentication code is sent to rooted.systems
as part of a URL parameter.
Issue
Aud claim is not verified during the jwt verification step.
Steps to reproduce
NA
Impact
The "aud" (audience) claim identifies the recipients that the JWT is intended for. Each principal intended to process the JWT MUST identify itself with a value in the audience claim. If the principal processing the claim does not identify itself with a value in the "aud" claim when this claim is present, then the JWT MUST be rejected. In this case, since the aud claim is not being verified, unintended principles might be able to process the jwt claim.
Remediation
From looking at the code in the lines mentioned below, there is already a check for the issuer and the issuer value and the aud value are the same from (https://github.com/Cloud-Foundations/keymaster/blob/master/cmd/keymasterd/jwt.go#L57 ). Please add a check that will verify the aud claim as well.
Code/Lines affected
keymaster/cmd/keymasterd/jwt.go
Line 77 in 69e7d71
keymaster/cmd/keymasterd/jwt.go
Line 145 in 69e7d71
For, not so great reasons, I am unable to put the valid x509 cert on the keymaster server. For this reason I am terminating https on an ALB. This works fine for browser, but I am unable to get the keymaster cli to work through this, receiving HTTP 464.
As a workaround I had added golang.org/x/net/http2
and ensured every request in the client had client.Transport = &http2.Transport{}
. This unblocked my issue.
HTTP 464
The load balancer received an incoming request protocol that is incompatible with the version config of the target group protocol.
Possible causes:
The request protocol is an HTTP/1.1, while the target group protocol version is a gRPC or HTTP/2.
The request protocol is a gRPC, while the target group protocol version is an HTTP/1.1.
The request protocol is an HTTP/2 and the request is not POST, while target group protocol version is a gRPC.
Usage of keymaster (version 1.7.0)
attempting to target '' for ''
top of doU2fAuthenticate
manufacturer = "Yubico", product = "Yubikey NEO U2F", vid = 0x0113, pid = 0x1050
u2fhid: error reading response, read timed out
In Yubikey Manager GUI it shows up as Yubikey NEO 3.0.0.
U2F works fine on various websites.
This is required for issue #21.
Impact:
Medium
(remotely explotiable with non-default configuration)
CVSS v 3.1 Vector:
AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N
The admin panel logs pages are vulnerable to HTML injection. An attacker can craft a phishing page using HTML + CSS and trick admins who view the page into disclosing their credentials. CSP prevents JS execution, but JS execution isn’t necessary to do damage.
When an admin registers a U2F token for a user (by visiting the profile page for that user), an attempt to verify the token for that user does not work as expected. Instead, token verification for the signed in user (the admin) is performed.
The verification operation should specify the username corresponding to the profile page that is being viewed.
When using Okta as the primary authentication back-end, a user can enter either username
or [email protected]
and the Okta API will treat them equivalently. As described in issue #3, this presents a problem during the 2FA verification, as the U2F tokens are typically registered with just username
. If the user tries to log in with [email protected]
the token looked will fail and thus the user will not be able to complete the 2FA challenge.
Note that the Okta configuration typically has company
as the domain. The implicit mapping to @company.com
is internal to Okta.
Here are some potential solutions:
Modify the Okta back-end to fail the login attempt if the user enters an @
, thus forcing them to enter only username
. This would prevent the user from getting into a limbo, half logged in state (as in issue #3), but it seems like an annoying user experience, as users have already gotten used to typing in [email protected]
. Further, it may be challenging to present a clear message to the user explaining what went wrong
Add a configuration option defining a filter regexp for the username string that the user enters. This provides a good user experience, but requires the administrator to modify the configuration (which may happen after some users complain and the administrator puts in the effort to figure out what's going wrong)
Modify the U2F back-end to strip out the @
and everything afterwards. Again, this gives a good user experience and doesn't require tweaking by the administrator, but would hard-code in a limitation which would prevent supporting users from multiple domains (i.e. @company1.com
and @company2.com
).
Overall, I think option (2) is best, as it provides a good user experience and doesn't reduce potential future flexibility.
There is a race condition between the background loop checking for okta push and the user sending a code. If the code is sent the background task might also send a query which will be invaldated because the user has already logged in.
We need to suspend sending background requests as soon as the user submits a code.
I recently upgraded to Firefox 91.0.
Upon upgrading, the next time I logged in to Keymaster, I got to the point where it would ask for my Yubikey. However, the prompt just never popped up.
Did some debugging with @rgooch and he observed the following message on an already-logged-in profile page:
Your browser does not support U2F. However you can still Enable/Disable/Delete U2F tokens
Is this some sort of browser-support-detection problem? (I was unable to find a similar bug at the U2F-API page, so they may not know yet?)
I am using keymaster as an openid connect provider. I use a U2F hardware key and Chrome 95.
After U2F SignResponse I am redirected to /idp/oauth2/authorize?access_type=offline&client_id=<REDACTED>&redirect_uri=https://<REDACTED>/callback&response_type=code&scope=openid+profile+email+offline_access&state=<REDACTED>
This is causing an issue w/ the golang net/http which no longer allows semicolons in req.URL.RawQuery per line 2873.
Error in keymaster log: http: URL query contains semicolon, which is no longer a supported separator; parts of the query may be stripped when parsed; see golang.org/issue/25192
Error in the browser: '500 Internal Server Error'
This does not occur when I use TOTP. This also does not occur when I log in to keymaster directly using U2F, only when it is part of an openid connect login for a different endpoint. Additionally I have no issue if I login to keymaster first and then navigate to my openid connect endpoint.
The dependency on github.com/cviecco/argon2 should be replaced with golang.org/x/crypto/argon2.
Generated certificates do not appear to match the CA in use. I ran keymaster on the same host and attempted to validate against ca.
SSH Key works fine.
$ keymaster
Password for myuser:
attempting to target 'https://keymaster.xxx.xxx' for 'myuser'
top of doU2fAuthenticate
manufacturer = "XXX", product = "XXX", vid = 0xXXX, pid = 0xXXX
version: U2F_V2
authenticating, provide user presence
counter = XXX, signature = XXX
Success
$ cd .ssl
$ openssl verify -CAfile /etc/keymaster/adminCA.pem keymaster.cert
O = keymaster, CN = myuser
error 20 at 0 depth lookup: unable to get local issuer certificate
error keymaster.cert: verification failed
$ openssl verify -CAfile /etc/keymaster/adminClient.pem keymaster.cert
O = keymaster, CN = myuser
error 20 at 0 depth lookup: unable to get local issuer certificate
error keymaster.cert: verification failed
Some back-end primary authentication services (i.e. Okta) can provide a profile image for a user. It would be cool if Keymaster could grab this information and pass it along to downstream consumers such as Web Service Providers (SPs).
If the back-end provides a URL to the profile image, that could be passed along as-is. However, if the back-end provides the image data inline then Keymaster must store the image data. The database used for managing U2F tokens is a good place for this, as these data are already automatically replicated to Keymaster instances. Since images can be large, they should be capped in size and transcoded prior to storage to prevent excessive growth of the database.
Even if the back-end provides a URL, it may be preferable to grab the data, cap and transcode it so that internal systems can obtain the profile information without having to connect to the back-end. This would enhance privacy and resiliency.
It appears that Keymaster is using the deprecated U2F plugin in Chrome. This will not work after Feb 2022. I get this warning with Chrome 96.
Currently u2f-api.js uses the Cryptotoken extension (kmendfapggjehodndflmmgagdbamhnfd) that is built into Chrome. This is being deprecated in favor of using webauthn in future versions of Chrome and thus U2F will stop working.
Tried to use the certgen GenSelfSignedCACert in another project and it failed because on the generation of the serial we use a signature using sha256. This does not work for P-384 (or EdDSA).
I've run into a few use-cases where it would be handy to be able to trigger the bootstrap workflow without deleting the current keys or where it would be handy to inhibit the bootstrap workflow but still have the user configured with no keys.
Would it be possible to do something like?
When a user completes primary authentication (username+password) and has no active U2F tokens, generate a short term (expires in 1 minute) OTP, use the API described in issue #14 and email the OTP value to the user, along with a clickable link to the login page.
This will allow self-service bootstrapping of new users.
This will allow distributing the CA certificate to machines for trust and not worry about the certificate trusting servers. The certificate should probably have only the ExtKeyUsageClientAuth
bit set
Gnome-keyring ships with an ssh agent that will load all keys in ~/.ssh/ that have a corresponding pub key. This is documented here.
This creates the an issue for Gnome users since all temporary ssh keys are loaded. OpenSSH defaults to MaxAuthTries to 6, meaning that after a week of usage you find yourself unable to utilize new keys due to the loading of the temporary keys.
We have a service using the oidc golib package and keymaster for auth and would like to make AJAX requests to the service from a client-side JS app.
Currently, if the user has not gone through the auth flow to get a cookie set for the service, our AJAX POST
request to the service will get redirected to the keymaster login, which will proceed to get blocked by CORS as it has no CORS headers on the response and prevent the browser from showing anything about the response.
Is there any way we could either set those headers for keymaster (not sure if thats actually what we want or how the flow would work in that case), be able to go through the flow in an iframe, or have the oidc golib package return a 401 Unauthorized
with a link to the keymaster auth on AJAX requests (denoted by some header) so that we can manually redirect the user?
More detail here.
I'm using keymaster as an openidc endpoint for a few sites and am seeing issues with the auth_cookie due to the lack of SameSite settings. I believe this should be set to "SameSite: None" if I am reading the Chrome FAQ correctly. Thoughts?
https://www.chromium.org/updates/same-site/faq
Q: What is the Lax + POST mitigation?
This is a specific exception made to account for existing cookie usage on some Single Sign-On implementations where a CSRF token is expected on a cross-site POST request. This is purely a temporary solution and will be removed in the future. It does not add any new behavior, but instead is just not applying the new SameSite=Lax default in certain scenarios.
Specifically, a cookie that is at most 2 minutes old will be sent on a top-level cross-site POST request. However, if you rely on this behavior, you should update these cookies with the SameSite=None; Secure attributes to ensure they continue to function in the future.
Issue
Logging out of Keymaster does not invalidate the auth_cookie ie the jwt that is issued upon login.
Steps to reproduce
Login to Keymaster. Using a proxy such as Burp, one would be able to see the auth_cookie that is issued upon successful login. This is a jwt whose expiry is around 12 hrs. Send this request to the Burp repeater.
Now click logout. We will notice that the request we sent to the burp repeater will still work successfully despite the logout.
Additionally, if we re-login, the old jwt/auth-cookie will still be valid.
Impact
If a session can still be used after logging out then the lifetime of the session is increased and that gives third parties that may have intercepted the session token more time to impersonate a user.
Remediation
One possible solution would be - to store a “blacklist” of all the tokens that are no longer valid and have not expired yet. One can use a DB that has TTL option on documents which would be set to the amount of time left until the token is expired. Redis is a good option for this, that will allow fast in memory access to the list. Then, in a middleware of some kind that runs on every authorized request, one should check if provided token is in the blacklist. If it is, then throw an unauthorized error. Else, let the JWT verification handle the request and identify if the jwt already expired or is still active.
(Ref - https://medium.com/devgorilla/how-to-log-out-when-using-jwt-a8c7823e8a6)
There are references in this repo to colud-foundations.org, but that domain has either been lost or the webserver is broken (shows a pretty empty file listing now).
Is that domain still supposed to be active? If not, probably this repo should drop references to it?
Some endpoints (such as angular) have much better support of PKCE code flow than for the standard openid connect code flow. This feature will allow PKCE libraries to be able to use keymaster as a web idp
Add a new authentication type based on Keymaster-signed X.509 certificates.
This will allow calls to the Keymaster API using Keymaster-issued X.509 certificates. This is required to support issue #14.
Have keymaster providing openid_connect_idp services to some services. Also have it configured to allow oauth2 logins.
When a user attempts to login to a service utilizing openid_connect_idp they are redirected to keymaster. If they click oauth2 login they are greeted with /profile/.
Steps to reproduce
Expected results
After oauth2 login succeeds I should be redirected to the original service (client under openid_connect_idp)
Running the MacOS Keymaster client with a Yubikey 5C nano plugged in I got this error:
top of doU2fAuthenticate manufacturer = "Yubico", product = "YubiKey OTP+FIDO+CCID", vid = 0x0407, pid = 0x1050 u2fhid: error reading response, read timed out
The Yubikey did not blink.
I then plugged in a Feitian U2F token as well and ran the Keymaster client again. The Feitian did not blink but the Yubikey did, so I pressed it and it worked. Before I pressed the Yubikey I pressed the (not blinking) Feitian to see what would happen and I just got OTP codes in my terminal.
I unplugged my Feitian token and tried again with just the Yubikey token and everything worked fine. I tried again and it worked.
Users should be alerted when a new U2F token is registered for them (whether by themselves or by an administrator). Send an email to the user for these events, including who registered the token.
Add a configuration option to control when administrators are also alerted about token registrations:
It would be great to add a Copy button (some JavaScript, that copies this token into system copy buffer) to a webpage that displays token for copying into CLI.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.