How to setup TLS for an NS record subdomain - ssl

I have an NS record setup for my.domain.com, which then resolves as http://my.domain.com >> https://thirdparty.domain.com
I need to setup a TLS certificate for my.domain.com so that it can be reached at https://my.domain.com >> https://thirdparty.domain.com
my.domain.com is managed in AWS, and as far as I know getting a certificate requires that certificate to live on a server. Whereas, the NS record seems to just point the domain at a server outside of my control. thirdparty.domain.com is a third party service.
Am I understanding this correctly? How/where will I need to setup the TLS certificate for https://my.domain.com
Example:
my.domain.com NS record:
some.thirdparty.server.
Results in 302: http://my.domain.com > RES: https://thirdparty.domain.com
I would like:
302: **https**://my.domain.com > RES: https://thirdparty.domain.com
In practice this is the flow:
main.domain.com POST >>
302: http://my.domain.com >>
RES: https://thirdparty.domain.com

The system that terminates (where decryption occurs) the TLS connection will need the certificate. The system that responds to a TCP connection on port 443 on the IP address which the domain that you type in your browser ultimately resolves to needs to have the TLS certificate.
my.domain.com NS record: some.thirdparty.server.
That means the third party controls which servers respond.
I would like: 302: **https**://my.domain.com > RES: https://thirdparty.domain.com
As far as I read this, this is about a HTTP redirect from the first to the second. What you would like requires to receive HTTPS connections on my.domain.com, to do that the servers that currently receives HTTP there need to also do so for HTTPS.
If you do not control these server and they currently do not answer to HTTPS, then the only way is to handle DNS yourself (i.e. remove the NS record) and point to servers that only do this redirect. (As you are currently using AWS: That is something their services S3 and CloudFront can achieve together.)

Related

Invalid certificate for "localhost" on Cloudflared

I am running a web server (Wordpress) locally using XAMPP (using Apache) and forwarding it to my Cloudflare-hosted domain using a Cloudflared tunnel. I am having an issue with the certificate when connecting over my domain.
I have a certificate I received from Cloudflare which is valid for my domain installed in XAMPP's location for its certificate, and I know that it is being sent with the HTTPS result. Also, my "SSL/TLS encryption mode" on Cloudflare is "Full (Strict)".
When connecting from the browser, I get a 502 Bad Gateway error, and Cloudflared prints this error: error="Unable to reach the origin service. The service may be down or it may not be responding to traffic from cloudflared: x509: certificate is valid for *.example.com, example.com, not localhost where example.com is my domain.
If I go to
http://example.com or https://example.com, I get the above error.
http://localhost, the website loads but does not load any of the resources, since Wordpress loads the resources by querying the domain, https://example.com/path/to/resource.
https://localhost, the same as above happens, but Chrome also give me a warning that the certificate is not valid.
Here are the ingress rules in Cloudflared's config.yml.
ingress:
- hostname: ssh.example.com # I haven't gotten this one to work yet.
service: ssh://localhost:22
- hostname: example.com # This is the one having a problem.
service: https://localhost
- service: https://localhost
What I believe is happening is that Cloudflared receives the certificate which is valid for my domain (*.example.com, example.com) and then tries to execute the ingress rule by going to https://localhost, but the certificate is not valid for localhost. I don't think I should just get a certificate which is valid for localhost AND example.com. Do I need one certificate (valid for localhost) to be returned whenever http(s)://localhost is called and another (valid for example.com) that Cloudflared checks when it tries to execute an ingress rule involving example.com? If so, how do I do this?
I solved it by using the noTLSVerify option in Cloudflared's config.yml. When a client connects to my domain, it goes like this:
Client > Cloudflare > Cloudflared instance running on my machine > Origin (which also happens to be my machine: https://localhost)
The certificate sent back by the Origin was not valid for the address Cloudflared was accessing it from, localhost, but by adding these lines to config.yml,
originRequest:
noTLSVerify: true
I think Cloudflared does not check the certificate received from the origin, although it still returns the certificate to Cloudflare, which checks it against my domain.

DNS a-route with SSL and Apache

I have a domain served at server A and I have set up an A-record to server B.
For http://mypage.com all works fine.
But there is also SSL on the domain. On server B there are a few virtual hosts set up. One of which has an SSL virtual host (443), theirpage.com. If I now go to https://mypage.com I end up at theirpage.com.
If I set up mypage.com MUST I have the SSL certificate from server A available for this new specific ssl-virualhost? The provider at server A does not share their ssl-certificates...
Assuming:
Server A - DNS only, no web services.
Server B - Web server.
The following is extreme oversimplification of what actually happens. For simplicity we exclude all caches, networking and application complexity.
What happens on the client:
User navigates to mypage.com (HTTPS)
Browser/OS does a lookup of who mypage.com is; receives the IP
Browser attempts to establish secure connection with IP of a webserver.
It is at this point browser will look at the SSL certificate provided by your web server. That certificate must be signed by trusted authority and have a valid alternate name of mypage.com. Not signed or name does not match to what user typed into the browser you will receive a certificate error.
If the certificate passed:
Browser will complete establishing connection
Browser will request a content named mypage.com
Browser displays content revived from the web server
In this scenario only web server must have a valid certificate, prooving to the client that it is indeed the server client attempts to connect to.
HTTP Scenario is similar, but connection is not secured and site will load. Most of the websites setup redirect request on HTTP calls, forcing the user's browser repeat it's request via HTTPS protocol.

How do I (manually) intercept and return a custom message to a browser making a HTTPS request

I am creating a 'firewall' type device (i.e. sitting in the middle of a communication) that in some cases need to intercept a HTTPS request and return a message to the client browser (like e.g. : sorry this is blocked).
I can do this for HTTP by redirecting (with iptables DNAT) to another port on the device where netcat is listening:
while true; do echo -e "HTTP/1.1 200 OK\n\nsorry this is blocked"|nc -l -p 8000; done
(so nc is listening on port 8000 and returning a normal code 200 reply. Could of course also be some other return code like 403 Forbidden etc.)
But what to do for HTTPS?
The whole thing is encapsulated in SSL/TLS and if intercepted the browser will just display a message that the secure connection failed.
I tried responding with a HTTP 307 Temporary Redirect with a Location pointing to http://127.0.0.1 (which would then give the above message). But the browser doesn't like this.
I need to display some sort of customized message (not necessarily HTML).
I realize that it would be a huge security issue if a HTTPS request could be changed to HTTP, thus stripping the security without the client noticing, but can a popup message or something not be forced in the client? Or at least a standard code like '403 Forbidden'..?
Is there something in the SSL or TLS protocols that I can (ab)use?
Thanks.
So you are developing a transparent proxy. When it comes to HTTPS traffic every proxy has the choice:
Pass it without decryption
Block it completely
Perform a man-in-the-middle attack for getting access to the content
If you performing the man-in-the-middle attack and the client does not trust the certificate used by the proxy it will get a certificate warning. You can not send anything HTTP related to the client because SSL/TLS already fails to establish the tunnel. No tunnel means that you will not be able to transmit a single "HTTP byte" (this also means that you can not redirect the client somewhere else).
And on SSL/TLS level there is AFAIK no way to send a custom message. The "TLS alert message" only allows pre-defined constant values.

https requests using a proxy

Let's say you want to perform an https request to a certain website but you have a proxy on the middle.
The aforesaid proxy doesn't look into the request but just relay all the traffic to the actual HTTPS server after the user-agent has used the HTTP CONNECT method (as in http://www.web-cache.com/Writings/Internet-Drafts/draft-luotonen-web-proxy-tunneling-01.txt).
Now my question is the following: after the proxy opens a SSL connection to the destination webserver, should it also upgrade the socket which handles the connection with the client to SSL as well? And if so, how would it forward packets to the server without sniffing the actual content?
What I mean here is that if the proxy actually reads data from SSL client socket and forwards them to SSL server socket, the data will be not encrypted to it.
The proxy has a plaintext connection open to the client, via which it received the CONNECT command. It opens a plaintext connection to the server. Thereafter it just copies bytes in both directions. The bytes coming from both client and server are SSL, so this works without the proxy knowing what's inside the ciphertext.

CONNECT request to a forward HTTP proxy over an SSL connection?

I am writing an HTTP proxy and I am having trouble understanding some details of making a CONNECT request over TLS. To get a better picture, I am experimenting with Apache to observe how it interacts with clients. This is from my default virtual host.
NameVirtualHost *:443
<VirtualHost>
ServerName example.com
DocumentRoot htdocs/example.com
ProxyRequests On
AllowConnect 22
SSLEngine on
SSLCertificateFile /root/ssl/example.com-startssl.pem
SSLCertificateKeyFile /root/ssl/example.com-startssl.key
SSLCertificateChainFile /root/ssl/sub.class1.server.ca.pem
SSLStrictSNIVHostCheck off
</VirtualHost>
The conversation between Apache and my client goes like this.
a. client connects to example.com:443 and sends example.com in the TLS handshake.
b. client sends HTTP request.
CONNECT 192.168.1.1:22 HTTP/1.1
Host: example.com
Proxy-Connection: Keep-Alive
c. Apache says HTTP/1.1 400 Bad Request. The Apache error log says
Hostname example.com provided via SNI and hostname 192.168.1.1
provided via HTTP are different.
It appears that Apache does not look at the Host header other than to see that it is there since HTTP/1.1 requires it. I get identical failed behavior if the client sends Host: foo. If I make the HTTP request to example.com:80 without TLS, then Apache will connect me to 192.168.1.1:22.
I don't completely understand this behavior. Is there something wrong with the CONNECT request? I can't seem to locate the relevant parts of the RFCs that explain all this.
It's not clear whether you're trying to use Apache Httpd as a proxy server, this would explain the 400 status code you're getting.
CONNECT is used by the client, and sent to the proxy server (possibly Apache Httpd, but usually not), not to the destination web server.
CONNECT is used between the client and the proxy server before establishing the TLS connection between the client and the end server. The client (C) connects to the proxy (P) proxy.example.com and sends this request (including blank line):
C->P: CONNECT www.example.com:443 HTTP/1.1
C->P: Host: www.example.com:443
C->P:
The proxy opens a TCP connection to www.example.com:443 (P-S) and responds to the client with a 200 status code, accepting the request:
P->C: 200 OK
P->C:
After this, the connection between the client and the proxy (C-P) is kept open. The proxy server relays everything on the C-P connection to and from P-S. The client upgrades its active (P-S) connection to an SSL/TLS connection, by initiating a TLS handshake on that channel. Since everything is now relayed to the server, it's as if the TLS exchange was done directly with www.example.com:443.
The proxy doesn't play any role in the handshake (and thus with SNI). The TLS handshake effectively happens directly between the client and the end server.
If you're writing a proxy server, all you need to do for allowing your clients to connect to HTTPS servers is read in the CONNECT request, make a connection from the proxy to the end server (given in the CONNECT request), send the client with a 200 OK reply and then forward everything that you read from the client to the server, and vice versa.
RFC 2616 treats CONNECT as a a way to establish a simple tunnel (which it is). There is more about it in RFC 2817, although the rest of RFC 2817 (upgrades to TLS within a non-proxy HTTP connection) is rarely used.
It looks like what you're trying to do is to have the connection between the client (C) and the proxy (P) over TLS. That's fine, but the client won't use CONNECT to connect to external web servers (unless it's a connection to an HTTPS server too).
You're doing everything right. It's Apache that got things wrong. Support for CONNECT over TLS was only added recently (https://issues.apache.org/bugzilla/show_bug.cgi?id=29744) and there's still some things to be ironed out. The issue you're hitting is one of them.
From RFC 2616 (section 14.23):
The Host request-header field specifies the Internet host and port
number of the resource being requested, as obtained from the original
URI given by the user or referring resource (generally an HTTP URL,
as described in section 3.2.2). The Host field value MUST represent
the naming authority of the origin server or gateway given by the
original URL.
My understanding is that you need to copy the address from CONNECT line to HOST line. All in all, the address of the resource is 192.168.1.1, and the fact that you are connecting via example.com doesn't change anything from RFC point of view.
It is quite seldom to see CONNECT Method inside TLS (https). I actually don't know any client who does that (and I would be interested to know who it does, cause I think it is actually a good feature).
Normally the client connects with http (plain tcp) to the proxy and sends the CONNECT method (and host header) to host:443. Then the proxy will make a transparent connection to the endpoint and then the client sends the SSL handshake through.
In this scenario the data is ssl protected "end to end".
The CONNECT method is not really specified, it is only reserved in the HTTP RFC. But typically it is quite simple so it is interoperable. The Method specifies host[:port]. Host: header can simply be ignored. Some additional proxy authentication headers might be needed. When the body of the connection begins no parsing has to happen by the proxy anymore (some do, because they check for valid SSL handshake).