feat: init commit
This commit is contained in:
@@ -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 }
|
||||
|
||||
@@ -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![])
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
|
||||
|
||||
63
native-pkcs11-piv/src/piv/util.rs
Normal file
63
native-pkcs11-piv/src/piv/util.rs
Normal 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))?
|
||||
}
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user