mysql_async/opts/
rustls_opts.rs1#![cfg(feature = "rustls-tls")]
2
3use rustls::pki_types::{pem, pem::PemObject, CertificateDer, PrivateKeyDer, PrivatePkcs1KeyDer};
4
5use std::{borrow::Cow, path::Path};
6
7use super::PathOrBuf;
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10pub struct ClientIdentity {
11 cert_chain: PathOrBuf<'static>,
12 priv_key: PathOrBuf<'static>,
13}
14
15impl ClientIdentity {
16 pub fn new(cert_chain: PathOrBuf<'static>, priv_key: PathOrBuf<'static>) -> Self {
21 Self {
22 cert_chain,
23 priv_key,
24 }
25 }
26
27 pub fn with_cert_chain(mut self, cert_chain: PathOrBuf<'static>) -> Self {
29 self.cert_chain = cert_chain;
30 self
31 }
32
33 pub fn with_priv_key<T>(mut self, priv_key: PathOrBuf<'static>) -> Self
35 where
36 T: Into<Cow<'static, Path>>,
37 {
38 self.priv_key = priv_key;
39 self
40 }
41
42 pub fn cert_chain(&self) -> PathOrBuf<'_> {
44 self.cert_chain.borrow()
45 }
46
47 pub fn priv_key(&self) -> PathOrBuf<'_> {
49 self.priv_key.borrow()
50 }
51
52 pub(crate) async fn load(
53 &self,
54 ) -> crate::Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>)> {
55 let cert_data = self.cert_chain.read().await?;
56 let key_data = self.priv_key.read().await?;
57
58 let mut cert_chain = Vec::new();
59 if std::str::from_utf8(&cert_data).is_err() {
60 cert_chain.push(CertificateDer::from(cert_data.into_owned()));
61 } else {
62 for cert in pem::SliceIter::<CertificateDer<'_>>::new(&cert_data) {
63 cert_chain.push(cert?);
64 }
65 }
66
67 let priv_key = if std::str::from_utf8(&key_data).is_err() {
68 PrivateKeyDer::Pkcs1(PrivatePkcs1KeyDer::from(key_data.into_owned()))
69 } else {
70 match PrivateKeyDer::from_pem_slice(&key_data) {
75 Ok(k) => k,
76 Err(pem::Error::NoItemsFound) => {
77 return Err(crate::DriverError::NoKeyFound.into());
78 }
79 Err(e) => return Err(e.into()),
80 }
81 };
82
83 Ok((cert_chain, priv_key))
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 const PKCS1_KEY: &[u8] = b"-----BEGIN RSA PRIVATE KEY-----\n\
93MIIEowIBAAKCAQEAxE2SbfMeeA4m6r3T+oZPTMTKCuwhhKV0qZgxoU/aC3STgkTR\n\
94lIDbx4ukRx0pZdNvum2LlgmkKBuMQvRE5ivLkS/pKgWkKAa+zylkEr4X5tAj6o3e\n\
95juvcg4ogy0CIfvyDl/l/2gLCrgc1VVsRIqM2cs1oZZVUl3f0NuixgPaoVotVjkTq\n\
96Oqv+KkPWpE+mUmGlrik0jzwPcYyF3ZqlecMyqADLMXW7JByasMYd9imQHNcuojtE\n\
971Z41JaKO60sNpT1ibEZHsve1ZF1spSRD5pRgStwV8GZ+a8mmIYIahEfgyJTLrHwM\n\
98Dhc00sivdsXXnynFgoTyyvOq+6KbjfDi0Fj0AQIDAQABAoIBAALWWTG4JB5ZnAPk\n\
99EwKJuu8x3/a484ISjyVdYwhBGnZ0bKZjHsFd/G89rDXv7LeBTxnbd/tG7+W5gjU8\n\
100iRtnkiVq0xytoLIIaO0fHMhtkXRfWUmMW+VmcNVA45j0eZSWS0Og0lGBHTW9Om7d\n\
101plmBEOonYGUpe6PF0tSRV/F0fzni+rDMkmLpX14BQdzzA/cBAF7O+kTkxjOZtufe\n\
102oNeEa/GwoWdlTKYtUaVx9XriEc4BDPHUPgbMQuT8Gepp/FQ1+L9TltFIyO8B4ytX\n\
103KRvo3tF+E/YI7Vz4GnuYU7IL5O/fb8BZnTb0jplhbcPddF26qQTGbbPzgV8dY6wA\n\
104Yy6jszECgYEA6ikNucjg0L7uQxwQz/8OCA1oFKYYPj+gmhzsW0BEZ5VzN+hDEw9J\n\
105sErPp0ZNpG50+YaZPNAPxGfk6culonOAPyg3G9hnRj71S/pqSe35gnUYvc7mttcG\n\
106LobMy/QerVmQRzoiR51VujrpH1wf4cT/KV7a2C/Pk1vjBuFffi3AkWkCgYEA1pyd\n\
107XQqNr7c+GYX7KUnxv93fkzWtnztEoXoigqszrCpiCevWSNKNX1kHk9mIXFuoJmlZ\n\
108PIIRDqOpibBCgcZu+j3R611F2if0elSPj1YNMNc1vh87brHkhNxdQpIp4YqeMSFg\n\
109tX1zsrAwVIA0hoZP+TFCVODyJJBXQITTBALn4tkCgYAx6gJlAe76UFjVsVvcGpBR\n\
110Ixp2nFk6m7GOaG/xm6d5NSBUYIw7udyJWckd7RyL2ofQ0OJFVkymH0dqluB92oUR\n\
1118W6d3ulUzgLX6U9S5wlyx6c4fqwreXZ14IIzT5xic18P79Jy1ZT6l6gt6SNaqvWB\n\
112Shj4UGi9Dq88Pjpu2S3dUQKBgQCGaJ3xyItGUphU+eF8UXBTvwyoMMUlZcQs8cYt\n\
113WjXJjN3L4uVYxG2AGs0xHttVJJ5iODaIO9mc9olWz4pHptSYayFOrCL0Z3OpLc6f\n\
114ccBfJ1nkUcEyKb26LB1IdSw/skYy9PmRkRll/wy1z3mWCwaJRf2KFTvyBGhw4v8Z\n\
115kwxRuQKBgFwRC0AXlHArWqf3EBZmYd7OoyyspRVkzzSoWEJXNPH+G2WSmQt/lSeE\n\
116nAF3k8yHWco7+bSbV3xLWsI+THNn0BNWrbfX7EAo1kWfliSy0qrevQWeaaJkd83V\n\
117zmF/Qc7Ilu47gQKZWz9GASWJkOkbvJKKIDIwlIQvvXX1eDoAevmY\n\
118-----END RSA PRIVATE KEY-----\n";
119
120 const PKCS8_KEY: &[u8] = b"-----BEGIN PRIVATE KEY-----\n\
122MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDETZJt8x54Dibq\n\
123vdP6hk9MxMoK7CGEpXSpmDGhT9oLdJOCRNGUgNvHi6RHHSll02+6bYuWCaQoG4xC\n\
1249ETmK8uRL+kqBaQoBr7PKWQSvhfm0CPqjd6O69yDiiDLQIh+/IOX+X/aAsKuBzVV\n\
125WxEiozZyzWhllVSXd/Q26LGA9qhWi1WOROo6q/4qQ9akT6ZSYaWuKTSPPA9xjIXd\n\
126mqV5wzKoAMsxdbskHJqwxh32KZAc1y6iO0TVnjUloo7rSw2lPWJsRkey97VkXWyl\n\
127JEPmlGBK3BXwZn5ryaYhghqER+DIlMusfAwOFzTSyK92xdefKcWChPLK86r7opuN\n\
1288OLQWPQBAgMBAAECggEAAtZZMbgkHlmcA+QTAom67zHf9rjzghKPJV1jCEEadnRs\n\
129pmMewV38bz2sNe/st4FPGdt3+0bv5bmCNTyJG2eSJWrTHK2gsgho7R8cyG2RdF9Z\n\
130SYxb5WZw1UDjmPR5lJZLQ6DSUYEdNb06bt2mWYEQ6idgZSl7o8XS1JFX8XR/OeL6\n\
131sMySYulfXgFB3PMD9wEAXs76ROTGM5m2596g14Rr8bChZ2VMpi1RpXH1euIRzgEM\n\
1328dQ+BsxC5PwZ6mn8VDX4v1OW0UjI7wHjK1cpG+je0X4T9gjtXPgae5hTsgvk799v\n\
133wFmdNvSOmWFtw910XbqpBMZts/OBXx1jrABjLqOzMQKBgQDqKQ25yODQvu5DHBDP\n\
134/w4IDWgUphg+P6CaHOxbQERnlXM36EMTD0mwSs+nRk2kbnT5hpk80A/EZ+Tpy6Wi\n\
135c4A/KDcb2GdGPvVL+mpJ7fmCdRi9zua21wYuhszL9B6tWZBHOiJHnVW6OukfXB/h\n\
136xP8pXtrYL8+TW+MG4V9+LcCRaQKBgQDWnJ1dCo2vtz4ZhfspSfG/3d+TNa2fO0Sh\n\
137eiKCqzOsKmIJ69ZI0o1fWQeT2YhcW6gmaVk8ghEOo6mJsEKBxm76PdHrXUXaJ/R6\n\
138VI+PVg0w1zW+HztuseSE3F1Ckinhip4xIWC1fXOysDBUgDSGhk/5MUJU4PIkkFdA\n\
139hNMEAufi2QKBgDHqAmUB7vpQWNWxW9wakFEjGnacWTqbsY5ob/Gbp3k1IFRgjDu5\n\
1403IlZyR3tHIvah9DQ4kVWTKYfR2qW4H3ahRHxbp3e6VTOAtfpT1LnCXLHpzh+rCt5\n\
141dnXggjNPnGJzXw/v0nLVlPqXqC3pI1qq9YFKGPhQaL0Orzw+Om7ZLd1RAoGBAIZo\n\
142nfHIi0ZSmFT54XxRcFO/DKgwxSVlxCzxxi1aNcmM3cvi5VjEbYAazTEe21UknmI4\n\
143Nog72Zz2iVbPikem1JhrIU6sIvRnc6ktzp9xwF8nWeRRwTIpvbosHUh1LD+yRjL0\n\
144+ZGRGWX/DLXPeZYLBolF/YoVO/IEaHDi/xmTDFG5AoGAXBELQBeUcCtap/cQFmZh\n\
1453s6jLKylFWTPNKhYQlc08f4bZZKZC3+VJ4ScAXeTzIdZyjv5tJtXfEtawj5Mc2fQ\n\
146E1att9fsQCjWRZ+WJLLSqt69BZ5pomR3zdXOYX9BzsiW7juBAplbP0YBJYmQ6Ru8\n\
147koogMjCUhC+9dfV4OgB6+Zg=\n\
148-----END PRIVATE KEY-----\n";
149
150 const SEC1_KEY: &[u8] = b"-----BEGIN EC PRIVATE KEY-----\n\
152MHcCAQEEIIfgf9+zR4IQO67je8L7RpFN7ILlUCHg8HHf2VDbIT4XoAoGCCqGSM49\n\
153AwEHoUQDQgAEyhKJO00+LzRLH50nrmX8KAJK6RtqqsWnW+rfCvOBs4nnUS1yruzM\n\
1545WB9UK1mVxsLVAPtNLXX0n0QvNBU6UkW7w==\n\
155-----END EC PRIVATE KEY-----\n";
156
157 const EC_CERT: &[u8] = b"-----BEGIN CERTIFICATE-----\n\
159MIIBlDCCATmgAwIBAgIUYB9LFUfast9GdpYQRTH8LqWphD4wCgYIKoZIzj0EAwIw\n\
160HjEcMBoGA1UEAwwTbXlzcWxfYXN5bmMtdGVzdC1lYzAgFw0yNjA1MjMwNjQ5MzNa\n\
161GA8yMTI2MDQyOTA2NDkzM1owHjEcMBoGA1UEAwwTbXlzcWxfYXN5bmMtdGVzdC1l\n\
162YzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABMoSiTtNPi80Sx+dJ65l/CgCSukb\n\
163aqrFp1vq3wrzgbOJ51Etcq7szOVgfVCtZlcbC1QD7TS119J9ELzQVOlJFu+jUzBR\n\
164MB0GA1UdDgQWBBSEYBKB4Y2cpNeLJCL4a444cXfQxzAfBgNVHSMEGDAWgBSEYBKB\n\
1654Y2cpNeLJCL4a444cXfQxzAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kA\n\
166MEYCIQCEKz/dG8PRLqE5asy+Xcja5H8EOzOdQId9rl9+UmfD2wIhAMIwy9puBewL\n\
1670fndnN33G44NOnqH6QPMstJSEDX+XmyZ\n\
168-----END CERTIFICATE-----\n";
169
170 const CERT: &[u8] = b"-----BEGIN CERTIFICATE-----\n\
172MIIC/zCCAeegAwIBAgIULM9bG/oB2Sts7i0XtMwbBjnhosswDQYJKoZIhvcNAQEL\n\
173BQAwDzENMAsGA1UEAwwEdGVzdDAeFw0yNjA1MjIxMzMwMjRaFw0yNjA1MjMxMzMw\n\
174MjRaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\n\
175AoIBAQDETZJt8x54DibqvdP6hk9MxMoK7CGEpXSpmDGhT9oLdJOCRNGUgNvHi6RH\n\
176HSll02+6bYuWCaQoG4xC9ETmK8uRL+kqBaQoBr7PKWQSvhfm0CPqjd6O69yDiiDL\n\
177QIh+/IOX+X/aAsKuBzVVWxEiozZyzWhllVSXd/Q26LGA9qhWi1WOROo6q/4qQ9ak\n\
178T6ZSYaWuKTSPPA9xjIXdmqV5wzKoAMsxdbskHJqwxh32KZAc1y6iO0TVnjUloo7r\n\
179Sw2lPWJsRkey97VkXWylJEPmlGBK3BXwZn5ryaYhghqER+DIlMusfAwOFzTSyK92\n\
180xdefKcWChPLK86r7opuN8OLQWPQBAgMBAAGjUzBRMB0GA1UdDgQWBBQ6IWIObXB0\n\
181XSoICqsjND3CIeNy8DAfBgNVHSMEGDAWgBQ6IWIObXB0XSoICqsjND3CIeNy8DAP\n\
182BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB2jfKJEUntMcyAi28T\n\
183bDc/jORi/WMIWhGjfYnxJPjzTtt6Lst3tvGhmCcAd99PKS4xXbrvwbY48FMNWcZq\n\
184p1FwDzRucgafLxLJFQW26YUMltXX/P1Fh93BGjBqPomUBbXyLVeLs4+QtyLaGNSj\n\
185Ijx10780osF0noZ0G3BUiXD6v3qAPOcD+29d83oiXhBeLo2OyzqUUFTJ0KR4cNjg\n\
186wWBGf/Anl7ptxEVmEQvKSI8jNln6E0og3kCz4D+cIqoHUZain4IRYTwpK+kapDyQ\n\
187Lf3esme5EHGvjY9cZq5jMJUYZNx67uvxdyj05dtLAg26MoXaUvojn3Kf7bOE7IKD\n\
188t2kx\n\
189-----END CERTIFICATE-----\n";
190
191 fn identity(cert: &'static [u8], key: &'static [u8]) -> ClientIdentity {
192 ClientIdentity::new(cert.into(), key.into())
193 }
194
195 #[tokio::test]
196 async fn loads_pkcs1_key() {
197 let (certs, key) = identity(CERT, PKCS1_KEY).load().await.unwrap();
198 assert_eq!(certs.len(), 1);
199 assert!(matches!(key, PrivateKeyDer::Pkcs1(_)));
200 }
201
202 #[tokio::test]
203 async fn loads_pkcs8_key() {
204 let (certs, key) = identity(CERT, PKCS8_KEY).load().await.unwrap();
205 assert_eq!(certs.len(), 1);
206 assert!(matches!(key, PrivateKeyDer::Pkcs8(_)));
207 }
208
209 #[tokio::test]
210 async fn loads_sec1_key() {
211 let (certs, key) = identity(EC_CERT, SEC1_KEY).load().await.unwrap();
212 assert_eq!(certs.len(), 1);
213 assert!(matches!(key, PrivateKeyDer::Sec1(_)));
214 }
215
216 #[tokio::test]
217 async fn no_key_marker_returns_error() {
218 let err = identity(CERT, b"not a pem key\n").load().await.unwrap_err();
219 assert!(matches!(
220 err,
221 crate::Error::Driver(crate::DriverError::NoKeyFound)
222 ));
223 }
224}