/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 | } |