-
Notifications
You must be signed in to change notification settings - Fork 283
Initial work for introducing openssl/boringssl as a TLS provider #956
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
54 commits
Select commit
Hold shift + click to select a range
e7cedcb
Initial draft work for introducing a separate TLS provider replaceing
4f8ab56
Initial draft work for introducing a separate TLS provider replaceing
db8435e
Fixing formatting
d148149
Cleanup
ee23261
Reducing the amount of duplicate for the boring implementation
b1bec69
Fixing mistakenly committed cargo change where debug symbols are gene…
a33f125
BoringSSL will now be built in FIPS mode
0cf011c
Formatting
b7ece50
Rebasing from main
87d3baf
Updated boring to 1.1.6
20059f1
Removing application specific ignores from .gitignore
9d4fe1e
fmt
olix0r 89392bb
Appease clippy
olix0r ebcf6d9
Merge branch 'main' into task/introduce-openssl-bindings
olix0r 7c54e1d
Simplifying implemenation of the Error trait by using thiserror:Error
e5efdd2
Addressing comments and removing more error trait boilerplate
3f25b9f
Simplifying verication on subject alt names
1b0ec20
Formatting
0d35990
Additional improvements, println removals
c78694b
Simplifying client id construction
7c42181
Reducing field visibility since no access is needed.
d8bd349
Client config display made more idiomatic
9afc8ae
Continuing with idiomatic improvements
607226e
Starting to remove the abundant amount of unwrap() calls that are not…
0b396b2
Temporarily reverting the SAN verification for the openssl/boringssl
612e4c7
Removing nested match call for certifications
93e19a3
Cleaning up the certificate verification
d359e11
Some additional cleanup and validation
c503c21
Minor logging fixes
6ac549e
Formatting
13db857
Removing commented out blocks
5c3440c
Reducing visibility of new constructor methods for both ClientConfig …
7916a12
Reverting change done to the dns name debug method and trust anchors …
9a94bdc
Swapping if statement to an if-let statement
81cccbb
Using thiserror to implement InvalidCrt error
a677a04
Additional improvements
2dabb0a
Removing std error
d8c25c8
Reimplemented Elisa's certificate SAN check
5d3e9c1
Fixing debug implementations for rustls
bd2f7a3
Revering dev symbols
7814330
Minor code organization
ee1da30
Formatting
1e5f92f
Accept and Connect handling for Boringssl updated
eb5f1cf
Openssl implementation accept and connect modified slightly
00abf28
Readded removed newline
f416e8b
Merge branch 'main' into task/introduce-openssl-bindings
olix0r aa16192
Merge branch 'main' of github.com:linkerd/linkerd2-proxy into task/in…
0b36303
Fixing unused import
a35e44b
Fixing borrow reference that was immediately dereferenced
83fe386
Removing openssl entirely
08092f3
Fixing local changes that were committed by mistake
bbb88c2
Removing extra newline
47a75d3
Adding newline at the end of file
2658a40
Updating cargo lock for updated boring module
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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,304 @@ | ||
| use std::fmt; | ||
| use std::sync::Arc; | ||
| use std::time::SystemTime; | ||
|
|
||
| use boring::{ | ||
| error::ErrorStack, | ||
| pkey::{PKey, Private}, | ||
| stack::Stack, | ||
| x509::{ | ||
| store::{X509Store, X509StoreBuilder}, | ||
| {X509StoreContext, X509VerifyResult, X509}, | ||
| }, | ||
| }; | ||
|
|
||
| use tracing::{debug, error, trace}; | ||
|
|
||
| use crate::{LocalId, Name}; | ||
| use std::fmt::Formatter; | ||
| use thiserror::Error; | ||
|
|
||
| #[derive(Clone, Debug)] | ||
| pub struct Key(pub Arc<PKey<Private>>); | ||
|
|
||
| impl Key { | ||
| pub fn from_pkcs8(b: &[u8]) -> Result<Key, Error> { | ||
| let key = PKey::private_key_from_pkcs8(b)?; | ||
| Ok(Key(Arc::new(key))) | ||
| } | ||
| } | ||
|
|
||
| #[derive(Clone, Debug, Error)] | ||
| #[error(transparent)] | ||
| pub struct Error(#[from] ErrorStack); | ||
|
|
||
| #[derive(Clone)] | ||
| pub struct TrustAnchors(Arc<X509Store>); | ||
|
|
||
| impl TrustAnchors { | ||
| fn store() -> X509StoreBuilder { | ||
| X509StoreBuilder::new().expect("unable to create certificate store") | ||
| } | ||
|
|
||
| #[cfg(any(test, feature = "test-util"))] | ||
| pub fn empty() -> Self { | ||
| Self(Arc::new(TrustAnchors::store().build())) | ||
| } | ||
|
|
||
| pub fn from_pem(s: &str) -> Option<Self> { | ||
| debug!("constructing trust trust anchors from pem {}", s); | ||
| return match X509::from_pem(s.as_bytes()) { | ||
| Ok(cert) => { | ||
| let mut store = TrustAnchors::store(); | ||
| trace!("adding certificate to trust anchors {:?}", cert); | ||
| if let Err(err) = store.add_cert(cert) { | ||
| error!("unable to add certificate to trust anchors, {}", err); | ||
| return None; | ||
| } | ||
|
|
||
| Some(Self(Arc::new(store.build()))) | ||
| } | ||
| Err(err) => { | ||
| error!("unable to construct trust anchor {}", err); | ||
| None | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| pub fn certify(&self, key: Key, crt: Crt) -> Result<CrtKey, InvalidCrt> { | ||
| let cert = crt.cert.clone(); | ||
| if !cert | ||
| .subject_alt_names() | ||
| .into_iter() | ||
| .flat_map(|alt_names| alt_names.into_iter()) | ||
| .any(|n| n.dnsname().expect("unable to convert to dns name") == crt.id.0.as_ref()) | ||
| { | ||
| return Err(InvalidCrt::SubjectAltName(crt.id)); | ||
| } | ||
|
|
||
| let mut chain = Stack::new()?; | ||
| chain.push(cert.clone())?; | ||
| for chain_crt in crt.chain.clone() { | ||
| chain.push(chain_crt)?; | ||
| } | ||
|
|
||
| let mut context = X509StoreContext::new()?; | ||
| context.init(&self.0, &cert, &chain, |c| match c.verify_cert() { | ||
| Ok(true) => Ok(Ok(true)), | ||
| Ok(false) => Ok(Err(InvalidCrt::Verify(c.error()))), | ||
| Err(err) => Err(err), | ||
| })??; | ||
|
|
||
| let server_config = | ||
| ServerConfig::new(vec![], self.0.clone(), Some(crt.clone()), Some(key.clone())); | ||
| let client_config = | ||
| ClientConfig::new(vec![], self.0.clone(), Some(crt.clone()), Some(key.clone())); | ||
|
|
||
| Ok(CrtKey { | ||
| id: crt.id.clone(), | ||
| expiry: crt.expiry.clone(), | ||
| client_config: Arc::new(client_config), | ||
| server_config: Arc::new(server_config), | ||
| }) | ||
| } | ||
|
|
||
| pub fn client_config(&self) -> Arc<ClientConfig> { | ||
| Arc::new(ClientConfig::new(vec![], self.0.clone(), None, None)) | ||
| } | ||
| } | ||
|
|
||
| impl fmt::Debug for TrustAnchors { | ||
| fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { | ||
| f.pad("boringssl::TrustAnchors") | ||
| } | ||
| } | ||
|
|
||
| #[derive(Clone, Debug, Error)] | ||
| pub enum InvalidCrt { | ||
| #[error("subject alt name incorrect ({0})")] | ||
| SubjectAltName(LocalId), | ||
| #[error("{0}")] | ||
| Verify(#[source] X509VerifyResult), | ||
| #[error(transparent)] | ||
| General(#[from] Error), | ||
| } | ||
|
|
||
| impl From<ErrorStack> for InvalidCrt { | ||
| fn from(err: ErrorStack) -> Self { | ||
| InvalidCrt::General(err.into()) | ||
| } | ||
| } | ||
|
|
||
| #[derive(Clone)] | ||
| pub struct CrtKey { | ||
| id: LocalId, | ||
| expiry: SystemTime, | ||
| client_config: Arc<ClientConfig>, | ||
| server_config: Arc<ServerConfig>, | ||
| } | ||
|
|
||
| // === CrtKey === | ||
| impl CrtKey { | ||
| pub fn name(&self) -> &Name { | ||
| self.id.as_ref() | ||
| } | ||
|
|
||
| pub fn expiry(&self) -> SystemTime { | ||
| self.expiry | ||
| } | ||
|
|
||
| pub fn id(&self) -> &LocalId { | ||
| &self.id | ||
| } | ||
|
|
||
| pub fn client_config(&self) -> Arc<ClientConfig> { | ||
| self.client_config.clone() | ||
| } | ||
|
|
||
| pub fn server_config(&self) -> Arc<ServerConfig> { | ||
| self.server_config.clone() | ||
| } | ||
| } | ||
|
|
||
| impl fmt::Debug for CrtKey { | ||
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { | ||
| f.debug_struct("boringssl::CrtKey") | ||
| .field("id", &self.id) | ||
| .field("expiry", &self.expiry) | ||
| .finish() | ||
| } | ||
| } | ||
|
|
||
| #[derive(Clone, Debug)] | ||
| pub struct Crt { | ||
| pub(crate) id: LocalId, | ||
| expiry: SystemTime, | ||
| pub cert: X509, | ||
| pub chain: Vec<X509>, | ||
| } | ||
|
|
||
| impl Crt { | ||
| pub fn new( | ||
| id: LocalId, | ||
| leaf: Vec<u8>, | ||
| intermediates: Vec<Vec<u8>>, | ||
| expiry: SystemTime, | ||
| ) -> Self { | ||
| let mut chain = Vec::with_capacity(intermediates.len() + 1); | ||
| let cert = X509::from_der(&leaf).expect("unable to convert to a x509 certificate"); | ||
| chain.extend( | ||
| intermediates | ||
| .into_iter() | ||
| .map(|crt| X509::from_der(&crt).expect("unable to add intermediate certificate")), | ||
| ); | ||
|
|
||
| Self { | ||
| id, | ||
| cert, | ||
| chain, | ||
| expiry, | ||
| } | ||
| } | ||
|
|
||
| pub fn name(&self) -> &Name { | ||
| self.id.as_ref() | ||
| } | ||
| } | ||
|
|
||
| #[derive(Clone)] | ||
| pub struct ClientConfig { | ||
| pub root_certs: Arc<X509Store>, | ||
| pub key: Option<Arc<Key>>, | ||
| pub cert: Option<Arc<Crt>>, | ||
| protocols: Arc<Vec<Vec<u8>>>, | ||
| } | ||
|
|
||
| impl fmt::Debug for ClientConfig { | ||
| fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { | ||
| f.debug_struct("openssl::ClientConfig") | ||
| .field("protocols", &self.protocols) | ||
| .finish() | ||
| } | ||
| } | ||
|
|
||
| impl ClientConfig { | ||
| fn new( | ||
| protocols: Vec<Vec<u8>>, | ||
| root_certs: Arc<X509Store>, | ||
| cert: Option<Crt>, | ||
| key: Option<Key>, | ||
| ) -> Self { | ||
| Self { | ||
| root_certs, | ||
| protocols: Arc::new(protocols), | ||
| key: key.map(Arc::new), | ||
| cert: cert.map(Arc::new), | ||
| } | ||
| } | ||
| pub fn empty() -> Self { | ||
| ClientConfig::new( | ||
| Vec::new(), | ||
| Arc::new( | ||
| X509StoreBuilder::new() | ||
| .expect("unable to construct root certs") | ||
| .build(), | ||
| ), | ||
| None, | ||
| None, | ||
| ) | ||
| } | ||
|
|
||
| pub fn set_protocols(&mut self, protocols: Vec<Vec<u8>>) { | ||
| self.protocols = Arc::new(protocols) | ||
| } | ||
| } | ||
|
|
||
| #[derive(Clone)] | ||
| pub struct ServerConfig { | ||
| pub root_certs: Arc<X509Store>, | ||
| pub key: Option<Arc<Key>>, | ||
| pub cert: Option<Arc<Crt>>, | ||
| alpn_protocols: Arc<Vec<Vec<u8>>>, | ||
| } | ||
|
|
||
| impl ServerConfig { | ||
| fn new( | ||
| alpn_protocols: Vec<Vec<u8>>, | ||
| root_certs: Arc<X509Store>, | ||
| cert: Option<Crt>, | ||
| key: Option<Key>, | ||
| ) -> Self { | ||
| Self { | ||
| alpn_protocols: Arc::new(alpn_protocols), | ||
| root_certs, | ||
| key: key.map(Arc::new), | ||
| cert: cert.map(Arc::new), | ||
| } | ||
| } | ||
| /// Produces a server config that fails to handshake all connections. | ||
| pub fn empty() -> Self { | ||
| ServerConfig::new( | ||
| Vec::new(), | ||
| Arc::new( | ||
| X509StoreBuilder::new() | ||
| .expect("unable to construct root certs") | ||
| .build(), | ||
| ), | ||
| None, | ||
| None, | ||
| ) | ||
| } | ||
|
|
||
| pub fn add_protocols(&mut self, protocols: Vec<u8>) { | ||
| self.alpn_protocols.as_ref().clone().push(protocols) | ||
| } | ||
| } | ||
|
|
||
| impl fmt::Debug for ServerConfig { | ||
| fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { | ||
| f.debug_struct("openssl::ServerConfig") | ||
| .field("alpn_protocols", &self.alpn_protocols) | ||
| .field("key", &self.key) | ||
| .finish() | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need golang here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yeah that's crazy, the boring-sys crate uses go as part of the whole build process.
We probably have to figure out a better way to handle this docker file.