commaai/openpilot · error · RuntimeError
Invalid smdpSigned2
Error message
Invalid smdpSigned2
What it means
prepare_download() decodes the SM-DP+ server's base64 smdpSigned2 blob and parses it as DER/BER-TLV looking for a root tag 0x30 (ASN.1 SEQUENCE). If no 0x30 element is found, the server response is structurally invalid from the client's perspective and RuntimeError('Invalid smdpSigned2') is raised.
Source
Thrown at openpilot/common/esim/lpa.py:499
device_info = encode_tlv(TAG_STATUS, tac) + encode_tlv(0xA1, b"")
ctx_inner = encode_tlv(TAG_STATUS, matching_id.encode("utf-8")) + encode_tlv(0xA1, device_info)
content = b64d(b64_signed1) + b64d(b64_sig1) + b64d(b64_pk_id) + b64d(b64_cert) + encode_tlv(0xA0, ctx_inner)
response = es10x_command(client, encode_tlv(TAG_AUTH_SERVER, content))
root = require_tag(response, TAG_AUTH_SERVER, "AuthenticateServerResponse")
error_tag = find_tag(root, 0xA1)
if error_tag is not None:
code = int.from_bytes(error_tag, "big") if error_tag else 0
raise RuntimeError(f"AuthenticateServer rejected by eUICC: {AUTH_SERVER_ERROR_CODES.get(code, 'unknown')} (0x{code:02X})")
return b64e(response)
def prepare_download(client: AtClient, b64_signed2: str, b64_sig2: str, b64_cert: str, cc: str | None = None) -> str:
smdp_signed2 = b64d(b64_signed2)
smdp_signature2 = b64d(b64_sig2)
smdp_certificate = b64d(b64_cert)
smdp_signed2_root = find_tag(smdp_signed2, 0x30)
if smdp_signed2_root is None:
raise RuntimeError("Invalid smdpSigned2")
transaction_id = find_tag(smdp_signed2_root, TAG_STATUS)
cc_required_flag = find_tag(smdp_signed2_root, 0x01)
if transaction_id is None or cc_required_flag is None:
raise RuntimeError("Invalid smdpSigned2")
content = smdp_signed2 + smdp_signature2
if int.from_bytes(cc_required_flag, "big") != 0:
if not cc:
raise RuntimeError("Confirmation code required but not provided")
content += encode_tlv(0x04, hashlib.sha256(hashlib.sha256(cc.encode("utf-8")).digest() + transaction_id).digest())
content += smdp_certificate
response = es10x_command(client, encode_tlv(TAG_PREPARE_DOWNLOAD, content))
require_tag(response, TAG_PREPARE_DOWNLOAD, "PrepareDownloadResponse")
return b64e(response)
def _parse_tlv_header_len(data: bytes) -> int:
tag_len = 2 if data[0] & 0x1F == 0x1F else 1
length_byte = data[tag_len]View on GitHub (pinned to 516ec1e682)
Solutions
- Verify the argument mapping: prepare_download(client, b64_signed2, b64_sig2, b64_cert, cc) must receive exactly the server's smdpSigned2, smdpSignature2, smdpCertificate fields
- Decode and inspect the blob offline (openssl asn1parse / base64 -d) to confirm it is a DER SEQUENCE
- If the server payload genuinely lacks structure, escalate to the carrier — their ES9+ response is malformed
Defensive patterns
Strategy: validation
Validate before calling
from openpilot.common.esim.lpa import find_tag
raw = base64.b64decode(b64_signed2)
if find_tag(raw, 0x30) is None:
raise SystemExit('smdpSigned2 is not a valid DER SEQUENCE — wrong field or server bug') Type guard
def is_valid_smdp_signed2(b64: str) -> bool:
try:
return find_tag(base64.b64decode(b64), 0x30) is not None
except Exception:
return False Prevention
- Map ES9+ JSON fields to function args with named constants, not positional habit
- Validate server payloads structurally before entering the eUICC download phase
- Capture raw server responses in debug logs to diagnose field mixups
When it happens
Trigger: handleNotification/authenticateClient exchange returned a smdpSigned2 that is not valid DER (wrong field passed, base64 of a different value, truncated payload), or a server response format that deviates from SGP.22 expectations.
Common situations: Field mixups when wiring the ES9+ JSON into prepare_download (passing smdpSignature2 or the cert in the signed2 slot); carrier server bugs or SGP.22 version differences; base64 decoding of a corrupted string.
Related errors
- {error_prefix} failed: {reason}/{subject} - {sd.get('message
- Missing {label or f'tag 0x{target:X}'}
- Invalid BoundProfilePackage
- Invalid profileMetadata
- no profile at index {ref} (have {len(profiles)})
AI-assisted analysis of commaai/openpilot@516ec1e682 (2026-08-15).
Data as JSON: /api/errors/0254790177f5d5fd.
Report an issue: GitHub.