Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

winhttp: support optional client cert #5384

Merged
merged 3 commits into from
Dec 13, 2020

Conversation

ianhattendorf
Copy link
Contributor

Some reverse proxies/applications can be configured to require client certificates (mutual TLS authentication). It's also possible that the server requests a client certificate, but doesn't require it (allowing anonymous access). For example, an HAProxy frontend can be configured as so: bind *:8443 ssl crt /etc/ssl/certs/server.pem ca-file /etc/ssl/certs/ca.crt verify required. verify required indicates that the server requires a valid client certificate to continue. Changing verify required to verify optional causes the server to request a client certificate, but allow anonymous access as well. In either case, WinHttpSendRequest will return ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED. If this is returned, the request can be retried after setting the option WINHTTP_OPTION_CLIENT_CERT_CONTEXT to either WINHTTP_NO_CLIENT_CERT_CONTEXT (in which case we are requesting anonymous access) or by attaching a valid client certificate context.

Originally reported in: #4204
Related PR: #4787

Copy link
Member

@pks-t pks-t left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks mostly good to me except for two style nits. @ethomson, want to have another look?

while (request_failed && attempts++ < 3) {
request_failed = 0;
cert_valid = 1;
client_cert_requested = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both cert_valid and client_cert_requested can be declared in the while loop

case ERROR_WINHTTP_SECURE_FAILURE: {
cert_valid = 0;
break;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually avoid braces in case bodies in case they're not required

git_error_set(GIT_ERROR_OS, "failed to set client cert context");
return -1;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we don't start supporting client certs, but simply start telling servers we ain't got one. I guess this is a good fix until we might land client certificates some time in the future and matches what Microsoft documents for this API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, to support client certs we would need to provide a callback for users to specify which client cert they would like to use. We can do this by querying WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST to get a list of valid client certs for the provided CA, providing this list in the callback, and letting the user select one. We could also provide a default callback that just picks the 1st valid cert. I'm able to successfully authenticate using this method, I would just need some free time to implement the callback and polish/test it so I'd like to handle that in a follow up.

@pks-t
Copy link
Member

pks-t commented Feb 6, 2020

Forgot to say: thanks for your effort!

@ianhattendorf
Copy link
Contributor Author

Forgot to say: thanks for your effort!

Thanks for getting to this so quickly!

@pks-t
Copy link
Member

pks-t commented Feb 7, 2020 via email

@ianhattendorf
Copy link
Contributor Author

@pks-t just wanted to ping you to make sure this doesn't get forgotten since it looks like v1.0 is out now.

Copy link
Member

@pks-t pks-t left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One remark, but otherwise this looks good to me. Sorry for the delays and thanks for your work!

request_failed = 1;
cert_valid = 0;
}
if (!request_failed || send_request_error == ERROR_WINHTTP_SECURE_FAILURE) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could be if (!request_failed || !cert_valid), which would make it code clearer to me.

Copy link
Member

@pks-t pks-t left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for amending! I'm approving, but ideally I'd like @ethomson to have another look as he's more knowledgable in the winhttp code.

@ethomson ethomson merged commit 86a1cdd into libgit2:master Dec 13, 2020
@ethomson
Copy link
Member

Thanks @ianhattendorf - sorry for the delay here, I'm trying to make my way through the backlog. LGTM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants