• 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

60.87
/src/token/cose/signed/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
use alloc::collections::BTreeSet;
12
use alloc::vec::Vec;
13

14
use coset::{iana, Algorithm, Header, KeyOperation};
15

16
pub use sign::{CoseSignBuilderExt, CoseSignExt};
17
pub use sign1::{CoseSign1BuilderExt, CoseSign1Ext};
18

19
use crate::error::CoseCipherError;
20
use crate::token::cose::key::{CoseEc2Key, CoseParsedKey, KeyProvider};
21
use crate::token::cose::util::{ensure_valid_ecdsa_key, try_cose_crypto_operation};
22
use crate::token::cose::CryptoBackend;
23

24
mod sign;
25
mod sign1;
26

27
/// Provides basic operations for signing and verifying COSE structures.
28
pub trait SignCryptoBackend: CryptoBackend {
29
    /// Cryptographically signs the `payload` value with the `key` using ECDSA and returns the
30
    /// signature.
31
    ///
32
    /// # Arguments
33
    ///
34
    /// * `algorithm` - The variant of ECDSA to use (determines the hash function).
35
    ///           If unsupported by the backend, a [`CoseCipherError::UnsupportedAlgorithm`] error
36
    ///           should be returned.
37
    ///           If the given algorithm is an IANA-assigned value that is unknown, the
38
    ///           implementation should return [`CoseCipherError::UnsupportedAlgorithm`] (in case
39
    ///           additional variants of ECDSA are ever added).
40
    ///           If the algorithm is not an ECDSA algorithm, the implementation may return
41
    ///           [`CoseCipherError::UnsupportedAlgorithm`] or panic.
42
    /// * `key` - Elliptic curve key that should be used.
43
    ///           Implementations may assume that if the [`CoseEc2Key::crv`] field is an IANA-assigned
44
    ///           value, it will always be a curve feasible for ECDSA.
45
    ///           If the given algorithm is an IANA-assigned value that is unknown, the
46
    ///           implementation should return [`CoseCipherError::UnsupportedAlgorithm`] (in case
47
    ///           additional variants of ECDSA are ever added). If the algorithm is not an ECDSA
48
    ///           algorithm, the implementation may return [`CoseCipherError::UnsupportedAlgorithm`]
49
    ///           or panic.
50
    ///           Note that curve and hash bit sizes do not necessarily match.
51
    ///           Implementations may assume the struct field `d` (the private key) to always be set
52
    ///           and panic if this is not the case.
53
    ///           The fields `x` and (`y` or `sign`) (the public key) may be used by implementations
54
    ///           if they are set. If they are not, implementations may either derive the public key
55
    ///           from `d` or return a [`CoseCipherError::UnsupportedKeyDerivation`] if this
56
    ///           derivation is unsupported.
57
    ///           If calculation of the public key from the `x` coordinate and `sign` is not
58
    ///           supported, a [`CoseCipherError::UnsupportedKeyDerivation`] may be returned as well.
59
    /// * `payload` - Data to be signed.
60
    ///
61
    /// # Returns
62
    ///
63
    /// It is expected that the return value is a signature conforming to RFC 9053, Section 2.1,
64
    /// i.e. the return value should consist of the `r` and `s` values of the signature, which are
65
    /// each padded (at the beginning) with zeros to the key size (rounded up to the next full
66
    /// byte).
67
    ///
68
    /// # Errors
69
    ///
70
    /// In case of errors, the implementation may return any valid [`CoseCipherError`].
71
    /// For backend-specific errors, [`CoseCipherError::Other`] may be used to convey a
72
    /// backend-specific error.
73
    ///
74
    /// # Panics
75
    ///
76
    /// Implementations may panic if the provided algorithm is not an ECDSA algorithm, the
77
    /// provided key is not part of a curve suitable for ECDSA, the `d` field of the key is not set
78
    /// or if an unrecoverable backend error occurs that necessitates a panic (at their own
79
    /// discretion).
80
    /// In the last of the above cases, additional panics should be documented on the backend level.
81
    ///
82
    /// For unknown algorithms or key curves, however, the implementation must not panic and return
83
    /// [`CoseCipherError::UnsupportedAlgorithm`] instead (in case new ECDSA variants are defined).
84
    #[allow(unused_variables)]
85
    fn sign_ecdsa(
×
86
        &mut self,
×
87
        algorithm: iana::Algorithm,
×
88
        key: &CoseEc2Key<'_, Self::Error>,
×
89
        payload: &[u8],
×
90
    ) -> Result<Vec<u8>, CoseCipherError<Self::Error>> {
×
91
        Err(CoseCipherError::UnsupportedAlgorithm(Algorithm::Assigned(
×
92
            algorithm,
×
93
        )))
×
94
    }
×
95

96
    /// Verifies the `signature` using the given `key` and `payload` (plaintext) using ECDSA.
97
    ///
98
    /// # Arguments
99
    ///
100
    /// * `algorithm` - The variant of ECDSA to use (determines the hash function).
101
    ///           If unsupported by the backend, a [`CoseCipherError::UnsupportedAlgorithm`] error
102
    ///           should be returned.
103
    ///           If the given algorithm is an IANA-assigned value that is unknown, the
104
    ///           implementation should return [`CoseCipherError::UnsupportedAlgorithm`] (in case
105
    ///           additional variants of ECDSA are ever added).
106
    ///           If the algorithm is not an ECDSA algorithm, the implementation may return
107
    ///           [`CoseCipherError::UnsupportedAlgorithm`] or panic.
108
    /// * `key` - Elliptic curve key that should be used.
109
    ///           Implementations may assume that if the [`CoseEc2Key::crv`] field is an IANA-assigned
110
    ///           value, it will always be a curve feasible for ECDSA.
111
    ///           If the given algorithm is an IANA-assigned value that is unknown, the
112
    ///           implementation should return [`CoseCipherError::UnsupportedAlgorithm`] (in case
113
    ///           additional variants of ECDSA are ever added). If the algorithm is not an ECDSA
114
    ///           algorithm, the implementation may return [`CoseCipherError::UnsupportedAlgorithm`]
115
    ///           or panic.
116
    ///           Note that curve and hash bit sizes do not necessarily match.
117
    ///           Implementations may assume that either `d` or (`x` and (`y` xor `sign`)) are set.
118
    ///           The fields x and (y or sign) (the public key) may be used by implementations if
119
    ///           they are set.
120
    ///           If they are not, but the private key `d` is present, implementations may either
121
    ///           derive the public key from `d` (if present) or return a
122
    ///           [`CoseCipherError::UnsupportedKeyDerivation`] if this derivation is unsupported.
123
    ///           If calculation of the public key from the `x` coordinate and `sign` is not
124
    ///           supported, a [`CoseCipherError::UnsupportedKeyDerivation`] may be returned as well.
125
    /// * `sig` - the signature to verify. This signature should be a valid signature
126
    ///           conforming to RFC 9053, Section 2.1 (i.e. the `r` and `s` values of the signature
127
    ///           are each padded with zeros at the beginning to the key size rounded up to the next
128
    ///           full byte), but as this is user-provided input, the implementation must not rely
129
    ///           on this being the case.
130
    /// * `payload` - Data that was presumably signed using the signature.
131
    ///
132
    /// # Returns
133
    ///
134
    /// It is expected that the return value is Ok(()) if the provided signature is a valid ECDSA
135
    /// signature for the provided key.
136
    ///
137
    /// # Errors
138
    ///
139
    /// If the signature is not malformed, but not valid for the given `algorithm`, `key`,
140
    /// and `payload`, a [`CoseCipherError::VerificationFailure`] must be returned.
141
    ///
142
    /// In case of other errors, the implementation may return any valid [`CoseCipherError`]
143
    /// (including [`CoseCipherError::VerificationFailure`]).
144
    /// For backend-specific errors, [`CoseCipherError::Other`] may be used to convey a
145
    /// backend-specific error.
146
    ///
147
    /// # Panics
148
    ///
149
    /// Implementations may panic if the provided algorithm is not an ECDSA algorithm, the
150
    /// provided key is not part of a curve suitable for ECDSA, neither the `x` and (`y` or `sign`)
151
    /// fields nor the `d` field of the provided key are set or if an unrecoverable backend error
152
    /// occurs that necessitates a panic (at their own discretion).
153
    /// In the last of the above cases, additional panics should be documented on the backend level.
154
    ///
155
    /// For unknown algorithms or key curves, however, the implementation must not panic and return
156
    /// [`CoseCipherError::UnsupportedAlgorithm`] instead (in case new ECDSA variants are defined).
157
    #[allow(unused_variables)]
158
    fn verify_ecdsa(
×
159
        &mut self,
×
160
        algorithm: iana::Algorithm,
×
161
        key: &CoseEc2Key<'_, Self::Error>,
×
162
        sig: &[u8],
×
163
        payload: &[u8],
×
164
    ) -> Result<(), CoseCipherError<Self::Error>> {
×
165
        Err(CoseCipherError::UnsupportedAlgorithm(Algorithm::Assigned(
×
166
            algorithm,
×
167
        )))
×
168
    }
×
169
}
170

171
/// Attempts to perform a COSE signing operation for a [`CoseSign`](coset::CoseSign) or
172
/// [`CoseSign1`](coset::CoseSign1) structure with the given `protected` and `unprotected`
173
/// headers and `payload` using the given `backend` and `key_provider`.
174
///
175
/// Also performs checks that ensure that the given parameters (esp. headers and keys) are valid and
176
/// are coherent with each other.
177
///
178
/// If the `key_provider` returns multiple keys, all will be tried until one can be successfully
179
/// used for the given operation.
180
fn try_sign<B: SignCryptoBackend, CKP: KeyProvider>(
83✔
181
    backend: &mut B,
83✔
182
    key_provider: &CKP,
83✔
183
    protected: Option<&Header>,
83✔
184
    unprotected: Option<&Header>,
83✔
185
    payload: &[u8],
83✔
186
) -> Result<Vec<u8>, CoseCipherError<B::Error>> {
83✔
187
    try_cose_crypto_operation(
83✔
188
        key_provider,
83✔
189
        protected,
83✔
190
        unprotected,
83✔
191
        BTreeSet::from_iter(vec![KeyOperation::Assigned(iana::KeyOperation::Sign)]),
83✔
192
        |key, alg, _protected, _unprotected| {
83✔
193
            let parsed_key = CoseParsedKey::try_from(key)?;
83✔
194
            match alg {
83✔
195
                iana::Algorithm::ES256
196
                | iana::Algorithm::ES384
197
                | iana::Algorithm::ES512
198
                | iana::Algorithm::ES256K => {
199
                    // Check if this is a valid ECDSA key.
200
                    let ec2_key = ensure_valid_ecdsa_key::<B::Error>(alg, parsed_key, true)?;
83✔
201

202
                    // Perform signing operation using backend.
203
                    backend.sign_ecdsa(alg, &ec2_key, payload)
83✔
204
                }
205
                alg => Err(CoseCipherError::UnsupportedAlgorithm(Algorithm::Assigned(
×
206
                    alg,
×
207
                ))),
×
208
            }
209
        },
83✔
210
    )
83✔
211
}
83✔
212

213
/// Attempts to perform a COSE signature verification operation for a [`CoseSign`](coset::CoseSign)
214
/// or [`CoseSign1`](coset::CoseSign1) structure with the given `protected` and `unprotected`
215
/// headers and `payload` using the given `backend` and `key_provider`.
216
///
217
/// Also performs checks that ensure that the given parameters (esp. headers and keys) are valid and
218
/// are coherent with each other.
219
///
220
/// If the `key_provider` returns multiple keys, all will be tried until one can be successfully
221
/// used for the given operation.
222
fn try_verify<B: SignCryptoBackend, CKP: KeyProvider>(
159✔
223
    backend: &mut B,
159✔
224
    key_provider: &CKP,
159✔
225
    protected: &Header,
159✔
226
    unprotected: &Header,
159✔
227

159✔
228
    signature: &[u8],
159✔
229
    toverify: &[u8],
159✔
230
) -> Result<(), CoseCipherError<B::Error>> {
159✔
231
    try_cose_crypto_operation(
159✔
232
        key_provider,
159✔
233
        Some(protected),
159✔
234
        Some(unprotected),
159✔
235
        BTreeSet::from_iter(vec![KeyOperation::Assigned(iana::KeyOperation::Verify)]),
159✔
236
        |key, alg, _protected, _unprotected| {
159✔
237
            let parsed_key = CoseParsedKey::try_from(key)?;
147✔
238
            match alg {
147✔
239
                iana::Algorithm::ES256
240
                | iana::Algorithm::ES384
241
                | iana::Algorithm::ES512
242
                | iana::Algorithm::ES256K => {
243
                    // Check if this is a valid ECDSA key.
244
                    let ec2_key = ensure_valid_ecdsa_key::<B::Error>(alg, parsed_key, false)?;
147✔
245

246
                    backend.verify_ecdsa(alg, &ec2_key, signature, toverify)
147✔
247
                }
248
                alg => Err(CoseCipherError::UnsupportedAlgorithm(Algorithm::Assigned(
×
249
                    alg,
×
250
                ))),
×
251
            }
252
        },
159✔
253
    )
159✔
254
}
159✔
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