• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

namib-project / dcaf-rs / 11935120896

20 Nov 2024 02:11PM UTC coverage: 86.555% (+1.3%) from 85.242%
11935120896

Pull #27

github

web-flow
Merge d2b3d706b into 383248641
Pull Request #27: ci: update grcov to latest stable version

6116 of 7066 relevant lines covered (86.56%)

167.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.11
/src/token/cose/maced/mac0/mod.rs
1
/*
2
 * Copyright (c) 2024 The NAMIB Project Developers.
3
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4
 * https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5
 * <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6
 * option. This file may not be copied, modified, or distributed
7
 * except according to those terms.
8
 *
9
 * SPDX-License-Identifier: MIT OR Apache-2.0
10
 */
11
//! Extensions for COSE_Mac0 objects and builders ([`CoseMac0`], [`CoseMac0Builder`]).
12
//!
13
//! Refer to the module-level documentation of [`crate::token::cose`] for some general information
14
//! regarding the way that headers and keys need to be set up.
15
use alloc::rc::Rc;
16
use core::cell::RefCell;
17

18
use coset::{CoseMac0, CoseMac0Builder, Header};
19

20
use crate::error::CoseCipherError;
21
use crate::token::cose::aad::AadProvider;
22
use crate::token::cose::key::KeyProvider;
23
use crate::token::cose::maced::{try_compute, try_verify, MacCryptoBackend};
24

25
#[cfg(all(test, feature = "std"))]
26
mod tests;
27

28
/// Extensions to the [`CoseMac0Builder`] type that enable usage of cryptographic backends.
29
pub trait CoseMac0BuilderExt: Sized {
30
    /// Attempts to compute the MAC using a cryptographic backend.
31
    ///
32
    /// # Parameters
33
    ///
34
    /// - `backend`      - cryptographic backend to use.
35
    /// - `key_provider` - provider for cryptographic keys to use (if you already know the
36
    ///                    corresponding key, simply provide an immutable borrow of it).
37
    /// - `protected`    - protected headers for the resulting [`CoseMac0`] instance. Will override
38
    ///                    headers previously set using [`CoseMac0Builder::protected`].
39
    /// - `unprotected`  - unprotected headers for the resulting [`CoseMac0`] instance. Will override
40
    ///                    headers previously set using [`CoseMac0Builder::unprotected`].
41
    /// - `external_aad` - provider of additional authenticated data that should be included in the
42
    ///                    MAC calculation.
43
    ///
44
    /// # Errors
45
    ///
46
    /// If the COSE structure, selected [`CoseKey`](coset::CoseKey) or AAD (or any combination of those) are malformed
47
    /// or otherwise unsuitable for MAC calculation, this function will return the most fitting
48
    /// [`CoseCipherError`] for the specific type of error.
49
    ///
50
    /// If the COSE object is not malformed, but an error in the cryptographic backend occurs, a
51
    /// [`CoseCipherError::Other`] containing the backend error will be returned.
52
    /// Refer to the backend module's documentation for information on the possible errors that may
53
    /// occur.
54
    ///
55
    /// If the COSE object is not malformed, but the key provider does not provide a key, a
56
    /// [`CoseCipherError::NoMatchingKeyFound`] will be returned.
57
    ///
58
    /// # Examples
59
    ///
60
    /// Refer to [the documentation for the CoseMac0 extensions](CoseMac0Ext) for examples.
61
    fn try_compute<B: MacCryptoBackend, CKP: KeyProvider, CAP: AadProvider>(
62
        self,
63
        backend: &mut B,
64
        key_provider: &CKP,
65
        protected: Option<Header>,
66
        unprotected: Option<Header>,
67
        external_aad: CAP,
68
    ) -> Result<Self, CoseCipherError<B::Error>>;
69
}
70

71
impl CoseMac0BuilderExt for CoseMac0Builder {
72
    fn try_compute<B: MacCryptoBackend, CKP: KeyProvider, CAP: AadProvider>(
27✔
73
        self,
27✔
74
        backend: &mut B,
27✔
75
        key_provider: &CKP,
27✔
76
        protected: Option<Header>,
27✔
77
        unprotected: Option<Header>,
27✔
78
        external_aad: CAP,
27✔
79
    ) -> Result<Self, CoseCipherError<B::Error>> {
27✔
80
        let mut builder = self;
27✔
81
        if let Some(protected) = &protected {
27✔
82
            builder = builder.protected(protected.clone());
20✔
83
        }
21✔
84
        if let Some(unprotected) = &unprotected {
27✔
85
            builder = builder.unprotected(unprotected.clone());
27✔
86
        }
27✔
87
        builder.try_create_tag(
27✔
88
            external_aad
27✔
89
                .lookup_aad(None, protected.as_ref(), unprotected.as_ref())
27✔
90
                .unwrap_or(&[] as &[u8]),
27✔
91
            |input| {
27✔
92
                try_compute(
27✔
93
                    backend,
27✔
94
                    key_provider,
27✔
95
                    protected.as_ref(),
27✔
96
                    unprotected.as_ref(),
27✔
97
                    input,
27✔
98
                )
27✔
99
            },
27✔
100
        )
27✔
101
    }
27✔
102
}
103

104
/// Extensions to the [`CoseMac0`] type that enable usage of cryptographic backends.
105
///
106
/// # Examples
107
///
108
/// Create a [`CoseMac0`] instance and compute a MAC for it, then verify it:
109
/// ```
110
///
111
/// use coset::{CoseKeyBuilder, CoseMac0Builder, HeaderBuilder, iana};
1✔
112
/// use dcaf::error::CoseCipherError;
113
/// use dcaf::token::cose::{CryptoBackend, CoseMac0BuilderExt, CoseMac0Ext};
114
/// use dcaf::token::cose::crypto_impl::openssl::OpensslContext;
115
///
116
/// let mut backend = OpensslContext::new();
117
///
1✔
118
/// let mut key_data = vec![0; 32];
1✔
119
/// backend.generate_rand(key_data.as_mut_slice())?;
1✔
120
/// let key = CoseKeyBuilder::new_symmetric_key(key_data).build();
1✔
121
///
1✔
122
/// let unprotected = HeaderBuilder::new().algorithm(iana::Algorithm::HMAC_256_256).build();
1✔
123
///
1✔
124
/// let cose_object = CoseMac0Builder::new()
125
///                     .payload("This is the payload!".as_bytes().to_vec())
1✔
126
///                     .try_compute(&mut backend, &key, None, Some(unprotected), &[] as &[u8])?
1✔
127
///                     .build();
1✔
128
///
1✔
129
/// assert!(cose_object.try_verify(&mut backend, &key, &[] as &[u8]).is_ok());
1✔
130
///
1✔
131
/// # Result::<(), CoseCipherError<<OpensslContext as CryptoBackend>::Error>>::Ok(())
132
/// ```
1✔
133
pub trait CoseMac0Ext {
1✔
134
    /// Attempts to verify the MAC using a cryptographic backend.
135
    ///
136
    /// # Parameters
137
    ///
138
    /// - `backend`      - cryptographic backend to use.
139
    /// - `key_provider` - provider for cryptographic keys to use (if you already know the
140
    ///                    corresponding key, simply provide an immutable borrow of it).
141
    /// - `external_aad` - provider of additional authenticated data that should be included in the
142
    ///                    MAC calculation.
143
    ///
144
    /// # Errors
145
    ///
146
    /// If the COSE structure, selected [`CoseKey`](coset::CoseKey) or AAD (or any combination of those) are malformed
147
    /// or otherwise unsuitable for MAC calculation, this function will return the most fitting
148
    /// [`CoseCipherError`] for the specific type of error.
149
    ///
150
    /// If the COSE object is not malformed, but an error in the cryptographic backend occurs, a
151
    /// [`CoseCipherError::Other`] containing the backend error will be returned.
152
    /// Refer to the backend module's documentation for information on the possible errors that may
153
    /// occur.
154
    ///
155
    /// If the COSE object is not malformed, but MAC verification fails for all key candidates
156
    /// provided by the key provider, a [`CoseCipherError::NoMatchingKeyFound`] will be
157
    /// returned.
158
    ///
159
    /// The error will then contain a list of attempted keys and the corresponding error that led to
160
    /// the verification error for that key.
161
    /// For an invalid MAC for an otherwise valid and suitable object+key pairing, this would
162
    /// usually be a [`CoseCipherError::VerificationFailure`].
163
    ///
164
    /// # Examples
165
    ///
166
    /// Verify the example `mac0-tests/mac-pass-01.json` from the `cose-wg/Examples` repository
167
    /// referenced in RFC 9052 using the [`OpensslContext`](super::super::crypto_impl::openssl::OpensslContext)
168
    /// backend:
169
    /// ```
170
    /// use base64::Engine;
1✔
171
    /// use coset::{CoseKeyBuilder, CoseMac0, TaggedCborSerializable};
172
    /// use dcaf::token::cose::CoseMac0Ext;
173
    /// use dcaf::token::cose::crypto_impl::openssl::OpensslContext;
174
    ///
175
    /// let cose_object_cbor_data = hex::decode("D18441A0A1010554546869732069732074686520636F6E74656E742E5820176DCE14C1E57430C13658233F41DC89AA4FA0FF9B8783F23B0EF51CA6B026BC").unwrap();
176
    /// let cose_symmetric_key_k = base64::engine::general_purpose::URL_SAFE_NO_PAD.decode("hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg").unwrap();
1✔
177
    ///
1✔
178
    /// // Parse the object using `coset`.
1✔
179
    /// let cose_object = CoseMac0::from_tagged_slice(cose_object_cbor_data.as_slice()).expect("unable to parse COSE object");
1✔
180
    /// // Create key and AAD as specified in the example.
1✔
181
    /// let key = CoseKeyBuilder::new_symmetric_key(cose_symmetric_key_k).build();
1✔
182
    /// let aad: Vec<u8> = Vec::new();
1✔
183
    ///
1✔
184
    /// assert!(
1✔
185
    ///     cose_object.try_verify(
1✔
186
    ///         &mut OpensslContext::new(),
1✔
187
    ///         &mut &key,
1✔
188
    ///         &aad
1✔
189
    ///     ).is_ok()
1✔
190
    /// );
1✔
191
    /// ```
1✔
192
    ///
1✔
193
    /// Attempt to verify the example `mac0-tests/mac-fail-02` from the `cose-wg/Examples`
194
    /// repository referenced in RFC 9052 using the
195
    /// [`OpensslContext`](super::super::crypto_impl::openssl::OpensslContext) backend (should fail, as the MAC
196
    /// is invalid):
197
    /// ```
198
    /// use base64::Engine;
1✔
199
    /// use coset::{CoseKeyBuilder, CoseMac0, TaggedCborSerializable};
200
    /// use dcaf::token::cose::CoseMac0Ext;
201
    /// use dcaf::token::cose::crypto_impl::openssl::OpensslContext;
202
    /// use dcaf::error::CoseCipherError;
203
    ///
204
    /// let cose_object_cbor_data =
205
    ///     hex::decode("D18443A10105A054546869732069732074686520636F6E74656E742E5820A1A848D3471F9D61EE49018D244C824772F223AD4F935293F1789FC3A08D8C59")
1✔
206
    ///         .unwrap();
1✔
207
    /// let cose_symmetric_key_k =
1✔
208
    ///     base64::engine::general_purpose::URL_SAFE_NO_PAD
1✔
209
    ///         .decode("hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg")
1✔
210
    ///         .unwrap();
1✔
211
    ///
1✔
212
    /// // Parse the object using `coset`.
1✔
213
    /// let cose_object = CoseMac0::from_tagged_slice(
1✔
214
    ///                     cose_object_cbor_data.as_slice()
1✔
215
    ///                   ).expect("unable to parse COSE object");
1✔
216
    /// // Create key and AAD as specified in the example.
1✔
217
    /// let key = CoseKeyBuilder::new_symmetric_key(cose_symmetric_key_k).build();
1✔
218
    /// let aad: Vec<u8> = Vec::new();
1✔
219
    ///
1✔
220
    /// assert!(
1✔
221
    ///     matches!(
1✔
222
    ///         cose_object.try_verify(
×
223
    ///             &mut OpensslContext::new(),
1✔
224
    ///             &mut &key,
1✔
225
    ///             &aad
1✔
226
    ///         ),
1✔
227
    ///         Err(CoseCipherError::NoMatchingKeyFound(_))
1✔
228
    ///     )
229
    /// );
230
    /// ```
231
    fn try_verify<B: MacCryptoBackend, CKP: KeyProvider, CAP: AadProvider>(
1✔
232
        &self,
233
        backend: &mut B,
234
        key_provider: &CKP,
235
        external_aad: CAP,
236
    ) -> Result<(), CoseCipherError<B::Error>>;
237
}
238

239
impl CoseMac0Ext for CoseMac0 {
240
    fn try_verify<B: MacCryptoBackend, CKP: KeyProvider, CAP: AadProvider>(
49✔
241
        &self,
49✔
242
        backend: &mut B,
49✔
243
        key_provider: &CKP,
49✔
244
        external_aad: CAP,
49✔
245
    ) -> Result<(), CoseCipherError<B::Error>> {
49✔
246
        let backend = Rc::new(RefCell::new(backend));
49✔
247
        self.verify_tag(
49✔
248
            external_aad
49✔
249
                .lookup_aad(None, Some(&self.protected.header), Some(&self.unprotected))
49✔
250
                .unwrap_or(&[] as &[u8]),
49✔
251
            |tag, input| {
49✔
252
                try_verify(
49✔
253
                    &backend,
49✔
254
                    key_provider,
49✔
255
                    &self.protected.header,
49✔
256
                    &self.unprotected,
49✔
257
                    tag,
49✔
258
                    input,
49✔
259
                )
49✔
260
            },
49✔
261
        )
49✔
262
    }
49✔
263
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc