{"record":{"id":"558e9defdacdff76","repo":"jumpserver/jumpserver","slug":"invalid-certificate-format","errorCode":null,"errorMessage":"Invalid certificate format","messagePattern":"Invalid certificate format","errorType":"exception","errorClass":"UKeyCertNormalizationError","httpStatus":403,"severity":"error","filePath":"apps/authentication/backends/ukey/backends.py","lineNumber":103,"sourceCode":"        self._verify_cert_cn(sm2_cert.get_subject().get('commonName'), username)\n        self._verify_sm2_signature(sm2_cert.get_subject_public_key(), signature, challenge)\n        return user\n\n    @staticmethod\n    def _load_sm2_cert(cert_pem):\n        \"\"\"将 PEM 字符串写入临时文件，加载为 Sm2Certificate 对象后立即删除临时文件。\"\"\"\n        from common.utils.gmssl_python import Sm2Certificate\n\n        fd, cert_file = tempfile.mkstemp(suffix='.crt')\n        try:\n            os.close(fd)\n            with open(cert_file, 'w', encoding='utf-8') as f:\n                f.write(cert_pem)\n            sm2_cert = Sm2Certificate()\n            sm2_cert.import_pem(cert_file)\n        except Exception as e:\n            logger.error('UKeyBackend: failed to load SM2 cert: %s', e)\n            raise UKeyCertNormalizationError()\n        finally:\n            if os.path.exists(cert_file):\n                os.unlink(cert_file)\n        return sm2_cert\n\n    @staticmethod\n    def _verify_sm2_cert_validity(sm2_cert):\n        \"\"\"校验 SM2 证书有效期（not_before / not_after）。\"\"\"\n        try:\n            validity = sm2_cert.get_validity()\n        except Exception as e:\n            logger.error('UKeyBackend: failed to get SM2 cert validity: %s', e)\n            raise UKeyCertExpiredError()\n        UKeyBackend._check_validity_period(validity.not_before, validity.not_after, 'SM2')\n\n    @staticmethod\n    def _verify_sm2_cert_chain(sm2_cert):\n        \"\"\"调用 Sm2Certificate.verify_by_ca_certificate 验证 SM2 证书链。\"\"\"","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/jumpserver/jumpserver/blob/6ec464fabd61b95912d539455a3a5f15f5c59fe0/apps/authentication/backends/ukey/backends.py#L85-L121","documentation":"UKeyCertNormalizationError raised when writing the submitted cert_pem to a temp file and importing it via Sm2Certificate().import_pem fails with any exception — the PEM is not a parseable SM2/CSR certificate (wrong format, corrupted, or an RSA/standard X.509 PEM handed to the GM parser).","triggerScenarios":"_authenticate_sm2 receives cert_pem that gmssl cannot import: truncated payload, base64/DER instead of PEM, or a non-SM2 certificate submitted on the SM2 path.","commonSituations":"Client sends the wrong certificate slot, frontend mangles newlines in the PEM, double-encoded base64, or an RSA UKey user routed into the SM2 branch.","solutions":["Inspect the submitted cert_pem (log length/head/tail) and confirm it begins with BEGIN CERTIFICATE and is intact.","Ensure the client sends the SM2 certificate PEM verbatim with real newlines.","Route non-SM2 certificates to _authenticate_other instead of the SM2 branch."],"exampleFix":"# before\ncert_pem = base64.b64encode(raw_der).decode()  # DER b64, not PEM\n\n# after\ncert_pem = raw_der.decode() if b'BEGIN CERTIFICATE' in raw_der else pem_encode(raw_der)","handlingStrategy":"validation","validationCode":"def is_valid_pem(cert_pem: str) -> bool:\n    return isinstance(cert_pem, str) and '-----BEGIN CERTIFICATE-----' in cert_pem \\\n        and '-----END CERTIFICATE-----' in cert_pem\n\nif not is_valid_pem(cert_pem):\n    return error_response('Invalid certificate payload', code='BAD_CERT')","typeGuard":"def is_sm2_pem(cert_pem: str) -> bool:\n    return (isinstance(cert_pem, str)\n            and cert_pem.lstrip().startswith('-----BEGIN CERTIFICATE-----')\n            and '\\n' in cert_pem)","tryCatchPattern":"try:\n    sm2_cert = UKeyBackend._load_sm2_cert(cert_pem)\nexcept UKeyCertNormalizationError:\n    return error_response('Certificate could not be parsed', status=400)","preventionTips":["Client sends PEM untouched (no newline escaping/base64 double-encoding)","Validate PEM markers server-side before tempfile round-trip","Route RSA/X.509 certs to the non-SM2 branch"],"tags":["ukey","sm2","certificate","pem","parsing"],"backgroundTag":"invalid-certificate-format","analyzedSha":"6ec464fabd61b95912d539455a3a5f15f5c59fe0","analyzedAt":"2026-08-28T11:33:00.925Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}