Hello! I am working on my very first Rust project. I am rewriting software I wrote in Python to Rust because of performance issues in Python.
I am running against a very particular problem. The very famous but it worked last week problem.
I have a function called create_connections which connects to an AMQP server (RabbitMQ). The connection uses TLS security. I have two files, a certificate.crt and a certificate.key file. I understand that I need to create a OwnedTLSConfig object and have the crt/key files formatted to DER.
I had this working last week and made a working connection to the external AMQP Server (I have no access to the management side of this server). But now when I run my code I get the following error:
2023-06-12T02:00:21.756652Z INFO proj_rust: responder thread started
2023-06-12T02:00:21.756675Z INFO proj_rust::amqp: create_connection
2023-06-12T02:00:21.756911Z INFO proj_rust::amqp: connection_url: amqps://USER:PASS@URL:50060/app # details ommitted
thread '<unnamed>' panicked at 'connection error: IOError(Custom { kind: InvalidData, error: ASN1Error { kind: Invalid } })', src/amqp.rs:20:13
stack backtrace:
It looks like the response is an actual error message from the server saying that the data is malformed/invalid. Which is weird because nothing changed codewise. When I run the project in Python .with the same crt/key files it does connect properly and work as intended. The only thing that has changed is that I upgraded my linux distro from 20.04 to 22.04, so I assume that the issues must be introduced here but I have no clue where to start. I downgraded my rustc to the lowest version acceptable to lapin but with no success.
use lapin::{Channel, Connection, ConnectionProperties, Queue, Result};
use lapin::types::FieldTable;
use tracing::info;
pub async fn create_connection() -> Result<Connection> {
info!("create_connection");
let connection = Connection::connect_with_config(
create_connection_url().as_str(),
ConnectionProperties::default(),
create_tls::get_tls_config(
env_vars::CERT_FILE.as_str(),
env_vars::KEY_FILE.as_str(),
),
).await.expect("connection error");
info!("connection: {:?}", connection);
Ok(connection)
}
extern crate openssl;
use std::fs::File;
use std::io::Read;
use lapin::tcp::{OwnedIdentity, OwnedTLSConfig};
use openssl::pkcs12::Pkcs12;
use openssl::pkey::PKey;
use openssl::x509::X509;
pub fn get_tls_config(path_to_cert: &str, path_to_key: &str) -> OwnedTLSConfig {
// Read in the certificate.
let mut cert_file = File::open(path_to_cert).expect("Unable to open certificate file");
let mut cert_data = vec![];
cert_file
.read_to_end(&mut cert_data)
.expect("Unable to read certificate file");
let cert = X509::from_pem(&cert_data).expect("Unable to parse certificate");
// Read in the private key.
let mut key_file = File::open(path_to_key).expect("Unable to open key file");
let mut key_data = vec![];
key_file
.read_to_end(&mut key_data)
.expect("Unable to read key file");
let key = PKey::private_key_from_pem(&key_data).expect("Unable to parse private key");
// Create a PKCS12 archive.
let password = "password";
let name = "client"; // The friendly name for the certificate/key pair.
let pkcs12 = Pkcs12::builder()
.name(name)
.pkey(&key)
.cert(&cert)
.build2(password)
.expect("Unable to create PKCS12 archive");
// Convert the PKCS12 archive to DER format.
let der = pkcs12
.to_der()
.expect("Unable to convert PKCS12 archive to DER format");
OwnedTLSConfig {
identity: Some(OwnedIdentity {
der,
password: password.to_string(),
}),
cert_chain: None,
}
}