feat: init commit

This commit is contained in:
2024-08-14 23:40:41 +08:00
parent e1e72ed097
commit 29a03ee225
11 changed files with 342 additions and 41 deletions

View File

@@ -28,6 +28,8 @@ tracing = "0.1.40"
tracing-error = { version = "0.2.0", default-features = false }
x509-cert = { version = "0.2.5", default-features = false }
yubikey = { version = "0.8.0", features = ["untested"] }
sha1 = "0.10"
x509-parser = "0.16.0"
[dev-dependencies]
serial_test = { version = "3.1.1", default-features = false }

View File

@@ -15,6 +15,9 @@
use std::sync::{Arc, Mutex};
use tracing::instrument;
use x509_cert::der::Encode;
use x509_parser::nom::Parser;
use yubikey::piv::AlgorithmId;
use yubikey::YubiKey;
use native_pkcs11_traits::{Backend, KeySearchOptions};
@@ -25,6 +28,9 @@ use native_pkcs11_traits::PrivateKey as P11PrivateKey;
use native_pkcs11_traits::PublicKey as P11PublicKey;
use native_pkcs11_traits::Result as P11Result;
use crate::certificate::YubikeyPivCertificate;
use crate::piv::util::get_algorithm_id_by_certificate;
#[derive(Debug, Default)]
pub struct YubikeyPivBackend {
cached_pin: Mutex<Option<String>>,
@@ -82,8 +88,26 @@ impl Backend for YubikeyPivBackend {
fn find_all_certificates(
&self,
) -> P11Result<Vec<Box<dyn P11Certificate>>> {
// TODO ...
Ok(vec![])
let mut certs = vec![];
self.run_with_yubikey(false, |yk| {
let keys = yk.piv_keys()?;
for key in keys {
let certificate_der = key.certificate().cert.to_der()?;
let public_key_der = key.certificate().cert.tbs_certificate.subject_public_key_info.to_der()?;
let algorithm_id = get_algorithm_id_by_certificate(key.certificate())?;
if algorithm_id == AlgorithmId::EccP256 || algorithm_id == AlgorithmId::EccP384 {
let cert: Box<dyn P11Certificate> = Box::new(YubikeyPivCertificate::new(
key.slot().to_string(),
key.slot().to_string(),
certificate_der,
public_key_der,
)?);
certs.push(cert);
}
}
Ok(())
})?;
Ok(certs)
}
#[instrument]
@@ -92,8 +116,12 @@ impl Backend for YubikeyPivBackend {
query: P11KeySearchOptions,
) -> P11Result<Option<Arc<dyn P11PrivateKey>>> {
match query {
KeySearchOptions::Label(label) => {}
KeySearchOptions::PublicKeyHash(public_key_hash) => {}
KeySearchOptions::Label(label) => {
println!(">>> find private key >>>: {}", label);
}
KeySearchOptions::PublicKeyHash(public_key_hash) => {
println!(">>> find private key >>>: {:?}", public_key_hash);
}
}
// TODO ...
Ok(None)
@@ -105,8 +133,12 @@ impl Backend for YubikeyPivBackend {
query: P11KeySearchOptions,
) -> P11Result<Option<Box<dyn P11PublicKey>>> {
match query {
KeySearchOptions::Label(label) => {}
KeySearchOptions::PublicKeyHash(public_key_hash) => {}
KeySearchOptions::Label(label) => {
println!(">>> find public key >>>: {}", label);
}
KeySearchOptions::PublicKeyHash(public_key_hash) => {
println!(">>> find public key >>>: {:?}", public_key_hash);
}
}
// TODO ...
Ok(None)
@@ -122,6 +154,9 @@ impl Backend for YubikeyPivBackend {
fn find_all_public_keys(
&self,
) -> P11Result<Vec<Arc<dyn P11PublicKey>>> {
// self.find_all_certificates().map(|c|{
// c.as_mut().map(|c| )
// })
// TODO ...
Ok(vec![])
}

View File

@@ -14,8 +14,9 @@
use std::fmt::Debug;
use native_pkcs11_traits::Certificate as P11Certificate;
use native_pkcs11_traits::{Certificate as P11Certificate, KeyAlgorithm};
use native_pkcs11_traits::PublicKey as P11PublicKey;
use native_pkcs11_traits::Result as P11Result;
use crate::key::YubikeyPivPublicKey;
@@ -27,6 +28,17 @@ pub struct YubikeyPivCertificate {
}
impl YubikeyPivCertificate {
pub fn new(label: String, identity: String, certificate_der: Vec<u8>, public_key_der: Vec<u8>) -> P11Result<Self> {
let public_key = YubikeyPivPublicKey::new(
label.clone(), KeyAlgorithm::Ecc, public_key_der,
)?;
Ok(Self {
label,
identity,
public_key,
certificate_der,
})
}
// pub fn new(identity: impl Into<SecIdentity>) -> Result<Self> {
// let identity: SecIdentity = identity.into();
// let label = identity.certificate().unwrap().subject_summary();

View File

@@ -19,6 +19,8 @@ use tracing::instrument;
use native_pkcs11_traits::{Backend, KeyAlgorithm, PrivateKey, PublicKey, SignatureAlgorithm};
use native_pkcs11_traits::Result as P11Result;
use crate::piv::util::sha1_bytes;
#[derive(Debug)]
pub enum Algorithm {
RSA,
@@ -107,6 +109,16 @@ pub struct YubikeyPivPublicKey {
}
impl YubikeyPivPublicKey {
#[instrument]
pub fn new(label: String, algorithm: KeyAlgorithm, public_key_der: Vec<u8>) -> P11Result<Self> {
let public_key_hash = sha1_bytes(&public_key_der);
Ok(Self {
label,
der: public_key_der,
public_key_hash,
algorithm,
})
}
// #[instrument]
// pub fn new(sec_key: SecKey, label: impl Into<String> + Debug) -> Result<Self> {
// let der = sec_key

View File

@@ -24,6 +24,7 @@ mod backend;
pub mod certificate;
pub mod key;
mod pinentry;
mod util;
pub type Result<T> = std::result::Result<T, Error>;

View File

@@ -0,0 +1,63 @@
use p256::ecdsa::signature::digest::Digest;
use p256::pkcs8::ObjectIdentifier;
use sha1::Sha1;
use spki::der::{Decode, Encode};
use spki::SubjectPublicKeyInfoOwned;
use x509_parser::prelude::FromDer;
use x509_parser::public_key::RSAPublicKey;
use yubikey::Certificate;
use yubikey::piv::AlgorithmId;
use native_pkcs11_traits::Result as P11Result;
const RSA: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.1");
const ECC: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.2.1");
// NIST recommended curves
// secp192r1 {1.2.840.10045.3.1.1}
// secp224r1 {1.3.132.0.33}
// secp256r1 {1.2.840.10045.3.1.7}
// secp384r1 {1.3.132.0.34}
// secp521r1 {1.3.132.0.35}
const ECC_P256: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7");
const ECC_P384: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.132.0.34");
pub fn sha1_bytes(input: &[u8]) -> Vec<u8> {
let mut digest = Sha1::default();
digest.update(input);
digest.finalize().to_vec()
}
pub fn get_algorithm_id_by_certificate(certificate: &Certificate) -> P11Result<AlgorithmId> {
let tbs_certificate = &certificate.cert.tbs_certificate;
get_algorithm_id(&tbs_certificate.subject_public_key_info)
}
pub fn get_algorithm_id(public_key_info: &SubjectPublicKeyInfoOwned) -> P11Result<AlgorithmId> {
if public_key_info.algorithm.oid == RSA {
let rsa_public_key = RSAPublicKey::from_der(public_key_info.subject_public_key.raw_bytes())?;
let starts_with_0 = rsa_public_key.1.modulus.starts_with(&[0]);
let public_key_bits = (rsa_public_key.1.modulus.len() - if starts_with_0 { 1 } else { 0 }) * 8;
if public_key_bits == 1024 {
return Ok(AlgorithmId::Rsa1024);
}
if public_key_bits == 2048 {
return Ok(AlgorithmId::Rsa2048);
}
Err(format!("Unknown rsa bits: {}", public_key_bits))?;
}
if public_key_info.algorithm.oid == ECC {
if let Some(any) = &public_key_info.algorithm.parameters {
let any_parameter_der = any.to_der()?;
let any_parameter_oid = ObjectIdentifier::from_der(&any_parameter_der)?;
if any_parameter_oid == ECC_P256 {
return Ok(AlgorithmId::EccP256);
}
if any_parameter_oid == ECC_P384 {
return Ok(AlgorithmId::EccP384);
}
Err(format!("Unknown any parameter oid: {}", any_parameter_oid))?;
}
}
Err(format!("Unknown algorithm: {}", public_key_info.algorithm.oid))?
}

View File

@@ -1,26 +0,0 @@
#!/bin/bash
# Copyright 2022 Google LLC
#
# 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.
set -e
# https://stackoverflow.com/questions/59895/how-do-i-get-the-directory-where-a-bash-script-is-located-from-within-the-script
cd $(dirname -- "$( readlink -f -- "$0"; )")
cargo build --bin signedtest
./codesigning-testing/codesign.sh $PWD/../target/debug/signedtest
(../target/debug/signedtest && echo SUCCESS) || (echo FAIL && exit 1)