Hi,
I new to rust and I would like to rewrite my program in rust. But one important requirement is to connect to an actor in my local home WIFI. The actor uses for communication a TLS connection.
I have no certificate or servername for the actor, I can reach it with it's IP: 192.168.0.3:52100.
In C, with openssl, I've done it in this way:
const char *server = "192.168.0.3:51200";
// Login mit PW -Request
#define REQLEN 39
const uint8_t req[REQLEN] = {192, 0, 35, 48, 0, 88, 50, 90, 78, 66, 75, 112, 100, 72, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 192};
#define RESLEN 8
const uint8_t res[RESLEN] = {0xc0, 0x00, 0x04, 0x30, 0x01, 0x00, 0x35, 0xc0};
static void logIntoklf()
{
printf("openssl init done.\n");
ctx = SSL_CTX_new(SSLv23_client_method());
SSL *ssl = NULL;
bio = BIO_new_ssl_connect(ctx);
check("BIO_new_ssl_connect", bio != NULL);
BIO_get_ssl(bio, &ssl);
check("BIO_get_ssl", ssl != NULL);
if (server_verify)
SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
else
SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
BIO_set_conn_hostname(bio, server);
out = BIO_new_fp(stdout, BIO_NOCLOSE);
check("BIO_do_connect", BIO_do_connect(bio) > 0);
check("BIO_write", BIO_write(bio, req, REQLEN) == REQLEN);
uint8_t buf[100];
int len = BIO_read(bio, buf, sizeof(buf));
check("BIO_read", len == RESLEN);
check("response data", memcmp(res, buf, RESLEN) == 0);
// KLF200 hängt beim BIO_ssl_shutdown(bio); => vermutlich ein KLF Problem
freeall();
printf("Ende\n");
}
Now, I tried it with rustls like this (it's the client example with minimal changes):
fn connect_velux() {
let mut root_store = RootCertStore::empty();
root_store.add_server_trust_anchors(
webpki_roots::TLS_SERVER_ROOTS
.0
.iter()
.map(|ta| {
OwnedTrustAnchor::from_subject_spki_name_constraints(
ta.subject,
ta.spki,
ta.name_constraints,
)
}),
);
let config = rustls::ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_store)
.with_no_client_auth();
let server_name = "VELUX_KLF_3139".try_into().unwrap();
let mut conn = rustls::ClientConnection::new(std::sync::Arc::new(config), server_name).unwrap();
let mut sock = std::net::TcpStream::connect("192.168.0.3:51200").unwrap();
println!("TCP established");
let mut tls = rustls::Stream::new(&mut conn, &mut sock);
let txbytes : Vec<u8> = vec![192, 0, 35, 48, 0, 88, 50, 90, 78, 66, 75, 112, 100, 72, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 192];
println!("{:?}", txbytes.as_slice());
tls.write_all(txbytes.as_slice()).unwrap();
println!("not reached.");
let ciphersuite = tls
.conn
.negotiated_cipher_suite()
.unwrap();
writeln!(
&mut std::io::stderr(),
"Current ciphersuite: {:?}",
ciphersuite.suite()
)
.unwrap();
let mut plaintext = Vec::new();
tls.read_to_end(&mut plaintext).unwrap();
println!("{:?}", plaintext);
// std::io::stdout().write_all(&plaintext).unwrap();
}
It doesn't work, I get Err
value: Custom { kind: InvalidData, error: InvalidCertificateData("invalid peer certificate: CaUsedAsEndEntity")
If I change the server_name:
let server_name = "192.168.0.3".try_into().unwrap();
it gives another errror: Custom { kind: InvalidData, error: UnsupportedNameType }
Would great if somebody here has a hint how to communicate only with IP over TLS in Rust. I would prefer to stick to rustls because I want to crosscompile the project for my raspberry pi.