Merge pull request #1153 from sturmsebastian/eddsa
Added support for Ed25519 and Ed448 signatures
This commit is contained in:
commit
79d6d1ff2b
|
|
@ -10,6 +10,10 @@ pub const EVP_PKEY_RSA: c_int = NID_rsaEncryption;
|
||||||
pub const EVP_PKEY_DSA: c_int = NID_dsa;
|
pub const EVP_PKEY_DSA: c_int = NID_dsa;
|
||||||
pub const EVP_PKEY_DH: c_int = NID_dhKeyAgreement;
|
pub const EVP_PKEY_DH: c_int = NID_dhKeyAgreement;
|
||||||
pub const EVP_PKEY_EC: c_int = NID_X9_62_id_ecPublicKey;
|
pub const EVP_PKEY_EC: c_int = NID_X9_62_id_ecPublicKey;
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub const EVP_PKEY_ED25519: c_int = NID_ED25519;
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub const EVP_PKEY_ED448: c_int = NID_ED448;
|
||||||
pub const EVP_PKEY_HMAC: c_int = NID_hmac;
|
pub const EVP_PKEY_HMAC: c_int = NID_hmac;
|
||||||
pub const EVP_PKEY_CMAC: c_int = NID_cmac;
|
pub const EVP_PKEY_CMAC: c_int = NID_cmac;
|
||||||
|
|
||||||
|
|
@ -153,6 +157,27 @@ cfg_if! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(ossl111)] {
|
||||||
|
extern "C" {
|
||||||
|
pub fn EVP_DigestSign(
|
||||||
|
ctx: *mut EVP_MD_CTX,
|
||||||
|
sigret: *mut c_uchar,
|
||||||
|
siglen: *mut size_t,
|
||||||
|
tbs: *const c_uchar,
|
||||||
|
tbslen: size_t
|
||||||
|
) -> c_int;
|
||||||
|
|
||||||
|
pub fn EVP_DigestVerify(
|
||||||
|
ctx: *mut EVP_MD_CTX,
|
||||||
|
sigret: *const c_uchar,
|
||||||
|
siglen: size_t,
|
||||||
|
tbs: *const c_uchar,
|
||||||
|
tbslen: size_t
|
||||||
|
) -> c_int;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(any(ossl102, libressl280))] {
|
if #[cfg(any(ossl102, libressl280))] {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
||||||
|
|
@ -912,3 +912,7 @@ pub const NID_rc4_hmac_md5: c_int = 915;
|
||||||
pub const NID_aes_128_cbc_hmac_sha1: c_int = 916;
|
pub const NID_aes_128_cbc_hmac_sha1: c_int = 916;
|
||||||
pub const NID_aes_192_cbc_hmac_sha1: c_int = 917;
|
pub const NID_aes_192_cbc_hmac_sha1: c_int = 917;
|
||||||
pub const NID_aes_256_cbc_hmac_sha1: c_int = 918;
|
pub const NID_aes_256_cbc_hmac_sha1: c_int = 918;
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub const NID_ED25519: c_int = 1087;
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub const NID_ED448: c_int = 1088;
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,11 @@ impl Id {
|
||||||
pub const DSA: Id = Id(ffi::EVP_PKEY_DSA);
|
pub const DSA: Id = Id(ffi::EVP_PKEY_DSA);
|
||||||
pub const DH: Id = Id(ffi::EVP_PKEY_DH);
|
pub const DH: Id = Id(ffi::EVP_PKEY_DH);
|
||||||
pub const EC: Id = Id(ffi::EVP_PKEY_EC);
|
pub const EC: Id = Id(ffi::EVP_PKEY_EC);
|
||||||
|
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519);
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub const ED448: Id = Id(ffi::EVP_PKEY_ED448);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait indicating that a key has parameters.
|
/// A trait indicating that a key has parameters.
|
||||||
|
|
@ -426,6 +431,40 @@ impl PKey<Private> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(ossl110)]
|
||||||
|
fn generate_eddsa(nid: c_int) -> Result<PKey<Private>, ErrorStack> {
|
||||||
|
unsafe {
|
||||||
|
let kctx = cvt_p(ffi::EVP_PKEY_CTX_new_id(nid, ptr::null_mut()))?;
|
||||||
|
let ret = cvt(ffi::EVP_PKEY_keygen_init(kctx));
|
||||||
|
if let Err(e) = ret {
|
||||||
|
ffi::EVP_PKEY_CTX_free(kctx);
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
let mut key = ptr::null_mut();
|
||||||
|
let ret = cvt(ffi::EVP_PKEY_keygen(kctx, &mut key));
|
||||||
|
|
||||||
|
ffi::EVP_PKEY_CTX_free(kctx);
|
||||||
|
|
||||||
|
if let Err(e) = ret {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(PKey::from_ptr(key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a new private Ed25519 key
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn generate_ed25519() -> Result<PKey<Private>, ErrorStack> {
|
||||||
|
PKey::generate_eddsa(ffi::EVP_PKEY_ED25519)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a new private Ed448 key
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn generate_ed448() -> Result<PKey<Private>, ErrorStack> {
|
||||||
|
PKey::generate_eddsa(ffi::EVP_PKEY_ED448)
|
||||||
|
}
|
||||||
|
|
||||||
private_key_from_pem! {
|
private_key_from_pem! {
|
||||||
/// Deserializes a private key from a PEM-encoded key type specific format.
|
/// Deserializes a private key from a PEM-encoded key type specific format.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,9 @@ impl<'a> Drop for Signer<'a> {
|
||||||
impl<'a> Signer<'a> {
|
impl<'a> Signer<'a> {
|
||||||
/// Creates a new `Signer`.
|
/// Creates a new `Signer`.
|
||||||
///
|
///
|
||||||
|
/// This cannot be used with Ed25519 or Ed448 keys. Please refer to
|
||||||
|
/// `new_without_digest`.
|
||||||
|
///
|
||||||
/// OpenSSL documentation at [`EVP_DigestSignInit`].
|
/// OpenSSL documentation at [`EVP_DigestSignInit`].
|
||||||
///
|
///
|
||||||
/// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html
|
/// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html
|
||||||
|
|
@ -138,7 +141,9 @@ impl<'a> Signer<'a> {
|
||||||
|
|
||||||
/// Creates a new `Signer` without a digest.
|
/// Creates a new `Signer` without a digest.
|
||||||
///
|
///
|
||||||
/// This can be used to create a CMAC.
|
/// This is the only way to create a `Verifier` for Ed25519 or Ed448 keys.
|
||||||
|
/// It can also be used to create a CMAC.
|
||||||
|
///
|
||||||
/// OpenSSL documentation at [`EVP_DigestSignInit`].
|
/// OpenSSL documentation at [`EVP_DigestSignInit`].
|
||||||
///
|
///
|
||||||
/// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html
|
/// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html
|
||||||
|
|
@ -249,6 +254,9 @@ impl<'a> Signer<'a> {
|
||||||
|
|
||||||
/// Feeds more data into the `Signer`.
|
/// Feeds more data into the `Signer`.
|
||||||
///
|
///
|
||||||
|
/// Please note that PureEdDSA (Ed25519 and Ed448 keys) do not support streaming.
|
||||||
|
/// Use `sign_oneshot` instead.
|
||||||
|
///
|
||||||
/// OpenSSL documentation at [`EVP_DigestUpdate`].
|
/// OpenSSL documentation at [`EVP_DigestUpdate`].
|
||||||
///
|
///
|
||||||
/// [`EVP_DigestUpdate`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestInit.html
|
/// [`EVP_DigestUpdate`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestInit.html
|
||||||
|
|
@ -272,6 +280,11 @@ impl<'a> Signer<'a> {
|
||||||
///
|
///
|
||||||
/// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestSignFinal.html
|
/// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestSignFinal.html
|
||||||
pub fn len(&self) -> Result<usize, ErrorStack> {
|
pub fn len(&self) -> Result<usize, ErrorStack> {
|
||||||
|
self.len_intern()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(ossl111))]
|
||||||
|
fn len_intern(&self) -> Result<usize, ErrorStack> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
cvt(ffi::EVP_DigestSignFinal(
|
cvt(ffi::EVP_DigestSignFinal(
|
||||||
|
|
@ -283,6 +296,21 @@ impl<'a> Signer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
fn len_intern(&self) -> Result<usize, ErrorStack> {
|
||||||
|
unsafe {
|
||||||
|
let mut len = 0;
|
||||||
|
cvt(ffi::EVP_DigestSign(
|
||||||
|
self.md_ctx,
|
||||||
|
ptr::null_mut(),
|
||||||
|
&mut len,
|
||||||
|
ptr::null(),
|
||||||
|
0
|
||||||
|
))?;
|
||||||
|
Ok(len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Writes the signature into the provided buffer, returning the number of bytes written.
|
/// Writes the signature into the provided buffer, returning the number of bytes written.
|
||||||
///
|
///
|
||||||
/// This method will fail if the buffer is not large enough for the signature. Use the `len`
|
/// This method will fail if the buffer is not large enough for the signature. Use the `len`
|
||||||
|
|
@ -313,6 +341,44 @@ impl<'a> Signer<'a> {
|
||||||
buf.truncate(len);
|
buf.truncate(len);
|
||||||
Ok(buf)
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Signs the data in data_buf and writes the siganture into the buffer sig_buf, returning the
|
||||||
|
/// number of bytes written.
|
||||||
|
///
|
||||||
|
/// For PureEdDSA (Ed25519 and Ed448 keys) this is the only way to sign data.
|
||||||
|
///
|
||||||
|
/// This method will fail if the buffer is not large enough for the signature. Use the `len`
|
||||||
|
/// method to get an upper bound on the required size.
|
||||||
|
///
|
||||||
|
/// OpenSSL documentation at [`EVP_DigestSign`].
|
||||||
|
///
|
||||||
|
/// [`EVP_DigestSign`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestSign.html
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn sign_oneshot(&self, sig_buf: &mut [u8], data_buf: &[u8]) -> Result<usize, ErrorStack> {
|
||||||
|
unsafe {
|
||||||
|
let mut sig_len = sig_buf.len();
|
||||||
|
cvt(ffi::EVP_DigestSign(
|
||||||
|
self.md_ctx,
|
||||||
|
sig_buf.as_mut_ptr() as *mut _,
|
||||||
|
&mut sig_len,
|
||||||
|
data_buf.as_ptr() as *const _,
|
||||||
|
data_buf.len()
|
||||||
|
))?;
|
||||||
|
Ok(sig_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the signature.
|
||||||
|
///
|
||||||
|
/// This is a simple convenience wrapper over `len` and `sign_oneshot`.
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn sign_oneshot_to_vec(&self, data_buf: &[u8]) -> Result<Vec<u8>, ErrorStack> {
|
||||||
|
let mut sig_buf = vec![0; self.len()?];
|
||||||
|
let len = self.sign_oneshot(&mut sig_buf, data_buf)?;
|
||||||
|
// The advertised length is not always equal to the real length for things like DSA
|
||||||
|
sig_buf.truncate(len);
|
||||||
|
Ok(sig_buf)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Write for Signer<'a> {
|
impl<'a> Write for Signer<'a> {
|
||||||
|
|
@ -348,10 +414,35 @@ impl<'a> Drop for Verifier<'a> {
|
||||||
impl<'a> Verifier<'a> {
|
impl<'a> Verifier<'a> {
|
||||||
/// Creates a new `Verifier`.
|
/// Creates a new `Verifier`.
|
||||||
///
|
///
|
||||||
|
/// This cannot be used with Ed25519 or Ed448 keys. Please refer to
|
||||||
|
/// `new_without_digest`.
|
||||||
|
///
|
||||||
/// OpenSSL documentation at [`EVP_DigestVerifyInit`].
|
/// OpenSSL documentation at [`EVP_DigestVerifyInit`].
|
||||||
///
|
///
|
||||||
/// [`EVP_DigestVerifyInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerifyInit.html
|
/// [`EVP_DigestVerifyInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerifyInit.html
|
||||||
pub fn new<T>(type_: MessageDigest, pkey: &'a PKeyRef<T>) -> Result<Verifier<'a>, ErrorStack>
|
pub fn new<T>(type_: MessageDigest, pkey: &'a PKeyRef<T>) -> Result<Verifier<'a>, ErrorStack>
|
||||||
|
where
|
||||||
|
T: HasPublic,
|
||||||
|
{
|
||||||
|
Verifier::new_intern(Some(type_), pkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new `Verifier` without a digest.
|
||||||
|
///
|
||||||
|
/// This is the only way to create a `Verifier` for Ed25519 or Ed448 keys.
|
||||||
|
///
|
||||||
|
/// OpenSSL documentation at [`EVP_DigestVerifyInit`].
|
||||||
|
///
|
||||||
|
/// [`EVP_DigestVerifyInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerifyInit.html
|
||||||
|
pub fn new_without_digest<T>(pkey: &'a PKeyRef<T>) -> Result<Verifier<'a>, ErrorStack>
|
||||||
|
where
|
||||||
|
T: HasPublic
|
||||||
|
{
|
||||||
|
Verifier::new_intern(None, pkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn new_intern<T>(type_: Option<MessageDigest>, pkey: &'a PKeyRef<T>) -> Result<Verifier<'a>, ErrorStack>
|
||||||
where
|
where
|
||||||
T: HasPublic,
|
T: HasPublic,
|
||||||
{
|
{
|
||||||
|
|
@ -363,7 +454,7 @@ impl<'a> Verifier<'a> {
|
||||||
let r = ffi::EVP_DigestVerifyInit(
|
let r = ffi::EVP_DigestVerifyInit(
|
||||||
ctx,
|
ctx,
|
||||||
&mut pctx,
|
&mut pctx,
|
||||||
type_.as_ptr(),
|
type_.map(|t| t.as_ptr()).unwrap_or(ptr::null()),
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
pkey.as_ptr(),
|
pkey.as_ptr(),
|
||||||
);
|
);
|
||||||
|
|
@ -448,6 +539,9 @@ impl<'a> Verifier<'a> {
|
||||||
|
|
||||||
/// Feeds more data into the `Verifier`.
|
/// Feeds more data into the `Verifier`.
|
||||||
///
|
///
|
||||||
|
/// Please note that PureEdDSA (Ed25519 and Ed448 keys) do not support streaming.
|
||||||
|
/// Use `verify_oneshot` instead.
|
||||||
|
///
|
||||||
/// OpenSSL documentation at [`EVP_DigestUpdate`].
|
/// OpenSSL documentation at [`EVP_DigestUpdate`].
|
||||||
///
|
///
|
||||||
/// [`EVP_DigestUpdate`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestInit.html
|
/// [`EVP_DigestUpdate`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestInit.html
|
||||||
|
|
@ -481,6 +575,32 @@ impl<'a> Verifier<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determines if the data given in buf matches the provided signature.
|
||||||
|
///
|
||||||
|
/// OpenSSL documentation at [`EVP_DigestVerify`].
|
||||||
|
///
|
||||||
|
/// [`EVP_DigestVerify`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestVerify.html
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
pub fn verify_oneshot(&self, signature: &[u8], buf: &[u8]) -> Result<bool, ErrorStack> {
|
||||||
|
unsafe {
|
||||||
|
let r = ffi::EVP_DigestVerify(
|
||||||
|
self.md_ctx,
|
||||||
|
signature.as_ptr() as *const _,
|
||||||
|
signature.len(),
|
||||||
|
buf.as_ptr() as *const _,
|
||||||
|
buf.len(),
|
||||||
|
);
|
||||||
|
match r {
|
||||||
|
1 => Ok(true),
|
||||||
|
0 => {
|
||||||
|
ErrorStack::get();
|
||||||
|
Ok(false)
|
||||||
|
},
|
||||||
|
_ => Err(ErrorStack::get()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Write for Verifier<'a> {
|
impl<'a> Write for Verifier<'a> {
|
||||||
|
|
@ -705,6 +825,19 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(ossl111)]
|
||||||
|
fn eddsa() {
|
||||||
|
let key = PKey::generate_ed25519().unwrap();
|
||||||
|
|
||||||
|
let signer = Signer::new_without_digest(&key).unwrap();
|
||||||
|
let signature = signer.sign_oneshot_to_vec(b"hello world").unwrap();
|
||||||
|
|
||||||
|
let verifier = Verifier::new_without_digest(&key).unwrap();
|
||||||
|
assert!(verifier.verify_oneshot(&signature, b"hello world").unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(ossl111)]
|
||||||
fn rsa_sign_verify() {
|
fn rsa_sign_verify() {
|
||||||
let key = include_bytes!("../test/rsa.pem");
|
let key = include_bytes!("../test/rsa.pem");
|
||||||
let private_key = Rsa::private_key_from_pem(key).unwrap();
|
let private_key = Rsa::private_key_from_pem(key).unwrap();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue