Skip to content

Commit 869cf7a

Browse files
authored
Merge pull request #1571 from sfackler/evp-sign
Expose raw sign/verify methods
2 parents e420d3c + bec5889 commit 869cf7a

File tree

3 files changed

+177
-3
lines changed

3 files changed

+177
-3
lines changed

openssl-sys/src/evp.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,22 @@ extern "C" {
649649
pub fn EVP_PKEY_keygen_init(ctx: *mut EVP_PKEY_CTX) -> c_int;
650650
pub fn EVP_PKEY_keygen(ctx: *mut EVP_PKEY_CTX, key: *mut *mut EVP_PKEY) -> c_int;
651651

652+
pub fn EVP_PKEY_sign_init(ctx: *mut EVP_PKEY_CTX) -> c_int;
653+
pub fn EVP_PKEY_sign(
654+
ctx: *mut EVP_PKEY_CTX,
655+
sig: *mut c_uchar,
656+
siglen: *mut size_t,
657+
tbs: *const c_uchar,
658+
tbslen: size_t,
659+
) -> c_int;
660+
pub fn EVP_PKEY_verify_init(ctx: *mut EVP_PKEY_CTX) -> c_int;
661+
pub fn EVP_PKEY_verify(
662+
ctx: *mut EVP_PKEY_CTX,
663+
sig: *const c_uchar,
664+
siglen: size_t,
665+
tbs: *const c_uchar,
666+
tbslen: size_t,
667+
) -> c_int;
652668
pub fn EVP_PKEY_encrypt_init(ctx: *mut EVP_PKEY_CTX) -> c_int;
653669
pub fn EVP_PKEY_encrypt(
654670
ctx: *mut EVP_PKEY_CTX,

openssl/src/md_ctx.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ use crate::error::ErrorStack;
7979
use crate::md::MdRef;
8080
use crate::pkey::{HasPrivate, PKeyRef};
8181
use crate::pkey_ctx::PkeyCtxRef;
82-
use crate::{cvt, cvt_p};
82+
use crate::{cvt, cvt_n, cvt_p};
8383
use cfg_if::cfg_if;
8484
use foreign_types::{ForeignType, ForeignTypeRef};
8585
use openssl_macros::corresponds;
@@ -303,7 +303,7 @@ impl MdCtxRef {
303303
#[inline]
304304
pub fn digest_verify_final(&mut self, signature: &[u8]) -> Result<bool, ErrorStack> {
305305
unsafe {
306-
let r = cvt(ffi::EVP_DigestVerifyFinal(
306+
let r = cvt_n(ffi::EVP_DigestVerifyFinal(
307307
self.as_ptr(),
308308
signature.as_ptr() as *mut _,
309309
signature.len(),
@@ -374,3 +374,33 @@ impl MdCtxRef {
374374
}
375375
}
376376
}
377+
378+
#[cfg(test)]
379+
mod test {
380+
use super::*;
381+
use crate::md::Md;
382+
use crate::pkey::PKey;
383+
use crate::rsa::Rsa;
384+
385+
#[test]
386+
fn verify_fail() {
387+
let key1 = Rsa::generate(4096).unwrap();
388+
let key1 = PKey::from_rsa(key1).unwrap();
389+
390+
let md = Md::sha256();
391+
let data = b"Some Crypto Text";
392+
393+
let mut ctx = MdCtx::new().unwrap();
394+
ctx.digest_sign_init(Some(md), &key1).unwrap();
395+
ctx.digest_sign_update(data).unwrap();
396+
let mut signature = vec![];
397+
ctx.digest_sign_final_to_vec(&mut signature).unwrap();
398+
399+
let bad_data = b"Some Crypto text";
400+
401+
ctx.digest_verify_init(Some(md), &key1).unwrap();
402+
ctx.digest_verify_update(bad_data).unwrap();
403+
let valid = ctx.digest_verify_final(&signature).unwrap();
404+
assert!(!valid);
405+
}
406+
}

openssl/src/pkey_ctx.rs

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,38 @@
3333
//! ctx.set_keygen_mac_key(b"0123456789abcdef").unwrap();
3434
//! let cmac_key = ctx.keygen().unwrap();
3535
//! ```
36+
//!
37+
//! Sign and verify data with RSA
38+
//!
39+
//! ```
40+
//! use openssl::pkey_ctx::PkeyCtx;
41+
//! use openssl::pkey::PKey;
42+
//! use openssl::rsa::Rsa;
43+
//!
44+
//! // Generate a random RSA key.
45+
//! let key = Rsa::generate(4096).unwrap();
46+
//! let key = PKey::from_rsa(key).unwrap();
47+
//!
48+
//! let text = b"Some Crypto Text";
49+
//!
50+
//! // Create the signature.
51+
//! let mut ctx = PkeyCtx::new(&key).unwrap();
52+
//! ctx.sign_init().unwrap();
53+
//! let mut signature = vec![];
54+
//! ctx.sign_to_vec(text, &mut signature).unwrap();
55+
//!
56+
//! // Verify the signature.
57+
//! let mut ctx = PkeyCtx::new(&key).unwrap();
58+
//! ctx.verify_init().unwrap();
59+
//! let valid = ctx.verify(text, &signature).unwrap();
60+
//! assert!(valid);
61+
//! ```
3662
use crate::cipher::CipherRef;
3763
use crate::error::ErrorStack;
3864
use crate::md::MdRef;
3965
use crate::pkey::{HasPrivate, HasPublic, Id, PKey, PKeyRef, Private};
4066
use crate::rsa::Padding;
41-
use crate::{cvt, cvt_p};
67+
use crate::{cvt, cvt_n, cvt_p};
4268
use foreign_types::{ForeignType, ForeignTypeRef};
4369
use libc::c_int;
4470
use openssl_macros::corresponds;
@@ -105,6 +131,17 @@ where
105131
Ok(())
106132
}
107133

134+
/// Prepares the context for signature verification using the public key.
135+
#[corresponds(EVP_PKEY_verify_init)]
136+
#[inline]
137+
pub fn verify_init(&mut self) -> Result<(), ErrorStack> {
138+
unsafe {
139+
cvt(ffi::EVP_PKEY_verify_init(self.as_ptr()))?;
140+
}
141+
142+
Ok(())
143+
}
144+
108145
/// Encrypts data using the public key.
109146
///
110147
/// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be
@@ -135,6 +172,31 @@ where
135172
out.truncate(base + len);
136173
Ok(len)
137174
}
175+
176+
/// Verifies the signature of data using the public key.
177+
///
178+
/// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error
179+
/// occurred.
180+
///
181+
/// # Note
182+
///
183+
/// This verifies the signature of the *raw* data. It is more common to compute and verify the signature of the
184+
/// cryptographic hash of an arbitrary amount of data. The [`MdCtx`](crate::md_ctx::MdCtx) type can be used to do
185+
/// that.
186+
#[corresponds(EVP_PKEY_verify)]
187+
#[inline]
188+
pub fn verify(&mut self, data: &[u8], sig: &[u8]) -> Result<bool, ErrorStack> {
189+
unsafe {
190+
let r = cvt_n(ffi::EVP_PKEY_verify(
191+
self.as_ptr(),
192+
sig.as_ptr(),
193+
sig.len(),
194+
data.as_ptr(),
195+
data.len(),
196+
))?;
197+
Ok(r == 1)
198+
}
199+
}
138200
}
139201

140202
impl<T> PkeyCtxRef<T>
@@ -152,6 +214,17 @@ where
152214
Ok(())
153215
}
154216

217+
/// Prepares the context for signing using the private key.
218+
#[corresponds(EVP_PKEY_sign_init)]
219+
#[inline]
220+
pub fn sign_init(&mut self) -> Result<(), ErrorStack> {
221+
unsafe {
222+
cvt(ffi::EVP_PKEY_sign_init(self.as_ptr()))?;
223+
}
224+
225+
Ok(())
226+
}
227+
155228
/// Sets the peer key used for secret derivation.
156229
#[corresponds(EVP_PKEY_derive_set_peer)]
157230
pub fn derive_set_peer<U>(&mut self, key: &PKeyRef<U>) -> Result<(), ErrorStack>
@@ -195,6 +268,42 @@ where
195268
out.truncate(base + len);
196269
Ok(len)
197270
}
271+
272+
/// Signs the contents of `data`.
273+
///
274+
/// If `sig` is set to `None`, an upper bound on the number of bytes required for the output buffere will be
275+
/// returned.
276+
///
277+
/// # Note
278+
///
279+
/// This computes the signature of the *raw* bytes of `data`. It is more common to sign the cryptographic hash of
280+
/// an arbitrary amount of data. The [`MdCtx`](crate::md_ctx::MdCtx) type can be used to do that.
281+
#[corresponds(EVP_PKEY_sign)]
282+
#[inline]
283+
pub fn sign(&mut self, data: &[u8], sig: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
284+
let mut written = sig.as_ref().map_or(0, |b| b.len());
285+
unsafe {
286+
cvt(ffi::EVP_PKEY_sign(
287+
self.as_ptr(),
288+
sig.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
289+
&mut written,
290+
data.as_ptr(),
291+
data.len(),
292+
))?;
293+
}
294+
295+
Ok(written)
296+
}
297+
298+
/// Like [`Self::sign`] but appends the signature to a [`Vec`].
299+
pub fn sign_to_vec(&mut self, data: &[u8], sig: &mut Vec<u8>) -> Result<usize, ErrorStack> {
300+
let base = sig.len();
301+
let len = self.sign(data, None)?;
302+
sig.resize(base + len, 0);
303+
let len = self.sign(data, Some(&mut sig[base..]))?;
304+
sig.truncate(base + len);
305+
Ok(len)
306+
}
198307
}
199308

200309
impl<T> PkeyCtxRef<T> {
@@ -629,4 +738,23 @@ mod test {
629738
.unwrap()
630739
);
631740
}
741+
742+
#[test]
743+
fn verify_fail() {
744+
let key1 = Rsa::generate(4096).unwrap();
745+
let key1 = PKey::from_rsa(key1).unwrap();
746+
747+
let data = b"Some Crypto Text";
748+
749+
let mut ctx = PkeyCtx::new(&key1).unwrap();
750+
ctx.sign_init().unwrap();
751+
let mut signature = vec![];
752+
ctx.sign_to_vec(data, &mut signature).unwrap();
753+
754+
let bad_data = b"Some Crypto text";
755+
756+
ctx.verify_init().unwrap();
757+
let valid = ctx.verify(bad_data, &signature).unwrap();
758+
assert!(!valid);
759+
}
632760
}

0 commit comments

Comments
 (0)