# Specifying the SNI hostname for an OpenSSL Context?

**URL:** https://forum.crystal-lang.org/t/specifying-the-sni-hostname-for-an-openssl-context/3872
**Category:** Help & Support
**Created:** [September 20, 2021, 8:17pm UTC](https://forum.crystal-lang.org/t/specifying-the-sni-hostname-for-an-openssl-context/3872 "2021-09-20T20:17:13Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![rob](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/rob/32/1409_2.png) [@rob](https://forum.crystal-lang.org/u/rob)
#### Post date: [September 20, 2021, 8:17pm UTC](https://forum.crystal-lang.org/t/specifying-the-sni-hostname-for-an-openssl-context/3872/1 "2021-09-20T20:17:13Z")

</div>

Is there a way to specify a SNI hostname on an `OpenSSL::SSL::Context`?

I spent some time digging around the stdlib implementation and the closest thing I see is [crystal/context.cr at 6d9a1d5830db5f276bf3df37fceeb0d5333e7e14 · crystal-lang/crystal · GitHub](https://github.com/crystal-lang/crystal/blob/6d9a1d583/src/openssl/ssl/context.cr#L86-L101) – which is used when `OpenSSL::SSL::Socket::Client.new` contains the hostname argument, but I don’t see any way that functionality is exposed through to `OpenSSL::SSL::Context`. I’m honestly not even clear if that hostname is even the right place to do so.

---

<div class="post-metadata">

### Author: ![jgaskins](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jgaskins/32/2449_2.png) [@jgaskins](https://forum.crystal-lang.org/u/jgaskins)
#### Post date: [September 20, 2021, 9:38pm UTC](https://forum.crystal-lang.org/t/specifying-the-sni-hostname-for-an-openssl-context/3872/2 "2021-09-20T21:38:25Z")

</div>

Yep, I had to do it for [the Neo4j driver](https://github.com/jgaskins/neo4j.cr). You’ve gotta pass [`hostname` to the `OpenSSL::SSL::Socket::Client` constructor](https://github.com/jgaskins/neo4j.cr/blob/9917f0496846a4ea75f5f9ab75f58ce47e5a6b66/src/neo4j/bolt/connection.cr#L72-L73) rather than setting it on the SSL context.

---

<div class="post-metadata">

### Author: ![rob](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/rob/32/1409_2.png) [@rob](https://forum.crystal-lang.org/u/rob)
#### Post date: [September 20, 2021, 9:51pm UTC](https://forum.crystal-lang.org/t/specifying-the-sni-hostname-for-an-openssl-context/3872/3 "2021-09-20T21:51:28Z")

</div>

Nice, thank you for the link. That’s what I was assuming was possible but I hadn’t actually stumbled through the process to correctly open a socket with SNI. Unfortunately it seems like [there isn’t a way](https://crystal-lang.org/api/1.1.1/HTTP/Client.html#new(host:String,port=nil,tls:TLSContext=nil)-class-method#constructors) to pass an existing OpenSSL::SSL::Socket::Client in to HTTP::Client in order to use the native HTTP library.

---

<div class="post-metadata">

### Author: ![jgaskins](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jgaskins/32/2449_2.png) [@jgaskins](https://forum.crystal-lang.org/u/jgaskins)
#### Post date: [September 20, 2021, 11:32pm UTC](https://forum.crystal-lang.org/t/specifying-the-sni-hostname-for-an-openssl-context/3872/4 "2021-09-20T23:32:30Z")

</div>

No, but when it establishes its own TLS connection [it does pass in the hostname for SNI](https://github.com/crystal-lang/crystal/blob/e5e2ca07432e4c4002b06621fab5152ad66587ae/src/http/client.cr#L798).

---

<div class="post-metadata">

### Author: ![rob](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/rob/32/1409_2.png) [@rob](https://forum.crystal-lang.org/u/rob)
#### Post date: [September 21, 2021, 12:34am UTC](https://forum.crystal-lang.org/t/specifying-the-sni-hostname-for-an-openssl-context/3872/5 "2021-09-21T00:34:07Z")

</div>

For most use cases that works; yea. I’m mapping out IP addresses which are supposed to respond for a given domain name and validating that each of them does in fact respond correctly. In order to do this I’m sending the request to the IP address and specifying the HOST header manually — the stdlib supports this intelligently.

I want to do certificate tracking which can be done without HTTP but when the server speaks HTTP I also want to validate that it responds to the right Host header.

Manually forming the request like this works great, unless the server is using SNI, which is fairly common. The SNI request then fails to establish a connection because that line asks the server for the certificate match for an IP address rather than the name. I’d argue that if present the SSL connect should take the host name front the SSL context instead.

---

<div class="post-metadata">

### Author: ![jgaskins](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jgaskins/32/2449_2.png) [@jgaskins](https://forum.crystal-lang.org/u/jgaskins)
#### Post date: [September 21, 2021, 12:59am UTC](https://forum.crystal-lang.org/t/specifying-the-sni-hostname-for-an-openssl-context/3872/6 "2021-09-21T00:59:01Z")

</div>

Can you expand more on this use case? Because right now it kinda sounds like you’re doing the work a load balancer should be doing. Unless … are you _writing_ a load balancer?

---

<div class="post-metadata">

### Author: ![rob](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/rob/32/1409_2.png) [@rob](https://forum.crystal-lang.org/u/rob)
#### Post date: [September 22, 2021, 4:05pm UTC](https://forum.crystal-lang.org/t/specifying-the-sni-hostname-for-an-openssl-context/3872/7 "2021-09-22T16:05:19Z")

</div>

> Unless … are you _writing_ a load balancer?

No, not quite. Good guess, but it’s almost the reverse.

The web applications I’m deploying are load balanced in several ways. One of those ways is to provide multiple A/AAAA records on DNS resolution, and the client resolver can decide on it’s own which IP address to hit. Typically each of those addresses are targeted at a load balancer, and behind the load balancer you have however many servers doing whatever.

On top of that DNS resolution is often geography sensitive so that requests can be “more local” – traffic is directed at local data centers.

Once in a rare while there is a network problem where one of the IP addresses published is not actually able to serve traffic for the published domain.

I’m writing software which attempts to detect this particular type of failure. It resolves a list of IP addresses from different geographically sourced IP addresses and targets each of those to ensure that they can all route traffic correctly. In order to do this I need to be able to target an SSL connection at each specific ip address and create an http request to the server as well.

---

<div class="post-metadata">

### Author: ![jgaskins](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jgaskins/32/2449_2.png) [@jgaskins](https://forum.crystal-lang.org/u/jgaskins)
#### Post date: [September 22, 2021, 5:11pm UTC](https://forum.crystal-lang.org/t/specifying-the-sni-hostname-for-an-openssl-context/3872/8 "2021-09-22T17:11:59Z")

</div>

Ah, you need this for something more related to infrastructure than a typical application. That makes perfect sense. Infrastructure code always has weird requirements. 😄

I was going to recommend possibly subclassing `HTTP::Client` to add a `@hostname` ivar and override how the connection is made but I think there may actually be a way to do this as-is. It requires setting up the TLS connection yourself and passing it to [this constructor](https://crystal-lang.org/api/1.1.1/HTTP/Client.html#new(io:IO,host=%22%22,port=80)-class-method) along with the hostname ():

```crystal
socket = TCPSocket.new(ip_address, port)
ssl = OpenSSL::SSL::Socket::Client.new(socket, hostname: hostname, sync_close: true)
http = HTTP::Client.new(ssl, host: hostname)

http.get(“/“)

```

I haven’t tried this because I’m writing on an iPad at the moment but from what I can tell in the docs and code I’m ~~almost 100%~~ a solid 80% confident that this might even compile once you supply `ip_address`, `port`, and `hostname`.

---

<div class="post-metadata">

### Author: ![rob](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/rob/32/1409_2.png) [@rob](https://forum.crystal-lang.org/u/rob)
#### Post date: [September 23, 2021, 4:29pm UTC](https://forum.crystal-lang.org/t/specifying-the-sni-hostname-for-an-openssl-context/3872/9 "2021-09-23T16:29:07Z")

</div>

@jgaskins that’s brilliant, thank you. I’ve been tripping over this configuration for literally months.
