SDK สำหรับ TESAIoT Dev Kit
คู่มืออ้างอิง API และ Tutorial (MTB & µPython)
Loading...
Searching...
No Matches

Functions

void bento_devmode_init (void)
 เป็น idempotent สร้าง secret ขนาด 32 ไบต์ใน RAM จุดเข้าสาธารณะของ devmode ทุกจุดเรียกฟังก์ชันนี้เอง
void bento_devmode_nonce_issue (uint8_t nonce_out[BENTO_DEVMODE_NONCE_LEN])
 เติม nonce ใหม่ขนาด 16 ไบต์ ทับตัวที่ค้างอยู่ทิ้ง และเริ่มนับนาฬิกา TTL
bool bento_devmode_unlock (const char *hmac_hex, size_t hmac_hex_len)
 ตรวจสอบ HMAC เทียบกับ nonce ที่ค้างอยู่ และทำให้ nonce ใช้ไม่ได้อีกทุกครั้งที่ถูกเรียก (ใช้ได้ครั้งเดียว)
void bento_devmode_lock (void)
 ล้าง flag ปลดล็อก
bool bento_devmode_is_unlocked (void)
 บอกว่า verb ที่มีสิทธิ์พิเศษ (bento.exec) ได้รับอนุญาตอยู่ในขณะนั้นหรือไม่
size_t bento_devmode_secret_hex (char *out, size_t out_sz)
 secret ในรูป hex 64 อักขระ + NUL หรือคืน 0 เมื่อบัฟเฟอร์เล็กเกินไป ห้ามพิมพ์ค่านี้ลง UART
void bento_devmode_emit_provision (void)
 ส่ง event provision หนึ่งครั้งต่อการบูตหนึ่งรอบ ตอนเปลี่ยนสถานะเป็น CONNECTED การส่งที่ล้มเหลวจะลองใหม่
size_t bento_devmode_secret_fp_hex (char *out, size_t out_sz)
 4 ไบต์แรกของ SHA-256(secret) ในรูป hex 8 อักขระ + NUL — พิมพ์ออกได้อย่างปลอดภัย

Detailed Description

8 ฟังก์ชัน: การปลดล็อกโหมดสำหรับผู้พัฒนา ในกลุ่ม bento_devmode_* คอมไพล์เฉพาะเมื่อ ENABLE_PAGE_BENTO_BUDDY=1 (ค่าตั้งต้นคือ 0, proj_cm33_ns/Makefile:64, :305) ให้ build ใหม่หลังจาก make getlibs — ดู Flag gate (อ่านก่อน)

การประกาศ: bento_devmode.h ส่วนการนำไปสร้างจริงใน bento_devmode.c ถูกเก็บไว้ใน libbento_secure.a secret ที่ใช้ร่วมกันนั้น อยู่ใน RAM เท่านั้นและถูกสร้างใหม่ทุกครั้งที่บูต (การคงค่าไว้ใน slot 0xE120 ของ OPTIGA ถูกเลื่อนออกไป bento_devmode.c:96-97) — ฝั่ง desktop ต้องจัดเตรียมใหม่หลังการบูตใหม่ทุกครั้ง TTL ของ nonce คือ BENTO_DEVMODE_NONCE_TTL_MS (60000) และมี challenge ค้างได้ครั้งละหนึ่งรายการ

สิ่งที่ challenge/response นี้ปกป้องได้ และสิ่งที่ปกป้องไม่ได้ การจัดเตรียมค่าเริ่มต้นนั้นทำโดยส่ง secret ออกไปในรูป plaintext ให้ peer ตัวแรกที่เชื่อมต่อสำเร็จ (Devmode ที่ bento_devmode_emit_provision) ผ่าน TX ที่ไม่ได้ตั้งบิต GATTDB_PERM_AUTH_* และตัว secret มาจาก xorshift32 ที่มีเอนโทรปีต่ำกว่า 32 บิต ขั้นตอน HMAC เองถูกต้อง แต่ผลลัพธ์รวมคือ gate ที่กัน peer ซึ่งมาทีหลังได้เท่านั้น จึงเป็นเครื่องกีดขวาง ไม่ใช่ขอบเขตการบังคับใช้สิทธิ์

variant ที่ใช้ได้
mtb-mpy และ mtb-only

Function Documentation

◆ bento_devmode_init()

void bento_devmode_init ( void )

เป็น idempotent สร้าง secret ขนาด 32 ไบต์ใน RAM จุดเข้าสาธารณะของ devmode ทุกจุดเรียกฟังก์ชันนี้เอง

ข้อกำหนดการเรียกใช้
เป็น idempotent (เรียกซ้ำแล้วผลเหมือนเดิม) โดยมี s_secret_ready เป็นตัวกัน (bento_devmode.c:92) ไม่จำเป็นต้องมีผู้เรียกจากภายนอก — จุดเข้าสาธารณะของ devmode ทุกจุดเรียกฟังก์ชันนี้เอง (:103, :210, :221, :255) ไม่มีการจับ lock ตั้งค่าตั้งต้นให้ PRNG แล้วเติม secret ขนาด 32 ไบต์ call site ในเทมเพลต: 0 (ใน archive: 4)

คุณภาพของ secret PRNG ที่ใช้คือ xorshift32 ซึ่ง seed จาก tick ของ FreeRTOS, แอดเดรสบน stack และค่าคงที่หนึ่งค่า (bento_devmode.c:54-66) เอนโทรปีจึงต่ำกว่า 32 บิต และคอมเมนต์ในซอร์สระบุไว้เองว่า "not cryptographically strong" ไม่ได้ใช้ RNG ของ OPTIGA การย้ายไปใช้ค่าจากชิปเป็นงานที่ยังไม่ได้ทำ

variant ที่ใช้ได้
mtb-mpy และ mtb-only
ที่มา
ยกมาจาก BENTO-TESAIoT-libraries/claw/common/ble_nus/bento_devmode.c:90-108 (คอมไพล์รวมอยู่ใน archive สำเร็จรูป ไม่ได้ส่งมอบมาเป็นซอร์ส)

◆ bento_devmode_nonce_issue()

void bento_devmode_nonce_issue ( uint8_t nonce_out[BENTO_DEVMODE_NONCE_LEN])

เติม nonce ใหม่ขนาด 16 ไบต์ ทับตัวที่ค้างอยู่ทิ้ง และเริ่มนับนาฬิกา TTL

ข้อกำหนดการเรียกใช้
เติม nonce ใหม่ขนาด 16 ไบต์ ทับตัวที่ค้างอยู่ทิ้ง แล้วเริ่มนับนาฬิกา TTL เรียก init ให้ตัวเอง (ข้อความตัดตอนใต้ bento_devmode_init() แสดงไว้แล้ว) call site ในเทมเพลต: 0 call site ใน archive อยู่ที่ nus_commands.c:1475 (bento_devmode_nonce_issue(nonce); คือ verb bento.devmode.nonce คอมไพล์รวมอยู่ใน libbento_secure.a ไม่ได้ส่งมอบมาเป็นซอร์ส)

ผลด้านความปลอดภัยที่ต้องระบุให้ตรง ฟังก์ชันนี้ส่ง secret ออกไปในรูป plaintext ให้ peer ตัวแรกที่เชื่อมต่อสำเร็จหลังการบูต และ characteristic TX ไม่ได้ตั้งบิต GATTDB_PERM_AUTH_* (ดู ข้อมูล GATT) ดังนั้น peer ที่ยังไม่ได้จับคู่ก็รับค่านี้ได้ ขั้นตอน HMAC-SHA256 เองถูกต้อง แต่การครอบครองกุญแจไม่ได้ถูกจำกัดไว้กับเครื่องเดสก์ท็อปที่ได้รับอนุญาต gate นี้จึงกัน peer ที่มาทีหลังได้เท่านั้น ให้ถือเป็นเครื่องกีดขวาง ไม่ใช่ขอบเขตการบังคับใช้สิทธิ์

variant ที่ใช้ได้
mtb-mpy และ mtb-only

◆ bento_devmode_unlock()

bool bento_devmode_unlock ( const char * hmac_hex,
size_t hmac_hex_len )

ตรวจสอบ HMAC เทียบกับ nonce ที่ค้างอยู่ และทำให้ nonce ใช้ไม่ได้อีกทุกครั้งที่ถูกเรียก (ใช้ได้ครั้งเดียว)

ข้อกำหนดการเรียกใช้
ตรวจสอบสตริง hex ของ HMAC-SHA256 เทียบกับ nonce ที่ค้างอยู่และกับ secret คืน true เมื่อค่าตรงกัน และ TTL ยังไม่หมดอายุ ซึ่งจะตั้ง flag ปลดล็อกด้วย ทำให้ nonce ใช้ไม่ได้อีกทุกครั้งที่ถูกเรียก (ใช้ได้ครั้งเดียว เป็นการป้องกันการเล่นซ้ำ) call site ในเทมเพลต: 0 call site ใน archive อยู่ที่ nus_commands.c:1506 (if (bento_devmode_unlock(json + t->start, hlen)) { — สตริง hex ถูกส่งตรงมาจาก token ของ JSON โดยไม่ได้ปิดท้ายด้วย NUL คอมไพล์รวมอยู่ใน libbento_secure.a ไม่ได้ส่งมอบมาเป็นซอร์ส)
variant ที่ใช้ได้
mtb-mpy และ mtb-only

◆ bento_devmode_lock()

void bento_devmode_lock ( void )

ล้าง flag ปลดล็อก

ข้อกำหนดการเรียกใช้
ล้าง flag ปลดล็อก call site ในเทมเพลต: 0 call site ใน archive อยู่ที่ nus_commands.c:1531 (bento_devmode_lock(); คอมไพล์รวมอยู่ใน libbento_secure.a ไม่ได้ส่งมอบมาเป็นซอร์ส)
variant ที่ใช้ได้
mtb-mpy และ mtb-only

◆ bento_devmode_is_unlocked()

bool bento_devmode_is_unlocked ( void )

บอกว่า verb ที่มีสิทธิ์พิเศษ (bento.exec) ได้รับอนุญาตอยู่ในขณะนั้นหรือไม่

ข้อกำหนดการเรียกใช้
บอกว่า verb ที่มีสิทธิ์พิเศษ (bento.exec) ได้รับอนุญาตอยู่ในขณะนั้นหรือไม่ call site ในเทมเพลต: 0 call site ใน archive อยู่ที่ nus_commands.c:1538 (if (!bento_devmode_is_unlocked()) { เป็นรูปแบบการตรวจ gate) และที่ :1335 (JSON สถานะ) — คอมไพล์รวมอยู่ใน libbento_secure.a ไม่ได้ส่งมอบมาเป็นซอร์ส
variant ที่ใช้ได้
mtb-mpy และ mtb-only

◆ bento_devmode_secret_hex()

size_t bento_devmode_secret_hex ( char * out,
size_t out_sz )

secret ในรูป hex 64 อักขระ + NUL หรือคืน 0 เมื่อบัฟเฟอร์เล็กเกินไป ห้ามพิมพ์ค่านี้ลง UART

ข้อกำหนดการเรียกใช้
เขียน secret ในรูป hex 64 อักขระ + NUL คืนค่าความยาวที่เขียนได้ หรือคืน 0 เมื่อบัฟเฟอร์เล็กเกินไป — ต้องตรวจค่า 0 ผู้เรียก ห้ามพิมพ์ค่านี้ลง UART call site ในเทมเพลต: 0 call site ใน archive อยู่ที่ bento_devmode.c:261 (if (bento_devmode_secret_hex(secret_hex, sizeof(secret_hex)) == 0) { ภายใน bento_devmode_emit_provision คอมไพล์รวมอยู่ใน libbento_secure.a ไม่ได้ส่งมอบมาเป็นซอร์ส)
variant ที่ใช้ได้
mtb-mpy และ mtb-only

◆ bento_devmode_emit_provision()

void bento_devmode_emit_provision ( void )

ส่ง event provision หนึ่งครั้งต่อการบูตหนึ่งรอบ ตอนเปลี่ยนสถานะเป็น CONNECTED การส่งที่ล้มเหลวจะลองใหม่

ข้อกำหนดการเรียกใช้
ส่ง {"evt":"bento.devmode.provision","secret":"<64 hex>"} ออกทาง NUS หนึ่งครั้งต่อการบูตหนึ่งรอบ (มี flag แบบ static บอกว่าส่งไปแล้ว การส่งที่ล้มเหลวจะปล่อย flag นั้นไว้โดยไม่ตั้งค่า การเปลี่ยนสถานะเป็น CONNECTED ครั้งถัดไปจึงลองใหม่) ต่อไว้กับการเปลี่ยนสถานะเป็น CONNECTED ใน ble_nus_lazy.c คู่กับ bento_fw_emit_boot_complete() หากไม่มีการส่งนี้ bento.devmode.unlock ทุกครั้งจะตอบ not_permitted call site ในเทมเพลต: 0 call site ใน archive อยู่ที่ ble_nus_lazy.c:101 (bento_devmode_emit_provision(); คอมเมนต์ที่ :37 ระบุ "SPEC §7.3 step 2" คอมไพล์รวมอยู่ใน libbento_secure.a ไม่ได้ส่งมอบมาเป็นซอร์ส)
variant ที่ใช้ได้
mtb-mpy และ mtb-only

◆ bento_devmode_secret_fp_hex()

size_t bento_devmode_secret_fp_hex ( char * out,
size_t out_sz )

4 ไบต์แรกของ SHA-256(secret) ในรูป hex 8 อักขระ + NUL — พิมพ์ออกได้อย่างปลอดภัย

ข้อกำหนดการเรียกใช้
4 ไบต์แรกของ SHA-256(secret) ในรูป hex 8 อักขระ + NUL — พิมพ์ออกได้อย่างปลอดภัย ทำให้ฝั่ง desktop กับเฟิร์มแวร์ยืนยันได้ว่าถือ secret ตัวเดียวกัน โดยไม่ทำให้ค่านั้นรั่วไหล คืนค่าความยาวที่เขียนได้ คืน 0 เมื่อบัฟเฟอร์เล็กเกินไป call site ในเทมเพลต: 0 (ใน archive: 3 — bento_devmode.c:277, nus_commands.c:1511, :1522)
variant ที่ใช้ได้
mtb-mpy และ mtb-only
ที่มา
ยกมาจาก BENTO-TESAIoT-libraries/claw/common/ble_nus/bento_devmode.c:269-285 (คอมไพล์รวมอยู่ใน archive สำเร็จรูป ไม่ได้ส่งมอบมาเป็นซอร์ส)