{"record":{"id":"856bc22d693a147d","repo":"kubernetes/kops","slug":"decoding-pkcs7-signature-w","errorCode":null,"errorMessage":"decoding PKCS7 signature: %w","messagePattern":"decoding PKCS7 signature: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/azure/attest.go","lineNumber":240,"sourceCode":"\t\treturn nil, fmt.Errorf(\"verifying PKCS7 certificate chain: %w\", err)\n\t}\n\tklog.V(4).Infof(\"PKCS7 certificate chain verified after resolving intermediate certificates for signer issuer %q\", signer.Issuer)\n\n\treturn data, nil\n}\n\n// parseAndValidatePKCS7Signer decodes and parses a base64-encoded PKCS7 signature, verifies its\n// self-signature, and validates that the signer certificate's SAN identifies an Azure metadata\n// endpoint. All checks here are CPU-only; no network I/O is performed, so this is safe to call\n// before triggering intermediate certificate fetches.\nfunc parseAndValidatePKCS7Signer(signature string) (*pkcs7.PKCS7, *x509.Certificate, error) {\n\tif signature == \"\" {\n\t\treturn nil, nil, fmt.Errorf(\"empty PKCS7 signature\")\n\t}\n\n\tsigBytes, err := base64.StdEncoding.DecodeString(signature)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"decoding PKCS7 signature: %w\", err)\n\t}\n\tklog.V(4).Infof(\"Decoded PKCS7 signature (%d bytes)\", len(sigBytes))\n\n\tp7, err := pkcs7.Parse(sigBytes)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"parsing PKCS7 signature: %w\", err)\n\t}\n\tklog.V(8).Infof(\"Parsed PKCS7 structure with %d embedded certificate(s)\", len(p7.Certificates))\n\n\t// Verify the PKCS7 signature against the embedded leaf certificate.\n\tif err := p7.Verify(); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"verifying PKCS7 signature: %w\", err)\n\t}\n\tklog.V(4).Infof(\"PKCS7 self-signature verified\")\n\n\tsigner := p7.GetOnlySigner()\n\tif signer == nil {\n\t\treturn nil, nil, fmt.Errorf(\"PKCS7 signer certificate not found\")","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/azure/attest.go#L222-L258","documentation":"parseAndValidatePKCS7Signer wraps the base64 decoding failure of the PKCS7 signature bytes taken from an Azure attested document. The signature field must be a valid base64-encoded DER PKCS#7/CMS blob; when Go's encoding/base64 rejects it (invalid characters, wrong length, empty-adjacent garbage) this error is returned. It means the attested document's signature was not transport-decoded correctly, so parsing was never attempted.","triggerScenarios":"verifyAttestedDocumentWithRootAndFetcher calls parseAndValidatePKCS7Signer with the 'signature' field extracted from the IMDS attested document JSON; base64.StdEncoding.DecodeString fails because the field is empty of valid base64, contains whitespace/newlines, uses base64url alphabet characters (-, _), or is truncated.","commonSituations":"Mock/test IMDS servers returning signature fields that are plain text or URL-safe base64 instead of standard base64; a proxy or middleware mangling the JSON response; manually copying an attested document and corrupting the signature string; Azure changing response encoding expectations in a custom fetcher.","solutions":["Log the raw signature string (klog.V(4) already logs decoded length on success; on failure log the first/last chars) and confirm it is standard base64 (RFC 4648, not base64url)","Trim surrounding whitespace/newlines from the signature before decoding, or normalize with strings.Map removing CR/LF/spaces","If using a custom attested-document fetcher, ensure it returns the IMDS JSON unmodified and that the 'signature' field is extracted as-is","Check for middleware/proxies or tests injecting invalid placeholder signatures; use a real base64-encoded PKCS7 blob in fixtures"],"exampleFix":"// before\nsig := rawSignature // may contain newlines from transport\np7, err := parseAndValidatePKCS7Signer(sig, ...)\n// after\nsig := strings.TrimSpace(rawSignature)\nsig = strings.ReplaceAll(sig, \"\\n\", \"\")\nsig = strings.ReplaceAll(sig, \"\\r\", \"\")\np7, err := parseAndValidatePKCS7Signer(sig, ...)","handlingStrategy":"validation","validationCode":"sig := strings.TrimSpace(attestedDoc.Signature)\nif sig == \"\" || strings.ContainsAny(sig, \" \\n\\r\\t\") {\n    return fmt.Errorf(\"signature is not contiguous standard base64\")\n}\nif _, err := base64.StdEncoding.DecodeString(sig); err != nil {\n    return fmt.Errorf(\"signature not valid standard base64: %w\", err)\n}","typeGuard":"func isStandardBase64(s string) bool {\n    if s == \"\" {\n        return false\n    }\n    _, err := base64.StdEncoding.DecodeString(s)\n    return err == nil\n}","tryCatchPattern":"sigBytes, err := base64.StdEncoding.DecodeString(signature)\nif err != nil {\n    klog.V(4).Infof(\"base64 decode failed for signature (len=%d): %v\", len(signature), err)\n    return nil, nil, fmt.Errorf(\"decoding PKCS7 signature: %w\", err)\n}","preventionTips":["Normalize whitespace/newlines out of the signature field before decoding","Use base64.StdEncoding, never URLEncoding, when handling IMDS signatures","In test fixtures, generate signatures with base64.StdEncoding.EncodeToString(realDER)","Log the decoded length at V(4) to quickly spot truncation"],"tags":["azure","pkcs7","base64","attestation"],"backgroundTag":"base64-decode-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}