Skip to content

Commit

Permalink
Replace manual concatenation with actual ASN.1 encoder (#78)
Browse files Browse the repository at this point in the history
While on its own the current implementation is perfectly stable due to
fixed lengths, adding support for other formats will become highly
problematic. Instead, replace the ASN.1 handling with a suitable
library.
  • Loading branch information
Firehed authored Mar 10, 2024
1 parent ef12eb8 commit 69fdcd3
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 16 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"ext-gmp": "*",
"ext-hash": "*",
"ext-openssl": "*",
"firehed/cbor": "^0.1.0"
"firehed/cbor": "^0.1.0",
"sop/asn1": "^4.1"
},
"require-dev": {
"maglnet/composer-require-checker": "^4.1",
Expand Down
2 changes: 2 additions & 0 deletions src/COSE/Curve.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ enum Curve: int

case ED448 = 7; // OKP

// RFC 5480
// §2.1.1.1 OIDs for named curves
public function getOid(): string
{
return match ($this) {
Expand Down
30 changes: 15 additions & 15 deletions src/PublicKey/EllipticCurve.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Firehed\WebAuthn\COSE;
use Firehed\WebAuthn\COSEKey;
use Firehed\WebAuthn\Errors\VerificationError;
use Sop\ASN1\Type as ASN;
use UnexpectedValueException;

use function gmp_pow;
Expand All @@ -31,6 +32,8 @@
*/
class EllipticCurve implements PublicKeyInterface
{
private const OID = '1.2.840.10045.2.1';

// CBOR decoding: RFC 9053 §7.1.1
private const INDEX_CURVE = -1; // ECC, OKP
private const INDEX_X_COORDINATE = -2; // ECC, OKP
Expand Down Expand Up @@ -121,22 +124,19 @@ public function getPemFormatted(): string
if ($this->curve !== COSE\Curve::P256) {
throw new DomainException('Only P256 curves can be PEM-formatted so far');
}
// Described in RFC 5480
// §2.1.1.1
// Just use an OID calculator to figure out *that* encoding
$der = hex2bin(
'3059' // SEQUENCE, length 89
. '3013' // SEQUENCE, length 19
. '0607' // OID, length 7
. '2a8648ce3d0201' // 1.2.840.10045.2.1 = EC Public Key
. '0608' // OID, length 8
. '2a8648ce3d030107' // 1.2.840.10045.3.1.7 = P-256 Curve
. '0342' // BIT STRING, length 66
. '00' // prepend with NUL
. '04' // uncompressed format

$asn = new ASN\Constructed\Sequence(
new ASN\Constructed\Sequence(
new ASN\Primitive\ObjectIdentifier(self::OID),
new ASN\Primitive\ObjectIdentifier($this->curve->getOid()),
),
new ASN\Primitive\BitString(
"\x04" // Uncompressed
. $this->x->unwrap()
. $this->y->unwrap(),
),
);
$der .= $this->x->unwrap();
$der .= $this->y->unwrap();
$der = $asn->toDER();

$pem = "-----BEGIN PUBLIC KEY-----\n";
$pem .= chunk_split(base64_encode($der), 64, "\n");
Expand Down

0 comments on commit 69fdcd3

Please sign in to comment.