-
-
Notifications
You must be signed in to change notification settings - Fork 749
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
Add SBGP extension handling #2053
base: master
Are you sure you want to change the base?
Conversation
FTR I think the job fails because of issues fixed in #2052 (just saying that it's nothing that you've introduced). |
Thank you for the hint! |
Signed-off-by: Markus Theil <theil.markus@gmail.com>
Signed-off-by: Markus Theil <theil.markus@gmail.com>
3bf5d75
to
d759114
Compare
This currently depends on #2055. After it is merged, I'll cleanup my temporary commits. |
5ff5364
to
6c1c43a
Compare
Signed-off-by: Markus Theil <theil.markus@gmail.com>
6c1c43a
to
815a951
Compare
Signed-off-by: Markus Theil <theil.markus@gmail.com>
I found another fix for the compilation with Rust 1.56. This PR is ready now from my side. |
* At the moment this is coded for simplicity, not speed. | ||
*/ | ||
#[cfg(ossl110)] | ||
fn addr_expand(addr: *mut u8, bs: *const ASN1_BIT_STRING, length: isize, fill: u8) -> bool { |
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.
This doesn't seem like something that should be in openssl-sys.
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.
This function, and associated functions , has now been replaced with a FFI binding to X509v3_addr_get_range
and X509v3_addr_get_afi
.
openssl/src/x509/extension.rs
Outdated
}; | ||
append(&mut value, &mut first, true, &asn_format); | ||
} | ||
X509Extension::new_nid(None, Some(ctx), Nid::SBGP_AUTONOMOUSSYSNUM, &value) |
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.
We need to move away from the string APIs for x509 extensions, and instead directly work with the relevant OpenSSL types.
} | ||
} | ||
|
||
pub fn ranges(&self) -> Option<Vec<(u32, u32)>> { |
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.
Does this correspond to some OpenSSL function?
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.
Same question for the other methods in this file.
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.
These function correspond to X509v3_addr_get_range
, but executed for the whole extension, since RFC 3779 encodings are rather tedious to work with. Same thing applies to the other functions in this file, they just parse the openssl-internal representation into their Rust-equivalents.
This is a very dangerous API full of traps and bugs. It needs to be wrapped very carefully. What is the use case you want to support by exposing these? Do you have some working code I could look at? |
- X509v3_addr_get_range - X509v3_addr_get_afi
@botovq We are currently in the process of reworking this PR. Our use case is certifying address ranges and ASNs in a datacenter fabric setting. Sadly I have no public code that I can share. @PetrichorIT is currently working on this. |
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.
I really think it is a bad idea to expose this API. What stops you from using rpki-rs for this?
As already mentioned, and you will have no doubt found while developing this, the OpenSSL RFC 3779 API is really bad. And I am not aware of any OpenSSL developer with domain expertise to speak of. So that's not going to change anytime soon.
You don't magically get memory safety by using this via ffi from Rust and then omitting error checks for functions that allocate internally. Very much the opposite of that.
There are omissions of necessary features, missing checks, etc. This all looks taylored to a narrow use case. I do not think this is anywhere close to being ready. People who will try to use this in the future will have a very hard time interoperating with modern RPKI validators.
openssl/src/x509/extension.rs
Outdated
/// Construct a new `SbgpAsIdentifier` extension. | ||
pub fn new() -> SbgpAsIdentifier { | ||
SbgpAsIdentifier { | ||
critical: false, |
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.
I don't think this should ever be non-critical. At least default to critical since that's what RPKI certs should contain. It's a MUST in RFC 6487 section 2, while RFC 3779 marks it as SHOULD, hence false is a poor default.
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.
yes, critical=true is now the default
openssl/src/x509/extension.rs
Outdated
} | ||
|
||
/// Sets the `critical` flag to `true`. The extension will be critical. | ||
pub fn critical(&mut self) -> &mut SbgpAsIdentifier { |
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.
Why do you need this knob at all?
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.
In its newer version fn critical(&mut self, value: bool)
is might be useful to have this configuration option for some legacy systems ? I personally cannot think of a use case, but just in case?
openssl/src/x509/extension.rs
Outdated
if min == max { | ||
ffi::X509v3_asid_add_id_or_range(asid, 0, min.as_ptr(), std::ptr::null_mut()); | ||
} else { | ||
ffi::X509v3_asid_add_id_or_range(asid, 0, min.as_ptr(), max.as_ptr()); |
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.
These can fail and will sometimes free min
and/or max
and sometimes they won't. In the former case you'll double free below.
Definitely needs error checking, but I'm unsure how you can avoid the double free without panicking and retain memory safety.
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.
The newer implementation should prevent double frees + free all nessecary allocations.
openssl/src/x509/extension.rs
Outdated
/// Construct a new `SbgpIpAddressIdentifier` extension. | ||
pub fn new() -> SbgpIpAddressIdentifier { | ||
SbgpIpAddressIdentifier { | ||
critical: false, |
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.
Again, default to critical
openssl/src/x509/extension.rs
Outdated
std::mem::forget(max); | ||
} | ||
|
||
X509Extension::new_internal(Nid::SBGP_AUTONOMOUSSYSNUM, self.critical, asid as *mut _) |
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.
Before doing this you should check that your extension data is canonical, otherwise you produce an extension with invalid DER encoding.
self.asn.push((asn_min, asn_max)); | ||
self | ||
} | ||
|
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.
add_inherit()
is missing in the builder.
use libc::*; | ||
|
||
#[repr(C)] | ||
#[cfg(ossl110)] |
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.
All these should probably condition on OPENSSL_NO_RFC3779
as well.
Given the current state of the RFC 3779 API, I think there are two options: Either we only expose a certain subset of the RFC 3779 API that we can assure to be "safe", or we expose the entire API with all meaningful features and checks and try to build a more abstract API around it, to ensure safety. I personally prefer a second approach. I'd like to try this approach and see where it leads. |
|
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.
Thanks for the explanations. I won't have time for a thorough review in the next days/week, so I only left a few quick comments.
I think we should aim at a good middle ground between the two options you describe: let's make it flexible enough to be generally usable and correct, but let's make it easy enough to use by not exposing things that aren't used in the wild.
So, for example, you currently don't expose the SAFI for IPAddressFamily and you don't expose the RDI variant for ASIdentifiers (which I think is good). In a similar vein, let's not expose criticality as a knob.
openssl/src/x509/extension.rs
Outdated
pub struct SbgpAsIdentifier { | ||
critical: bool, | ||
asn: Vec<(u32, u32)>, | ||
inherit: bool, |
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.
I think it is good hygiene to make illegal states non-representable as far as possible/reasonable. The ASIdentifiers should either inherit or contain a (non-empty) list of ASIds and ASRanges. So I think this should be an enum with an Inherit and an ASNumber variant that contains the Vec<(u32, u32)>
with the list of ASIds and ASNumbers.
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.
I think this is a good idea. However I think patterns like type-state would be overkill in this scenario, so assertions / panics remain nessecary to prevent silent failures.
openssl/src/x509/extension.rs
Outdated
@@ -428,6 +443,258 @@ impl AuthorityKeyIdentifier { | |||
} | |||
} | |||
|
|||
#[cfg(ossl110)] | |||
pub struct SbgpAsIdentifier { | |||
critical: bool, |
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.
I would suggest that you omit this field. If anyone really needs to fiddle with criticality, they can readily add the field and accessor with a solid justification.
openssl/src/x509/extension.rs
Outdated
pub struct SbgpIpAddressIdentifier { | ||
critical: bool, | ||
ip_ranges: Vec<(IpAddr, IpAddr)>, | ||
inherit: Option<IPVersion>, |
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.
Similarly here, let's omit the criticality marker and for the sake of correctness, I think this should have two optional enums, one for IPv4 and one for IPv6. Each of these enums contains either an Inherit marker or a vector of IP ranges of the correct kind.
Unless I'm missing something, this struct doesn't currently allow representing inheritance of both IPv4 and IPv6.
So this PR should be ready now. In regards to the extension builders, criticality will no longer be a configuration option, SbgpAsIdentifier::new()
.add_asn(1234)
.add_inherit()
.build() would panic, since the assigned AS number would be lost when the inherit flag is set. The functions In regards to The APIs for interacting with store contextes and validation paths |
Thanks. I will try to find time to take a look soon.
|
Apologies for the delay. I haven't forgotten. I won't be able to review this properly before mid-March. |
Did you find any time to review the PR? Greetings |
On Tue, Mar 26, 2024 at 04:50:52AM -0700, Simon Buttgereit wrote:
> Apologies for the delay. I haven't forgotten. I won't be able to review this properly before mid-March.
Did you find any time to review the PR?
I did. Not quite through yet.
|
Knowing that my request may be annoying: I would like to kindly remind you that this pull request is still open. |
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.
Ignoring the comment on X509_get_ext_d2i()
, the use of the C API looks about as sane as it can be now.
Regress coverage is decent. As noted, various panic strings need a typo fix (allready -> already). Whether rust-openssl would like panics or different error handling is up to the maintainers of the crate -- as are other API concerns on the rust side of things.
As far as the reservations I had are concerned, this should be ready to proceed.
ffi::NID_sbgp_autonomousSysNum, | ||
std::ptr::null_mut(), | ||
std::ptr::null_mut(), | ||
); |
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.
X509_get_ext_d2i
is a tricky API to use correctly. As far as I can see, no caller in rust-openssl gets it right.
This can return NULL
for several reasons: the benign reason is that there is no extension corresponding to the nid in the cert. However, there could also be a library-internal error (malformed extension, memory allocation error, ...), or other errors, like multiple extensions of the same type, which this idiom silently ignores.
The correct way is to pass in a pointer crit
to a c_int
as third argument. If NULL
is returned and crit
is set to anything but -1
, an error should be raised.
Not sure if this should be fixed in this PR or if rust-openssl wants to land this as-is and fix the issue in a sweep.
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.
After considering this further, if there would be a minimally invasive solution available, I'd opt to address it within this PR. However, it seems that we require some new Error construct due to the fact that X509_get_ext_d2i doesn't set the internal OpenSSL error, making the ErrorStack inapplicable.
I'm unsure if this issue extends to other OpenSSL functions as well, where a new Error construct would also help to handle return values properly. After all, I propose addressing this in a separate PR to avoid overloading the current one.
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.
In the meantime of the last few months we also got some additional X509 functionality.
Yet, I suggest following the same procedure: let's complete the current task first, and then I'll create an additional PR specifically for the new functions.
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.
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.
@HolyShitMan I'm inclined to agree, but it isn't my call. I opened #2226, which, once addressed, should also fix the instance in this PR.
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.
openssl/src/x509/extension.rs
Outdated
pub fn add_inherit(&mut self) -> &mut SbgpAsIdentifier { | ||
if let SbgpAsIdentifierOrInherit::List(ref l) = self.0 { | ||
if !l.is_empty() { | ||
panic!("cannot set extension to inherit, list allready contains elements"); |
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.
panic!("cannot set extension to inherit, list allready contains elements"); | |
panic!("cannot set extension to inherit, list already contains elements"); |
Similar typos are throughout the panic strings
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.
No problem, I will fix all these
This PR adds support for parsing SBGP ASNs and IP-Ranges. A basic test is also added.