How gRPC's NewClientTLSFromCert generates TLS credentials from public key? - ssl

The google.golang.org/grpc/credentials library has the following method.
// NewClientTLSFromCert constructs TLS credentials from the provided root
// certificate authority certificate(s) to validate server connections. If
// certificates to establish the identity of the client need to be included in
// the credentials (eg: for mTLS), use NewTLS instead, where a complete
// tls.Config can be specified.
// serverNameOverride is for testing only. If set to a non empty string,
// it will override the virtual host name of authority (e.g. :authority header
// field) in requests.
func NewClientTLSFromCert(cp *x509.CertPool, serverNameOverride string) TransportCredentials {
return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp})
}
I am confused about how it can generate TLS credentials from a public key (the certificate here).
How will this work? If I generate credentials from a public cert, why would it be accepted on the server side whose TLS cert has been signed with the private key of the TLS CA?
What exactly happens here and how is the connection secured over here?

Transport "credentials" in gRPC are fully responsible for the handshake with the client/server. That means they include configuration other than just "credentials" like private keys and other secrets. For TLS here, it includes the root trust certificates to use when verifying the server's certificate. You can think of it as just "TLS configuration."

Related

What's the "system trust roots on the apiserver" for the "caBundle" in defination of "WebhookClientConfig" of Kubernetes

When I check the definition of "WebhookClientConfig" of API of Kubernetes I found comments like this:
// `caBundle` is a PEM encoded CA bundle which will be used to validate the webhook's server certificate.
// If unspecified, system trust roots on the apiserver are used.
// +optional
CABundle []byte `json:"caBundle,omitempty" protobuf:"bytes,2,opt,name=caBundle"`
in WebhookClientConfig
I wonder to know, what's exactly the "system trust roots "?
and I'm afraid the internal signer for CSR API of Kubernetes is not one of them.
It is a good practice to use secure network connections. A Webhook-endpoint in Kubernetes is typically an endpoint in a private network. A custom private CABundle can be used to generate the TLS certificate to achieve a secure connection within the cluster. See e.g. contacting the webhook.
Webhooks can either be called via a URL or a service reference, and can optionally include a custom CA bundle to use to verify the TLS connection.
This CABundle is optional. See also service reference for how to connect.
If the webhook is running within the cluster, then you should use service instead of url. The service namespace and name are required. The port is optional and defaults to 443. The path is optional and defaults to "/".
Here is an example of a mutating webhook configured to call a service on port "1234" at the subpath "/my-path", and to verify the TLS connection against the ServerName my-service-name.my-service-namespace.svc using a custom CA bundle

How to get Remote server untrusted SSL certificate using Apache HTTP Client API

I have a remote server which may or may not be running using a valid SSL cert (using self-signed SSL cert).
We are making connection to remote server, which may fail if remote server is using self-signed SSL cert. So, we want to be able to download/view the remote server cert if our SSL handshake fails.
If I use Apache HTTP Client then I couldn't find a method which could allow me to view remote server certificate (you can do it with HttpsURLConnection but we are trying to avoid using it see this example).
I also looked into Spring RestTemplate, and it didn't provide any option either - I searched on Google and didn't find anything around Spring or Apache HTTP Client.
This should give you pretty much a complete control over the process of trust verification.
SSLContext sslContext = SSLContextBuilder.create()
.loadTrustMaterial((chain, authType) -> {
for (X509Certificate cert: chain) {
System.out.println(cert.getSubjectDN());
}
// Let the standard trust managers decide
// whether or not the cert chain is trusted
return false;
})
.build();
CloseableHttpClient client = HttpClientBuilder.create()
.setSSLContext(sslContext)
.build();

Can server send multiple certificates to client?

I have written small Java 7 Client and Server application. I have keystore with 3 Self-signed X.509 RSA Certificates. When client connects through SSL, server sends SSL Certificate message with only one certificate. I am bit new to SSL/TLS. I also looked at JSSE code sun.security.ssl.X509KeyManagerImpl, and found below comments:
/*
* Return the best alias that fits the given parameters.
* The algorithm we use is:
* . scan through all the aliases in all builders in order
* . as soon as we find a perfect match, return
* (i.e. a match with a cert that has appropriate key usage
* and is not expired).
* . if we do not find a perfect match, keep looping and remember
* the imperfect matches
* . at the end, sort the imperfect matches. we prefer expired certs
* with appropriate key usage to certs with the wrong key usage.
* return the first one of them.
*/
private String More ...chooseAlias(List<KeyType> keyTypeList,
Principal[] issuers, CheckType checkType)
Comment is pretty clear that server will send single best matching certificate but I don't seem to understand the reason. Like in my case, I want server to send all 3 certificates, so client can pick one and validate the chain. And also, if my client doesn't have the certificate that server sends, the connection is dropped with SSLHandshakeException 'No trusted certificate found'. So my question is that why can't server send all 3 certificates if the client requested information (from ClientHello) matches with all 3 certificates ? Is it something to do with TLS 1.0 vs TLS 1.2 ?
The TLS handshake protocol only provides for the transmission of one client end-entity certificate (this is also the case for server certificates). Intermediate certificates can be transmitted, but what you seem to want - transmission of multiple end-entity certificates - is not possible.
The structure of the TLS Server / Client Certificate message is defined in RFC 5246 (TLS 1.2) section 7.4.2:
Structure of this message:
opaque ASN.1Cert<1..2^24-1>;
struct {
ASN.1Cert certificate_list<0..2^24-1>;
} Certificate;
certificate_list
This is a sequence (chain) of certificates. The sender's
certificate MUST come first in the list. Each following
certificate MUST directly certify the one preceding it. Because
certificate validation requires that root keys be distributed
independently, the self-signed certificate that specifies the root
certificate authority MAY be omitted from the chain, under the
assumption that the remote end must already possess it in order to
validate it in any case.
In regards to which certificate the client selects to present, if you configure your server to advertise its trusted CAs for client certificate validation (the certificate_authorities field of the CertificateRequest message; see below), then the client-side code that selects the certificate to present ought to select a certificate that is certified by one of the advertised CAs.
7.4.4. Certificate Request
...
Structure of this message:
enum {
rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
rsa_ephemeral_dh_RESERVED(5), dss_ephemeral_dh_RESERVED(6),
fortezza_dms_RESERVED(20), (255)
} ClientCertificateType;
opaque DistinguishedName<1..2^16-1>;
struct {
ClientCertificateType certificate_types<1..2^8-1>;
SignatureAndHashAlgorithm
supported_signature_algorithms<2^16-1>;
DistinguishedName certificate_authorities<0..2^16-1>;
} CertificateRequest;
...
certificate_authorities
A list of the distinguished names [X501] of acceptable
certificate_authorities, represented in DER-encoded format. These
distinguished names may specify a desired distinguished name for a
root CA or for a subordinate CA; thus, this message can be used to
describe known roots as well as a desired authorization space. If
the certificate_authorities list is empty, then the client MAY
send any certificate of the appropriate ClientCertificateType,
unless there is some external arrangement to the contrary.
And, from section 7.4.6:
If the certificate_authorities list in the certificate request
message was non-empty, one of the certificates in the certificate
chain SHOULD be issued by one of the listed CAs.
Bad luck, you can only send one. See RFC 2616 &ff.

Self Signed Certificate: Can I trust the client being indeed the owner of the public key?

I am playing around with OpenSSL, and in my server code I have the following:
rc = SSL_get_verify_result(ssl);
printf("SSL_get_verify_result(): %i\n", rc);
cert = SSL_get_peer_certificate(ssl);
printf("SSL_get_peer_certificate(): %p\n", cert);
pkey = X509_get_pubkey(cert);
printf("X509_get_pubkey(): %p\n", pkey);
SSL_get_verify_result() returns X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN which is expected.
My question is, can I trust that the client is actually the owner of the pub key that I get using X509_get_pubkey() after SSL_get_verify_result() has failed with the above error.
In other words, can I perform authentication using this public key (assuming my server somehow has knowledge of this public key).
Thanks!
You can trust that the peer owns the private key of the certificate he supplies, because he also supplies a digital signature which is checked by SSL using the public key in the certificate. Only the owner of the private key can do that.
Whether you trust that the peer owns the identity expressed in the subject DN comes down to whether you trust the issuer, which in the case of a self-signed certificate is himself.
And whether that identity is authorised to communicate with your application is yet another question, which only your application can answer.

SSL error RemoteCertificateNameMismatch

I am using WCF for the client to access service. I am trying to access the endpoint with TLS (https). I have certificates with both private and public keys.
If I have the end point of the service to have the host name same as the certificate name ("Issued To"), then i am able to access the service from the client.
If the names of the "issued to" and end point domain name are different i get the error "Could not establish trust relationship for the SSL/TLS secure channel with authority". I have added the certificates to "Trusted Root", "Personal" and "trusted People". In my service i have used "PeerOrChainTrust".
Please let me know if anybody has any idea on this.
Thanks,
Jan
In that case, you need to define the trust policy for the server on client side,
Call SetCertPolicy once before you make any call to the services.
using System.Net;
using System.Security.Cryptography.X509Certificates;
public static void SetCertPolicy()
{
ServicePointManager.ServerCertificateValidationCallback += RemoteCertValidate;
}
private static bool RemoteCertValidate( object sender, X509Certificate cert, X509Chain chain,
SslPolicyErrors error )
{
// trust any cert!!!
return true;
}
I don't think you can override the check on whether the certificate name matches the server name.
Some agents allow you to manually override after the warnings, but unless WCF has a setting to disable certificate validation with all the dangers that brings. SSL is designed first and foremost for the client to be able to validate which server it is talking to, otherwise you will be open to all sorts of vulnerabilities (including man-in-the-middle and fake servers).