web-auth / cose-lib Goto Github PK
View Code? Open in Web Editor NEWCose Key and Algorithms support
License: MIT License
Cose Key and Algorithms support
License: MIT License
Current git master
Is it intentional that this file exists in git:
https://github.com/web-auth/cose-lib/blob/v4.0/infection.txt?
If it is, then it should be added to .gitattributes
as export-ignore
, otherwise consumers will need to download 250kB of useless text.
Look at the git repository.
Delete the file.
No response
4.0.5
https://github.com/web-auth/cose-lib/search?q=COSE_ALGORITHM_EdDSA 👀
Change it to COSE_ALGORITHM_EDDSA
4.2.0
When you check fields 1 and -1 of an OKP key, you assume the value is an integer, or following rfc9053, it can also be a text string. So if I have a registered key and the cbor map contains tstr as values and not integer, verify
throw an exception.
Linked to issue 448 of web-auth/webauthn-framework
(web-auth/webauthn-framework#448)
With this binary key:
0xA401634F4B50032720674564323535313921582098C91448E657A3366C3C04551DAFD92A8BB2BA35138B4ACB94CA1E79D2627BAE
{1: "OKP", 3: -8, -1: "Ed25519", -2: h'98C91448E657A3366C3C04551DAFD92A8BB2BA35138B4ACB94CA1E79D2627BAE'}
Currently the lib throw an exception but the key is valid.
No response
No response
I’ve been looking for a COSEToPEMConverter that’s compatible with PHP 5.6, because the minimum requirement for web-auth/cose-lib is PHP 7.0. It’s been a desperate search, taking up 2 weeks of my time. If anyone else finds this library and realizes their version is also PHP 5.6, you can try it out, giving you a glimmer of hope. This is just the most basic support, I’ve only tested it with Windows Hello, I can’t afford to buy a physical key because it’s too expensive. So, I haven’t tried ES256, but RSA works fine.
class COSEToPEMConverter_v2 {
public function extractCoseKeyAndAlg($attestationObject) {
$attestationObject_decode = base64url_decode($attestationObject);
$decoder = new CBOREncoder();
$decoded = $decoder->decode($attestationObject_decode);
// Extract attStmt from decoded structure
$attStmt = $decoded['attStmt'];
$alg = $attStmt['alg'];
// Extract authData from decoded structure
$authData = $decoded['authData']->get_byte_string();
$coseKey = $this->extractCoseKeyFromAuthData($authData);
return ['coseKey'=>$coseKey, 'alg'=> $alg];
}
private function extractCoseKeyFromAuthData($authData) {
$offset = 37; // RP ID Hash (32) + Flags (1) + Sign Count (4)
$aaguid = substr($authData, $offset, 16);
$offset += 16;
$credentialIdLength = unpack('n', substr($authData, $offset, 2))[1];
$offset += 2;
$credentialId = substr($authData, $offset, $credentialIdLength);
$offset += $credentialIdLength;
// The remaining data is the COSE Key
$coseKey = substr($authData, $offset);
return $coseKey;
}
public function createPemFromCoseKey($coseKey, $alg) {
$decoder = new CBOREncoder();
$coseData = $decoder->decode($coseKey);
// Debug: Print the COSE data
//var_dump($coseData);
if ($alg == -257) { // RS256 algorithm
$n = $coseData[-1]->get_byte_string();
$e = $coseData[-2]->get_byte_string();
// Debug: Print the key parameters
// var_dump($n, $e);
$asn1 = $this->buildRsaPublicKey($n, $e);
$pem = "-----BEGIN PUBLIC KEY-----\n";
$pem .= chunk_split(base64_encode($asn1), 64, "\n");
$pem .= "-----END PUBLIC KEY-----\n";
return $pem;
} elseif ($alg == -7) { // ES256 (ECDSA) algorithm
$x = $coseData[-2]->get_byte_string();
$y = $coseData[-3]->get_byte_string();
// Debug: Print the key parameters
//var_dump($x, $y);
$asn1 = $this->buildEcdsaPublicKey($x, $y);
$pem = "-----BEGIN PUBLIC KEY-----\n";
$pem .= chunk_split(base64_encode($asn1), 64, "\n");
$pem .= "-----END PUBLIC KEY-----\n";
return $pem;
} else {
throw new Exception('Unsupported key type or algorithm');
}
}
private function buildRsaPublicKey($n, $e) {
// Ensure the length of n and e are correctly encoded in ASN.1 format
$n = ltrim($n, "\x00"); // Remove leading null bytes
$e = ltrim($e, "\x00"); // Remove leading null bytes
// ASN.1 structure
$asn1_n = "\x02" . $this->lengthBytes(strlen($n)) . $n;
$asn1_e = "\x02" . $this->lengthBytes(strlen($e)) . $e;
$asn1_seq = "\x30" . $this->lengthBytes(strlen($asn1_n) + strlen($asn1_e)) . $asn1_n . $asn1_e;
$asn1_bitstring = "\x03" . $this->lengthBytes(strlen($asn1_seq) + 1) . "\x00" . $asn1_seq;
$asn1_algo = "\x30\x0D\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00";
$asn1_pubkey = "\x30" . $this->lengthBytes(strlen($asn1_algo) + strlen($asn1_bitstring)) . $asn1_algo . $asn1_bitstring;
return $asn1_pubkey;
}
private function buildEcdsaPublicKey($x, $y) {
// Ensure the length of x and y are correctly encoded in ASN.1 format
$x = ltrim($x, "\x00"); // Remove leading null bytes
$y = ltrim($y, "\x00"); // Remove leading null bytes
$ecPublicKey = "\x04" . $x . $y;
// ASN.1 structure
$asn1_bitstring = "\x03" . $this->lengthBytes(strlen($ecPublicKey) + 1) . "\x00" . $ecPublicKey;
$asn1_algo = "\x30\x13\x06\x07\x2A\x86\x48\xCE\x3D\x02\x01\x06\x08\x2A\x86\x48\xCE\x3D\x03\x01\x07";
$asn1_pubkey = "\x30" . $this->lengthBytes(strlen($asn1_algo) + strlen($asn1_bitstring)) . $asn1_algo . $asn1_bitstring;
return $asn1_pubkey;
}
private function lengthBytes($length) {
if ($length < 128) {
return chr($length);
} elseif ($length < 256) {
return "\x81" . chr($length);
} else {
return "\x82" . pack('n', $length);
}
}
}
function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
function base64url_decode($data) {
return base64_decode(strtr($data, '-_', '+/'));
}
使用方法:
// Decode the CBOR object
// composer require 2tvenom/cborencode 安装命令
$converter = new COSEToPEMConverter_v2();
$CoseKeyAndAlg = $converter->extractCoseKeyAndAlg($attestationObject);
$pemKey = $converter->createPemFromCoseKey($CoseKeyAndAlg['coseKey'], $CoseKeyAndAlg['alg']);
// 创建一个 OpenSSL 公钥资源
$publicKey = openssl_pkey_get_public($pemKey);
备注 :
"The object passed from the front end to the back end depends on the encoding you use. The navigator.credentials.create
function returns a credential
, where attestationObject
is base64url(credential.response.attestationObject)
.
Because I'm using the following function to encode:
function base64url(buffer) {
return btoa(String.fromCharCode.apply(null, new Uint8Array(buffer)))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
Wishing good luck to those who come after, the fallen 5.6.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.