gravitational/teleport · error

cred required for %q ceremony

Error message

cred required for %q ceremony

What it means

makeAttestationData builds the WebAuthn attestation response for a Touch ID ceremony. A Create (registration) ceremony inherently needs the newly generated credential data (credential ID, public key, etc.); if the cred argument is nil for a create ceremony, the function refuses rather than producing an invalid attestation object. Login ceremonies may legitimately pass nil, so only CreateCeremony is checked.

Source

Thrown at lib/auth/touchid/api.go:396

type attestationResponse struct {
	ccdJSON     []byte
	rawAuthData []byte
	digest      []byte
}

// TODO(codingllama): Share a single definition with webauthncli / mocku2f.
type collectedClientData struct {
	Type      string `json:"type"`
	Challenge string `json:"challenge"`
	Origin    string `json:"origin"`
}

func makeAttestationData(ceremony protocol.CeremonyType, origin, rpID string, challenge []byte, cred *credentialData) (*attestationResponse, error) {
	// Sanity check.
	isCreate := ceremony == protocol.CreateCeremony
	if isCreate && cred == nil {
		return nil, fmt.Errorf("cred required for %q ceremony", ceremony)
	}

	ccd := &collectedClientData{
		Type:      string(ceremony),
		Challenge: base64.RawURLEncoding.EncodeToString(challenge),
		Origin:    origin,
	}
	ccdJSON, err := json.Marshal(ccd)
	if err != nil {
		return nil, trace.Wrap(err)
	}
	ccdHash := sha256.Sum256(ccdJSON)
	rpIDHash := sha256.Sum256([]byte(rpID))

	flags := byte(protocol.FlagUserPresent | protocol.FlagUserVerified)
	if isCreate {
		flags |= byte(protocol.FlagAttestedCredentialData)
	}

View on GitHub (pinned to 1283425b60)

Solutions

  1. Ensure the Touch ID Register flow creates credentialData (via Secure Enclave key generation) before calling makeAttestationData.
  2. Pass the non-nil *credentialData returned by the key-creation step into makeAttestationData for CreateCeremony.
  3. If you hit this after refactoring, audit that the credential generation error is not being swallowed upstream.
  4. For Login ceremonies, pass nil cred intentionally — no fix needed there.

Example fix

// before
resp, err := makeAttestationData(protocol.CreateCeremony, origin, rpID, challenge, nil)
// after
cred, err := createSecureEnclaveCredential(rpID, user)
if err != nil { return nil, trace.Wrap(err) }
resp, err := makeAttestationData(protocol.CreateCeremony, origin, rpID, challenge, cred)
Defensive patterns

Strategy: validation

Validate before calling

if ceremony == protocol.CreateCeremony && cred == nil {
    return errors.New("registration ceremony requires credential data from Secure Enclave key creation")
}

Type guard

func hasCredentialForCeremony(ceremony protocol.CeremonyType, cred *credentialData) bool {
    return ceremony != protocol.CreateCeremony || cred != nil
}

Try / catch

resp, err := makeAttestationData(ceremony, origin, rpID, challenge, cred)
if err != nil {
    if strings.Contains(err.Error(), "cred required") {
        return nil, trace.Wrap(err, "register flow failed to create credential; check Secure Enclave key generation")
    }
    return nil, trace.Wrap(err)
}

Prevention

When it happens

Trigger: Calling makeAttestationData (via Register or Login) with ceremony == protocol.CreateCeremony while passing cred == nil — i.e. the register flow failed to produce or store credentialData before building the attestation response.

Common situations: A bug or modified code path in the Touch ID Register flow where Secure Enclave key generation failed silently or credentialData was not threaded through; tests invoking makeAttestationData directly with missing arguments.

Related errors


AI-assisted analysis of gravitational/teleport@1283425b60 (2026-09-02). Data as JSON: /api/errors/00b2bc4f29768f62. Report an issue: GitHub.