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

186
Cargo.lock generated
View File

@@ -11,6 +11,45 @@ dependencies = [
"memchr",
]
[[package]]
name = "asn1-rs"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ad1373757efa0f70ec53939aabc7152e1591cb485208052993070ac8d2429d"
dependencies = [
"asn1-rs-derive",
"asn1-rs-impl",
"displaydoc",
"nom",
"num-traits",
"rusticata-macros",
"thiserror",
"time",
]
[[package]]
name = "asn1-rs-derive"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "asn1-rs-impl"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "autocfg"
version = "1.3.0"
@@ -164,6 +203,12 @@ dependencies = [
"typenum",
]
[[package]]
name = "data-encoding"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
[[package]]
name = "der"
version = "0.7.9"
@@ -177,6 +222,20 @@ dependencies = [
"zeroize",
]
[[package]]
name = "der-parser"
version = "9.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553"
dependencies = [
"asn1-rs",
"displaydoc",
"nom",
"num-bigint",
"num-traits",
"rusticata-macros",
]
[[package]]
name = "der_derive"
version = "0.7.2"
@@ -188,6 +247,15 @@ dependencies = [
"syn",
]
[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
]
[[package]]
name = "des"
version = "0.8.1"
@@ -209,6 +277,17 @@ dependencies = [
"subtle",
]
[[package]]
name = "displaydoc"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "ecdsa"
version = "0.16.9"
@@ -381,6 +460,12 @@ dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "lazy_static"
version = "1.4.0"
@@ -508,11 +593,13 @@ dependencies = [
"rsa",
"secrecy",
"serial_test",
"sha1",
"spki",
"thiserror",
"tracing",
"tracing-error",
"x509-cert",
"x509-parser",
"yubikey",
]
@@ -545,6 +632,16 @@ dependencies = [
"winapi",
]
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-bigint-dig"
version = "0.8.4"
@@ -563,6 +660,12 @@ dependencies = [
"zeroize",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-integer"
version = "0.1.46"
@@ -593,6 +696,15 @@ dependencies = [
"libm",
]
[[package]]
name = "oid-registry"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d"
dependencies = [
"asn1-rs",
]
[[package]]
name = "once_cell"
version = "1.19.0"
@@ -750,6 +862,12 @@ version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
@@ -934,6 +1052,15 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rusticata-macros"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
dependencies = [
"nom",
]
[[package]]
name = "rustix"
version = "0.38.34"
@@ -1145,6 +1272,17 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "synstructure"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thiserror"
version = "1.0.61"
@@ -1175,6 +1313,37 @@ dependencies = [
"once_cell",
]
[[package]]
name = "time"
version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "tls_codec"
version = "0.4.1"
@@ -1504,6 +1673,23 @@ dependencies = [
"tls_codec",
]
[[package]]
name = "x509-parser"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69"
dependencies = [
"asn1-rs",
"data-encoding",
"der-parser",
"lazy_static",
"nom",
"oid-registry",
"rusticata-macros",
"thiserror",
"time",
]
[[package]]
name = "yubikey"
version = "0.8.0"

View File

@@ -3,3 +3,16 @@ Yubikey PIV PKCS#11
> Fork form: https://github.com/google/native-pkcs11
<br>
Alias:
```shell
alias p11='pkcs11-tool --module /FULLPATH/libyubikey_piv_pkcs11.dylib'
```
List certificates
```shell
p11 --list-object --type cert
```

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)

View File

@@ -277,7 +277,7 @@ cryptoki_fn!(
}
);
#[cfg(not(feature = "custom-function-list"))]
// #[cfg(not(feature = "custom-function-list"))]
cryptoki_fn!(
unsafe fn C_GetFunctionList(ppFunctionList: CK_FUNCTION_LIST_PTR_PTR) {
not_null!(ppFunctionList);

View File

@@ -15,22 +15,23 @@
use std::collections::HashMap;
use cached::{Cached, TimedCache};
use tracing::{instrument, warn};
use native_pkcs11_core::{
attribute::{Attribute, AttributeType, Attributes},
attribute::{Attribute, Attributes, AttributeType},
Result,
};
use native_pkcs11_traits::{backend, KeySearchOptions};
use pkcs11_sys::{
CK_OBJECT_HANDLE,
CKO_CERTIFICATE,
CKO_PRIVATE_KEY,
CKO_PUBLIC_KEY,
CKO_SECRET_KEY,
CKP_BASELINE_PROVIDER,
CK_OBJECT_HANDLE,
};
use tracing::{instrument, warn};
use crate::{object::Object, Error};
use crate::{Error, object::Object};
#[derive(Debug)]
pub struct ObjectStore {
@@ -200,13 +201,15 @@ impl Default for ObjectStore {
mod tests {
use std::vec;
use native_pkcs11_traits::{backend, random_label, KeyAlgorithm};
use pkcs11_sys::CKO_PRIVATE_KEY;
use serial_test::serial;
use super::*;
use native_pkcs11_traits::{backend, KeyAlgorithm, random_label};
use pkcs11_sys::CKO_PRIVATE_KEY;
use crate::tests::test_init;
use super::*;
#[test]
#[serial]
fn test_object_store() {