Check a PDF
The whole file is compared with the one we issued, so this is the check to use when someone hands you a report.
Look up a report id
Shows the totals we hold for a report (not the per-shift record). This is also where the QR code on the report leads.
How it works, honestly
Any change to the file is detected by the online verifier (byte-exact match against the file we issued). The embedded record is digitally signed and can be checked offline with our public key. The printed pages themselves are not signed — always trust the verifier's numbers, not the numbers printed on a file that fails the byte-exact check.
When a worker creates a report, our server writes the report's data as a fixed record, signs that record with its private key (RSA-PSS with SHA-256), embeds the record and signature in the PDF as an attachment (sunsub-hours.json), and stores a fingerprint of the exact file it handed out. Every check made here is logged (verdict, time, network address) so forged files can be spotted. The result is one of:
| Verdict | Meaning |
|---|---|
| Authentic | The file is byte-for-byte the one we issued. Its numbers can be relied on. |
| Revoked | We issued this report but have since withdrawn it (for example the account holder asked us to, or it was found to rest on false records). Do not rely on it. |
| Record valid, file altered | The signed record inside the file is genuine and matches a report we issued, but the file itself is not the one we handed out: something about it has changed. The verifier shows the numbers we hold; use those, not the printed pages. |
| Unknown record | The file carries a valid-looking signature but we have no matching report. Treat it as forged; we are alerted when this happens. |
| Not verified | The file could not be checked: no signed record inside it, a signature that does not check out, or a file that is not a Sun Sub report at all. |
Verify the signed record offline
Anyone can check the embedded record without trusting this website, using only our published public key. Our keys are listed at https://estimating.sunpaintingva.com/sunsub/keys; the report names the key it was signed with by its kid in the footer and inside the attachment. With pdfdetach (poppler-utils), jq and openssl:
# 1. Pull the attachment out of the PDF: it is named sunsub-hours.json pdfdetach -saveall report.pdf # 2. Fetch the public key the record names ("kid" in the file) KID=$(jq -r .kid sunsub-hours.json) curl -fsSO https://estimating.sunpaintingva.com/sunsub/keys/$KID.pem # 3. Split the envelope into the exact signed bytes and the signature jq -rj .payload_canonical sunsub-hours.json > payload.json jq -r .signature_b64 sunsub-hours.json | base64 -d > sig.bin # 4. Check the signature: RSA-PSS, SHA-256, salt length 32 (the digest length) openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:32 \ -verify $KID.pem -signature sig.bin payload.json # → "Verified OK" # 5. The record fingerprint printed on every page is the SHA-256 of those bytes sha256sum payload.json
payload.json is the signed record itself (worker, period, totals and every shift with its provenance), so once step 4 says Verified OK you can read the numbers from it directly.
What offline checking cannot tell you. A valid signature proves the attached record was produced and signed by our server and has not been altered since. It does not prove that the printed pages of the PDF match that record (the pages are not signed — compare them yourself, or trust the record), and it cannot tell you whether the report has since been revoked. Only the online check does the byte-exact comparison and the revocation lookup.
For systems that check many reports
The same check is available as JSON. Send the PDF as a multipart field named report, or as the raw request body with Content-Type: application/pdf. Limits: 3 MB per file, 30 checks per 15 minutes per network address.
curl -sS -F report=@report.pdf https://estimating.sunpaintingva.com/api/sunsub/verify
# or
curl -sS -H 'Content-Type: application/pdf' --data-binary @report.pdf https://estimating.sunpaintingva.com/api/sunsub/verify
The response carries verdict (authentic, revoked, record_valid_file_altered, unknown_record or not_verified), a reason for the last of those, the individual checks, the file's file_sha256, and — when we hold a matching record — the public report projection and its record_url. Public keys: GET https://estimating.sunpaintingva.com/sunsub/keys (JSON) and GET https://estimating.sunpaintingva.com/sunsub/keys/<kid>.pem.
Questions about a report? support@sunpaintingva.com · (434) 207-2025. Sun Sub is made by Sun Painting Virginia; reports are issued for the worker named on them and the verifier states only what our server can vouch for.