Skip to content

Commit

Permalink
Added public key information for getPublicKey and getPublicKeyAlg
Browse files Browse the repository at this point in the history
  • Loading branch information
LucFauvel committed Apr 25, 2024
1 parent 14c7ac1 commit 71aeb56
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 21 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "slauth"
version = "0.7.6-beta.1"
version = "0.7.6-beta.2"
authors = ["richer <richer.arc@gmail.com>", "LucFauvel <luc.fauvel@hotmail.com>"]
edition = "2021"
description = "oath HOTP and TOTP complient implementation"
Expand Down
59 changes: 40 additions & 19 deletions src/webauthn/authenticator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::webauthn::{
},
};
use base64::URL_SAFE_NO_PAD;
use ed25519_dalek::{SignatureError, Signer};
use ed25519_dalek::{pkcs8::EncodePublicKey, SignatureError, Signer};
use hmac::digest::Digest;
use p256::ecdsa::VerifyingKey;
use rand::rngs::OsRng;
Expand All @@ -29,11 +29,13 @@ use sha2::Sha256;
use uuid::Uuid;

use crate::webauthn::{
authenticator::responses::PrivateKeyResponse,
authenticator::responses::{AuthenticatorCredentialCreationResponseAdditionalData, PrivateKeyResponse},
proto::{
constants::WEBAUTHN_REQUEST_TYPE_GET,
raw_message::AttestationStatement,
web_message::{get_default_rp_id, AuthenticatorAttestationResponseRaw, PublicKeyCredentialRaw, PublicKeyCredentialRequestOptions},
web_message::{
get_default_rp_id, AuthenticatorAttestationResponseRaw, PublicKeyCredentialRaw, PublicKeyCredentialRequestOptions, Transport,
},
},
};
#[cfg(test)]
Expand All @@ -57,6 +59,7 @@ pub enum WebauthnCredentialRequestError {
RsaError(rsa::pkcs1::Error),
Base64Error(base64::DecodeError),
Ed25519Error(ed25519_dalek::SignatureError),
Ed25519SPKIError(ed25519_dalek::pkcs8::spki::Error),
}

impl From<serde_json::Error> for WebauthnCredentialRequestError {
Expand Down Expand Up @@ -95,6 +98,12 @@ impl From<SignatureError> for WebauthnCredentialRequestError {
}
}

impl From<ed25519_dalek::pkcs8::spki::Error> for WebauthnCredentialRequestError {
fn from(e: ed25519_dalek::pkcs8::spki::Error) -> Self {
WebauthnCredentialRequestError::Ed25519SPKIError(e)
}
}

pub struct WebauthnAuthenticator;

impl WebauthnAuthenticator {
Expand Down Expand Up @@ -127,7 +136,7 @@ impl WebauthnAuthenticator {
hasher.update(rp_id);

let alg = Self::find_best_supported_algorithm(&credential_creation_options.pub_key_cred_params)?;
let (key_info, private_key_response) = match alg {
let (key_info, private_key_response, der) = match alg {
CoseAlgorithmIdentifier::Ed25519 => {
let keypair = ed25519_dalek::SigningKey::generate(&mut OsRng);
let bytes = keypair.verifying_key().to_bytes();
Expand All @@ -144,14 +153,16 @@ impl WebauthnAuthenticator {
},
}),
base64::encode(serde_cbor::to_vec(&private_key)?),
keypair.verifying_key().to_public_key_der()?.to_vec(),
)
}

CoseAlgorithmIdentifier::EC2 => {
let secret_key = p256::ecdsa::SigningKey::random(&mut OsRng);
let keypair = VerifyingKey::from(&secret_key).to_encoded_point(false);
let y = keypair.y().ok_or(WebauthnCredentialRequestError::CouldNotGenerateKey)?;
let x = keypair.x().ok_or(WebauthnCredentialRequestError::CouldNotGenerateKey)?;
let verifying_key = VerifyingKey::from(&secret_key);
let points = verifying_key.to_encoded_point(false);
let y = points.y().ok_or(WebauthnCredentialRequestError::CouldNotGenerateKey)?;
let x = points.x().ok_or(WebauthnCredentialRequestError::CouldNotGenerateKey)?;
let private_key = PrivateKeyResponse {
private_key: secret_key.to_bytes().to_vec(),
key_alg: alg.clone(),
Expand All @@ -165,6 +176,7 @@ impl WebauthnAuthenticator {
},
}),
base64::encode(serde_cbor::to_vec(&private_key)?),
verifying_key.to_public_key_der()?.to_vec(),
)
}

Expand All @@ -180,6 +192,7 @@ impl WebauthnAuthenticator {
e: key.e().to_bytes_be(),
}),
base64::encode(serde_cbor::to_vec(&private_key)?),
key.to_public_key().to_public_key_der()?.to_vec(),
)
}

Expand All @@ -200,18 +213,20 @@ impl WebauthnAuthenticator {
None
};

let auth_data = AuthenticatorData {
rp_id_hash: hasher
.finalize_reset()
.to_vec()
.try_into()
.map_err(|e: Vec<u8>| WebauthnCredentialRequestError::RpIdHashInvalidLength(e.len()))?,
flags: attestation_flags,
sign_count: 0,
attested_credential_data,
extensions: Value::Null,
};

let attestation_object = AttestationObject {
auth_data: AuthenticatorData {
rp_id_hash: hasher
.finalize_reset()
.to_vec()
.try_into()
.map_err(|e: Vec<u8>| WebauthnCredentialRequestError::RpIdHashInvalidLength(e.len()))?,
flags: attestation_flags,
sign_count: 0,
attested_credential_data,
extensions: Value::Null,
},
auth_data: auth_data.clone(),
raw_auth_data: vec![],
fmt: WEBAUTHN_FORMAT_NONE.to_owned(),
att_stmt: Some(AttestationStatement::None),
Expand All @@ -233,15 +248,20 @@ impl WebauthnAuthenticator {
response: Some(AuthenticatorAttestationResponseRaw {
attestation_object: Some(attestation_object),
client_data_json: serde_json::to_string(&collected_client_data)?.into_bytes(),
authenticator_data: None,
authenticator_data: auth_data.to_vec().ok(),
signature: None,
user_handle: None,
transports: vec![Transport::Internal],
}),
};

Ok(AuthenticatorCredentialCreationResponse {
credential_response: credential,
private_key_response,
additional_data: AuthenticatorCredentialCreationResponseAdditionalData {
public_key_der: der,
public_key_alg: alg.into(),
},
})
}

Expand Down Expand Up @@ -329,6 +349,7 @@ impl WebauthnAuthenticator {
authenticator_data: Some(auth_data_bytes),
signature: Some(signature),
user_handle,
transports: vec![Transport::Internal],
}),
})
}
Expand Down
7 changes: 7 additions & 0 deletions src/webauthn/authenticator/responses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ use serde_derive::{Deserialize, Serialize};
pub struct AuthenticatorCredentialCreationResponse {
pub credential_response: PublicKeyCredentialRaw,
pub private_key_response: String,
pub additional_data: AuthenticatorCredentialCreationResponseAdditionalData,
}

#[derive(Serialize, Clone)]
pub struct AuthenticatorCredentialCreationResponseAdditionalData {
pub public_key_der: Vec<u8>,
pub public_key_alg: i64,
}

#[derive(Serialize, Deserialize)]
Expand Down
2 changes: 1 addition & 1 deletion src/webauthn/proto/raw_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,7 @@ impl FromStr for Coordinates {
}
}

#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone, Copy)]
pub enum CoseAlgorithmIdentifier {
Ed25519 = -8,
EC2 = -7,
Expand Down
11 changes: 11 additions & 0 deletions src/webauthn/proto/web_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,17 @@ pub struct AuthenticatorAttestationResponseRaw {
pub signature: Option<Vec<u8>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user_handle: Option<Vec<u8>>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub transports: Vec<Transport>,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub enum Transport {
Usb,
Nfc,
Ble,
Internal,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
Expand Down

0 comments on commit 71aeb56

Please sign in to comment.