mirror of
https://github.com/bytedance/g3.git
synced 2026-05-05 23:41:57 +00:00
g3keymess: allow to check key existence
This commit is contained in:
parent
a9da70cd0d
commit
9856786d6d
13 changed files with 113 additions and 31 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
|
@ -1142,7 +1142,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "g3-tls-cert"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
|
|
@ -1373,11 +1373,13 @@ dependencies = [
|
|||
"clap_complete",
|
||||
"futures-util",
|
||||
"g3-ctl",
|
||||
"g3-tls-cert",
|
||||
"g3keymess-proto",
|
||||
"hex",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tongsuo",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ g3-stdlog = { version = "0.1", path = "lib/g3-stdlog" }
|
|||
g3-syslog = { version = "0.6", path = "lib/g3-syslog" }
|
||||
g3-slog-types = { version = "0.1", path = "lib/g3-slog-types" }
|
||||
g3-geoip = { version = "0.1", path = "lib/g3-geoip" }
|
||||
g3-tls-cert = { version = "0.3", path = "lib/g3-tls-cert" }
|
||||
g3-tls-cert = { version = "0.4", path = "lib/g3-tls-cert" }
|
||||
g3-types = { version = "0.3", path = "lib/g3-types" }
|
||||
g3-xcrypt = { version = "0.1", path = "lib/g3-xcrypt" }
|
||||
g3-yaml = { version = "0.4.1", path = "lib/g3-yaml" }
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use openssl::pkey::{Id, PKey, Private, Public};
|
|||
use openssl::pkey_ctx::PkeyCtx;
|
||||
use openssl::rsa::Padding;
|
||||
|
||||
use g3_tls_cert::ext::{X509Ext, X509Pubkey};
|
||||
use g3_tls_cert::ext::{PublicKeyExt, X509Ext};
|
||||
|
||||
const ARG_CERT: &str = "cert";
|
||||
const ARG_PKEY: &str = "key";
|
||||
|
|
@ -203,18 +203,10 @@ impl KeylessGlobalArgs {
|
|||
let key = crate::target::openssl::load_key(file)?;
|
||||
|
||||
// verify SKI match
|
||||
let x509_pubkey = X509Pubkey::from_pubkey(&key).map_err(|e| {
|
||||
anyhow!(
|
||||
"failed to create x509 pubkey from key in file {}: {e}",
|
||||
file.display()
|
||||
)
|
||||
})?;
|
||||
let encoded_bytes = x509_pubkey
|
||||
.encoded_bytes()
|
||||
.map_err(|e| anyhow!("failed to get encoded pubkey data: {e}"))?;
|
||||
let digest = openssl::hash::hash(MessageDigest::sha1(), encoded_bytes)
|
||||
.map_err(|e| anyhow!("failed to get sha1 hash of pubkey: {e}"))?;
|
||||
let ski = digest.to_vec();
|
||||
let ski = key
|
||||
.ski()
|
||||
.map_err(|e| anyhow!("failed to get SKI from key file {}: {e}", file.display()))?;
|
||||
let ski = ski.to_vec();
|
||||
|
||||
if let Some(ski_cert) = &public_key_ski {
|
||||
if ski.ne(ski_cert) {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ interface ProcControl {
|
|||
|
||||
publishKey @4 (pem: Text) -> (result :Types.OperationResult);
|
||||
listKeys @5 () -> (result :List(Data));
|
||||
checkKey @7 (ski: Data) -> (result: Types.OperationResult);
|
||||
|
||||
addMetricsTag @6 (name :Text, value :Text) -> (result :Types.OperationResult);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,15 @@ pub(crate) async fn list_keys() -> anyhow::Result<Vec<Vec<u8>>> {
|
|||
run_in_main_thread(async move { Ok(crate::store::get_all_ski()) }).await
|
||||
}
|
||||
|
||||
pub(crate) async fn check_key(ski: Vec<u8>) -> anyhow::Result<()> {
|
||||
run_in_main_thread(async move {
|
||||
crate::store::get_by_ski(&ski)
|
||||
.map(|_| ())
|
||||
.ok_or_else(|| anyhow!("key not found"))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn run_in_main_thread<T, F>(future: F) -> anyhow::Result<T>
|
||||
where
|
||||
T: Send + 'static,
|
||||
|
|
|
|||
|
|
@ -108,6 +108,19 @@ impl proc_control::Server for ProcControlImpl {
|
|||
})
|
||||
}
|
||||
|
||||
fn check_key(
|
||||
&mut self,
|
||||
params: proc_control::CheckKeyParams,
|
||||
mut results: proc_control::CheckKeyResults,
|
||||
) -> Promise<(), capnp::Error> {
|
||||
let ski = pry!(pry!(params.get()).get_ski()).to_vec();
|
||||
Promise::from_future(async move {
|
||||
let r = crate::control::bridge::check_key(ski).await;
|
||||
set_operation_result(results.get().init_result(), r);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn add_metrics_tag(
|
||||
&mut self,
|
||||
params: proc_control::AddMetricsTagParams,
|
||||
|
|
|
|||
|
|
@ -18,10 +18,9 @@ use std::cell::RefCell;
|
|||
|
||||
use ahash::AHashMap;
|
||||
use anyhow::anyhow;
|
||||
use openssl::hash::{DigestBytes, MessageDigest};
|
||||
use openssl::pkey::{HasPublic, PKey, Private};
|
||||
use openssl::pkey::{PKey, Private};
|
||||
|
||||
use g3_tls_cert::ext::X509Pubkey;
|
||||
use g3_tls_cert::ext::PublicKeyExt;
|
||||
|
||||
mod ops;
|
||||
pub use ops::{load_all, reload_all};
|
||||
|
|
@ -33,7 +32,7 @@ thread_local! {
|
|||
}
|
||||
|
||||
pub(crate) fn add_global(key: PKey<Private>) -> anyhow::Result<()> {
|
||||
let ski = public_key_ski(&key)?;
|
||||
let ski = key.ski().map_err(|e| anyhow!("failed to get SKI: {e}"))?;
|
||||
GLOBAL_SKI_MAP.with_borrow_mut(|map| {
|
||||
map.insert(ski.to_vec(), key);
|
||||
});
|
||||
|
|
@ -48,13 +47,3 @@ pub(crate) fn get_all_ski() -> Vec<Vec<u8>> {
|
|||
pub(crate) fn get_by_ski(ski: &[u8]) -> Option<PKey<Private>> {
|
||||
GLOBAL_SKI_MAP.with_borrow(|map| map.get(ski).cloned())
|
||||
}
|
||||
|
||||
fn public_key_ski<T: HasPublic>(key: &PKey<T>) -> anyhow::Result<DigestBytes> {
|
||||
let x =
|
||||
X509Pubkey::from_pubkey(key).map_err(|e| anyhow!("failed to build X509 PUBKEY: {e}"))?;
|
||||
let encoded = x
|
||||
.encoded_bytes()
|
||||
.map_err(|e| anyhow!("failed to get encoded X509 PUBKEY bytes: {e}"))?;
|
||||
openssl::hash::hash(MessageDigest::sha1(), encoded)
|
||||
.map_err(|e| anyhow!("failed to calculate SKI value: {e}"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,5 +17,7 @@ futures-util.workspace = true
|
|||
capnp-rpc.workspace = true
|
||||
capnp.workspace = true
|
||||
hex.workspace = true
|
||||
openssl.workspace = true
|
||||
g3-ctl.workspace = true
|
||||
g3-tls-cert.workspace = true
|
||||
g3keymess-proto = { path = "../../proto" }
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ fn build_cli_args() -> Command {
|
|||
.subcommand(proc::commands::offline())
|
||||
.subcommand(proc::commands::list())
|
||||
.subcommand(proc::commands::publish_key())
|
||||
.subcommand(proc::commands::check_key())
|
||||
.subcommand(server::command())
|
||||
}
|
||||
|
||||
|
|
@ -172,6 +173,7 @@ async fn main() -> anyhow::Result<()> {
|
|||
proc::COMMAND_OFFLINE => proc::offline(&proc_control).await,
|
||||
proc::COMMAND_LIST => proc::list(&proc_control, args).await,
|
||||
proc::COMMAND_PUBLISH_KEY => proc::publish_key(&proc_control, args).await,
|
||||
proc::COMMAND_CHECK_KEY => proc::check_key(&proc_control, args).await,
|
||||
server::COMMAND => server::run(&proc_control, args).await,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,11 @@ use std::path::PathBuf;
|
|||
|
||||
use anyhow::anyhow;
|
||||
use clap::ArgMatches;
|
||||
use openssl::pkey::PKey;
|
||||
|
||||
use g3_ctl::{CommandError, CommandResult};
|
||||
|
||||
use g3_tls_cert::ext::PublicKeyExt;
|
||||
use g3keymess_proto::proc_capnp::proc_control;
|
||||
use g3keymess_proto::server_capnp::server_control;
|
||||
|
||||
|
|
@ -30,6 +32,7 @@ pub const COMMAND_VERSION: &str = "version";
|
|||
pub const COMMAND_OFFLINE: &str = "offline";
|
||||
pub const COMMAND_LIST: &str = "list";
|
||||
pub const COMMAND_PUBLISH_KEY: &str = "publish-key";
|
||||
pub const COMMAND_CHECK_KEY: &str = "check-key";
|
||||
|
||||
const COMMAND_LIST_ARG_RESOURCE: &str = "resource";
|
||||
const RESOURCE_VALUE_SERVER: &str = "server";
|
||||
|
|
@ -69,6 +72,17 @@ pub mod commands {
|
|||
.value_hint(ValueHint::FilePath),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn check_key() -> Command {
|
||||
Command::new(COMMAND_CHECK_KEY).arg(
|
||||
Arg::new(COMMAND_ARG_FILE)
|
||||
.help("Private key file in pem format")
|
||||
.required(true)
|
||||
.num_args(1)
|
||||
.value_parser(value_parser!(PathBuf))
|
||||
.value_hint(ValueHint::FilePath),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn version(client: &proc_control::Client) -> CommandResult<()> {
|
||||
|
|
@ -130,3 +144,25 @@ pub async fn publish_key(client: &proc_control::Client, args: &ArgMatches) -> Co
|
|||
let rsp = req.send().promise.await?;
|
||||
parse_operation_result(rsp.get()?.get_result()?)
|
||||
}
|
||||
|
||||
pub async fn check_key(client: &proc_control::Client, args: &ArgMatches) -> CommandResult<()> {
|
||||
let file = args.get_one::<PathBuf>(COMMAND_ARG_FILE).unwrap();
|
||||
let content = std::fs::read_to_string(file).map_err(|e| {
|
||||
CommandError::Cli(anyhow!(
|
||||
"failed to read content of file {}: {e}",
|
||||
file.display()
|
||||
))
|
||||
})?;
|
||||
|
||||
let key = PKey::private_key_from_pem(content.as_bytes()).map_err(|e| {
|
||||
CommandError::Cli(anyhow!("failed to load key from {}: {e}", file.display()))
|
||||
})?;
|
||||
let ski = key.ski().map_err(|e| {
|
||||
CommandError::Cli(anyhow!("failed to get SKI for key {}: {e}", file.display()))
|
||||
})?;
|
||||
|
||||
let mut req = client.check_key_request();
|
||||
req.get().set_ski(&ski);
|
||||
let rsp = req.send().promise.await?;
|
||||
parse_operation_result(rsp.get()?.get_result()?)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "g3-tls-cert"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,10 @@ mod x509_builder;
|
|||
pub use x509_builder::X509BuilderExt;
|
||||
|
||||
mod x509_pubkey;
|
||||
pub use x509_pubkey::{X509Pubkey, X509PubkeyRef};
|
||||
use x509_pubkey::{X509Pubkey, X509PubkeyRef};
|
||||
|
||||
mod rsa;
|
||||
pub use rsa::RsaExt;
|
||||
|
||||
mod pkey;
|
||||
pub use pkey::PublicKeyExt;
|
||||
|
|
|
|||
33
lib/g3-tls-cert/src/ext/pkey.rs
Normal file
33
lib/g3-tls-cert/src/ext/pkey.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2023 ByteDance and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use openssl::error::ErrorStack;
|
||||
use openssl::hash::{DigestBytes, MessageDigest};
|
||||
use openssl::pkey::{HasPublic, PKey};
|
||||
|
||||
use super::X509Pubkey;
|
||||
|
||||
pub trait PublicKeyExt {
|
||||
fn ski(&self) -> Result<DigestBytes, ErrorStack>;
|
||||
}
|
||||
|
||||
impl<T: HasPublic> PublicKeyExt for PKey<T> {
|
||||
fn ski(&self) -> Result<DigestBytes, ErrorStack> {
|
||||
let x = X509Pubkey::from_pubkey(self)?;
|
||||
let encoded = x.encoded_bytes()?;
|
||||
openssl::hash::hash(MessageDigest::sha1(), encoded)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue