Skip to content

Latest commit

 

History

History
1033 lines (759 loc) · 26.5 KB

File metadata and controls

1033 lines (759 loc) · 26.5 KB

Bundle Tool

A command-line utility for creating, inspecting, and manipulating Bundle Protocol version 7 (BPv7) bundles as defined in RFC 9171.

Table of Contents

Overview

The bundle tool provides a comprehensive set of subcommands for working with DTN bundles:

  • Bundle Creation: Create new bundles from payload data
  • Inspection: Examine bundle structure and content
  • Block Manipulation: Add, remove, and update extension blocks
  • Security Operations: Sign, encrypt, and verify blocks using BPSec (RFC 9172/9173)
  • Validation: Verify bundle correctness

Building

cargo build --release -p hardy-bpv7-tools

The binary will be available at target/release/bundle.

Common Workflows

Creating and Inspecting a Bundle

# Create a bundle with inline payload
bundle create \
  --source dtn://node1/app \
  --destination dtn://node2/app \
  --payload "Hello, DTN!" \
  --output hello.bundle

# Or from stdin
echo "Hello, DTN!" | bundle create \
  --source dtn://node1/app \
  --destination dtn://node2/app \
  --payload-file - \
  --output hello.bundle

# Inspect bundle (human-readable format)
bundle inspect hello.bundle

# Inspect bundle (JSON format)
bundle inspect --format json hello.bundle

# Inspect bundle (pretty-printed JSON)
bundle inspect --format json-pretty hello.bundle

Securing Bundles with BPSec

# Sign block 1 (payload) using HMAC-SHA256
bundle sign -b 1 \
  --keys keys.json \
  --kid hmackey \
  --output signed.bundle \
  input.bundle

# Encrypt block 1 using AES-GCM
bundle encrypt -b 1 \
  --keys keys.json \
  --kid aesgcmkey \
  --output encrypted.bundle \
  signed.bundle

# Verify signature
bundle verify -b 1 \
  --keys keys.json \
  signed.bundle

# Extract payload from encrypted bundle
bundle extract -b 1 \
  --keys keys.json \
  --output payload.dat \
  encrypted.bundle

Working with Extension Blocks

# Add a hop-count block
bundle add-block --type hop-count \
  --payload "hop-limit: 32" \
  --flags must-replicate \
  --output with-hop.bundle \
  input.bundle

# Update block 2's payload and flags
bundle update-block -n 2 \
  --payload "updated data" \
  --flags must-replicate,report-on-failure \
  --output updated.bundle \
  input.bundle

# Remove block 2
bundle remove-block -n 2 \
  --output cleaned.bundle \
  input.bundle

Subcommand Reference

create

Create a new bundle with payload.

Usage:

bundle create [OPTIONS] --source <EID> --destination <EID> (--payload <STRING> | --payload-file <FILE>)

Required Arguments:

  • -s, --source <EID> - Source Endpoint ID (e.g., dtn://node/service or ipn:1.2, see RFC 9171 §4.2.5 and RFC 9758)
  • -d, --destination <EID> - Destination Endpoint ID
  • Payload (one required):
    • -p, --payload <STRING> - Payload as string
    • --payload-file <FILE> - Payload from file (use - for stdin)

Optional Arguments:

  • -r, --report-to <EID> - Report-to Endpoint ID
  • -o, --output <OUTPUT> - Output file (default: stdout)
  • -f, --flags <FLAGS> - Bundle processing flags (comma-separated, see RFC 9171 §4.2.3):
    • all, none
    • admin-record, admin
    • do-not-fragment, dnf
    • ack-requested, ack
    • report-status-time, time
    • report-receiption, rcv
    • report-forwarding, fwd
    • report-delivery, dlv
    • report-deletion, del
  • -c, --crc-type <TYPE> - CRC type for both the primary and payload blocks (see RFC 9171 §4.2.1): crc16, crc32 (default: crc32). Note: none is not allowed for bundle creation because the primary block requires a CRC per RFC 9171 §4.3.1. Use update-block after creation to set a different CRC type for the payload block (e.g., bundle update-block -n 1 --crc-type none).
  • -l, --lifetime <DURATION> - Bundle lifetime (default: 24h)
  • -H, --hop-limit <COUNT> - Maximum hop count

Examples:

# Create bundle with payload from file
bundle create \
  --source dtn://node1/app \
  --destination dtn://node2/app \
  --payload-file message.txt \
  --flags do-not-fragment \
  --crc-type crc32 \
  --lifetime 48h \
  --output bundle.cbor

# Create bundle with inline payload
bundle create \
  --source dtn://node1/app \
  --destination dtn://node2/app \
  --payload "Hello, DTN!" \
  --output bundle.cbor

inspect

Inspect and display bundle information in various formats.

Usage:

bundle inspect [OPTIONS] [INPUT]

Arguments:

  • <INPUT> - Bundle file path (use - for stdin)

Optional Arguments:

  • --format <FORMAT> - Output format (default: markdown):
    • markdown - Human-readable markdown format (default)
    • json - Machine-readable JSON format
    • json-pretty - Pretty-printed JSON format
  • -o, --output <OUTPUT> - Output file (default: stdout)
  • --keys <JWKS> - Key set for decrypting blocks during inspection (JSON string or file path)

Examples:

# Display bundle in human-readable format
bundle inspect bundle.cbor

# Output as JSON for machine processing
bundle inspect --format json bundle.cbor

# Pretty-print JSON and save to file
bundle inspect --format json-pretty -o bundle.json bundle.cbor

# Inspect bundle with encrypted blocks (requires keys)
bundle inspect --keys keys.json encrypted.bundle

validate

Check one or more bundles for validity.

Usage:

bundle validate [OPTIONS] [INPUT]...

Arguments:

  • <INPUT>... - One or more bundle files to validate

Optional Arguments:

  • --keys <JWKS> - Key set for validating encrypted bundles (JSON string or file path)

Example:

# Validate multiple bundles
bundle validate bundle1.cbor bundle2.cbor bundle3.cbor

# Validate bundle with encrypted blocks
bundle validate --keys keys.json encrypted.bundle

rewrite

Rewrite a bundle, removing unsupported blocks and canonicalizing.

Usage:

bundle rewrite [OPTIONS] [INPUT]

Arguments:

  • <INPUT> - Bundle file path (use - for stdin)

Optional Arguments:

  • -o, --output <OUTPUT> - Output file (default: stdout)
  • --keys <JWKS> - Key set for processing encrypted bundles (JSON string or file path)

Example:

bundle rewrite --output clean.bundle bundle.cbor

extract

Extract the payload or data from a specific block. If the block is encrypted, it will be automatically decrypted if keys are provided.

Usage:

bundle extract [OPTIONS] [INPUT]

Arguments:

  • <INPUT> - Bundle file path (use - for stdin)

Optional Arguments:

  • -b, --block <NUMBER> - Block number to extract (default: 1 - payload). Block 0 is the primary block, block 1 is the payload, blocks 2+ are extension blocks (see RFC 9171 §4.1)
  • -o, --output <OUTPUT> - Output file (default: stdout)
  • --keys <JWKS> - Key set for decrypting encrypted blocks (JSON string or file path)

Example:

# Extract payload
bundle extract bundle.cbor > payload.dat

# Extract block 3 data
bundle extract -b 3 bundle.cbor > block3.dat

# Extract encrypted payload
bundle extract --keys keys.json encrypted.bundle > payload.dat

Verifying Encryption Before Extraction:

The extract command will transparently decrypt blocks if keys are provided, regardless of whether the block was actually encrypted. To verify that a block is protected by a BCB before extracting (strict decryption), use inspect with jq:

# Check if block 1 is encrypted (has a bcb field), then extract
if bundle inspect --format json input.bundle | jq -e '.blocks["1"].bcb' > /dev/null 2>&1; then
    bundle extract --keys keys.json input.bundle > payload.dat
else
    echo "Error: Block 1 is not encrypted" >&2
    exit 1
fi

add-block

Add an extension block to a bundle.

Usage:

bundle add-block [OPTIONS] --type <TYPE> [INPUT]

Required Arguments:

  • -t, --type <TYPE> - Block type (see RFC 9171 §4.1):
    • bundle-age (alias: age)
    • hop-count (alias: hop)
    • previous-node (alias: prev)
    • block-integrity (alias: bib)
    • block-security (alias: bcb)
    • Numeric type code (e.g., 192 for custom block types)

Block Content (one required):

  • -p, --payload <STRING> - Payload as string
  • --payload-file <FILE> - Payload from file (use - for stdin)

Optional Arguments:

  • -o, --output <OUTPUT> - Output file (default: stdout)
  • -f, --flags <FLAGS> - Block processing flags (comma-separated, see RFC 9171 §4.2.4):
    • all, none
    • must-replicate, replicate
    • report-on-failure, report
    • delete-bundle-on-failure, delete-bundle
    • delete-block-on-failure, delete-block
  • -c, --crc-type <TYPE> - CRC type for the block
  • --force - Replace existing block of same type if present
  • --keys <JWKS> - Key set for parsing bundles with encrypted blocks (JSON string or file path)

Example:

# Add a bundle-age block
bundle add-block --type bundle-age \
  --payload "12345" \
  --flags must-replicate \
  --output with-age.bundle \
  input.bundle

# Add block with force (replace if exists)
bundle add-block --type hop-count \
  --payload "data" \
  --force \
  input.bundle

update-block

Update an existing block's payload, flags, or CRC. If the block is a security target of a BIB or BCB, it will be automatically removed from those target lists (since the signature/encryption would be invalid after modification). If the BIB itself is encrypted, use remove-integrity first.

Usage:

bundle update-block [OPTIONS] --block-number <NUMBER> [INPUT]

Arguments:

  • <INPUT> - Bundle file path (use - for stdin)

Required Arguments:

  • -n, --block-number <NUMBER> - Block number to update

Update Options (at least one):

  • -p, --payload <STRING> - New payload as string
  • --payload-file <FILE> - New payload from file (use - for stdin)
  • -f, --flags <FLAGS> - New block processing flags (comma-separated, same as add-block)
  • -c, --crc-type <TYPE> - New CRC type

Other Arguments:

  • -o, --output <OUTPUT> - Output file (default: stdout)
  • --keys <JWKS> - Key set for parsing bundles with encrypted blocks (JSON string or file path)

Example:

# Update payload and flags of block 2
bundle update-block -n 2 \
  --payload "new data" \
  --flags must-replicate,report-on-failure \
  --output updated.bundle \
  input.bundle

# Update only CRC type
bundle update-block -n 3 \
  --crc-type crc32 \
  input.bundle

update-primary

Update the primary block of a bundle, including lifetime, creation timestamp, source, destination, report-to EID, flags, or CRC type. If the primary block is protected by a BIB, use remove-integrity first to remove the signature.

Usage:

bundle update-primary [OPTIONS] [INPUT]

Arguments:

  • <INPUT> - Bundle file path (use - for stdin)

Update Options (at least one required):

  • -l, --lifetime <DURATION> - New lifetime duration (e.g., 1year, 30days, 24h)
  • -t, --reset-timestamp - Reset creation timestamp to now
  • -s, --source <EID> - New source Endpoint ID
  • -d, --destination <EID> - New destination Endpoint ID
  • -r, --report-to <EID> - New report-to Endpoint ID
  • -f, --flags <FLAGS> - Bundle processing flags (comma-separated, replaces existing flags)
  • -c, --crc-type <TYPE> - CRC type for the primary block

Other Arguments:

  • -o, --output <OUTPUT> - Output file (default: stdout)
  • --keys <JWKS> - Key set for parsing bundles with encrypted blocks (JSON string or file path)

Examples:

# Extend lifetime to 1 year and reset timestamp
bundle update-primary \
  --lifetime 1year \
  --reset-timestamp \
  --output refreshed.bundle \
  input.bundle

# Update just the lifetime (keep original timestamp)
bundle update-primary \
  --lifetime 30days \
  --output updated.bundle \
  input.bundle

# Change destination EID
bundle update-primary \
  --destination dtn://newnode/app \
  --output redirected.bundle \
  input.bundle

# Update flags
bundle update-primary \
  --flags do-not-fragment,report-delivery \
  --output updated.bundle \
  input.bundle

Note: If the primary block is signed by a BIB, you must first remove the integrity protection:

bundle remove-integrity -b 0 input.bundle | \
  bundle update-primary --lifetime 1year - \
  > updated.bundle

remove-block

Remove an extension block from a bundle. If the block is a security target of a BIB or BCB, it will be automatically removed from those target lists. If the BIB itself is encrypted, use remove-integrity first.

Usage:

bundle remove-block [OPTIONS] --block-number <NUMBER> [INPUT]

Arguments:

  • <INPUT> - Bundle file path (use - for stdin)

Required Arguments:

  • -n, --block-number <NUMBER> - Block number to remove (cannot remove block 0 or 1)

Optional Arguments:

  • -o, --output <OUTPUT> - Output file (default: stdout)
  • --keys <JWKS> - Key set for parsing bundles with encrypted blocks (JSON string or file path)

Example:

bundle remove-block -n 2 --output cleaned.bundle input.bundle

sign

Sign a block using BPSec Block Integrity Block (BIB) with HMAC-SHA2 (see RFC 9173 §3).

Usage:

bundle sign [OPTIONS] (--key <KEY> | --keys <KEYS> --kid <KEY_ID>) [INPUT]

Arguments:

  • <INPUT> - Bundle file path (use - for stdin)

Key Specification (one required):

  • --key <KEY> - Single JWK key (JSON string or file path)
  • --keys <KEYS> --kid <KEY_ID> - Select key from JWKS by key ID. The full keyset is also used to parse bundles with encrypted blocks.

Optional Arguments:

  • -b, --block <NUMBER> - Block number to sign (default: 1)
  • -o, --output <OUTPUT> - Output file (default: stdout)
  • -s, --source <EID> - Security source EID (default: bundle source)
  • -f, --flags <FLAGS> - BPSec scope flags control Additional Authenticated Data (comma-separated, see RFC 9172 §3.6):
    • all - Include all in AAD (default when no flags specified)
    • none - Clear all flags
    • primary - Include primary block
    • target - Include target header
    • source - Include security source header

Examples:

# Using a key from a JWKS file
bundle sign -b 1 \
  --keys keys.json \
  --kid hmackey \
  --flags primary,target \
  --output signed.bundle \
  input.bundle

# Using a single JWK key
bundle sign -b 1 \
  --key '{"kty":"oct","k":"..."}' \
  --output signed.bundle \
  input.bundle

verify

Verify the integrity signature of a block.

Usage:

bundle verify [OPTIONS] [INPUT]

Arguments:

  • <INPUT> - Bundle file path (use - for stdin)

Optional Arguments:

  • -b, --block <NUMBER> - Block number to verify (default: 1)
  • --keys <JWKS> - Key set for verification (JSON string or file path)

Example:

bundle verify -b 1 \
  --keys keys.json \
  signed.bundle

remove-integrity

Remove a block from BIB protection. This command removes the specified block from the BIB's security target list, discarding its integrity signature. The BIB itself is only removed from the bundle if it has no remaining security targets (see RFC 9172 §3.4).

Usage:

bundle remove-integrity [OPTIONS] [INPUT]

Arguments:

  • <INPUT> - Bundle file path (use - for stdin)

Optional Arguments:

  • -b, --block <NUMBER> - Block number to remove integrity protection from (default: 1)
  • -o, --output <OUTPUT> - Output file (default: stdout)
  • --keys <JWKS> - Key set for processing (JSON string or file path)

Example:

bundle remove-integrity -b 1 --output unsigned.bundle signed.bundle

encrypt

Encrypt a block using BPSec Block Confidentiality Block (BCB) with AES-GCM (see RFC 9173 §4).

Usage:

bundle encrypt [OPTIONS] (--key <KEY> | --keys <KEYS> --kid <KEY_ID>) [INPUT]

Arguments:

  • <INPUT> - Bundle file path (use - for stdin)

Key Specification (one required):

  • --key <KEY> - Single JWK key (JSON string or file path)
  • --keys <KEYS> --kid <KEY_ID> - Select key from JWKS by key ID. The full keyset is also used to parse bundles with encrypted blocks.

Optional Arguments:

  • -b, --block <NUMBER> - Block number to encrypt (default: 1)
  • -o, --output <OUTPUT> - Output file (default: stdout)
  • -s, --source <EID> - Security source EID (default: bundle source)
  • -f, --flags <FLAGS> - BPSec scope flags (comma-separated, see RFC 9172 §3.6, same as sign)

Example:

bundle encrypt -b 1 \
  --keys keys.json \
  --kid aesgcmkey \
  --output encrypted.bundle \
  input.bundle

remove-encryption

Decrypt a block and remove it from BCB protection. This command removes the specified block from the BCB's security target list and restores the block's plaintext data. The BCB itself is only removed from the bundle if it has no remaining security targets (see RFC 9172 §3.4).

Usage:

bundle remove-encryption [OPTIONS] [INPUT]

Arguments:

  • <INPUT> - Bundle file path (use - for stdin)

Optional Arguments:

  • -b, --block <NUMBER> - Block number to remove encryption from (default: 1)
  • -o, --output <OUTPUT> - Output file (default: stdout)
  • --keys <JWKS> - Key set for decryption (JSON string or file path)

Example:

bundle remove-encryption -b 1 \
  --keys keys.json \
  --output decrypted.bundle \
  encrypted.bundle

Working with Keys

BPSec operations use JSON Web Key (JWK) format as defined in RFC 7517.

Key Structure

A JWK key consists of several fields that determine its usage:

Required Fields:

  • kty (Key Type): "oct" for symmetric keys (most common for BPSec)
  • k (Key Value): Base64url-encoded key material

Important Optional Fields:

  • kid (Key ID): String identifier for the key (e.g., "hmackey")
  • alg (Algorithm): Key management/signing algorithm (see below)
  • enc (Encryption Algorithm): Content encryption algorithm (for encryption operations)
  • key_ops (Key Operations): Array of permitted operations (e.g., ["sign", "verify"])
  • use (Public Key Use): "sig" for signature or "enc" for encryption

Supported Algorithms

Key/Signing Algorithms (alg):

  • dir - Direct use (key used as-is)
  • HS256, HS384, HS512 - HMAC with SHA-256/384/512
  • A128KW, A192KW, A256KW - AES Key Wrap (128/192/256-bit)
  • Combined: HS256+A128KW, HS384+A256KW, etc.

Content Encryption Algorithms (enc):

  • A128GCM - AES-128-GCM
  • A256GCM - AES-256-GCM

Key Operations (key_ops):

  • sign - Create digital signatures (BIB)
  • verify - Verify digital signatures
  • encrypt - Encrypt content (BCB)
  • decrypt - Decrypt content
  • wrapKey / unwrapKey - Key wrapping operations

Generating Keys

You can generate JWK keys using standard Linux utilities like openssl. The key material must be base64url-encoded (RFC 4648 §5).

Generate HMAC-SHA256 Key (256-bit for signing):

# Generate 32 random bytes and convert to base64url
K=$(openssl rand 32 | base64 | tr '+/' '-_' | tr -d '=')

# Create JWK
cat > hmac-key.json <<EOF
{
  "kty": "oct",
  "kid": "hmackey",
  "alg": "HS256",
  "key_ops": ["sign", "verify"],
  "k": "$K"
}
EOF

Generate AES-128-GCM Key (128-bit for encryption):

# Generate 16 random bytes and convert to base64url
K=$(openssl rand 16 | base64 | tr '+/' '-_' | tr -d '=')

# Create JWK
cat > aes128-key.json <<EOF
{
  "kty": "oct",
  "kid": "aes128key",
  "alg": "dir",
  "enc": "A128GCM",
  "key_ops": ["encrypt", "decrypt"],
  "k": "$K"
}
EOF

Generate AES-256-GCM Key (256-bit for encryption):

# Generate 32 random bytes and convert to base64url
K=$(openssl rand 32 | base64 | tr '+/' '-_' | tr -d '=')

# Create JWK
cat > aes256-key.json <<EOF
{
  "kty": "oct",
  "kid": "aes256key",
  "alg": "dir",
  "enc": "A256GCM",
  "key_ops": ["encrypt", "decrypt"],
  "k": "$K"
}
EOF

Create a JWKS Key Set:

# Combine multiple keys into a key set using jq
jq -n --slurpfile hmac hmac-key.json \
      --slurpfile aes128 aes128-key.json \
      --slurpfile aes256 aes256-key.json \
      '{keys: [$hmac[0], $aes128[0], $aes256[0]]}' > keys.json

# Or manually create the key set
cat > keys.json <<'EOF'
{
  "keys": [
    {
      "kty": "oct",
      "kid": "hmackey",
      "alg": "HS256",
      "key_ops": ["sign", "verify"],
      "k": "YOUR_BASE64URL_HMAC_KEY_HERE"
    },
    {
      "kty": "oct",
      "kid": "aes128key",
      "alg": "dir",
      "enc": "A128GCM",
      "key_ops": ["encrypt", "decrypt"],
      "k": "YOUR_BASE64URL_AES128_KEY_HERE"
    },
    {
      "kty": "oct",
      "kid": "aes256key",
      "alg": "dir",
      "enc": "A256GCM",
      "key_ops": ["encrypt", "decrypt"],
      "k": "YOUR_BASE64URL_AES256_KEY_HERE"
    }
  ]
}
EOF

Note: Base64url encoding differs from standard base64:

  • Uses - instead of +
  • Uses _ instead of /
  • Omits padding = characters

Complete Example - Generate Keys and Use Them:

# 1. Generate an HMAC key for signing
K=$(openssl rand 32 | base64 | tr '+/' '-_' | tr -d '=')
cat > test-hmac.json <<EOF
{
  "kty": "oct",
  "kid": "test-hmac",
  "alg": "HS256",
  "key_ops": ["sign", "verify"],
  "k": "$K"
}
EOF

# 2. Generate an AES key for encryption
K=$(openssl rand 16 | base64 | tr '+/' '-_' | tr -d '=')
cat > test-aes.json <<EOF
{
  "kty": "oct",
  "kid": "test-aes",
  "alg": "dir",
  "enc": "A128GCM",
  "key_ops": ["encrypt", "decrypt"],
  "k": "$K"
}
EOF

# 3. Create a key set
jq -n --slurpfile hmac test-hmac.json \
      --slurpfile aes test-aes.json \
      '{keys: [$hmac[0], $aes[0]]}' > test-keys.json

# 4. Use the keys with bundle tool
echo "Test message" | \
  bundle create -s dtn://alice -d dtn://bob --payload-file - | \
  bundle sign -b 1 --keys test-keys.json --kid test-hmac - | \
  bundle encrypt -b 1 --keys test-keys.json --kid test-aes - | \
  bundle remove-encryption -b 1 --keys test-keys.json - | \
  bundle verify --keys test-keys.json - | \
  bundle extract -

Key Selection

For signing/encryption operations:

  • With --key <JWK>: The provided key is used directly
  • With --keys <JWKS> --kid <KEY_ID>: The key with matching kid is selected

For verification/decryption operations:

  • With --keys <JWKS>: The tool automatically selects keys that:
    1. Have the required operation in their key_ops field
    2. Match the algorithm specified in the security block

Example Keys

HMAC-SHA256 Key for Signing:

{
  "kty": "oct",
  "kid": "hmackey",
  "alg": "HS256",
  "key_ops": ["sign", "verify"],
  "k": "AES256...base64url..."
}

AES-GCM Key for Encryption:

{
  "kty": "oct",
  "kid": "aesgcmkey",
  "alg": "dir",
  "enc": "A128GCM",
  "key_ops": ["encrypt", "decrypt"],
  "k": "AES128...base64url..."
}

JWKS Key Set:

{
  "keys": [
    {
      "kty": "oct",
      "kid": "hmackey",
      "alg": "HS256",
      "key_ops": ["sign", "verify"],
      "k": "..."
    },
    {
      "kty": "oct",
      "kid": "aesgcmkey",
      "alg": "dir",
      "enc": "A256GCM",
      "key_ops": ["encrypt", "decrypt"],
      "k": "..."
    }
  ]
}

Usage Examples

# Using a single JWK from a file
bundle sign -b 1 --key mykey.jwk input.bundle

# Using a single JWK as JSON string
bundle sign -b 1 --key '{"kty":"oct","alg":"HS256","k":"..."}' input.bundle

# Using a key from a JWKS file by kid
bundle sign -b 1 --keys keys.json --kid hmackey input.bundle

# Verification automatically finds the right key based on key_ops
bundle verify -b 1 --keys keys.json signed.bundle

# Encryption with specific key
bundle encrypt -b 1 --keys keys.json --kid aesgcmkey input.bundle

# Extract from encrypted bundle (automatically decrypts with matching key)
bundle extract -b 1 --keys keys.json encrypted.bundle

Piping and Composition

The tool is designed for Unix-style composition using pipes:

# Create, sign, encrypt, and save in one pipeline
echo "Secret message" | \
  bundle create -s dtn://alice/app -d dtn://bob/app --payload-file - | \
  bundle sign -b 1 --keys keys.json --kid sign-key | \
  bundle encrypt -b 1 --keys keys.json --kid encrypt-key \
  > secure.bundle

# Remove encryption, verify, and extract
bundle remove-encryption -b 1 --keys keys.json secure.bundle | \
  bundle verify --keys keys.json - | \
  bundle extract - > message.txt

Exit Codes

  • 0 - Success
  • Non-zero - Error (with diagnostic message to stderr)

See Also