Skip to content

schannel: Handle pkcs12 client certificates which contain CA certificates #16825

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

Closed

Conversation

JDepooter
Copy link
Contributor

The SChannel code uses the CertFindCertificateInStore function to retrieve the client certificate from a pkcs12 certificate store. However, when called with the CERT_FIND_ANY flag, this function does not provide any guarantees on the order in which certificates are retrieved. If a pkcs12 file contains an entire certificate chain instead of a single client certificate, the CertFindCertificateInStore function may return the CA or an intermediate certificate instead of the desired client certificate. Since there is no associated private key for such a certificate, the TLS handshake fails.

With this change, we now pass the CERT_FIND_HAS_PRIVATE_KEY flag. This ensures that the CertFindCertificateInStore function will return a certificate which has a corresponding private key. This will stop the CA and intermediate certificates from being selected. I don't think there would be much use in a client certificate which has no associated private key, so this should ensure the client certificate is selected. I suppose it may be possible for a pkcs12 file to contain multiple certificates with private keys and the new behaviour may not guarantee which is selected. However, this is no worse that the previous behaviour in which any certificate may been selected.

The CERT_FIND_HAS_PRIVATE_KEY flag is only available in Windows 8 / Server 2012 (aka Windows NT6.2). For older versions, we will fall back to using the CERT_FIND_ANY flag.

@github-actions github-actions bot added TLS Windows Windows-specific labels Mar 24, 2025
…ates

The SChannel code uses the CertFindCertificateInStore function to retrieve the client certificate from a pkcs12 certificate store. However, when called with the CERT_FIND_ANY flag, this function does not provide any guarantees on the order in which certificates are retrieved. If a pkcs12 file contains an entire certificate chain instead of a single client certificate, the CertFindCertificateInStore function may return the CA or an intermediate certificate instead of the desired client certificate. Since there is no associated private key for such a certificate, the TLS handshake fails.

With this change, we now pass the CERT_FIND_HAS_PRIVATE_KEY flag. This ensures that the CertFindCertificateInStore function will return a certificate which has a corresponding private key. This will stop the CA and intermediate certificates from being selected. I don't think there would be much use in a client certificate which has no associated private key, so this should ensure the client certificate is selected. I suppose it may be possible for a pkcs12 file to contain multiple certificates with private keys and the new behaviour may not guarantee which is selected. However, this is no worse that the previous behaviour in which any certificate may been selected.

The CERT_FIND_HAS_PRIVATE_KEY is only available in Windows 8 / Server 2012 (aka Windows NT6.2). For older versions, we will fall back to using the CERT_FIND_ANY flag.
@JDepooter JDepooter force-pushed the schannel_support_p12_file_with_ca_certs branch from 293e114 to b003bbc Compare March 24, 2025 23:40
@testclutch

This comment was marked as outdated.

@JDepooter
Copy link
Contributor Author

@vszakats and @bagder, is there anything else needed before this can be merged? I would like to get this in while the feature window is open.

@vszakats
Copy link
Member

LGTM from my end.

@bagder bagder closed this in fe9898d Apr 15, 2025
@bagder
Copy link
Member

bagder commented Apr 15, 2025

Thanks! (also thanks for the reminder)

@JDepooter JDepooter deleted the schannel_support_p12_file_with_ca_certs branch April 15, 2025 22:10
nbaws pushed a commit to nbaws/curl that referenced this pull request Apr 26, 2025
…ates

The SChannel code uses the CertFindCertificateInStore function to
retrieve the client certificate from a pkcs12 certificate store.
However, when called with the CERT_FIND_ANY flag, this function does not
provide any guarantees on the order in which certificates are retrieved.
If a pkcs12 file contains an entire certificate chain instead of a
single client certificate, the CertFindCertificateInStore function may
return the CA or an intermediate certificate instead of the desired
client certificate. Since there is no associated private key for such a
certificate, the TLS handshake fails.

With this change, we now pass the CERT_FIND_HAS_PRIVATE_KEY flag. This
ensures that the CertFindCertificateInStore function will return a
certificate which has a corresponding private key. This will stop the CA
and intermediate certificates from being selected. I don't think there
would be much use in a client certificate which has no associated
private key, so this should ensure the client certificate is selected. I
suppose it may be possible for a pkcs12 file to contain multiple
certificates with private keys and the new behaviour may not guarantee
which is selected. However, this is no worse that the previous behaviour
in which any certificate may been selected.

The CERT_FIND_HAS_PRIVATE_KEY is only available in Windows 8 / Server
2012 (aka Windows NT6.2). For older versions, we will fall back to using
the CERT_FIND_ANY flag.

Closes curl#16825
nbaws pushed a commit to nbaws/curl that referenced this pull request Apr 26, 2025
…ates

The SChannel code uses the CertFindCertificateInStore function to
retrieve the client certificate from a pkcs12 certificate store.
However, when called with the CERT_FIND_ANY flag, this function does not
provide any guarantees on the order in which certificates are retrieved.
If a pkcs12 file contains an entire certificate chain instead of a
single client certificate, the CertFindCertificateInStore function may
return the CA or an intermediate certificate instead of the desired
client certificate. Since there is no associated private key for such a
certificate, the TLS handshake fails.

With this change, we now pass the CERT_FIND_HAS_PRIVATE_KEY flag. This
ensures that the CertFindCertificateInStore function will return a
certificate which has a corresponding private key. This will stop the CA
and intermediate certificates from being selected. I don't think there
would be much use in a client certificate which has no associated
private key, so this should ensure the client certificate is selected. I
suppose it may be possible for a pkcs12 file to contain multiple
certificates with private keys and the new behaviour may not guarantee
which is selected. However, this is no worse that the previous behaviour
in which any certificate may been selected.

The CERT_FIND_HAS_PRIVATE_KEY is only available in Windows 8 / Server
2012 (aka Windows NT6.2). For older versions, we will fall back to using
the CERT_FIND_ANY flag.

Closes curl#16825
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
TLS Windows Windows-specific
Development

Successfully merging this pull request may close these issues.

4 participants