Digital signatures
Every signed Broker–Carrier Agreement on CarrierPacket.Link is a real cryptographically-signed PDF using a CMS / PKCS#7 envelope embedded per ISO 32000 PDF signature dictionaries, paired with an external RFC 3161 trusted-timestamp sidecar. Substantively equivalent to PAdES B‑T — same cryptographic anchors, same legal weight under E-SIGN/UETA/eIDAS — with one technical caveat noted in the Known limits section. This page explains what's actually in the bytes and how to verify it yourself.
The standard
The signature is a CMS / PKCS#7 detached envelope embedded in the PDF byte stream per the ISO 32000 signature-dictionary spec, using SubFilter adbe.pkcs7.detached (Adobe's pre-PAdES filter, recognized by every standards-compliant PDF reader). The envelope wraps an X.509 certificate + RSA-2048 + SHA-256 signed-data structure. A RFC 3161 trusted timestamp from FreeTSA is generated alongside as a separate .tsr sidecar file, downloadable from the verification page.
This is functionally equivalent to PAdES B‑T (ETSI EN 319 142) — the cryptographic anchors are identical and the legal weight is the same — but technically uses Adobe's older SubFilter that predates the formal ETSI profile. Compatibility table:
| What it gives you | Our implementation | Strict PAdES B-T equivalent |
|---|---|---|
| Document tamper-evidence | SubFilter adbe.pkcs7.detached over the document ByteRange | SubFilter ETSI.CAdES.detached over the same ByteRange |
| Signer identity | X.509 cert embedded in the CMS envelope | Same |
| Independent signing-time attestation | RFC 3161 TSR as a sidecar .tsr file (download from the verify page) | RFC 3161 TSR embedded as an unsigned attribute on the CMS signature |
| Long-term validation (CRL/OCSP) | Not embedded | Required at PAdES B-LT, not B-T |
For broker–carrier agreements with the typical 30–60 day payment cycle, this profile is the right level. The strict-PAdES upgrade (embedded TSR + ETSI SubFilter) is on the roadmap; it requires either patching our PDF library or moving to a commercial signing service.
What gets captured at signing
The act of signing a packet captures four cryptographic anchors plus a packet of audit metadata. Each anchor answers a different question that might be asked of the document later:
| Anchor | Algorithm | Answers… |
|---|---|---|
| Embedded PDF signature | RSA-2048 + SHA-256, CMS / CAdES per ISO 32000-1 and -2 | "Have the document bytes been changed since signing?" |
| RFC 3161 timestamp | SHA-256 hash of the signature, signed by FreeTSA | "When was this signed, attested by an independent third party?" |
| Consent text hash | SHA-256 of the agreement HTML the signer viewed | "Is the agreement on file the same one the signer agreed to?" |
| Audit envelope (signature_events row) | Append-only DB record of IP, user-agent, OS, timestamps | "Who signed, from where, on what device?" |
The signing certificate
We sign with a self-issued RSA-2048 certificate held by CarrierPacket.Link. The certificate's CN is CarrierPacket.Link Signing Authority and it's stored outside the docroot, readable only by the Apache process. Adobe Reader will show "Signed by CarrierPacket.Link Signing Authority · Issuer trust unknown" when opening a signed PDF; this is expected behavior for a self-signed issuer and does not affect cryptographic validity.
To make Adobe Reader show a green check instead of "trust unknown" you'd need to either (a) add our root certificate to the reader's trust store, or (b) re-sign with a certificate purchased from a Certificate Authority whose root is on the Adobe Approved Trust List (AATL). AATL is Adobe's published list of trusted root CAs and Qualified Trust Service Providers; we'd buy a cert from an AATL-listed CA, not "join" AATL ourselves — that path is for the issuing authorities, not for end-user signing organizations.
Certificate of Completion
Every signed packet PDF includes a final page titled Certificate of Completion. This is the human-readable companion to the cryptographic anchors: signer name, signer email, signer IP, signing time (server-side and TSA-attested), the SHA-256 of the agreement text, and the signing algorithm. A reader who can't (or won't) verify the embedded signature can still read this page and see the audit story.
How to verify a signed PDF
Method 1 — Adobe Reader (or any standards-compliant PDF reader)
Open the PDF, click the signature panel (left sidebar in Adobe). You'll see:
- Whether the document has been modified since signing
- The signing certificate — CN, issuer, validity dates
- The signing time, including the TSA-attested time when present
- The PAdES level achieved (B‑T)
Method 2 — cpl's integrity endpoint
Inside the broker dashboard, every submission profile has a Verify integrity button. It re-hashes the PDF on disk and compares to the stored SHA-256, returning one of:
| Verdict | Meaning |
|---|---|
ok | Bytes are intact. The signature is valid (or at minimum: the hash hasn't drifted). |
tampered | Hash on disk doesn't match the hash recorded at signing. Do not trust this PDF. |
missing | Stored hash exists but the PDF file is gone from disk. |
no-pdf | Signing predates PAdES rollout; only audit metadata exists. |
Method 3 — Programmatic, via the REST API
Pull the submission via GET /api/v1/submissions/{id}. The response includes signed_pdf_sha256; download the artifact via ?mode=pdf&version_id=N on the broker's session, re-hash with SHA-256, and compare.
curl -H "X-API-Token: $TOKEN" \
https://carrierpacket.link/api/v1/submissions/123 \
| jq -r '.signed_pdf_sha256'
# → e.g. 74e485d30859158b...
curl -H "Cookie: auth=...; uid=...; token=..." \
"https://carrierpacket.link/app/api/version_api.php?mode=pdf&version_id=123" \
| sha256sum
# → must match the value above
Method 4 — Verify the trusted timestamp
Every signed agreement has a sidecar .tsr file (the FreeTSA RFC 3161 token). Download both the PDF and the TSR from the public verification page (/v/<hashid> → "Download signed PDF" + "Timestamp token"), then verify with OpenSSL:
openssl ts -verify \
-in signed_packet_<hashid>.tsr \
-data signed_packet_<hashid>.pdf \
-CAfile freetsa-cacert.pem
# → "Verification: OK"
The FreeTSA root certificate is publicly available at freetsa.org.
Why this is legally binding
In the United States, electronic signatures are governed by the E-SIGN Act (15 U.S.C. § 7001) and UETA — both of which give an electronic signature the same legal weight as a wet-ink signature, provided four elements are met:
| Requirement | How CarrierPacket.Link satisfies it |
|---|---|
| Intent to sign | Carrier clicks "Sign here" after explicit consent UI |
| Consent to do business electronically | Agreement text is shown verbatim on the form before signing; consent is part of the click-to-sign action |
| Attribution to the signer | IP, user-agent, signed-at timestamp captured per-version + email verification of the signer |
| Record retention | Signed PDF stored on disk; SHA-256 stored in DB; signature_events table is append-only |
For European agreements covered by eIDAS (Regulation EU 910/2014), our signatures qualify as a simple electronic signature (often abbreviated SES in industry, though the regulation itself doesn't use that acronym). Upgrades to higher tiers are deferred:
- Advanced Electronic Signature (AES) — requires a certificate from a Qualified Trust Service Provider (QTSP) plus signer-control properties (uniquely linked to the signer, capable of identifying them, sole-control creation, tamper detection).
- Qualified Electronic Signature (QES) — AES plus creation by a Qualified Signature Creation Device (QSCD). A QSCD can be a hardware token (HSM, smart card, USB key) or a certified remote signing service backed by HSM technology — eIDAS doesn't strictly require on-premises hardware.
Known limits
- SubFilter is
adbe.pkcs7.detached, notETSI.CAdES.detached— PHP's TCPDF library produces Adobe's pre-PAdES filter by default. Cryptographic anchors (X.509 cert, RSA-2048 + SHA-256, signed ByteRange) are identical to a strict-PAdES B-B signature; verifiers that strictly enforce the ETSI SubFilter byte-string would flag this as "PDF signature, not PAdES." Most readers (Adobe Reader, Foxit, pdf-lib, MuPDF) treat both as equivalent. Upgrading is on the roadmap. - RFC 3161 timestamp is a sidecar, not embedded — strict PAdES B-T embeds the TSR as an unsigned attribute on the CMS signature. Ours lives as a separate
.tsrfile alongside the PDF (downloadable from/v/<hashid>). Cryptographically equivalent — the timestamp still attests to the document's SHA-256 at signing time — just an extra file to fetch.openssl ts -verifyagainst the sidecar gives the same trust outcome as embedded would. - Self-signed cert — Adobe Reader shows "trust unknown" until our cert is added to a reader's trust store. The cryptographic check still validates that the bytes haven't changed; the "unknown" warning is purely about issuer reputation.
- No PAdES B-LT yet — we don't embed CRL/OCSP info into the signature. If our signing cert is revoked or expires, signatures made before revocation are still valid by their cryptographic anchors but a strict B-LT verifier would warn. We expect to upgrade to B-LT before any signed contract reaches the 5-year mark.
- Simple-electronic-signature level under eIDAS — sufficient for most B2B agreements but not the highest tier of cross-border legal weight. Customers who need AES/QES should contact us for the upgrade path.
- RSA-2048 will eventually need rotation — NIST has signaled RSA-2048 deprecation by 2030 and disallowance by 2035 (NIST IR 8547). New deployments increasingly prefer ECDSA P-256 / P-384. Our 2026-issued cert is well within its useful window; future rotations will likely move to ECDSA.
The CarrierPacket.Link signing certificate
Every signed Broker–Carrier Agreement on this platform is signed by one organization-wide certificate. Adobe Reader and any standards-compliant PDF reader can read the certificate from the signed PDF directly — but you can also download it here for inspection or trust-store installation.
| Subject CN | CarrierPacket.Link Signing Authority |
| Issuer CN | CarrierPacket.Link Signing Authority (self-signed) |
| Valid from | 2026-05-09 |
| Valid until | 2036-05-06 |
| Public key | RSA-2048 |
| Signature algorithm | SHA-256 with RSA |
| Serial | 26392F695988A181C22D08CE03971E3665C4852B |
| SHA-256 fingerprint | E41A 5ED2 7850 F3B9 36EC 4404 5B51 A662 CCFE 2193 E008 4718 511E 1975 35D3 5F2E |
| SHA-1 fingerprint | 5F28 9111 ADCD 4CC3 3E56 9530 FD05 16D4 81E1 B891 |
Download cert (PEM) Public certificate only — safe to share.
Adding the cert to Adobe Reader's trust store
By default, Adobe Reader shows our signed PDFs as "Signed and all signatures are valid" with a small note that the signer's identity is unknown. The cryptographic check is fine; Adobe just doesn't have our self-signed root in its built-in trust list. To upgrade to a full green-check verification:
- Click Download cert (PEM) above (or any signed PDF's signature panel → Show Signer's Certificate)
- In Adobe Acrobat / Reader: Edit → Preferences → Signatures → Identities & Trusted Certificates → More…
- Select Trusted Certificates in the left panel, then Import
- Browse to the downloaded
.pemfile, select it, and check "Use this certificate as a trusted root" + "Certified documents" on the next screen
Online verification
Every signed agreement has a public verification URL printed on its Certificate of Completion page (the audit trail page appended to every signed PDF):
https://carrierpacket.link/v/<hashid>
Anyone with the URL can confirm the signature is still valid and the document bytes have not been altered — no Adobe Reader needed, no cryptographic know-how. The verification page shows the broker, the carrier, the signing time, the signature standard, and the cryptographic anchors (SHA-256 of the signed PDF + cert fingerprint). It deliberately does not expose signer email, IP, or other PII; that audit data stays in the broker dashboard.