Skip to content

Commit afb2ffd

Browse files
committed
function extract_key_pair is a workaround for the faulty function wc_Ed25519PrivateKeyDecode
1 parent b5e14d3 commit afb2ffd

File tree

1 file changed

+101
-42
lines changed
  • rustls-wolfcrypt-provider/src/sign

1 file changed

+101
-42
lines changed

rustls-wolfcrypt-provider/src/sign/eddsa.rs

Lines changed: 101 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,87 @@ pub struct Ed25519PrivateKey {
2020
algo: SignatureAlgorithm,
2121
}
2222

23+
impl Ed25519PrivateKey {
24+
/// Extract ED25519 private and if available public key values from a PKCS#8 DER formatted key
25+
fn extract_key_pair(input_key: &[u8]) -> Result<([u8; 32], Option<[u8; 32]>), rustls::Error> {
26+
let mut public_key_raw: [u8; 32] = [0; ED25519_PUB_KEY_SIZE as usize];
27+
let mut private_key_raw: [u8; 32] = [0; ED25519_KEY_SIZE as usize];
28+
let mut skip_bytes: usize;
29+
let mut key_sub_slice = input_key;
30+
31+
const SHORT_FORM_LEN_MAX: u8 = 127;
32+
const TAG_SEQUENCE: u8 = 0x30;
33+
const TAG_OCTET_SEQUENCE: u8 = 0x04;
34+
const TAG_OPTIONAL_SET_OF_ATTRIBUTES: u8 = 0x80; //Implicit, context-specific, and primitive underlying type (SET OF)
35+
const TAG_OPTIONAL_PUBLIC_KEY_BIT_STRING: u8 = 0x81; //Implicit, context-specific, and primitive underlying type (BIT STRING)
36+
37+
// The input key is encoded in PKCS#8 DER format with a structure as in
38+
// https://www.rfc-editor.org/rfc/rfc5958.html
39+
//
40+
// AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
41+
42+
// OneAsymmetricKey ::= SEQUENCE {
43+
// version Version,
44+
// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
45+
// privateKey PrivateKey,
46+
// attributes [0] Attributes OPTIONAL,
47+
// ...,
48+
// [[2: publicKey [1] PublicKey OPTIONAL ]],
49+
// ...
50+
// }
51+
52+
// The key structure must begin with a SEQUENCE tag with at least 2 bytes length if short
53+
// length format is used
54+
if key_sub_slice[0] != TAG_SEQUENCE || key_sub_slice.len() < 2 {
55+
return Err(rustls::Error::General(
56+
"Faulty PKCS#8 ED25519 private key structure".into(),
57+
));
58+
}
59+
// Check which length format and skip tag and length encoding bytes
60+
if key_sub_slice[1] > SHORT_FORM_LEN_MAX {
61+
skip_bytes = (2 + (key_sub_slice[1] & 0x7F)) as usize;
62+
} else {
63+
skip_bytes = 2;
64+
}
65+
66+
// Skip version (3 bytes), algorithm ID sequence (0x30 + length encoding bytes + 5 ID bytes),
67+
skip_bytes += 3 + 7;
68+
key_sub_slice = input_key.get(skip_bytes..).unwrap();
69+
70+
// Check if next bytes are 0x04, 0x22, 0x04, 0x20
71+
if !matches!(
72+
key_sub_slice,
73+
[TAG_OCTET_SEQUENCE, 0x22, TAG_OCTET_SEQUENCE, 0x20, ..]
74+
) {
75+
return Err(rustls::Error::General(
76+
"Faulty PKCS#8 ED25519 private key structure".into(),
77+
));
78+
}
79+
80+
// Copy private key value
81+
skip_bytes += 4;
82+
key_sub_slice = input_key.get(skip_bytes..).unwrap();
83+
private_key_raw.copy_from_slice(&key_sub_slice[..ED25519_KEY_SIZE as usize]);
84+
skip_bytes += ED25519_KEY_SIZE as usize;
85+
key_sub_slice = input_key.get(skip_bytes..).unwrap();
86+
87+
// Check if optional SET OF attributes exists and skip
88+
if key_sub_slice[0] == TAG_OPTIONAL_SET_OF_ATTRIBUTES {
89+
skip_bytes += (2 + (key_sub_slice[1])) as usize;
90+
key_sub_slice = input_key.get(skip_bytes..).unwrap();
91+
}
92+
93+
// Check if optional public key value exists. If exists, skip tag, length encoding byte,
94+
// and bits-used byte
95+
if key_sub_slice[0] == TAG_OPTIONAL_PUBLIC_KEY_BIT_STRING {
96+
public_key_raw.copy_from_slice(&key_sub_slice[3..(3 + ED25519_KEY_SIZE as usize)]);
97+
Ok((private_key_raw, Some(public_key_raw)))
98+
} else {
99+
Ok((private_key_raw, None))
100+
}
101+
}
102+
}
103+
23104
impl TryFrom<&PrivateKeyDer<'_>> for Ed25519PrivateKey {
24105
type Error = rustls::Error;
25106

@@ -28,57 +109,35 @@ impl TryFrom<&PrivateKeyDer<'_>> for Ed25519PrivateKey {
28109
PrivateKeyDer::Pkcs8(der) => {
29110
let mut ed25519_c_type: ed25519_key = unsafe { mem::zeroed() };
30111
let ed25519_key_object = ED25519KeyObject::new(&mut ed25519_c_type);
31-
let mut priv_key_raw: [u8; 32] = [0; 32];
32-
let mut priv_key_raw_len: word32 = priv_key_raw.len() as word32;
33-
let mut pub_key_raw: [u8; 32] = [0; 32];
34-
let pub_key_raw_len: word32 = pub_key_raw.len() as word32;
112+
let mut pub_raw: [u8; 32] = [0; 32];
113+
let pub_key_raw_len: word32 = pub_raw.len() as word32;
35114
let pkcs8: &[u8] = der.secret_pkcs8_der();
36-
let pkcs8_sz: word32 = pkcs8.len() as word32;
37-
let mut ret;
115+
let (priv_key_raw, pub_key_raw) = match Ed25519PrivateKey::extract_key_pair(pkcs8) {
116+
Ok((priv_raw, pub_raw)) => (priv_raw, pub_raw),
117+
118+
Err(error) => return Err(error),
119+
};
38120

39121
// This function initiliazes an ed25519_key object for
40122
// using it to sign a message.
41123
ed25519_key_object.init();
42124

43-
let mut idx: u32 = 0;
44-
45-
// This function reads in an ED25519 private key from the input buffer, input,
46-
// parses the private key, and uses it to generate an ed25519_key object,
47-
// which it stores in key.
48-
ret = unsafe {
49-
wc_Ed25519PrivateKeyDecode(
50-
pkcs8.as_ptr() as *mut u8,
51-
&mut idx,
52-
ed25519_key_object.as_ptr(),
53-
pkcs8_sz,
54-
)
55-
};
56-
check_if_zero(ret)
57-
.map_err(|_| rustls::Error::General("FFI function failed".into()))?;
58-
59-
ret = unsafe {
60-
wc_ed25519_make_public(
61-
ed25519_key_object.as_ptr(),
62-
pub_key_raw.as_mut_ptr(),
63-
pub_key_raw_len,
64-
)
65-
};
66-
check_if_zero(ret)
67-
.map_err(|_| rustls::Error::General("FFI function failed".into()))?;
68-
69-
ret = unsafe {
70-
wc_ed25519_export_private_only(
71-
ed25519_key_object.as_ptr(),
72-
priv_key_raw.as_mut_ptr(),
73-
&mut priv_key_raw_len,
74-
)
75-
};
76-
check_if_zero(ret)
77-
.map_err(|_| rustls::Error::General("FFI function failed".into()))?;
125+
// Generate pub key part if not given
126+
if pub_key_raw.is_none() {
127+
let ret = unsafe {
128+
wc_ed25519_make_public(
129+
ed25519_key_object.as_ptr(),
130+
pub_raw.as_mut_ptr(),
131+
pub_key_raw_len,
132+
)
133+
};
134+
check_if_zero(ret)
135+
.map_err(|_| rustls::Error::General("FFI function failed".into()))?;
136+
}
78137

79138
Ok(Self {
80139
priv_key: Arc::new(priv_key_raw.to_vec()),
81-
pub_key: Arc::new(pub_key_raw.to_vec()),
140+
pub_key: Arc::new(pub_raw.to_vec()),
82141
algo: SignatureAlgorithm::ED25519,
83142
})
84143
}

0 commit comments

Comments
 (0)