Skip to content
Snippets Groups Projects

Draft: Resolve "Object / Person identification using SDM NFC cards"

3 files
+ 43
43
Compare changes
  • Side-by-side
  • Inline
Files
3
from binascii import unhexlify
from typing import Optional
from django.core.exceptions import BadRequest
from django.http import HttpRequest
from libsdm import EncMode, InvalidMessage, decrypt_sun_message
from libsdm.derive import derive_tag_key, derive_undiversified_key
from libsdm.util import parse_parameters
from pylibsdm.backend.validate import ParamValidator
from aleksis.core.mixins import ExtensibleModel, ObjectAuthenticator
from aleksis.core.util.core_helpers import get_site_preferences
@@ -17,48 +16,36 @@ class NfcSdmAuthenticator(ObjectAuthenticator):
"""Object authenticator using NFC SDM."""
name = "nfc_sdm"
require_lrp = False
def authenticate(self, request: HttpRequest, obj: ExtensibleModel):
def authenticate(self, request: HttpRequest, obj: Optional[ExtensibleModel]):
"""SUN decrypting authenticator"""
master_key = unhexlify(get_site_preferences()["kort__sdm_master_key"])
try:
param_mode, picc_enc_data, enc_file_data, sdmmac = parse_parameters(request.GET)
except ValueError as e:
raise BadRequest(**e.args)
file_read_key = unhexlify(get_site_preferences()["kort__sdm_file_read_key"])
meta_read_key = unhexlify(get_site_preferences()["kort__sdm_meta_read_key"])
try:
res = decrypt_sun_message(
param_mode=param_mode,
sdm_meta_read_key=derive_undiversified_key(master_key, 1),
sdm_file_read_key=lambda uid: derive_tag_key(master_key, uid, 2),
picc_enc_data=picc_enc_data,
sdmmac=sdmmac,
enc_file_data=enc_file_data,
)
except InvalidMessage:
raise BadRequest("Invalid SUN message or signature")
if self.require_lrp and res["encryption_mode"] != EncMode.LRP:
raise BadRequest("LRP required")
validator = ParamValidator(file_read_key, meta_read_key)
validator.parse_uri(request.build_absolute_uri())
# FIXME do tag tamper check here
if validator.uid is None or validator.read_ctr is None or not validator.cmac_valid:
raise BadRequest("Invalid SUN message or signature")
try:
card = Card.objects.get(chip_number__iexact=res["uid"].hex())
card = Card.objects.get(chip_number__iexact=validator.uid.hex())
except Card.DoesNotExist:
return False
if obj is None:
if self.object is None:
self.object = card.person
obj = card.person
else:
obj = self.object
if card.person != obj:
raise BadRequest("Card is not linked to identified object")
if card.last_read_counter >= res["read_ctr"]:
if card.last_read_counter >= validator.read_ctr:
raise BadRequest("Read counter went backwards, possible replay attack")
card.last_read_counter = res["read_ctr"]
card.last_read_counter = validator.read_ctr
card.save()
return True
class NfcSdmAuthenticatorRequireLrp(NfcSdmAuthenticator):
name = "nfc_sdm_lrp"
require_lrp = True
Loading