Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Cose Lib Laravel Package

web-auth/cose-lib

PHP 8.1+ COSE (RFC 9052/9053) library for CBOR Object Signing and Encryption. Supports COSE_Sign1/Sign, Encrypt0/Encrypt, Mac0/Mac tags plus ECDSA, EdDSA, RSA/PS and HMAC algorithms; useful for WebAuthn/FIDO2 and certificates.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require web-auth/cose-lib spomky-labs/cbor-php
    

    Ensure PHP 8.1+ with ext-json and ext-openssl enabled.

  2. First Use Case: Verify a COSE_Sign1 signature (e.g., from a WebAuthn attestation or EU Digital COVID Certificate):

    use CBOR\Decoder;
    use CBOR\StringStream;
    use CBOR\Tag\TagManager;
    use Cose\Signature\CoseSign1Tag;
    
    $tagManager = TagManager::create()->add(CoseSign1Tag::class);
    $decoder = Decoder::create($tagManager);
    $stream = new StringStream($cborData);
    $coseSign1 = $decoder->decode($stream);
    
    // Extract components for verification
    $protectedHeader = $coseSign1->getProtectedHeader();
    $payload = $coseSign1->getPayload();
    $signature = $coseSign1->getSignature();
    
  3. Where to Look First:

    • doc/Usage.md: Detailed workflows for all COSE tags.
    • src/Cose/: Core classes (Signature/, Encryption/, Mac/).
    • Test fixtures (tests/): Real-world examples (e.g., COVID certificates).

Implementation Patterns

1. Signature Workflows

Signing Data (COSE_Sign1)

use Cose\Signature\CoseSign1Tag;
use CBOR\MapObject;

// 1. Define headers (alg, kid)
$protectedHeader = MapObject::create([
    [1, -7], // ES256
    [4, 'key-id'] // kid
]);

// 2. Generate signature (using `web-token/jwt-framework` or `paragonie/sodium`)
$signature = generateEcdsaSignature($privateKey, $payload);

// 3. Create COSE_Sign1
$coseSign1 = CoseSign1Tag::create(
    $protectedHeader,
    MapObject::create(), // unprotected
    $payload,
    $signature
);

Verification Pipeline

// 1. Decode COSE_Sign1
$coseSign1 = $decoder->decode($cborData);

// 2. Reconstruct Sig_structure (RFC 9052 §3.1)
$sigStructure = Signature1::create(
    $coseSign1->getProtectedHeader(),
    $coseSign1->getPayload()
);

// 3. Verify with OpenSSL
$isValid = openssl_verify(
    (string) $sigStructure,
    $signature->getValue(),
    $publicKey,
    'sha256'
);

2. Encryption Workflows

Encrypting for a Single Recipient (COSE_Encrypt0)

use Cose\Encryption\CoseEncrypt0Tag;

// 1. Generate ephemeral key pair and shared secret
$ephemeralKey = generateEcdhKeyPair();
$sharedSecret = deriveSharedSecret($ephemeralKey, $recipientPublicKey);

// 2. Encrypt payload (e.g., using AES-GCM)
$ciphertext = encryptWithAesGcm($sharedSecret, $payload);

// 3. Create COSE_Encrypt0
$protectedHeader = MapObject::create([
    [1, -35], // ECDH-ES-AES128-GCM
    [5, $ephemeralKey->getPublicKey()] // epk
]);

$coseEncrypt0 = CoseEncrypt0Tag::create(
    $protectedHeader,
    MapObject::create([[-1, $iv]]), // IV in unprotected header
    $ciphertext
);

Decryption Pipeline

// 1. Decode COSE_Encrypt0
$coseEncrypt0 = $decoder->decode($cborData);

// 2. Extract ephemeral key and IV
$ephemeralKey = $coseEncrypt0->getProtectedHeaderAsMap()[[5]];
$iv = $coseEncrypt0->getUnprotectedHeader()[[-1]];

// 3. Derive shared secret and decrypt
$sharedSecret = deriveSharedSecret($recipientPrivateKey, $ephemeralKey);
$plaintext = decryptWithAesGcm($sharedSecret, $iv, $ciphertext);

3. MAC Workflows

Generating a MAC (COSE_Mac0)

use Cose\Mac\CoseMac0Tag;

// 1. Generate HMAC (e.g., HS256)
$mac = generateHmac($key, $payload);

// 2. Create COSE_Mac0
$protectedHeader = MapObject::create([[1, 5]]); // HS256
$coseMac0 = CoseMac0Tag::create(
    $protectedHeader,
    MapObject::create(),
    $payload,
    $mac
);

Verification

// 1. Decode COSE_Mac0
$coseMac0 = $decoder->decode($cborData);

// 2. Recompute MAC
$expectedMac = generateHmac($key, $coseMac0->getPayload());

// 3. Compare
$isValid = hash_equals($expectedMac, $coseMac0->getTag());

4. Integration Tips

Laravel Service Provider

// app/Providers/CoseServiceProvider.php
public function register()
{
    $this->app->singleton(CoseDecoder::class, function () {
        $tagManager = TagManager::create()
            ->add(CoseSign1Tag::class)
            ->add(CoseEncrypt0Tag::class);
        return Decoder::create($tagManager);
    });
}

Middleware for COSE Validation

// app/Http/Middleware/ValidateCoseSignature.php
public function handle(Request $request, Closure $next)
{
    $coseData = $request->header('X-Cose-Signature');
    $decoder = app(CoseDecoder::class);
    $coseSign1 = $decoder->decode($coseData);

    if (!$this->verifySignature($coseSign1)) {
        abort(403, 'Invalid COSE signature');
    }

    return $next($request);
}

Key Management

Use Laravel’s Hash facade or web-token/jwt-framework for key storage:

// Store private key (e.g., in config)
config(['cose.keys.private' => $privateKey]);

// Retrieve in a service
$privateKey = config('cose.keys.private');

Gotchas and Tips

Pitfalls

  1. Protected Header Decoding:

    • The protectedHeader in COSE is a CBOR-encoded map, not a plain PHP array. Use getProtectedHeaderAsMap() to decode it:
      $protectedHeaderMap = $coseSign1->getProtectedHeaderAsMap();
      $algorithm = $protectedHeaderMap[[1]]; // ES256 (-7)
      
  2. Signature Structure Reconstruction:

    • The Sig_structure (RFC 9052 §3.1) must include the protected header as a CBOR byte string. Omitting it will cause verification to fail:
      // WRONG: Missing protected header
      $sigStructure = $payload;
      
      // CORRECT: Include protected header
      $sigStructure = Signature1::create(
          $coseSign1->getProtectedHeader(), // <-- Critical!
          $coseSign1->getPayload()
      );
      
  3. Algorithm Mismatch:

    • The alg field in the protected header must match the actual algorithm used to generate the signature. For example:
      • If alg = -7 (ES256), use openssl_verify with 'sha256'.
      • If alg = -8 (EdDSA), use a library like paragonie/sodium:
        $isValid = sodium_crypto_sign_verify_detached(
            $signature,
            (string) $sigStructure,
            $publicKey
        );
        
  4. CBOR Tag Registration:

    • Forge missing tags if the library doesn’t support a COSE tag out of the box. Extend TagManager:
      $tagManager = TagManager::create()
          ->add(CoseSign1Tag::class)
          ->add(MyCustomTag::class); // Your custom tag
      
  5. Key ID (kid) Handling:

    • The kid (key ID) in unprotected headers is not validated by default. Ensure it matches your key storage system:
      $kid = $coseSign1->getUnprotectedHeader()[[4]];
      $publicKey = $this->keyStore->findByKid($kid);
      

Debugging Tips

  1. Inspect CBOR Data: Use `spom
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
andydefer/laravel-actions
aimeos/prisma
besmartand-pro/php-quality-config
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor