Skip to content

Commit fa41943

Browse files
committed
Change the certificate_check callback to support passthrough.
This is essential to being able to validate an SSH host key while still relying on libgit2 to validate TLS certificates.
1 parent 84e21aa commit fa41943

File tree

2 files changed

+29
-8
lines changed

2 files changed

+29
-8
lines changed

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ pub use crate::refspec::Refspec;
123123
pub use crate::remote::{
124124
FetchOptions, PushOptions, Refspecs, Remote, RemoteConnection, RemoteHead, RemoteRedirect,
125125
};
126-
pub use crate::remote_callbacks::{Credentials, RemoteCallbacks};
126+
pub use crate::remote_callbacks::{CertificateCheckStatus, Credentials, RemoteCallbacks};
127127
pub use crate::remote_callbacks::{TransportMessage, UpdateTips};
128128
pub use crate::repo::{Repository, RepositoryInitOptions};
129129
pub use crate::revert::RevertOptions;

src/remote_callbacks.rs

+28-7
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,18 @@ pub type UpdateTips<'a> = dyn FnMut(&str, Oid, Oid) -> bool + 'a;
5151
///
5252
/// The second argument is the hostname for the connection is passed as the last
5353
/// argument.
54-
pub type CertificateCheck<'a> = dyn FnMut(&Cert<'_>, &str) -> bool + 'a;
54+
pub type CertificateCheck<'a> =
55+
dyn FnMut(&Cert<'_>, &str) -> Result<CertificateCheckStatus, Error> + 'a;
56+
57+
/// The return value for the [`CertificateCheck`] callback.
58+
pub enum CertificateCheckStatus {
59+
/// Indicates that the certificate should be accepted.
60+
CertificateOk,
61+
/// Indicates that the certificate callback is neither accepting nor
62+
/// rejecting the certificate. The result of the certificate checks
63+
/// built-in to libgit2 will be used instead.
64+
CertificatePassthrough,
65+
}
5566

5667
/// Callback for each updated reference on push.
5768
///
@@ -162,7 +173,7 @@ impl<'a> RemoteCallbacks<'a> {
162173
/// connection to proceed.
163174
pub fn certificate_check<F>(&mut self, cb: F) -> &mut RemoteCallbacks<'a>
164175
where
165-
F: FnMut(&Cert<'_>, &str) -> bool + 'a,
176+
F: FnMut(&Cert<'_>, &str) -> Result<CertificateCheckStatus, Error> + 'a,
166177
{
167178
self.certificate_check = Some(Box::new(cb) as Box<CertificateCheck<'a>>);
168179
self
@@ -371,16 +382,26 @@ extern "C" fn certificate_check_cb(
371382
let payload = &mut *(data as *mut RemoteCallbacks<'_>);
372383
let callback = match payload.certificate_check {
373384
Some(ref mut c) => c,
374-
None => return true,
385+
None => return Ok(CertificateCheckStatus::CertificatePassthrough),
375386
};
376387
let cert = Binding::from_raw(cert);
377388
let hostname = str::from_utf8(CStr::from_ptr(hostname).to_bytes()).unwrap();
378389
callback(&cert, hostname)
379390
});
380-
if ok == Some(true) {
381-
0
382-
} else {
383-
-1
391+
match ok {
392+
Some(Ok(CertificateCheckStatus::CertificateOk)) => 0,
393+
Some(Ok(CertificateCheckStatus::CertificatePassthrough)) => raw::GIT_PASSTHROUGH as c_int,
394+
Some(Err(e)) => {
395+
let s = CString::new(e.message()).unwrap();
396+
unsafe {
397+
raw::git_error_set_str(e.class() as c_int, s.as_ptr());
398+
}
399+
e.raw_code() as c_int
400+
}
401+
None => {
402+
// Panic. The *should* get resumed by some future call to check().
403+
-1
404+
}
384405
}
385406
}
386407

0 commit comments

Comments
 (0)