boring 5.3.0

BoringSSL bindings
Documentation
//! See https://github.com/google/boringssl/blob/cc696073cffe7978d489297fbdeac4c0030384aa/crypto/x509/x509_test.cc#L3977-L3980

use crate::stack::Stack;
use crate::x509::store::X509StoreBuilder;
use crate::x509::verify::X509VerifyParamRef;
use crate::x509::{X509Ref, X509StoreContext, X509VerifyResult, X509};

#[test]
fn test_verify_cert() {
    let root2_expired = X509::from_pem(include_bytes!("../../../test/root-ca-2.pem")).unwrap();
    let root1 = X509::from_pem(include_bytes!("../../../test/root-ca.pem")).unwrap();
    let root1_cross = X509::from_pem(include_bytes!("../../../test/root-ca-cross.pem")).unwrap();
    let intermediate = X509::from_pem(include_bytes!("../../../test/intermediate-ca.pem")).unwrap();
    let leaf = X509::from_pem(include_bytes!("../../../test/cert-with-intermediate.pem")).unwrap();

    // Two paths:
    // Leaf -- Intermediate -- Root1
    //                       \
    //                         Root1_cross -- Root2 (expired)
    //
    // In the past, X509_V_FLAG_TRUSTED_FIRST had to be set to avoid the second invalid path. This
    // is now the default, and that flag no longer has any effect.
    assert_eq!(Ok(()), verify(&leaf, &[&root1], &[&intermediate], |_| {}));

    assert_eq!(
        Ok(()),
        verify(
            &leaf,
            &[&root1, &root2_expired],
            &[&intermediate, &root1_cross],
            |_| {}
        )
    );
}

fn verify(
    cert: &X509Ref,
    trusted: &[&X509Ref],
    untrusted: &[&X509Ref],
    configure: impl FnOnce(&mut X509VerifyParamRef),
) -> X509VerifyResult {
    let trusted = {
        let mut builder = X509StoreBuilder::new().unwrap();

        for cert in trusted {
            builder.add_cert(cert).unwrap();
        }

        builder.build()
    };

    let untrusted = {
        let mut stack = Stack::new().unwrap();

        for cert in untrusted {
            stack.push((**cert).to_owned()).unwrap();
        }

        stack
    };

    let mut store_ctx = X509StoreContext::new().unwrap();

    store_ctx
        .init(&trusted, cert, &untrusted, |ctx| {
            configure(ctx.verify_param_mut());
            ctx.verify_cert().unwrap();

            Ok(ctx.verify_result())
        })
        .expect("failed to obtain X509VerifyResult")
}