commaai/openpilot · error · RuntimeError

AuthenticateServer rejected by eUICC: {AUTH_SERVER_ERROR_COD

Error message

AuthenticateServer rejected by eUICC: {AUTH_SERVER_ERROR_CODES.get(code, 'unknown')} (0x{code:02X})

What it means

authenticate_server() sends the ES10b AuthenticateServer command (SM-DP+ signed data, signature, cert) to the eUICC. If the response contains tag 0xA1 instead of a success payload, the eUICC refused authentication and the integer code is mapped through AUTH_SERVER_ERROR_CODES (e.g. 0x05 invalidServerSignature, 0x0A matchingIdRefused, 0x10 insufficientMemory); unmapped codes print 'unknown'.

Source

Thrown at openpilot/common/esim/lpa.py:489

  challenge_resp = es10x_command(client, encode_tlv(TAG_EUICC_CHALLENGE, b""))
  challenge = require_tag(require_tag(challenge_resp, TAG_EUICC_CHALLENGE, "GetEuiccDataResponse"),
                          TAG_STATUS, "challenge in response")
  info_resp = es10x_command(client, encode_tlv(TAG_EUICC_INFO, b""))
  require_tag(info_resp, TAG_EUICC_INFO, "GetEuiccInfo1Response")
  return challenge, info_resp


def authenticate_server(client: AtClient, b64_signed1: str, b64_sig1: str, b64_pk_id: str, b64_cert: str, matching_id: str) -> str:
  tac = bytes([0x35, 0x29, 0x06, 0x11])
  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")

View on GitHub (pinned to 516ec1e682)

Solutions

  1. Map the hex code: 0x01 eUICC verification failed, 0x02/0x03 eUICC cert expired/revoked (hardware issue, replace eSIM), 0x05 invalid server signature (server/carrier problem), 0x0A matchingId refused (wrong or used QR), 0x10 insufficient memory (delete profiles)
  2. For 0x0A: request a fresh QR code; the current one is bound to another session/device
  3. For 0x10: delete unused profiles to free eUICC memory, then retry download
  4. For 0x05/0x06: retry later or escalate to the carrier; also verify device clock is correct (cert validation is time-sensitive)

Example fix

# before
b64_auth = authenticate_server(client, s1, sig1, pkid, cert, matching_id)
# RuntimeError: AuthenticateServer rejected by eUICC: matchingIdRefused (0x0A)

# after
from openpilot.common.esim.lpa import authenticate_server

try:
  b64_auth = authenticate_server(client, s1, sig1, pkid, cert, matching_id)
except RuntimeError as e:
  if '(0x0A)' in str(e):
    raise SystemExit('QR code matching ID refused; get a new QR code from carrier') from e
  if '(0x10)' in str(e):
    raise SystemExit('eUICC memory full; delete profiles and retry') from e
  raise
Defensive patterns

Strategy: try-catch

Validate before calling

from openpilot.common.esim.lpa import list_profiles

# pre-flight: free memory for 0x10, valid QR for 0x0A
if len(list_profiles(client)) >= max_profiles_supported:
  raise SystemExit('eUICC near memory limit; delete profiles before download')

Try / catch

try:
  b64_auth = authenticate_server(client, s1, sig1, pkid, cert, matching_id)
except RuntimeError as e:
  code = str(e).rsplit('0x', 1)[-1]
  if code == '0A':
    raise SystemExit('QR matching ID refused; obtain fresh QR') from e
  if code == '10':
    raise SystemExit('eUICC memory full; delete profiles') from e
  if code in ('02', '03'):
    raise SystemExit('eUICC certificate issue; hardware replacement needed') from e
  raise

Prevention

When it happens

Trigger: During profile download when the eUICC rejects the SM-DP+: server signature invalid (0x05), eUICC certificate expired/revoked (0x02/0x03), matching ID from the QR refused (0x0A), eUICC GSMA CI public key unknown (0x06), or insufficient eUICC memory (0x10).

Common situations: QR code whose matchingId doesn't match the reserved profile (wrong QR / already consumed elsewhere); carrier server certificate/signature issues; test eUICCs with expired certificates; eUICC memory full from many installed profiles.

Understand the failure class

Related errors


AI-assisted analysis of commaai/openpilot@516ec1e682 (2026-08-15). Data as JSON: /api/errors/47e74a4bb4bc99a9. Report an issue: GitHub.