Public Key plain byte encoding (#540)
* public key is encoded in bytes * ECDSA pubkey in uncompressed format
This commit is contained in:
23
build.rs
23
build.rs
@@ -15,7 +15,6 @@
|
|||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use openssl::{bn, ec, nid};
|
use openssl::{bn, ec, nid};
|
||||||
use sk_cbor::cbor_map;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@@ -52,25 +51,7 @@ fn main() {
|
|||||||
.public_key()
|
.public_key()
|
||||||
.to_bytes(&group, conversion_form, &mut ctx)
|
.to_bytes(&group, conversion_form, &mut ctx)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
const POINT_LEN: usize = 32;
|
let upgrade_pubkey_path = Path::new(&out_dir).join("opensk_upgrade_pubkey.bin");
|
||||||
assert_eq!(raw_bytes.len(), 1 + 2 * POINT_LEN);
|
|
||||||
assert_eq!(raw_bytes[0], 0x04);
|
|
||||||
let x_bytes = &raw_bytes[1..][..POINT_LEN];
|
|
||||||
let y_bytes = &raw_bytes[1 + POINT_LEN..][..POINT_LEN];
|
|
||||||
|
|
||||||
const EC2_KEY_TYPE: i64 = 2;
|
|
||||||
const P_256_CURVE: i64 = 1;
|
|
||||||
const ES256_ALGORITHM: i64 = -7;
|
|
||||||
let pub_key_cbor = sk_cbor::cbor_map! {
|
|
||||||
1 => EC2_KEY_TYPE,
|
|
||||||
3 => ES256_ALGORITHM,
|
|
||||||
-1 => P_256_CURVE,
|
|
||||||
-2 => x_bytes,
|
|
||||||
-3 => y_bytes,
|
|
||||||
};
|
|
||||||
let mut cbor_bytes = vec![];
|
|
||||||
sk_cbor::writer::write(pub_key_cbor, &mut cbor_bytes).unwrap();
|
|
||||||
let upgrade_pubkey_path = Path::new(&out_dir).join("opensk_upgrade_pubkey_cbor.bin");
|
|
||||||
let mut upgrade_pub_bin_file = File::create(&upgrade_pubkey_path).unwrap();
|
let mut upgrade_pub_bin_file = File::create(&upgrade_pubkey_path).unwrap();
|
||||||
upgrade_pub_bin_file.write_all(&cbor_bytes).unwrap();
|
upgrade_pub_bin_file.write_all(&raw_bytes).unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,8 @@ use super::exponent256::ExponentP256;
|
|||||||
use super::gfp256::GFP256;
|
use super::gfp256::GFP256;
|
||||||
use super::int256::Int256;
|
use super::int256::Int256;
|
||||||
use super::montgomery::Montgomery;
|
use super::montgomery::Montgomery;
|
||||||
#[cfg(test)]
|
|
||||||
use arrayref::array_mut_ref;
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
use arrayref::array_mut_ref;
|
||||||
use arrayref::array_ref;
|
use arrayref::array_ref;
|
||||||
use core::ops::Add;
|
use core::ops::Add;
|
||||||
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
|
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
|
||||||
@@ -45,7 +44,6 @@ impl PointP256 {
|
|||||||
/** Serialization **/
|
/** Serialization **/
|
||||||
// This uses uncompressed point format from "SEC 1: Elliptic Curve Cryptography" ("Standards for
|
// This uses uncompressed point format from "SEC 1: Elliptic Curve Cryptography" ("Standards for
|
||||||
// Efficient Cryptography").
|
// Efficient Cryptography").
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub fn from_bytes_uncompressed_vartime(bytes: &[u8]) -> Option<PointP256> {
|
pub fn from_bytes_uncompressed_vartime(bytes: &[u8]) -> Option<PointP256> {
|
||||||
if bytes.len() != 65 || bytes[0] != 0x04 {
|
if bytes.len() != 65 || bytes[0] != 0x04 {
|
||||||
None
|
None
|
||||||
@@ -57,7 +55,7 @@ impl PointP256 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(feature = "std")]
|
||||||
pub fn to_bytes_uncompressed(&self, bytes: &mut [u8; 65]) {
|
pub fn to_bytes_uncompressed(&self, bytes: &mut [u8; 65]) {
|
||||||
bytes[0] = 0x04;
|
bytes[0] = 0x04;
|
||||||
self.x.to_int().to_bin(array_mut_ref![bytes, 1, 32]);
|
self.x.to_int().to_bin(array_mut_ref![bytes, 1, 32]);
|
||||||
|
|||||||
@@ -231,13 +231,12 @@ impl PubKey {
|
|||||||
.map(|p| PubKey { p })
|
.map(|p| PubKey { p })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub fn from_bytes_uncompressed(bytes: &[u8]) -> Option<PubKey> {
|
pub fn from_bytes_uncompressed(bytes: &[u8]) -> Option<PubKey> {
|
||||||
PointP256::from_bytes_uncompressed_vartime(bytes).map(|p| PubKey { p })
|
PointP256::from_bytes_uncompressed_vartime(bytes).map(|p| PubKey { p })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(feature = "std")]
|
||||||
fn to_bytes_uncompressed(&self, bytes: &mut [u8; 65]) {
|
pub fn to_bytes_uncompressed(&self, bytes: &mut [u8; 65]) {
|
||||||
self.p.to_bytes_uncompressed(bytes);
|
self.p.to_bytes_uncompressed(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -836,8 +836,8 @@ impl From<ecdh::PubKey> for CoseKey {
|
|||||||
|
|
||||||
impl From<ecdsa::PubKey> for CoseKey {
|
impl From<ecdsa::PubKey> for CoseKey {
|
||||||
fn from(pk: ecdsa::PubKey) -> Self {
|
fn from(pk: ecdsa::PubKey) -> Self {
|
||||||
let mut x_bytes = [0; ecdh::NBYTES];
|
let mut x_bytes = [0; ecdsa::NBYTES];
|
||||||
let mut y_bytes = [0; ecdh::NBYTES];
|
let mut y_bytes = [0; ecdsa::NBYTES];
|
||||||
pk.to_coordinates(&mut x_bytes, &mut y_bytes);
|
pk.to_coordinates(&mut x_bytes, &mut y_bytes);
|
||||||
CoseKey {
|
CoseKey {
|
||||||
x_bytes,
|
x_bytes,
|
||||||
|
|||||||
@@ -14,9 +14,9 @@
|
|||||||
|
|
||||||
pub const ATTESTATION_PRIVATE_KEY_LENGTH: usize = 32;
|
pub const ATTESTATION_PRIVATE_KEY_LENGTH: usize = 32;
|
||||||
pub const AAGUID_LENGTH: usize = 16;
|
pub const AAGUID_LENGTH: usize = 16;
|
||||||
pub const UPGRADE_PUBLIC_KEY_LENGTH: usize = 77;
|
pub const UPGRADE_PUBLIC_KEY_LENGTH: usize = 65;
|
||||||
|
|
||||||
pub const AAGUID: &[u8; AAGUID_LENGTH] =
|
pub const AAGUID: &[u8; AAGUID_LENGTH] =
|
||||||
include_bytes!(concat!(env!("OUT_DIR"), "/opensk_aaguid.bin"));
|
include_bytes!(concat!(env!("OUT_DIR"), "/opensk_aaguid.bin"));
|
||||||
pub const UPGRADE_PUBLIC_KEY: &[u8; UPGRADE_PUBLIC_KEY_LENGTH] =
|
pub const UPGRADE_PUBLIC_KEY: &[u8; UPGRADE_PUBLIC_KEY_LENGTH] =
|
||||||
include_bytes!(concat!(env!("OUT_DIR"), "/opensk_upgrade_pubkey_cbor.bin"));
|
include_bytes!(concat!(env!("OUT_DIR"), "/opensk_upgrade_pubkey.bin"));
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ use self::credential_id::{
|
|||||||
use self::credential_management::process_credential_management;
|
use self::credential_management::process_credential_management;
|
||||||
use self::crypto_wrapper::PrivateKey;
|
use self::crypto_wrapper::PrivateKey;
|
||||||
use self::data_formats::{
|
use self::data_formats::{
|
||||||
AuthenticatorTransport, CoseKey, CredentialProtectionPolicy, EnterpriseAttestationMode,
|
AuthenticatorTransport, CredentialProtectionPolicy, EnterpriseAttestationMode,
|
||||||
GetAssertionExtensions, PackedAttestationStatement, PinUvAuthProtocol,
|
GetAssertionExtensions, PackedAttestationStatement, PinUvAuthProtocol,
|
||||||
PublicKeyCredentialDescriptor, PublicKeyCredentialParameter, PublicKeyCredentialSource,
|
PublicKeyCredentialDescriptor, PublicKeyCredentialParameter, PublicKeyCredentialSource,
|
||||||
PublicKeyCredentialType, PublicKeyCredentialUserEntity, SignatureAlgorithm,
|
PublicKeyCredentialType, PublicKeyCredentialUserEntity, SignatureAlgorithm,
|
||||||
@@ -266,9 +266,8 @@ fn verify_signature(
|
|||||||
) -> Result<(), Ctap2StatusCode> {
|
) -> Result<(), Ctap2StatusCode> {
|
||||||
let signature = ecdsa::Signature::from_bytes(signature_bytes)
|
let signature = ecdsa::Signature::from_bytes(signature_bytes)
|
||||||
.ok_or(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)?;
|
.ok_or(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)?;
|
||||||
let cbor_public_key = cbor_read(public_key_bytes)?;
|
let public_key = ecdsa::PubKey::from_bytes_uncompressed(public_key_bytes)
|
||||||
let cose_key = CoseKey::try_from(cbor_public_key)?;
|
.ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)?;
|
||||||
let public_key = ecdsa::PubKey::try_from(cose_key)?;
|
|
||||||
if !public_key.verify_hash_vartime(signed_hash, &signature) {
|
if !public_key.verify_hash_vartime(signed_hash, &signature) {
|
||||||
return Err(Ctap2StatusCode::CTAP2_ERR_INTEGRITY_FAILURE);
|
return Err(Ctap2StatusCode::CTAP2_ERR_INTEGRITY_FAILURE);
|
||||||
}
|
}
|
||||||
@@ -3492,18 +3491,13 @@ mod test {
|
|||||||
metadata[32..96].copy_from_slice(&signature_bytes);
|
metadata[32..96].copy_from_slice(&signature_bytes);
|
||||||
|
|
||||||
let public_key = private_key.genpk();
|
let public_key = private_key.genpk();
|
||||||
let mut public_key_bytes = vec![];
|
let mut public_key_bytes = [0; 65];
|
||||||
cbor_write(
|
public_key.to_bytes_uncompressed(&mut public_key_bytes);
|
||||||
cbor::Value::from(CoseKey::from(public_key)),
|
|
||||||
&mut public_key_bytes,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_metadata(upgrade_locations, &public_key_bytes, &metadata),
|
parse_metadata(upgrade_locations, &public_key_bytes, &metadata),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
|
||||||
// Any manipulation of data fails.
|
// Any manipulation of data fails.
|
||||||
metadata[METADATA_SIGN_OFFSET] = 0x88;
|
metadata[METADATA_SIGN_OFFSET] = 0x88;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -3542,12 +3536,8 @@ mod test {
|
|||||||
signature.to_bytes(&mut signature_bytes);
|
signature.to_bytes(&mut signature_bytes);
|
||||||
|
|
||||||
let public_key = private_key.genpk();
|
let public_key = private_key.genpk();
|
||||||
let mut public_key_bytes = vec![];
|
let mut public_key_bytes = [0; 65];
|
||||||
cbor_write(
|
public_key.to_bytes_uncompressed(&mut public_key_bytes);
|
||||||
cbor::Value::from(CoseKey::from(public_key)),
|
|
||||||
&mut public_key_bytes,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
verify_signature(&signature_bytes, &public_key_bytes, &signed_hash),
|
verify_signature(&signature_bytes, &public_key_bytes, &signed_hash),
|
||||||
@@ -3560,7 +3550,7 @@ mod test {
|
|||||||
public_key_bytes[0] ^= 0x01;
|
public_key_bytes[0] ^= 0x01;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
verify_signature(&signature_bytes, &public_key_bytes, &signed_hash),
|
verify_signature(&signature_bytes, &public_key_bytes, &signed_hash),
|
||||||
Err(Ctap2StatusCode::CTAP2_ERR_INVALID_CBOR)
|
Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)
|
||||||
);
|
);
|
||||||
public_key_bytes[0] ^= 0x01;
|
public_key_bytes[0] ^= 0x01;
|
||||||
signature_bytes[0] ^= 0x01;
|
signature_bytes[0] ^= 0x01;
|
||||||
|
|||||||
Reference in New Issue
Block a user