1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
extern crate cose;

use std::slice;
use cose::decoder::decode_signature;
use cose::SignatureAlgorithm;

unsafe fn from_raw(ptr: *const u8, len: usize) -> Vec<u8> {
    slice::from_raw_parts(ptr, len).to_vec()
}

type VerifyCallback = extern "C" fn(*const u8, /* payload */
                                    usize, /* payload len */
                                    *const *const u8, /* cert_chain */
                                    usize, /* # certs */
                                    *const usize, /* cert lengths in cert_chain */
                                    *const u8, /* signer cert */
                                    usize, /* signer cert len */
                                    *const u8, /* signature bytes */
                                    usize, /* signature len */
                                    u8 /* signature algorithm */)
                                    -> bool;

#[no_mangle]
pub extern "C" fn verify_cose_signature_ffi(
    payload: *const u8,
    payload_len: usize,
    cose_signature: *const u8,
    cose_signature_len: usize,
    verify_callback: VerifyCallback,
) -> bool {
    if payload.is_null() || cose_signature.is_null() || payload_len == 0 ||
        cose_signature_len == 0
    {
        return false;
    }

    // Build Rust variables from C parameters.
    let payload = unsafe { from_raw(payload, payload_len) };
    let cose_signature = unsafe { from_raw(cose_signature, cose_signature_len) };

    // Parse the incoming signature.
    let cose_signatures = decode_signature(cose_signature, &payload);
    let cose_signatures = match cose_signatures {
        Ok(signature) => signature,
        Err(_) => Vec::new(),
    };
    if cose_signatures.len() < 1 {
        return false;
    }

    let mut result = true;
    for cose_signature in cose_signatures {
        let signature_type = cose_signature.signature_type;
        // ES256 = 0, ES384 = 1, ES512 = 2, PS256 = 3
        let signature_type = match signature_type {
            SignatureAlgorithm::ES256 => 0,
            SignatureAlgorithm::ES384 => 1,
            SignatureAlgorithm::ES512 => 2,
            SignatureAlgorithm::PS256 => 3,
        };
        let signature_bytes = cose_signature.signature;
        let real_payload = cose_signature.to_verify;

        // Build cert chain params.
        let mut cert_lens: Vec<usize> = Vec::new();
        let mut certs: Vec<*const u8> = Vec::new();
        for cert in &cose_signature.certs {
            cert_lens.push(cert.len());
            certs.push(cert.as_ptr());
        }

        // Call callback to verify the parsed signatures.
        result &= verify_callback(
            real_payload.as_ptr(),
            real_payload.len(),
            certs.as_ptr(),
            certs.len(),
            cert_lens.as_ptr(),
            cose_signature.signer_cert.as_ptr(),
            cose_signature.signer_cert.len(),
            signature_bytes.as_ptr(),
            signature_bytes.len(),
            signature_type,
        );

        // We can stop early. The cose_signature is not valid.
        if !result {
            return result;
        }
    }

    result
}