@@ -344,10 +344,6 @@ def _normalize_attestation_report(report):
344344 return normalized
345345
346346
347- ATTEST_NONCE_SKEW_SECONDS = int (os .getenv ("ATTEST_NONCE_SKEW_SECONDS" , "60" ))
348- _ATTEST_CHALLENGE_NONCE_RE = re .compile (r"^[0-9a-f]{64}$" , re .IGNORECASE )
349-
350-
351347def attest_ensure_tables (conn ):
352348 """Create the attestation nonce tables expected by replay protection."""
353349 conn .execute ("CREATE TABLE IF NOT EXISTS nonces (nonce TEXT PRIMARY KEY, expires_at INTEGER)" )
@@ -373,29 +369,8 @@ def attest_cleanup_expired(conn, now_ts: Optional[int] = None):
373369 conn .commit ()
374370
375371
376- def extract_attestation_timestamp (data : dict , report : dict , nonce : Optional [str ]) -> Optional [int ]:
377- """Extract an optional attestation timestamp from request payload fields."""
378- for source in (report or {}, data or {}):
379- for field_name in ("nonce_ts" , "nonce_timestamp" , "timestamp" , "server_time" ):
380- raw_value = source .get (field_name )
381- if isinstance (raw_value , bool ):
382- continue
383- if isinstance (raw_value , (int , float )):
384- if math .isfinite (raw_value ):
385- return int (raw_value )
386- continue
387- if isinstance (raw_value , str ) and raw_value .strip ().isdigit ():
388- return int (raw_value .strip ())
389- return None
390-
391-
392- def _attest_nonce_requires_challenge (nonce : str , nonce_ts : Optional [int ]) -> bool :
393- """Current challenge endpoint emits 64-hex nonces with no embedded timestamp."""
394- return nonce_ts is None and bool (_ATTEST_CHALLENGE_NONCE_RE .fullmatch (nonce ))
395-
396-
397372def attest_validate_challenge (conn , nonce : str , now_ts : Optional [int ] = None ):
398- """Validate and consume a one-time challenge nonce."""
373+ """Validate and consume a one-time challenge nonce from the active node store ."""
399374 now_ts = int (time .time ()) if now_ts is None else int (now_ts )
400375 attest_cleanup_expired (conn , now_ts = now_ts )
401376 row = conn .execute (
@@ -421,10 +396,8 @@ def attest_validate_and_store_nonce(
421396 miner : str ,
422397 nonce : str ,
423398 now_ts : Optional [int ] = None ,
424- nonce_ts : Optional [int ] = None ,
425- skew_seconds : int = ATTEST_NONCE_SKEW_SECONDS ,
426399):
427- """Reject replayed or stale attestation nonces and persist accepted ones ."""
400+ """Require a live server-issued challenge and persist accepted attestation nonces ."""
428401 now_ts = int (time .time ()) if now_ts is None else int (now_ts )
429402 nonce = _attest_text (nonce )
430403 miner = _attest_valid_miner (miner ) or _attest_text (miner ) or ""
@@ -439,15 +412,11 @@ def attest_validate_and_store_nonce(
439412 if replay_row :
440413 return False , "nonce_replay" , None
441414
442- challenge_expires_at = None
443- if _attest_nonce_requires_challenge (nonce , nonce_ts ):
444- ok , err , challenge_expires_at = attest_validate_challenge (conn , nonce , now_ts = now_ts )
445- if not ok :
446- return False , err , None
447- elif nonce_ts is not None and abs (int (nonce_ts ) - now_ts ) > max (int (skew_seconds ), 0 ):
448- return False , "nonce_stale" , None
415+ ok , err , challenge_expires_at = attest_validate_challenge (conn , nonce , now_ts = now_ts )
416+ if not ok :
417+ return False , err , None
449418
450- expires_at = challenge_expires_at or ( now_ts + max ( int (skew_seconds ), 1 ) )
419+ expires_at = int (challenge_expires_at )
451420 conn .execute (
452421 "INSERT INTO used_nonces (nonce, miner_id, first_seen, expires_at) VALUES (?, ?, ?, ?)" ,
453422 (nonce , miner , now_ts , expires_at ),
@@ -2481,7 +2450,11 @@ def miner_dashboard_page():
24812450
24822451@app .route ('/attest/challenge' , methods = ['POST' ])
24832452def get_challenge ():
2484- """Issue challenge for hardware attestation"""
2453+ """Issue challenge for hardware attestation.
2454+
2455+ Deployments with multiple attestation backends should keep submit traffic
2456+ sticky to the issuing node or share the nonce store across nodes.
2457+ """
24852458 nonce = secrets .token_hex (32 )
24862459 expires = int (time .time ()) + 300 # 5 minutes
24872460
@@ -2629,14 +2602,12 @@ def _submit_attestation_impl():
26292602 "code" : "MISSING_NONCE"
26302603 }), 400
26312604
2632- nonce_ts = extract_attestation_timestamp (data , report , nonce )
26332605 with sqlite3 .connect (DB_PATH ) as nonce_conn :
26342606 nonce_ok , nonce_err , _ = attest_validate_and_store_nonce (
26352607 nonce_conn ,
26362608 miner = miner ,
26372609 nonce = nonce ,
26382610 now_ts = int (time .time ()),
2639- nonce_ts = nonce_ts ,
26402611 )
26412612 if not nonce_ok :
26422613 nonce_messages = {
@@ -2650,11 +2621,6 @@ def _submit_attestation_impl():
26502621 "Attestation nonce has already been used" ,
26512622 "NONCE_REPLAY" ,
26522623 ),
2653- "nonce_stale" : (
2654- "nonce_stale" ,
2655- "Attestation nonce timestamp is outside the allowed skew window" ,
2656- "NONCE_STALE" ,
2657- ),
26582624 }
26592625 error_name , message , code = nonce_messages .get (
26602626 nonce_err ,
0 commit comments