1 use libc
::{c_void, c_char, c_int, size_t}
;
6 use foreign_types
::{ForeignType, ForeignTypeRef}
;
13 use rsa
::{Rsa, Padding}
;
14 use error
::ErrorStack
;
15 use util
::{CallbackState, invoke_passwd_cb, invoke_passwd_cb_old}
;
18 type CType
= ffi
::EVP_PKEY
;
19 fn drop
= ffi
::EVP_PKEY_free
;
26 /// Returns a copy of the internal RSA key.
27 pub fn rsa(&self) -> Result
<Rsa
, ErrorStack
> {
29 let rsa
= try
!(cvt_p(ffi
::EVP_PKEY_get1_RSA(self.as_ptr())));
30 Ok(Rsa
::from_ptr(rsa
))
34 /// Returns a copy of the internal DSA key.
35 pub fn dsa(&self) -> Result
<Dsa
, ErrorStack
> {
37 let dsa
= try
!(cvt_p(ffi
::EVP_PKEY_get1_DSA(self.as_ptr())));
38 Ok(Dsa
::from_ptr(dsa
))
42 /// Returns a copy of the internal DH key.
43 pub fn dh(&self) -> Result
<Dh
, ErrorStack
> {
45 let dh
= try
!(cvt_p(ffi
::EVP_PKEY_get1_DH(self.as_ptr())));
50 /// Returns a copy of the internal elliptic curve key.
51 pub fn ec_key(&self) -> Result
<EcKey
, ErrorStack
> {
53 let ec_key
= try
!(cvt_p(ffi
::EVP_PKEY_get1_EC_KEY(self.as_ptr())));
54 Ok(EcKey
::from_ptr(ec_key
))
58 public_key_to_pem
!(ffi
::PEM_write_bio_PUBKEY
);
59 private_key_to_pem
!(ffi
::PEM_write_bio_PKCS8PrivateKey
);
61 private_key_to_der
!(ffi
::i2d_PrivateKey
);
62 public_key_to_der
!(ffi
::i2d_PUBKEY
);
64 /// Returns the size of the key.
66 /// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the
67 /// group order for an elliptic curve key, for example.
68 pub fn bits(&self) -> u32 {
69 unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 }
72 /// Compares the public component of this key with another.
73 pub fn public_eq(&self, other
: &PKeyRef
) -> bool
{
74 unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 }
78 unsafe impl Send
for PKey {}
79 unsafe impl Sync
for PKey {}
82 /// Creates a new `PKey` containing an RSA key.
83 pub fn from_rsa(rsa
: Rsa
) -> Result
<PKey
, ErrorStack
> {
85 let evp
= try
!(cvt_p(ffi
::EVP_PKEY_new()));
87 try
!(cvt(ffi
::EVP_PKEY_assign(pkey
.0, ffi
::EVP_PKEY_RSA
, rsa
.as_ptr() as *mut _
)));
93 /// Creates a new `PKey` containing a DSA key.
94 pub fn from_dsa(dsa
: Dsa
) -> Result
<PKey
, ErrorStack
> {
96 let evp
= try
!(cvt_p(ffi
::EVP_PKEY_new()));
98 try
!(cvt(ffi
::EVP_PKEY_assign(pkey
.0, ffi
::EVP_PKEY_DSA
, dsa
.as_ptr() as *mut _
)));
104 /// Creates a new `PKey` containing a Diffie-Hellman key.
105 pub fn from_dh(dh
: Dh
) -> Result
<PKey
, ErrorStack
> {
107 let evp
= try
!(cvt_p(ffi
::EVP_PKEY_new()));
108 let pkey
= PKey(evp
);
109 try
!(cvt(ffi
::EVP_PKEY_assign(pkey
.0, ffi
::EVP_PKEY_DH
, dh
.as_ptr() as *mut _
)));
115 /// Creates a new `PKey` containing an elliptic curve key.
116 pub fn from_ec_key(ec_key
: EcKey
) -> Result
<PKey
, ErrorStack
> {
118 let evp
= try
!(cvt_p(ffi
::EVP_PKEY_new()));
119 let pkey
= PKey(evp
);
120 try
!(cvt(ffi
::EVP_PKEY_assign(pkey
.0, ffi
::EVP_PKEY_EC
, ec_key
.as_ptr() as *mut _
)));
126 /// Creates a new `PKey` containing an HMAC key.
129 /// To compute HMAC values, use the `sign` module.
130 pub fn hmac(key
: &[u8]) -> Result
<PKey
, ErrorStack
> {
132 assert
!(key
.len() <= c_int
::max_value() as usize);
133 let key
= try
!(cvt_p(ffi
::EVP_PKEY_new_mac_key(ffi
::EVP_PKEY_HMAC
,
135 key
.as_ptr() as *const _
,
136 key
.len() as c_int
)));
141 private_key_from_pem
!(PKey
, ffi
::PEM_read_bio_PrivateKey
);
142 public_key_from_pem
!(PKey
, ffi
::PEM_read_bio_PUBKEY
);
143 public_key_from_der
!(PKey
, ffi
::d2i_PUBKEY
);
145 /// Deserializes a DER-formatted PKCS#8 private key, using a callback to retrieve the password
146 /// if the key is encrpyted.
148 /// The callback should copy the password into the provided buffer and return the number of
150 pub fn private_key_from_pkcs8_callback
<F
>(der
: &[u8], callback
: F
) -> Result
<PKey
, ErrorStack
>
151 where F
: FnOnce(&mut [u8]) -> Result
<usize, ErrorStack
>
155 let mut cb
= CallbackState
::new(callback
);
156 let bio
= try
!(MemBioSlice
::new(der
));
157 cvt_p(ffi
::d2i_PKCS8PrivateKey_bio(bio
.as_ptr(),
159 Some(invoke_passwd_cb
::<F
>),
160 &mut cb
as *mut _
as *mut _
))
165 /// Deserializes a DER-formatted PKCS#8 private key, using the supplied password if the key is
170 /// Panics if `passphrase` contains an embedded null.
171 pub fn private_key_from_pkcs8_passphrase(der
: &[u8],
173 -> Result
<PKey
, ErrorStack
> {
176 let bio
= try
!(MemBioSlice
::new(der
));
177 let passphrase
= CString
::new(passphrase
).unwrap();
178 cvt_p(ffi
::d2i_PKCS8PrivateKey_bio(bio
.as_ptr(),
181 passphrase
.as_ptr() as *const _
as *mut _
))
186 #[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")]
187 pub fn private_key_from_pem_cb
<F
>(buf
: &[u8], pass_cb
: F
) -> Result
<PKey
, ErrorStack
>
188 where F
: FnOnce(&mut [c_char
]) -> usize
191 let mut cb
= CallbackState
::new(pass_cb
);
192 let mem_bio
= try
!(MemBioSlice
::new(buf
));
194 let evp
= try
!(cvt_p(ffi
::PEM_read_bio_PrivateKey(mem_bio
.as_ptr(),
196 Some(invoke_passwd_cb_old
::<F
>),
197 &mut cb
as *mut _
as *mut c_void
)));
198 Ok(PKey
::from_ptr(evp
))
204 type CType
= ffi
::EVP_PKEY_CTX
;
205 fn drop
= ffi
::EVP_PKEY_CTX_free
;
208 pub struct PKeyCtxRef
;
211 unsafe impl Send
for PKeyCtx {}
212 unsafe impl Sync
for PKeyCtx {}
215 pub fn from_pkey(pkey
: &PKeyRef
) -> Result
<PKeyCtx
, ErrorStack
> {
217 let evp
= try
!(cvt_p(ffi
::EVP_PKEY_CTX_new(pkey
.as_ptr(), ptr
::null_mut())));
224 pub fn set_rsa_padding(&mut self, pad
: Padding
) -> Result
<(), ErrorStack
> {
226 try
!(cvt(ffi
::EVP_PKEY_CTX_set_rsa_padding(self.as_ptr(), pad
.as_raw())));
231 pub fn rsa_padding(&self) -> Result
<Padding
, ErrorStack
> {
232 let mut pad
: c_int
= 0;
234 try
!(cvt(ffi
::EVP_PKEY_CTX_get_rsa_padding(self.as_ptr(), &mut pad
)));
236 Ok(Padding
::from_raw(pad
))
239 pub fn derive_init(&mut self) -> Result
<(), ErrorStack
> {
241 try
!(cvt(ffi
::EVP_PKEY_derive_init(self.as_ptr())));
246 pub fn derive_set_peer(&mut self, peer
: &PKeyRef
) -> Result
<(), ErrorStack
> {
248 try
!(cvt(ffi
::EVP_PKEY_derive_set_peer(self.as_ptr(), peer
.as_ptr())));
253 pub fn derive(&mut self) -> Result
<Vec
<u8>, ErrorStack
> {
254 let mut len
: size_t
= 0;
255 unsafe { try!(cvt(ffi::EVP_PKEY_derive(self.as_ptr(), ptr::null_mut(), &mut len))); }
257 let mut key
= vec
![0u8; len
];
258 unsafe { try!(cvt(ffi::EVP_PKEY_derive(self.as_ptr(), key.as_mut_ptr(), &mut len))); }
268 use ec
::{EcGroup, EcKey}
;
275 fn test_to_password() {
276 let rsa
= Rsa
::generate(2048).unwrap();
277 let pkey
= PKey
::from_rsa(rsa
).unwrap();
278 let pem
= pkey
.private_key_to_pem_passphrase(Cipher
::aes_128_cbc(), b
"foobar").unwrap();
279 PKey
::private_key_from_pem_passphrase(&pem
, b
"foobar").unwrap();
280 assert
!(PKey
::private_key_from_pem_passphrase(&pem
, b
"fizzbuzz").is_err());
284 fn test_encrypted_pkcs8_passphrase() {
285 let key
= include_bytes
!("../test/pkcs8.der");
286 PKey
::private_key_from_pkcs8_passphrase(key
, b
"mypass").unwrap();
290 fn test_encrypted_pkcs8_callback() {
291 let mut password_queried
= false;
292 let key
= include_bytes
!("../test/pkcs8.der");
293 PKey
::private_key_from_pkcs8_callback(key
, |password
| {
294 password_queried
= true;
295 password
[..6].copy_from_slice(b
"mypass");
299 assert
!(password_queried
);
303 fn test_private_key_from_pem() {
304 let key
= include_bytes
!("../test/key.pem");
305 PKey
::private_key_from_pem(key
).unwrap();
309 fn test_public_key_from_pem() {
310 let key
= include_bytes
!("../test/key.pem.pub");
311 PKey
::public_key_from_pem(key
).unwrap();
315 fn test_public_key_from_der() {
316 let key
= include_bytes
!("../test/key.der.pub");
317 PKey
::public_key_from_der(key
).unwrap();
322 let key
= include_bytes
!("../test/key.pem");
323 let key
= PKey
::private_key_from_pem(key
).unwrap();
325 let priv_key
= key
.private_key_to_pem().unwrap();
326 let pub_key
= key
.public_key_to_pem().unwrap();
328 // As a super-simple verification, just check that the buffers contain
329 // the `PRIVATE KEY` or `PUBLIC KEY` strings.
330 assert
!(priv_key
.windows(11).any(|s
| s
== b
"PRIVATE KEY"));
331 assert
!(pub_key
.windows(10).any(|s
| s
== b
"PUBLIC KEY"));
335 fn test_rsa_accessor() {
336 let rsa
= Rsa
::generate(2048).unwrap();
337 let pkey
= PKey
::from_rsa(rsa
).unwrap();
339 assert
!(pkey
.dsa().is_err());
343 fn test_dsa_accessor() {
344 let dsa
= Dsa
::generate(2048).unwrap();
345 let pkey
= PKey
::from_dsa(dsa
).unwrap();
347 assert
!(pkey
.rsa().is_err());
351 fn test_dh_accessor() {
352 let dh
= include_bytes
!("../test/dhparams.pem");
353 let dh
= Dh
::from_pem(dh
).unwrap();
354 let pkey
= PKey
::from_dh(dh
).unwrap();
356 assert
!(pkey
.rsa().is_err());
360 fn test_ec_key_accessor() {
361 let ec_key
= EcKey
::from_curve_name(nid
::X9_62_PRIME256V1
).unwrap();
362 let pkey
= PKey
::from_ec_key(ec_key
).unwrap();
363 pkey
.ec_key().unwrap();
364 assert
!(pkey
.rsa().is_err());
368 fn test_ec_key_derive() {
369 let group
= EcGroup
::from_curve_name(nid
::X9_62_PRIME256V1
).unwrap();
370 let ec_key
= EcKey
::generate(&group
).unwrap();
371 let ec_key2
= EcKey
::generate(&group
).unwrap();
372 let pkey
= PKey
::from_ec_key(ec_key
).unwrap();
373 let pkey2
= PKey
::from_ec_key(ec_key2
).unwrap();
374 let mut pkey_ctx
= PKeyCtx
::from_pkey(&pkey
).unwrap();
375 pkey_ctx
.derive_init().unwrap();
376 pkey_ctx
.derive_set_peer(&pkey2
).unwrap();
377 let shared
= pkey_ctx
.derive().unwrap();
378 assert
!(!shared
.is_empty());