Coverage Report

Created: 2026-05-18 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/git/checkouts/nss-rs-71e20fe79ef91440/9b94ca3/src/ec.rs
Line
Count
Source
1
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4
// option. This file may not be copied, modified, or distributed
5
// except according to those terms.
6
7
use std::ptr;
8
9
use pkcs11_bindings::{
10
    CK_FALSE, CKA_VALUE, CKM_EC_EDWARDS_KEY_PAIR_GEN, CKM_EC_KEY_PAIR_GEN,
11
    CKM_EC_MONTGOMERY_KEY_PAIR_GEN,
12
};
13
14
// use std::ptr::null;
15
// use std::ptr::null_mut;
16
use crate::{
17
    PrivateKey, PublicKey, SECItem, SECItemBorrowed, der,
18
    err::{Error, IntoResult as _, secstatus_to_res},
19
    init,
20
    p11::{
21
        KU_ALL, PK11_ExportDERPrivateKeyInfo, PK11_GenerateKeyPair,
22
        PK11_ImportDERPrivateKeyInfoAndReturnKey, PK11_ImportPublicKey, PK11_PubDeriveWithKDF,
23
        PK11_ReadRawAttribute, PK11ObjectType::PK11_TypePrivKey,
24
        SECKEY_DecodeDERSubjectPublicKeyInfo, Slot,
25
    },
26
    ssl::PRBool,
27
    util::SECItemMut,
28
};
29
//
30
// Constants
31
//
32
33
#[derive(Clone, Debug, Eq, PartialEq)]
34
pub enum EcCurve {
35
    P256,
36
    P384,
37
    P521,
38
    X25519,
39
    Ed25519,
40
}
41
42
pub type EcdhPublicKey = PublicKey;
43
pub type EcdhPrivateKey = PrivateKey;
44
45
pub struct EcdhKeypair {
46
    pub public: EcdhPublicKey,
47
    pub private: EcdhPrivateKey,
48
}
49
50
#[derive(Clone, Debug, Eq, PartialEq)]
51
pub struct Ecdh(EcCurve);
52
53
impl Ecdh {
54
    #[must_use]
55
0
    pub const fn new(curve: EcCurve) -> Self {
56
0
        Self(curve)
57
0
    }
58
59
0
    pub fn generate_keypair(curve: &EcCurve) -> Result<EcdhKeypair, Error> {
60
0
        ecdh_keygen(curve)
61
0
    }
62
}
63
64
// Object identifiers in DER tag-length-value form
65
pub const OID_EC_PUBLIC_KEY_BYTES: &[u8] = &[
66
    /* RFC 5480 (id-ecPublicKey) */
67
    0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
68
];
69
pub const OID_SECP256R1_BYTES: &[u8] = &[
70
    /* RFC 5480 (secp256r1) */
71
    0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
72
];
73
pub const OID_SECP384R1_BYTES: &[u8] = &[
74
    /* RFC 5480 (secp384r1) */
75
    0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x34,
76
];
77
pub const OID_SECP521R1_BYTES: &[u8] = &[
78
    /* RFC 5480 (secp521r1) */
79
    0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x35,
80
];
81
82
pub const OID_ED25519_BYTES: &[u8] = &[/* RFC 8410 (id-ed25519) */ 0x2b, 0x65, 0x70];
83
pub const OID_RS256_BYTES: &[u8] = &[
84
    /* RFC 4055 (sha256WithRSAEncryption) */
85
    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
86
];
87
88
pub const OID_X25519_BYTES: &[u8] = &[
89
    /* https://tools.ietf.org/html/draft-josefsson-pkix-newcurves-01
90
     * 1.3.6.1.4.1.11591.15.1 */
91
    0x2b, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01,
92
];
93
94
0
pub fn object_id(val: &[u8]) -> Result<Vec<u8>, Error> {
95
0
    let mut out = Vec::with_capacity(der::MAX_TAG_AND_LENGTH_BYTES + val.len());
96
0
    der::write_tag_and_length(&mut out, der::TAG_OBJECT_ID, val.len())?;
97
0
    out.extend_from_slice(val);
98
0
    Ok(out)
99
0
}
100
101
0
fn ec_curve_to_oid(alg: &EcCurve) -> Vec<u8> {
102
0
    match alg {
103
0
        EcCurve::X25519 => OID_X25519_BYTES.to_vec(),
104
0
        EcCurve::Ed25519 => OID_ED25519_BYTES.to_vec(),
105
0
        EcCurve::P256 => OID_SECP256R1_BYTES.to_vec(),
106
0
        EcCurve::P384 => OID_SECP384R1_BYTES.to_vec(),
107
0
        EcCurve::P521 => OID_SECP521R1_BYTES.to_vec(),
108
    }
109
0
}
110
111
0
const fn ec_curve_to_ckm(alg: &EcCurve) -> pkcs11_bindings::CK_MECHANISM_TYPE {
112
0
    match alg {
113
0
        EcCurve::P256 | EcCurve::P384 | EcCurve::P521 => CKM_EC_KEY_PAIR_GEN,
114
0
        EcCurve::Ed25519 => CKM_EC_EDWARDS_KEY_PAIR_GEN,
115
0
        EcCurve::X25519 => CKM_EC_MONTGOMERY_KEY_PAIR_GEN,
116
    }
117
0
}
118
119
//
120
// Curve functions
121
//
122
123
0
pub fn ecdh_keygen(curve: &EcCurve) -> Result<EcdhKeypair, Error> {
124
0
    init()?;
125
126
    // Get the OID for the Curve
127
0
    let curve_oid = ec_curve_to_oid(curve);
128
0
    let oid_bytes = object_id(&curve_oid)?;
129
0
    let mut oid = SECItemBorrowed::wrap(&oid_bytes)?;
130
0
    let oid_ptr: *mut SECItem = oid.as_mut();
131
132
    // Get the Mechanism based on the Curve and its use
133
0
    let ckm = ec_curve_to_ckm(curve);
134
135
    // Get the PKCS11 slot
136
0
    let slot = Slot::internal()?;
137
138
    // Create a pointer for the public key
139
0
    let mut pk_ptr = ptr::null_mut();
140
141
    // https://github.com/mozilla/nss-gk-api/issues/1
142
    unsafe {
143
0
        let sk = PK11_GenerateKeyPair(
144
0
            *slot,
145
0
            ckm,
146
0
            oid_ptr.cast(),
147
0
            &raw mut pk_ptr,
148
0
            CK_FALSE.into(),
149
0
            CK_FALSE.into(),
150
0
            ptr::null_mut(),
151
        )
152
0
        .into_result()?;
153
154
0
        let pk = EcdhPublicKey::from_ptr(pk_ptr)?;
155
156
0
        let kp = EcdhKeypair {
157
0
            public: pk,
158
0
            private: sk,
159
0
        };
160
161
0
        Ok(kp)
162
    }
163
0
}
164
165
0
pub fn export_ec_private_key_pkcs8(key: &PrivateKey) -> Result<Vec<u8>, Error> {
166
0
    init()?;
167
    unsafe {
168
0
        let sk: crate::ScopedSECItem =
169
0
            PK11_ExportDERPrivateKeyInfo(**key, ptr::null_mut()).into_result()?;
170
0
        Ok(sk.into_vec())
171
    }
172
0
}
173
174
0
pub fn import_ec_public_key_from_spki(spki: &[u8]) -> Result<PublicKey, Error> {
175
0
    init()?;
176
0
    let mut spki_item = SECItemBorrowed::wrap(spki)?;
177
0
    let spki_item_ptr = spki_item.as_mut();
178
0
    let slot = Slot::internal()?;
179
    unsafe {
180
0
        let spki = SECKEY_DecodeDERSubjectPublicKeyInfo(spki_item_ptr).into_result()?;
181
0
        let pk: PublicKey =
182
0
            crate::p11::SECKEY_ExtractPublicKey(spki.as_mut().ok_or(Error::InvalidInput)?)
183
0
                .into_result()?;
184
185
0
        let handle = PK11_ImportPublicKey(*slot, *pk, PRBool::from(false));
186
0
        if handle == pkcs11_bindings::CK_INVALID_HANDLE {
187
0
            return Err(Error::InvalidInput);
188
0
        }
189
190
0
        Ok(pk)
191
    }
192
0
}
193
194
0
pub fn import_ec_private_key_pkcs8(pki: &[u8]) -> Result<PrivateKey, Error> {
195
0
    init()?;
196
197
    // Get the PKCS11 slot
198
0
    let slot = Slot::internal()?;
199
0
    let mut der_pki = SECItemBorrowed::wrap(pki)?;
200
0
    let der_pki_ptr: *mut SECItem = der_pki.as_mut();
201
202
    // Create a pointer for the private key
203
0
    let mut pk_ptr = ptr::null_mut();
204
205
    unsafe {
206
0
        secstatus_to_res(PK11_ImportDERPrivateKeyInfoAndReturnKey(
207
0
            *slot,
208
0
            der_pki_ptr,
209
0
            ptr::null_mut(),
210
0
            ptr::null_mut(),
211
            0,
212
            0,
213
            KU_ALL,
214
0
            &raw mut pk_ptr,
215
0
            ptr::null_mut(),
216
0
        ))?;
217
218
0
        let sk = EcdhPrivateKey::from_ptr(pk_ptr)?;
219
0
        Ok(sk)
220
    }
221
0
}
222
223
0
pub fn export_ec_private_key_from_raw(key: &PrivateKey) -> Result<Vec<u8>, Error> {
224
0
    init()?;
225
0
    let mut key_item = SECItemMut::make_empty();
226
0
    unsafe {
227
0
        PK11_ReadRawAttribute(PK11_TypePrivKey, key.cast(), CKA_VALUE, key_item.as_mut());
228
0
    }
229
0
    Ok(key_item.as_slice().to_owned())
230
0
}
231
232
0
pub fn ecdh(sk: &PrivateKey, pk: &PublicKey) -> Result<Vec<u8>, Error> {
233
0
    init()?;
234
0
    let sym_key = unsafe {
235
0
        PK11_PubDeriveWithKDF(
236
0
            sk.cast(),
237
0
            pk.cast(),
238
            0,
239
0
            ptr::null_mut(),
240
0
            ptr::null_mut(),
241
            pkcs11_bindings::CKM_ECDH1_DERIVE,
242
            pkcs11_bindings::CKM_SHA512_HMAC,
243
            pkcs11_bindings::CKA_SIGN,
244
            0,
245
            pkcs11_bindings::CKD_NULL,
246
0
            ptr::null_mut(),
247
0
            ptr::null_mut(),
248
        )
249
0
        .into_result()?
250
    };
251
252
0
    let key = sym_key.key_data()?;
253
0
    Ok(key.to_vec())
254
0
}
255
256
0
pub fn convert_to_public(sk: &PrivateKey) -> Result<PublicKey, Error> {
257
0
    init()?;
258
    unsafe {
259
0
        let pk = crate::p11::SECKEY_ConvertToPublicKey(**sk).into_result()?;
260
0
        Ok(pk)
261
    }
262
0
}
263
264
0
pub fn sign(
265
0
    private_key: &PrivateKey,
266
0
    data: &[u8],
267
0
    mechanism: std::os::raw::c_ulong,
268
0
) -> Result<Vec<u8>, Error> {
269
0
    init()?;
270
0
    let data_signature = vec![0u8; 0x40];
271
272
0
    let mut data_to_sign = SECItemBorrowed::wrap(data)?;
273
0
    let mut signature = SECItemBorrowed::wrap(&data_signature)?;
274
    unsafe {
275
0
        secstatus_to_res(crate::p11::PK11_SignWithMechanism(
276
0
            private_key.as_mut().ok_or(Error::InvalidInput)?,
277
0
            mechanism,
278
0
            ptr::null_mut(),
279
0
            signature.as_mut(),
280
0
            data_to_sign.as_mut(),
281
0
        ))?;
282
283
0
        let signature = signature.as_slice().to_vec();
284
0
        Ok(signature)
285
    }
286
0
}
287
288
#[allow(clippy::allow_attributes)]
289
#[allow(clippy::useless_conversion)]
290
0
pub fn sign_ecdsa(private_key: &PrivateKey, data: &[u8]) -> Result<Vec<u8>, Error> {
291
0
    sign(private_key, data, crate::p11::CKM_ECDSA.into())
292
0
}
293
294
#[allow(clippy::allow_attributes)]
295
#[allow(clippy::useless_conversion)]
296
0
pub fn sign_eddsa(private_key: &PrivateKey, data: &[u8]) -> Result<Vec<u8>, Error> {
297
0
    sign(private_key, data, crate::p11::CKM_EDDSA.into())
298
0
}
299
300
0
pub fn verify(
301
0
    public_key: &PublicKey,
302
0
    data: &[u8],
303
0
    signature: &[u8],
304
0
    mechanism: std::os::raw::c_ulong,
305
0
) -> Result<bool, Error> {
306
0
    init()?;
307
    unsafe {
308
0
        let mut data_to_sign = SECItemBorrowed::wrap(data)?;
309
0
        let mut signature = SECItemBorrowed::wrap(signature)?;
310
311
0
        let rv = crate::p11::PK11_VerifyWithMechanism(
312
0
            public_key.as_mut().ok_or(Error::InvalidInput)?,
313
0
            mechanism,
314
0
            ptr::null_mut(),
315
0
            signature.as_mut(),
316
0
            data_to_sign.as_mut(),
317
0
            ptr::null_mut(),
318
        );
319
320
0
        match rv {
321
0
            0 => Ok(true),
322
0
            _ => Ok(false),
323
        }
324
    }
325
0
}
326
327
#[allow(clippy::allow_attributes)]
328
#[allow(clippy::useless_conversion)]
329
0
pub fn verify_ecdsa(public_key: &PublicKey, data: &[u8], signature: &[u8]) -> Result<bool, Error> {
330
0
    verify(public_key, data, signature, crate::p11::CKM_ECDSA.into())
331
0
}
332
333
#[allow(clippy::allow_attributes)]
334
#[allow(clippy::useless_conversion)]
335
0
pub fn verify_eddsa(public_key: &PublicKey, data: &[u8], signature: &[u8]) -> Result<bool, Error> {
336
0
    verify(public_key, data, signature, crate::p11::CKM_EDDSA.into())
337
0
}