Add attestation support

This commit is contained in:
pjht 2023-08-29 10:36:45 -05:00
parent d04e75ce3b
commit 29fc403d81
Signed by: pjht
GPG Key ID: CA239FC6934E6F3A
6 changed files with 462 additions and 53 deletions

View File

@ -1,43 +1,43 @@
- fido_assert_allow_cred
- fido_assert_authdata_len
- fido_assert_authdata_ptr
- fido_assert_blob_len
- fido_assert_blob_ptr
- fido_assert_clientdata_hash_len
- fido_assert_clientdata_hash_ptr
- fido_assert_count
Y fido_assert_authdata_len
Y fido_assert_authdata_ptr
Y fido_assert_blob_len
Y fido_assert_blob_ptr
Y fido_assert_clientdata_hash_len
Y fido_assert_clientdata_hash_ptr
Y fido_assert_count
- fido_assert_empty_allow_list
- fido_assert_flags
- fido_assert_free
- fido_assert_hmac_secret_len
- fido_assert_hmac_secret_ptr
- fido_assert_id_len
- fido_assert_id_ptr
- fido_assert_largeblob_key_len
- fido_assert_largeblob_key_ptr
- fido_assert_new
- fido_assert_rp_id
- fido_assert_set_authdata
- fido_assert_set_authdata_raw
- fido_assert_set_clientdata
- fido_assert_set_clientdata_hash
- fido_assert_set_count
- fido_assert_set_extensions
- fido_assert_set_hmac_salt
- fido_assert_set_hmac_secret
- fido_assert_set_rp
- fido_assert_set_sig
- fido_assert_set_up
- fido_assert_set_uv
- fido_assert_sig_len
- fido_assert_sig_ptr
- fido_assert_sigcount
- fido_assert_user_display_name
- fido_assert_user_icon
- fido_assert_user_id_len
- fido_assert_user_id_ptr
- fido_assert_user_name
- fido_assert_verify
Y fido_assert_flags
Y fido_assert_free
Y fido_assert_hmac_secret_len
Y fido_assert_hmac_secret_ptr
Y fido_assert_id_len
Y fido_assert_id_ptr
Y fido_assert_largeblob_key_len
Y fido_assert_largeblob_key_ptr
Y fido_assert_new
Y fido_assert_rp_id
Y fido_assert_set_authdata
Y fido_assert_set_authdata_raw
Y fido_assert_set_clientdata
Y fido_assert_set_clientdata_hash
Y fido_assert_set_count
Y fido_assert_set_extensions
Y fido_assert_set_hmac_salt
Y fido_assert_set_hmac_secret
Y fido_assert_set_rp
Y fido_assert_set_sig
Y fido_assert_set_up
Y fido_assert_set_uv
Y fido_assert_sig_len
Y fido_assert_sig_ptr
Y fido_assert_sigcount
Y fido_assert_user_display_name
Y fido_assert_user_icon
Y fido_assert_user_id_len
Y fido_assert_user_id_ptr
Y fido_assert_user_name
Y fido_assert_verify
- fido_bio_dev_enroll_begin
- fido_bio_dev_enroll_cancel

View File

@ -1,3 +1,309 @@
use std::ffi::{CStr, CString};
use crate::{
error::{check, Result},
pkey::PubKey,
util::{check_initialized, opt_bool_to_fido_opt},
CoseAlg,
};
use libfido2_sys::*;
c_type_wrapper!(fido_assert_t, Assertion, free = fido_assert_free);
impl Assertion {
pub fn new(&self) -> Result<Self> {
check_initialized()?;
unsafe { Ok(Self::from_ptr(fido_assert_new())) }
}
}
impl AssertionRef {
pub fn authdata(&self, idx: usize) -> Option<&[u8]> {
assert!(idx < self.count());
unsafe {
if fido_assert_authdata_ptr(self.as_ptr(), idx).is_null() {
None
} else {
Some(std::slice::from_raw_parts(
fido_assert_authdata_ptr(self.as_ptr(), idx),
fido_assert_authdata_len(self.as_ptr(), idx),
))
}
}
}
pub fn blob(&self, idx: usize) -> Option<&[u8]> {
assert!(idx < self.count());
unsafe {
if fido_assert_blob_ptr(self.as_ptr(), idx).is_null() {
None
} else {
Some(std::slice::from_raw_parts(
fido_assert_blob_ptr(self.as_ptr(), idx),
fido_assert_blob_len(self.as_ptr(), idx),
))
}
}
}
pub fn clientdata_hash(&self) -> Option<&[u8]> {
unsafe {
if fido_assert_clientdata_hash_ptr(self.as_ptr()).is_null() {
None
} else {
Some(std::slice::from_raw_parts(
fido_assert_clientdata_hash_ptr(self.as_ptr()),
fido_assert_clientdata_hash_len(self.as_ptr()),
))
}
}
}
pub fn count(&self) -> usize {
unsafe { fido_assert_count(self.as_ptr()) }
}
pub fn flags(&self, idx: usize) -> u8 {
assert!(idx < self.count());
unsafe { fido_assert_flags(self.as_ptr(), idx) }
}
pub fn hmac_secret(&self, idx: usize) -> Option<&[u8]> {
assert!(idx < self.count());
unsafe {
if fido_assert_hmac_secret_ptr(self.as_ptr(), idx).is_null() {
None
} else {
Some(std::slice::from_raw_parts(
fido_assert_hmac_secret_ptr(self.as_ptr(), idx),
fido_assert_hmac_secret_len(self.as_ptr(), idx),
))
}
}
}
pub fn id(&self, idx: usize) -> Option<&[u8]> {
assert!(idx < self.count());
unsafe {
if fido_assert_id_ptr(self.as_ptr(), idx).is_null() {
None
} else {
Some(std::slice::from_raw_parts(
fido_assert_id_ptr(self.as_ptr(), idx),
fido_assert_id_len(self.as_ptr(), idx),
))
}
}
}
pub fn largeblob_key(&self, idx: usize) -> &[u8] {
assert!(idx < self.count());
unsafe {
std::slice::from_raw_parts(
fido_assert_largeblob_key_ptr(self.as_ptr(), idx),
fido_assert_largeblob_key_len(self.as_ptr(), idx),
)
}
}
pub fn rp_id(&self) -> Option<&str> {
unsafe {
let ptr = fido_assert_rp_id(self.as_ptr());
if ptr.is_null() {
None
} else {
Some(CStr::from_ptr(ptr).to_str().unwrap())
}
}
}
pub fn set_authdata(&mut self, idx: usize, data: &[u8]) -> Result<()> {
assert!(idx < self.count());
unsafe {
check(fido_assert_set_authdata(
self.as_ptr_mut(),
idx,
&data[0],
data.len(),
))
}
}
pub fn set_authdata_raw(&mut self, idx: usize, data: &[u8]) -> Result<()> {
assert!(idx < self.count());
unsafe {
check(fido_assert_set_authdata_raw(
self.as_ptr_mut(),
idx,
&data[0],
data.len(),
))
}
}
pub fn set_clientdata(&mut self, data: &[u8]) -> Result<()> {
unsafe {
check(fido_assert_set_clientdata(
self.as_ptr_mut(),
&data[0],
data.len(),
))
}
}
pub fn set_clientdata_hash(&mut self, hash: &[u8]) -> Result<()> {
unsafe {
check(fido_assert_set_clientdata_hash(
self.as_ptr_mut(),
&hash[0],
hash.len(),
))
}
}
pub fn set_count(&mut self, count: usize) -> Result<()> {
unsafe { check(fido_assert_set_count(self.as_ptr_mut(), count)) }
}
pub fn set_extensions(&mut self, extensions: i32) -> Result<()> {
unsafe { check(fido_assert_set_extensions(self.as_ptr_mut(), extensions)) }
}
pub fn set_hmac_salt(&mut self, data: &[u8]) -> Result<()> {
unsafe {
check(fido_assert_set_hmac_salt(
self.as_ptr_mut(),
&data[0],
data.len(),
))
}
}
pub fn set_hmac_secret(&mut self, idx: usize, data: &[u8]) -> Result<()> {
assert!(idx < self.count());
unsafe {
check(fido_assert_set_hmac_secret(
self.as_ptr_mut(),
idx,
&data[0],
data.len(),
))
}
}
pub fn set_rp(&mut self, rp: impl AsRef<str>) -> Result<()> {
let rp = CString::new(rp.as_ref()).unwrap();
unsafe { check(fido_assert_set_rp(self.as_ptr_mut(), rp.as_ptr())) }
}
pub fn set_sig(&mut self, idx: usize, data: &[u8]) -> Result<()> {
assert!(idx < self.count());
unsafe {
check(fido_assert_set_sig(
self.as_ptr_mut(),
idx,
&data[0],
data.len(),
))
}
}
pub fn set_up(&mut self, up: Option<bool>) -> Result<()> {
unsafe {
check(fido_assert_set_up(
self.as_ptr_mut(),
opt_bool_to_fido_opt(up),
))
}
}
pub fn set_uv(&mut self, uv: Option<bool>) -> Result<()> {
unsafe {
check(fido_assert_set_uv(
self.as_ptr_mut(),
opt_bool_to_fido_opt(uv),
))
}
}
pub fn sig(&self, idx: usize) -> Option<&[u8]> {
assert!(idx < self.count());
unsafe {
if fido_assert_sig_ptr(self.as_ptr(), idx).is_null() {
None
} else {
Some(std::slice::from_raw_parts(
fido_assert_sig_ptr(self.as_ptr(), idx),
fido_assert_sig_len(self.as_ptr(), idx),
))
}
}
}
pub fn sigcount(&self, idx: usize) -> u32 {
assert!(idx < self.count());
unsafe { fido_assert_sigcount(self.as_ptr(), idx) }
}
pub fn user_display_name(&self, idx: usize) -> Option<&str> {
assert!(idx < self.count());
unsafe {
let ptr = fido_assert_user_display_name(self.as_ptr(), idx);
if ptr.is_null() {
None
} else {
Some(CStr::from_ptr(ptr).to_str().unwrap())
}
}
}
pub fn user_icon(&self, idx: usize) -> Option<&str> {
assert!(idx < self.count());
unsafe {
let ptr = fido_assert_user_icon(self.as_ptr(), idx);
if ptr.is_null() {
None
} else {
Some(CStr::from_ptr(ptr).to_str().unwrap())
}
}
}
pub fn user_id(&self, idx: usize) -> Option<&[u8]> {
assert!(idx < self.count());
unsafe {
if fido_assert_user_id_ptr(self.as_ptr(), idx).is_null() {
None
} else {
Some(std::slice::from_raw_parts(
fido_assert_user_id_ptr(self.as_ptr(), idx),
fido_assert_user_id_len(self.as_ptr(), idx),
))
}
}
}
pub fn user_name(&self, idx: usize) -> Option<&str> {
assert!(idx < self.count());
unsafe {
let ptr = fido_assert_user_name(self.as_ptr(), idx);
if ptr.is_null() {
None
} else {
Some(CStr::from_ptr(ptr).to_str().unwrap())
}
}
}
pub fn verify(&self, idx: usize, alg: CoseAlg, pubkey: PubKey) -> Result<()> {
assert!(idx < self.count());
unsafe {
check(fido_assert_verify(
self.as_ptr(),
idx,
alg as i32,
pubkey.as_ptr(),
))
}
}
}

View File

@ -4,7 +4,7 @@ use std::{
ffi::{CStr, CString},
fmt::Debug,
ops::Index,
ptr::{self, NonNull},
ptr::NonNull,
};
use libfido2_sys::*;

View File

@ -96,7 +96,6 @@ impl DeviceCborInfoRef {
unsafe { fido_cbor_info_new_pin_required(self.as_ptr()) }
}
pub fn options(&self) -> HashMap<String, bool> {
let mut map = HashMap::new();
unsafe {
@ -126,10 +125,12 @@ impl DeviceCborInfoRef {
}
pub fn rk_remaining(&self) -> Option<u64> {
unsafe { match fido_cbor_info_rk_remaining(self.as_ptr()) {
unsafe {
match fido_cbor_info_rk_remaining(self.as_ptr()) {
-1 => None,
x => Some(x as u64),
}}
}
}
}
pub fn transports(&self) -> Vec<String> {
@ -147,17 +148,21 @@ impl DeviceCborInfoRef {
}
pub fn uv_attempts(&self) -> Option<u64> {
unsafe { match fido_cbor_info_uv_attempts(self.as_ptr()) {
unsafe {
match fido_cbor_info_uv_attempts(self.as_ptr()) {
0 => None,
x => Some(x),
}}
}
}
}
pub fn uv_modality(&self) -> Option<u64> {
unsafe { match fido_cbor_info_uv_modality(self.as_ptr()) {
unsafe {
match fido_cbor_info_uv_modality(self.as_ptr()) {
0 => None,
x => Some(x),
}}
}
}
}
pub fn versions(&self) -> Vec<String> {

View File

@ -10,6 +10,7 @@ pub mod assert;
pub mod cred;
pub mod device;
pub mod error;
pub mod pkey;
#[repr(i32)]
#[derive(Debug, Clone, Copy, TryFromPrimitive)]

97
src/pkey.rs Normal file
View File

@ -0,0 +1,97 @@
use std::ffi::c_void;
use libfido2_sys::*;
use crate::error::Result;
use crate::util::check_initialized;
c_type_wrapper!(eddsa_pk_t, Ec25519PubKey, free = eddsa_pk_free);
c_type_wrapper!(es256_pk_t, Ecdsa256PubKey, free = es256_pk_free);
c_type_wrapper!(es384_pk, Ecdsa384PubKey, free = es384_pk_free);
c_type_wrapper!(rs256_pk, Rsa256PubKey, free = rs256_pk_free);
impl Ec25519PubKey {
pub fn new(data: &[u8]) -> Result<Self> {
check_initialized()?;
unsafe {
let ptr = eddsa_pk_new();
eddsa_pk_from_ptr(ptr, &data[0] as *const u8 as *const c_void, data.len());
Ok(Self::from_ptr(ptr))
}
}
}
impl Ecdsa256PubKey {
pub fn new(data: &[u8]) -> Result<Self> {
check_initialized()?;
unsafe {
let ptr = es256_pk_new();
es256_pk_from_ptr(ptr, &data[0] as *const u8 as *const c_void, data.len());
Ok(Self::from_ptr(ptr))
}
}
}
impl Ecdsa384PubKey {
pub fn new(data: &[u8]) -> Result<Self> {
check_initialized()?;
unsafe {
let ptr = es384_pk_new();
es384_pk_from_ptr(ptr, &data[0] as *const u8 as *const c_void, data.len());
Ok(Self::from_ptr(ptr))
}
}
}
impl Rsa256PubKey {
pub fn new(data: &[u8]) -> Result<Self> {
check_initialized()?;
unsafe {
let ptr = rs256_pk_new();
rs256_pk_from_ptr(ptr, &data[0] as *const u8 as *const c_void, data.len());
Ok(Self::from_ptr(ptr))
}
}
}
pub enum PubKey {
Ec25519(Ec25519PubKey),
Ecdsa256(Ecdsa256PubKey),
Ecdsa384(Ecdsa384PubKey),
Rsa256PubKey(Rsa256PubKey),
}
impl From<Rsa256PubKey> for PubKey {
fn from(v: Rsa256PubKey) -> Self {
Self::Rsa256PubKey(v)
}
}
impl From<Ecdsa384PubKey> for PubKey {
fn from(v: Ecdsa384PubKey) -> Self {
Self::Ecdsa384(v)
}
}
impl From<Ecdsa256PubKey> for PubKey {
fn from(v: Ecdsa256PubKey) -> Self {
Self::Ecdsa256(v)
}
}
impl From<Ec25519PubKey> for PubKey {
fn from(v: Ec25519PubKey) -> Self {
Self::Ec25519(v)
}
}
impl PubKey {
pub(crate) fn as_ptr(&self) -> *const c_void {
match self {
PubKey::Ec25519(pk) => pk.as_ptr() as *const c_void,
PubKey::Ecdsa256(pk) => pk.as_ptr() as *const c_void,
PubKey::Ecdsa384(pk) => pk.as_ptr() as *const c_void,
PubKey::Rsa256PubKey(pk) => pk.as_ptr() as *const c_void,
}
}
}