Refactor key management (#3296)

* Add Call type to extensible transactions.

Cleanup some naming

* Merge Resource and BlockExhausted into just Exhausted

* Fix

* Another fix

* Call

* Some fixes

* Fix srml tests.

* Fix all tests.

* Refactor crypto so each application of it has its own type.

* Introduce new AuthorityProvider API into Aura

This will eventually allow for dynamic determination of authority
keys and avoid having to set them directly on CLI.

* Introduce authority determinator for Babe.

Experiment with modular consensus API.

* Work in progress to introduce KeyTypeId and avoid polluting API
with validator IDs

* Finish up drafting imonline

* Rework offchain workers API.

* Rework API implementation.

* Make it compile for wasm, simplify app_crypto.

* Fix compilation of im-online.

* Fix compilation of im-online.

* Fix more compilation errors.

* Make it compile.

* Fixing tests.

* Rewrite `keystore`

* Fix session tests

* Bring back `TryFrom`'s'

* Fix `srml-grandpa`

* Fix `srml-aura`

* Fix consensus babe

* More fixes

* Make service generate keys from dev_seed

* Build fixes

* Remove offchain tests

* More fixes and cleanups

* Fixes finality grandpa

* Fix `consensus-aura`

* Fix cli

* Fix `node-cli`

* Fix chain_spec builder

* Fix doc tests

* Add authority getter for grandpa.

* Test fix

* Fixes

* Make keystore accessible from the runtime

* Move app crypto to its own crate

* Update `Cargo.lock`

* Make the crypto stuff usable from the runtime

* Adds some runtime crypto tests

* Use last finalized block for grandpa authority

* Fix warning

* Adds `SessionKeys` runtime api

* Remove `FinalityPair` and `ConsensusPair`

* Minor governance tweaks to get it inline with docs.

* Make the governance be up to date with the docs.

* Build fixes.

* Generate the inital session keys

* Failing keystore is a hard error

* Make babe work again

* Fix grandpa

* Fix tests

* Disable `keystore` in consensus critical stuff

* Build fix.

* ImOnline supports multiple authorities at once.

* Update core/application-crypto/src/ed25519.rs

* Merge branch 'master' into gav-in-progress

* Remove unneeded code for now.

* Some `session` testing

* Support querying the public keys

* Cleanup offchain

* Remove warnings

* More cleanup

* Apply suggestions from code review

Co-Authored-By: Benjamin Kampmann <ben.kampmann@googlemail.com>

* More cleanups

* JSONRPC API for setting keys.

Also, rename traits::KeyStore* -> traits::BareCryptoStore*

* Bad merge

* Fix integration tests

* Fix test build

* Test fix

* Fixes

* Warnings

* Another warning

* Bump version.
This commit is contained in:
Gavin Wood
2019-08-07 20:47:48 +02:00
committed by GitHub
parent a6a6779f01
commit 1a524b8207
160 changed files with 4467 additions and 2769 deletions
+149 -197
View File
@@ -19,8 +19,9 @@ pub use rstd;
pub use rstd::{mem, slice};
use core::{intrinsics, panic::PanicInfo};
use rstd::{vec::Vec, cell::Cell, convert::TryInto, convert::TryFrom};
use rstd::{vec::Vec, cell::Cell, convert::TryInto};
use primitives::{offchain, Blake2Hasher};
use codec::Decode;
#[cfg(not(feature = "no_panic_handler"))]
#[panic_handler]
@@ -158,7 +159,7 @@ pub mod ext {
(
$(
$( #[$attr:meta] )*
fn $name:ident ( $( $arg:ident : $arg_ty:ty ),* ) $( -> $ret:ty )?;
fn $name:ident ( $( $arg:ident : $arg_ty:ty ),* $(,)? ) $( -> $ret:ty )?;
)*
) => {
$(
@@ -352,25 +353,72 @@ pub mod ext {
fn ext_twox_256(data: *const u8, len: u32, out: *mut u8);
/// Keccak256 hash
fn ext_keccak_256(data: *const u8, len: u32, out: *mut u8);
/// Note: ext_ed25519_verify returns 0 if the signature is correct, nonzero otherwise.
/// Returns all `ed25519` public keys for the given key type from the keystore.
fn ext_ed25519_public_keys(id: *const u8, result_len: *mut u32) -> *mut u8;
/// Note: `ext_ed25519_verify` returns `0` if the signature is correct, nonzero otherwise.
fn ext_ed25519_verify(
msg_data: *const u8,
msg_len: u32,
sig_data: *const u8,
pubkey_data: *const u8
pubkey_data: *const u8,
) -> u32;
/// Note: ext_sr25519_verify returns 0 if the signature is correct, nonzero otherwise.
/// Generate an `ed25519` key pair for the given key type id and store the public key
/// in `out`.
fn ext_ed25519_generate(id: *const u8, seed: *const u8, seed_len: u32, out: *mut u8);
/// Sign the given `msg` with the `ed25519` key pair that corresponds to then given key
/// type id and public key. The raw signature is stored in `out`.
///
/// # Returns
///
/// - `0` on success
/// - nonezero if something failed, e.g. retrieving of the key.
fn ext_ed25519_sign(
id: *const u8,
pubkey: *const u8,
msg: *const u8,
msg_len: u32,
out: *mut u8,
) -> u32;
/// Returns all `sr25519` public keys for the given key type from the keystore.
fn ext_sr25519_public_keys(id: *const u8, result_len: *mut u32) -> *mut u8;
/// Note: `ext_sr25519_verify` returns 0 if the signature is correct, nonzero otherwise.
fn ext_sr25519_verify(
msg_data: *const u8,
msg_len: u32,
sig_data: *const u8,
pubkey_data: *const u8
pubkey_data: *const u8,
) -> u32;
/// Generate an `sr25519` key pair for the given key type id and store the public
/// key in `out`.
fn ext_sr25519_generate(id: *const u8, seed: *const u8, seed_len: u32, out: *mut u8);
/// Sign the given `msg` with the `sr25519` key pair that corresponds to then given key
/// type id and public key. The raw signature is stored in `out`.
///
/// # Returns
///
/// - `0` on success
/// - nonezero if something failed, e.g. retrieving of the key.
fn ext_sr25519_sign(
id: *const u8,
pubkey: *const u8,
msg: *const u8,
msg_len: u32,
out: *mut u8,
) -> u32;
/// Note: ext_secp256k1_ecdsa_recover returns 0 if the signature is correct, nonzero otherwise.
fn ext_secp256k1_ecdsa_recover(
msg_data: *const u8,
sig_data: *const u8,
pubkey_data: *mut u8
pubkey_data: *mut u8,
) -> u32;
//================================
@@ -398,94 +446,6 @@ pub mod ext {
/// runtime code can always rely on it.
fn ext_network_state(written_out: *mut u32) -> *mut u8;
/// Returns the locally configured authority public key, if available.
/// The `crypto` argument is `offchain::CryptoKind` converted to `u32`.
///
/// # Returns
///
/// The encoded `Result<PublicKey encoded to Vec<u8>, ()>`.
/// `written_out` contains the length of the message.
///
/// The ownership of the returned buffer is transferred to the runtime
/// code and the runtime is responsible for freeing it. This is always
/// a properly allocated pointer (which cannot be NULL), hence the
/// runtime code can always rely on it.
fn ext_pubkey(key: u64, written_out: *mut u32) -> *mut u8;
/// Create new key(pair) for signing/encryption/decryption.
///
/// # Returns
///
/// - A crypto key id (if the value is less than u16::max_value)
/// - `u32::max_value` in case the crypto is not supported
fn ext_new_crypto_key(crypto: u32) -> u64;
/// Encrypt a piece of data using given crypto key.
///
/// If `key` is `0`, it will attempt to use current authority key of given `kind`.
///
/// # Returns
///
/// - `0` in case the key is invalid, `msg_len` is set to `u32::max_value`
/// - Otherwise, pointer to the encrypted message in memory,
/// `msg_len` contains the length of the message.
fn ext_encrypt(
key: u64,
data: *const u8,
data_len: u32,
msg_len: *mut u32
) -> *mut u8;
/// Decrypt a piece of data using given crypto key.
///
/// If `key` is `0`, it will attempt to use current authority key of given `kind`.
///
/// # Returns
///
/// - `0` in case the key is invalid or data couldn't be decrypted,
/// `msg_len` is set to `u32::max_value`
/// - Otherwise, pointer to the decrypted message in memory,
/// `msg_len` contains the length of the message.
fn ext_decrypt(
key: u64,
data: *const u8,
data_len: u32,
msg_len: *mut u32
) -> *mut u8;
/// Sign a piece of data using given crypto key.
///
/// If `key` is `0`, it will attempt to use current authority key of given `kind`.
///
/// # Returns
///
/// - `0` in case the key is invalid,
/// `sig_data_len` is set to `u32::max_value`
/// - Otherwise, pointer to the signature in memory,
/// `sig_data_len` contains the length of the signature.
fn ext_sign(
key: u64,
data: *const u8,
data_len: u32,
sig_data_len: *mut u32
) -> *mut u8;
/// Verifies that `signature` for `msg` matches given `key`.
///
/// If `key` is `0`, it will attempt to use current authority key of given `kind`.
///
/// # Returns
/// - `0` in case the signature is correct
/// - `1` in case it doesn't match the key
/// - `u32::max_value` if the key is invalid.
fn ext_verify(
key: u64,
msg: *const u8,
msg_len: u32,
signature: *const u8,
signature_len: u32
) -> u32;
/// Returns current UNIX timestamp (milliseconds)
fn ext_timestamp() -> u64;
@@ -871,15 +831,105 @@ impl HashingApi for () {
}
impl CryptoApi for () {
fn ed25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool {
fn ed25519_public_keys(id: KeyTypeId) -> Vec<ed25519::Public> {
let mut res_len = 0u32;
unsafe {
ext_ed25519_verify.get()(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ref().as_ptr()) == 0
let res_ptr = ext_ed25519_public_keys.get()(id.0.as_ptr(), &mut res_len);
Vec::decode(&mut rstd::slice::from_raw_parts(res_ptr, res_len as usize)).unwrap_or_default()
}
}
fn sr25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool {
fn ed25519_generate(id: KeyTypeId, seed: Option<&str>) -> ed25519::Public {
let mut res = [0u8; 32];
let seed = seed.as_ref().map(|s| s.as_bytes()).unwrap_or(&[]);
unsafe {
ext_sr25519_verify.get()(msg.as_ptr(), msg.len() as u32, sig.as_ptr(), pubkey.as_ref().as_ptr()) == 0
ext_ed25519_generate.get()(id.0.as_ptr(), seed.as_ptr(), seed.len() as u32, res.as_mut_ptr())
};
ed25519::Public(res)
}
fn ed25519_sign<M: AsRef<[u8]>>(
id: KeyTypeId,
pubkey: &ed25519::Public,
msg: &M,
) -> Option<ed25519::Signature> {
let mut res = [0u8; 64];
let success = unsafe {
ext_ed25519_sign.get()(
id.0.as_ptr(),
pubkey.0.as_ptr(),
msg.as_ref().as_ptr(),
msg.as_ref().len() as u32,
res.as_mut_ptr(),
) == 0
};
if success {
Some(ed25519::Signature(res))
} else {
None
}
}
fn ed25519_verify(sig: &ed25519::Signature, msg: &[u8], pubkey: &ed25519::Public) -> bool {
unsafe {
ext_ed25519_verify.get()(
msg.as_ptr(),
msg.len() as u32,
sig.0.as_ptr(),
pubkey.0.as_ptr(),
) == 0
}
}
fn sr25519_public_keys(id: KeyTypeId) -> Vec<sr25519::Public> {
let mut res_len = 0u32;
unsafe {
let res_ptr = ext_sr25519_public_keys.get()(id.0.as_ptr(), &mut res_len);
Vec::decode(&mut rstd::slice::from_raw_parts(res_ptr, res_len as usize)).unwrap_or_default()
}
}
fn sr25519_generate(id: KeyTypeId, seed: Option<&str>) -> sr25519::Public {
let mut res = [0u8;32];
let seed = seed.as_ref().map(|s| s.as_bytes()).unwrap_or(&[]);
unsafe {
ext_sr25519_generate.get()(id.0.as_ptr(), seed.as_ptr(), seed.len() as u32, res.as_mut_ptr())
};
sr25519::Public(res)
}
fn sr25519_sign<M: AsRef<[u8]>>(
id: KeyTypeId,
pubkey: &sr25519::Public,
msg: &M,
) -> Option<sr25519::Signature> {
let mut res = [0u8; 64];
let success = unsafe {
ext_sr25519_sign.get()(
id.0.as_ptr(),
pubkey.0.as_ptr(),
msg.as_ref().as_ptr(),
msg.as_ref().len() as u32,
res.as_mut_ptr(),
) == 0
};
if success {
Some(sr25519::Signature(res))
} else {
None
}
}
fn sr25519_verify(sig: &sr25519::Signature, msg: &[u8], pubkey: &sr25519::Public) -> bool {
unsafe {
ext_sr25519_verify.get()(
msg.as_ptr(),
msg.len() as u32,
sig.0.as_ptr(),
pubkey.0.as_ptr(),
) == 0
}
}
@@ -925,104 +975,6 @@ impl OffchainApi for () {
}
}
fn pubkey(key: CryptoKey) -> Result<Vec<u8>, ()> {
let mut len = 0u32;
let raw_result = unsafe {
let ptr = ext_pubkey.get()(
key.into(),
&mut len,
);
from_raw_parts(ptr, len)
};
match raw_result {
Some(raw_result) => codec::Decode::decode(&mut &*raw_result).unwrap_or(Err(())),
None => Err(())
}
}
fn new_crypto_key(crypto: offchain::CryptoKind) -> Result<offchain::CryptoKey, ()> {
let crypto = crypto.into();
let ret = unsafe {
ext_new_crypto_key.get()(crypto)
};
offchain::CryptoKey::try_from(ret)
}
fn encrypt(
key: offchain::CryptoKey,
data: &[u8],
) -> Result<Vec<u8>, ()> {
let mut len = 0_u32;
unsafe {
let ptr = ext_encrypt.get()(
key.into(),
data.as_ptr(),
data.len() as u32,
&mut len
);
from_raw_parts(ptr, len).ok_or(())
}
}
fn decrypt(
key: offchain::CryptoKey,
data: &[u8],
) -> Result<Vec<u8>, ()> {
let mut len = 0_u32;
unsafe {
let ptr = ext_decrypt.get()(
key.into(),
data.as_ptr(),
data.len() as u32,
&mut len
);
from_raw_parts(ptr, len).ok_or(())
}
}
fn sign(
key: offchain::CryptoKey,
data: &[u8],
) -> Result<Vec<u8>, ()> {
let mut len = 0_u32;
unsafe {
let ptr = ext_sign.get()(
key.into(),
data.as_ptr(),
data.len() as u32,
&mut len
);
from_raw_parts(ptr, len).ok_or(())
}
}
fn verify(
key: offchain::CryptoKey,
msg: &[u8],
signature: &[u8],
) -> Result<bool, ()> {
let val = unsafe {
ext_verify.get()(
key.into(),
msg.as_ptr(),
msg.len() as u32,
signature.as_ptr(),
signature.len() as u32,
)
};
match val {
0 => Ok(true),
1 => Ok(false),
_ => Err(()),
}
}
fn timestamp() -> offchain::Timestamp {
offchain::Timestamp::from_unix_millis(unsafe {
ext_timestamp.get()()