{"record":{"id":"00b2bc4f29768f62","repo":"gravitational/teleport","slug":"cred-required-for-q-ceremony","errorCode":null,"errorMessage":"cred required for %q ceremony","messagePattern":"cred required for %q ceremony","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/auth/touchid/api.go","lineNumber":396,"sourceCode":"\ntype attestationResponse struct {\n\tccdJSON     []byte\n\trawAuthData []byte\n\tdigest      []byte\n}\n\n// TODO(codingllama): Share a single definition with webauthncli / mocku2f.\ntype collectedClientData struct {\n\tType      string `json:\"type\"`\n\tChallenge string `json:\"challenge\"`\n\tOrigin    string `json:\"origin\"`\n}\n\nfunc makeAttestationData(ceremony protocol.CeremonyType, origin, rpID string, challenge []byte, cred *credentialData) (*attestationResponse, error) {\n\t// Sanity check.\n\tisCreate := ceremony == protocol.CreateCeremony\n\tif isCreate && cred == nil {\n\t\treturn nil, fmt.Errorf(\"cred required for %q ceremony\", ceremony)\n\t}\n\n\tccd := &collectedClientData{\n\t\tType:      string(ceremony),\n\t\tChallenge: base64.RawURLEncoding.EncodeToString(challenge),\n\t\tOrigin:    origin,\n\t}\n\tccdJSON, err := json.Marshal(ccd)\n\tif err != nil {\n\t\treturn nil, trace.Wrap(err)\n\t}\n\tccdHash := sha256.Sum256(ccdJSON)\n\trpIDHash := sha256.Sum256([]byte(rpID))\n\n\tflags := byte(protocol.FlagUserPresent | protocol.FlagUserVerified)\n\tif isCreate {\n\t\tflags |= byte(protocol.FlagAttestedCredentialData)\n\t}","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/lib/auth/touchid/api.go#L378-L414","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the Touch ID Register flow creates credentialData (via Secure Enclave key generation) before calling makeAttestationData.","Pass the non-nil *credentialData returned by the key-creation step into makeAttestationData for CreateCeremony.","If you hit this after refactoring, audit that the credential generation error is not being swallowed upstream.","For Login ceremonies, pass nil cred intentionally — no fix needed there."],"exampleFix":"// before\nresp, err := makeAttestationData(protocol.CreateCeremony, origin, rpID, challenge, nil)\n// after\ncred, err := createSecureEnclaveCredential(rpID, user)\nif err != nil { return nil, trace.Wrap(err) }\nresp, err := makeAttestationData(protocol.CreateCeremony, origin, rpID, challenge, cred)","handlingStrategy":"validation","validationCode":"if ceremony == protocol.CreateCeremony && cred == nil {\n    return errors.New(\"registration ceremony requires credential data from Secure Enclave key creation\")\n}","typeGuard":"func hasCredentialForCeremony(ceremony protocol.CeremonyType, cred *credentialData) bool {\n    return ceremony != protocol.CreateCeremony || cred != nil\n}","tryCatchPattern":"resp, err := makeAttestationData(ceremony, origin, rpID, challenge, cred)\nif err != nil {\n    if strings.Contains(err.Error(), \"cred required\") {\n        return nil, trace.Wrap(err, \"register flow failed to create credential; check Secure Enclave key generation\")\n    }\n    return nil, trace.Wrap(err)\n}","preventionTips":["Always generate and propagate credentialData before building the attestation response.","Do not swallow errors from Secure Enclave key creation.","Cover Register with a test asserting cred != nil at the makeAttestationData call site."],"tags":["webauthn","touchid","attestation"],"backgroundTag":"missing-credential-data","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}