-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
net.mbedtls: support Server Name Indication (SNI) (#22012)
- Loading branch information
1 parent
ac7fedb
commit d7bdb72
Showing
5 changed files
with
315 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# generates the certificates used by the server_sni_advanced.v example | ||
|
||
# default | ||
gen_key type=rsa rsa_keysize=4096 filename=0x.dk.key | ||
cert_write selfsign=1 issuer_key=0x.dk.key \ | ||
issuer_name=CN=0x.dk,O=0x,C=DK \ | ||
not_before=20130101000000 not_after=20251231235959 \ | ||
is_ca=1 max_pathlen=0 output_file=0x.dk.crt | ||
|
||
# 1x.dk | ||
gen_key type=rsa rsa_keysize=4096 filename=1x.dk.key | ||
cert_write selfsign=1 issuer_key=1x.dk.key \ | ||
issuer_name=CN=1x.dk,O=1x.dk,C=DK \ | ||
not_before=20130101000000 not_after=20251231235959 \ | ||
is_ca=1 max_pathlen=0 output_file=1x.dk.crt | ||
|
||
# 2x.dk | ||
gen_key type=rsa rsa_keysize=4096 filename=2x.dk.key | ||
cert_write selfsign=1 issuer_key=2x.dk.key \ | ||
issuer_name=CN=2x.dk,O=2x.dk,C=DK \ | ||
not_before=20130101000000 not_after=20251231235959 \ | ||
is_ca=1 max_pathlen=0 output_file=2x.dk.crt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import io | ||
import os | ||
import net.mbedtls | ||
|
||
// This example shows a very minimal HTTP server, that supports SNI. | ||
// Server Name Indication (SNI) is defined in RFC 6066. | ||
// See https://mbed-tls.readthedocs.io/en/latest/kb/how-to/use-sni/ | ||
|
||
// Use the following commands, in separate shells, to test that it works, | ||
// after you start the server: | ||
// curl -ik --resolve 1x.dk:8443:0.0.0.0 https://1x.dk:8443/abcd | ||
// curl -ik --resolve example.com:8443:0.0.0.0 https://example.com:8443/xyz | ||
// Both of them should work, and the server should show that it tried to load | ||
// certificates, responding to the given domain name in each of the requests. | ||
|
||
// callback to return the certificates to use for the connection | ||
fn get_cert(mut l mbedtls.SSLListener, host string) !&mbedtls.SSLCerts { | ||
println('reading certificates for ${host} ...') | ||
|
||
// For our example, just always use the same certificates. In a real server, | ||
// that should be dependent on the host parameter, and perhaps there should | ||
// be some caching, so that they are not read each time for each request from | ||
// the filesystem. | ||
|
||
cert := os.read_file('cert/server.crt') or { | ||
return error('Failed to read certificate ${host}: ${err}') | ||
} | ||
key := os.read_file('cert/server.key') or { return error('Failed to read key ${host}: ${err}') } | ||
println('read certs for ${host}') | ||
|
||
if mut c := mbedtls.new_sslcerts_in_memory('', cert, key) { | ||
return c | ||
} else { | ||
return error('mbedtls.new_sslcerts_in_memory err: ${err}') | ||
} | ||
} | ||
|
||
fn main() { | ||
mut server := mbedtls.new_ssl_listener('0.0.0.0:8443', mbedtls.SSLConnectConfig{ | ||
verify: os.resource_abs_path('cert/ca.crt') | ||
cert: os.resource_abs_path('cert/server.crt') | ||
cert_key: os.resource_abs_path('cert/server.key') | ||
validate: false | ||
get_certificate: get_cert // set the SNI callback to enable this feature | ||
})! | ||
println('Listening on https://0.0.0.0:8443/ ...') | ||
for { | ||
mut client := server.accept() or { | ||
println('accept error: ${err}') | ||
continue | ||
} | ||
mut reader := io.new_buffered_reader(reader: client) | ||
for { | ||
line := reader.read_line() or { break } | ||
if line.len == 0 { | ||
break | ||
} | ||
println(line) | ||
} | ||
client.write_string('HTTP/1.1 200 OK\r\n') or { continue } | ||
|
||
client.write_string('Content-Type: text/html\r\n') or { continue } | ||
client.write_string('Connection: close\r\n') or { continue } | ||
client.write_string('\r\n') or { continue } | ||
|
||
client.write_string('Hello\n') or { continue } | ||
client.shutdown()! | ||
} | ||
server.shutdown()! | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import net.mbedtls | ||
import os | ||
import io | ||
import net.http | ||
|
||
// first run cert/makecerts.sh to generate the certificates for this server | ||
|
||
// start the server with: | ||
// v run server_sni_advanced.v | ||
|
||
// test using curl: | ||
|
||
// connection using the 1x.dk certificate | ||
// curl -vik --resolve 1x.dk:8443:0.0.0.0 https://1x.dk:8443/ | ||
|
||
// connection using the 2x.dk certificate | ||
// curl -vik --resolve 2x.dk:8443:0.0.0.0 https://2x.dk:8443/ | ||
|
||
// default certificate (no sni callback) | ||
// curl -vik https://0.0.0.0:8443/ | ||
|
||
@[heap] | ||
struct CertManager { | ||
mut: | ||
// cache for the certificates | ||
certs map[string]&mbedtls.SSLCerts | ||
} | ||
|
||
fn (mut cm CertManager) get_cert(mut l mbedtls.SSLListener, host string) !&mbedtls.SSLCerts { | ||
println('${host}') | ||
|
||
if c := cm.certs[host] { | ||
println('read certs for ${host} already ready') | ||
return c | ||
} else { | ||
cert := os.read_file('cert/${host}.crt') or { | ||
return error('Failed to read certificate ${host}: ${err}') | ||
} | ||
key := os.read_file('cert/${host}.key') or { | ||
return error('Failed to read key ${host}: ${err}') | ||
} | ||
println('read certs for ${host}') | ||
|
||
if mut c := mbedtls.new_sslcerts_in_memory('', cert, key) { | ||
cm.certs[host] = c | ||
return c | ||
} else { | ||
return error('mbedtls.new_sslcerts_in_memory err: ${err}') | ||
} | ||
} | ||
} | ||
|
||
fn main() { | ||
// Load the default certificates | ||
cert := os.read_file('cert/0x.dk.crt') or { | ||
eprintln('Failed to read certificate: ${err}') | ||
return | ||
} | ||
key := os.read_file('cert/0x.dk.key') or { | ||
eprintln('Failed to read key: ${err}') | ||
return | ||
} | ||
|
||
cm := CertManager{} | ||
|
||
// Create the SSL configuration | ||
mut config := mbedtls.SSLConnectConfig{ | ||
cert: cert | ||
cert_key: key | ||
in_memory_verification: true // !importent | ||
get_certificate: cm.get_cert | ||
} | ||
|
||
mut server := mbedtls.new_ssl_listener('0.0.0.0:8443', config) or { | ||
println('new_ssl_listener : ${err.msg()} : ${err.code()}') | ||
return | ||
} | ||
println('Listening on https://0.0.0.0:8443') | ||
|
||
// Accept and handle connections | ||
for { | ||
mut client := server.accept() or { | ||
println('accept : ${err.msg()} : ${err.code()}') | ||
continue | ||
} | ||
go handle_connection(mut client) | ||
} | ||
|
||
server.shutdown() or { | ||
println('server.shutdown : ${err.msg()} : ${err.code()}') | ||
return | ||
} | ||
} | ||
|
||
fn handle_connection(mut ssl_conn mbedtls.SSLConn) { | ||
mut reader := io.new_buffered_reader(reader: ssl_conn) | ||
|
||
request := http.parse_request(mut reader) or { | ||
println('parse_request failed : ${err}') | ||
return | ||
} | ||
|
||
println('Received request: ${request.url}') | ||
|
||
// Respond to the request | ||
body := 'Hello, HTTPS!' | ||
res := http.new_response(http.ResponseConfig{ | ||
body: body | ||
}) | ||
|
||
ssl_conn.write(res.bytes()) or { | ||
eprintln('Failed to write response: ${err}') | ||
return | ||
} | ||
|
||
ssl_conn.shutdown() or { | ||
eprintln('Failed to shutdown connection: ${err}') | ||
return | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters