hickory_proto/openssl/
tls_server.rs1use std::fs::File;
11use std::io;
12use std::io::Read;
13use std::path::Path;
14
15use crate::error::{ProtoError, ProtoResult};
16use openssl::ssl::{SslAcceptor, SslMethod, SslOptions, SslVerifyMode};
17
18pub use openssl::pkcs12::Pkcs12;
19pub use openssl::pkey::{PKey, Private};
20pub use openssl::stack::Stack;
21pub use openssl::x509::X509;
22
23#[allow(clippy::type_complexity)]
27pub fn read_cert_pkcs12(
28 path: &Path,
29 password: Option<&str>,
30) -> ProtoResult<((Option<X509>, Option<Stack<X509>>), Option<PKey<Private>>)> {
31 let mut file = File::open(path).map_err(|e| {
32 ProtoError::from(format!(
33 "error opening pkcs12 cert file: {}: {}",
34 path.display(),
35 e
36 ))
37 })?;
38
39 let mut pkcs12_bytes = vec![];
40 file.read_to_end(&mut pkcs12_bytes).map_err(|e| {
41 ProtoError::from(format!(
42 "could not read pkcs12 from: {}: {}",
43 path.display(),
44 e
45 ))
46 })?;
47 let pkcs12 = Pkcs12::from_der(&pkcs12_bytes).map_err(|e| {
48 ProtoError::from(format!(
49 "badly formatted pkcs12 from: {}: {}",
50 path.display(),
51 e
52 ))
53 })?;
54 let parsed = pkcs12.parse2(password.unwrap_or("")).map_err(|e| {
55 ProtoError::from(format!(
56 "failed to open pkcs12 from: {}: {}",
57 path.display(),
58 e
59 ))
60 })?;
61
62 Ok(((parsed.cert, parsed.ca), parsed.pkey))
63}
64
65pub fn read_cert_pem(path: &Path) -> ProtoResult<(X509, Option<Stack<X509>>)> {
69 let mut file = File::open(path).map_err(|e| {
70 ProtoError::from(format!(
71 "error opening cert file: {}: {}",
72 path.display(),
73 e
74 ))
75 })?;
76
77 let mut key_bytes = vec![];
78 file.read_to_end(&mut key_bytes).map_err(|e| {
79 ProtoError::from(format!(
80 "could not read cert key from: {}: {}",
81 path.display(),
82 e
83 ))
84 })?;
85
86 let cert_chain = X509::stack_from_pem(&key_bytes)?;
87 let cert_count = cert_chain.len();
88 let mut iter = cert_chain.into_iter();
89
90 let cert = match iter.next() {
91 None => {
92 return Err(ProtoError::from(format!(
93 "no certs read from file: {}",
94 path.display()
95 )))
96 }
97 Some(cert) => cert,
98 };
99
100 if cert_count < 1 {
101 Ok((cert, None))
102 } else {
103 let mut stack = Stack::<X509>::new()?;
104 for c in iter {
105 stack.push(c)?;
106 }
107 Ok((cert, Some(stack)))
108 }
109}
110
111pub fn read_key_from_pkcs8(path: &Path, password: Option<&str>) -> ProtoResult<PKey<Private>> {
113 let mut file = File::open(path)?;
114 let mut buf = Vec::new();
115 file.read_to_end(&mut buf)?;
116
117 match password.map(str::as_bytes) {
118 Some(password) => {
119 PKey::private_key_from_pkcs8_passphrase(&buf, password).map_err(Into::into)
120 }
121 None => PKey::private_key_from_pkcs8_passphrase(&buf, &[0_u8; 0]).map_err(Into::into),
122 }
123}
124
125pub fn read_key_from_der(path: &Path) -> ProtoResult<PKey<Private>> {
127 let mut file = File::open(path)?;
128 let mut buf = Vec::new();
129 file.read_to_end(&mut buf)?;
130
131 PKey::private_key_from_der(&buf).map_err(Into::into)
132}
133
134pub fn new_acceptor(
136 cert: X509,
137 chain: Option<Stack<X509>>,
138 key: PKey<Private>,
139) -> io::Result<SslAcceptor> {
140 let mut builder = SslAcceptor::mozilla_modern(SslMethod::tls())?;
142
143 builder.set_private_key(&key)?;
144 builder.set_certificate(&cert)?;
145 builder.set_verify(SslVerifyMode::NONE);
146 builder.set_options(
147 SslOptions::NO_COMPRESSION
148 | SslOptions::NO_SSLV2
149 | SslOptions::NO_SSLV3
150 | SslOptions::NO_TLSV1
151 | SslOptions::NO_TLSV1_1,
152 );
153
154 if let Some(ref chain) = chain {
155 for cert in chain {
156 builder.add_extra_chain_cert(cert.to_owned())?;
157 }
158 }
159
160 builder.check_private_key()?;
162
163 Ok(builder.build())
164}