feat(acme, zerossl): ACME (RFC 8555) and ZeroSSL SDKs - #542
Open
sam-goodwin wants to merge 3 commits into
Open
Conversation
`@distilled.cloud/acme`: a hand-authored OpenAPI document for RFC 8555 (directory, nonce, account, order, authorization, challenge, certificate, revocation) converted to Smithy and compiled by the shared generator. The protocol is hand-written: every POST is a flattened JWS signed by the account key from `Credentials` (kid vs embedded JWK, POST-as-GET reads, External Account Binding on newAccount), requests are addressed via the CA's directory or the resource `url` label, nonces are cached per CA, and RFC 7807 problem documents are matched on their `type` URN against 24 typed `Acme*` errors patched onto the model (`patches/acme/errors.json`). `Jose` exports WebCrypto-only helpers: account key generation, thumbprints, key authorizations, DNS-01 values. `@distilled.cloud/zerossl`: the REST API's `generateEabCredentials`, authenticated by the `access_key` query parameter, with `success: false` bodies decoded as typed errors. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A deactivated or purged account answers `urn:ietf:params:acme:error:accountDoesNotExist` on any request signed with its `kid`, not only `newAccount`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There is no vendor spec for either API, so the OpenAPI document was only an intermediary: the converter turned it into Smithy, and a 1000-line JSON patch then added the typed errors. The models are now written directly as Smithy (`specs/acme.json`, `specs/zerossl.json`) with the error shapes and traits inline — one source of truth, no `convert.ts`, no `.generated-specs`, no patch chain. The generated SDKs are unchanged apart from the converter's `RespondChallengeRequest2` name becoming `RespondChallengeRequest`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two SDKs for issuing TLS certificates: ACME (RFC 8555) and ZeroSSL's REST API. Both models are hand-written Smithy — there is no vendor spec for either, and an OpenAPI intermediary would only add a conversion step and a patch chain to the same content.
@distilled.cloud/acmespecs/acme.jsontranscribes RFC 8555: twelve operations (getDirectory,newNonce,newAccount,updateAccount,newOrder,getOrder,finalizeOrder,getAuthorization,deactivateAuthorization,respondChallenge,downloadCertificate,revokeCertificate), the RFC's shapes with their wire member names, and the 24urn:ietf:params:acme:error:*types (§6.7) as error structures matched on a problem document'stype, attached to the operations that raise them (AcmeBadNonceandAcmeServerInternalretryable,AcmeRateLimitedcarriesretryAfter,AcmeAccountDoesNotExiston every kid-authenticated op).src/protocol.tsis the one hand-written piece of runtime — ACME is JWS-signed JSON the generic REST protocol can't express:newNonce/newAccount/newOrder/revokeCertresolve from the directory, everything else names its resource by the absoluteurllabel the CA returned. The model'shttpuris are placeholders that identify the operation.newAccountembeds the JWK and attaches the External Account Binding fromCredentials; later requests usekid; reads are POST-as-GET. Nonces are cached per CA fromReplay-Nonce.Jose: WebCrypto-only account keys, thumbprints, key authorizations and DNS-01 TXT values.Directoriespresets: Let's Encrypt (+ staging), ZeroSSL, Google Trust Services (+ staging).@distilled.cloud/zerosslgenerateEabCredentials, authenticated by theaccess_keyquery parameter, withsuccess: falsebodies decoded as typed errors (InvalidAccessKey,RateLimitExceeded).Verified live against ZeroSSL (EAB → account → wildcard order → DNS-01 authorization), Let's Encrypt staging and Pebble, and consumed by alchemy-run/alchemy#1464.
🤖 Generated with Claude Code