@@ -35,14 +35,16 @@ usage(int status) {
3535 " crc Calculate CRC-32 of flash region\n"
3636 " dlm Show Device Lifecycle Management state\n"
3737 " dlm-transit <state> Transition DLM state (ssd/nsecsd/dpl/lck_dbg/lck_boot)\n"
38+ " dlm-auth <state> <key> Authenticated DLM transition (ssd/nsecsd/rma_req)\n"
39+ " Key format: file:<path> or hex:<32_hex_chars>\n"
3840 " boundary Show secure/non-secure boundary settings\n"
3941 " boundary-set Set TrustZone boundaries (requires --cfs1/--cfs2/--dfs/--srs1/--srs2)\n"
4042 " param Show device parameter (initialization command)\n"
4143 " param-set <enable|disable> Enable/disable initialization command\n"
4244 " init Initialize device (factory reset to SSD state)\n"
4345 " osis Show OSIS (ID code protection) status\n"
44- " key-set <idx > <file> Inject wrapped key from file at index \n"
45- " key-verify <idx > Verify key at index \n"
46+ " key-set <type > <file> Inject wrapped DLM key (secdbg|nonsecdbg|rma) \n"
47+ " key-verify <type > Verify DLM key (secdbg|nonsecdbg|rma) \n"
4648 " ukey-set <idx> <file> Inject user wrapped key from file at index\n"
4749 " ukey-verify <idx> Verify user key at index\n"
4850 "\n"
@@ -130,6 +132,7 @@ enum command {
130132 CMD_CRC ,
131133 CMD_DLM ,
132134 CMD_DLM_TRANSIT ,
135+ CMD_DLM_AUTH ,
133136 CMD_BOUNDARY ,
134137 CMD_BOUNDARY_SET ,
135138 CMD_PARAM ,
@@ -142,6 +145,114 @@ enum command {
142145 CMD_UKEY_VERIFY ,
143146};
144147
148+ /* DLM key types (KYTY) per R01AN5562 */
149+ #define KYTY_SECDBG 0x01
150+ #define KYTY_NONSECDBG 0x02
151+ #define KYTY_RMA 0x03
152+
153+ /* DLM authentication key length (16 bytes / 128 bits) */
154+ #define DLM_AUTH_KEY_LEN 16
155+
156+ /*
157+ * Parse DLM authentication key from hex string
158+ * Returns: 0 on success, -1 on error
159+ */
160+ static int
161+ parse_hex_key (const char * str , uint8_t * key ) {
162+ size_t len = strlen (str );
163+
164+ /* Accept with or without 0x prefix */
165+ if (len >= 2 && str [0 ] == '0' && (str [1 ] == 'x' || str [1 ] == 'X' )) {
166+ str += 2 ;
167+ len -= 2 ;
168+ }
169+
170+ if (len != DLM_AUTH_KEY_LEN * 2 ) {
171+ warnx ("authentication key must be %d hex bytes (%d hex characters)" ,
172+ DLM_AUTH_KEY_LEN ,
173+ DLM_AUTH_KEY_LEN * 2 );
174+ return -1 ;
175+ }
176+
177+ for (int i = 0 ; i < DLM_AUTH_KEY_LEN ; i ++ ) {
178+ unsigned int byte ;
179+ if (sscanf (str + i * 2 , "%2x" , & byte ) != 1 ) {
180+ warnx ("invalid hex character in key at position %d" , i * 2 );
181+ return -1 ;
182+ }
183+ key [i ] = (uint8_t )byte ;
184+ }
185+
186+ return 0 ;
187+ }
188+
189+ /*
190+ * Load DLM authentication key from file (binary, 16 bytes)
191+ * Returns: 0 on success, -1 on error
192+ */
193+ static int
194+ load_key_from_file (const char * filename , uint8_t * key ) {
195+ FILE * f = fopen (filename , "rb" );
196+ if (f == NULL ) {
197+ warn ("failed to open key file: %s" , filename );
198+ return -1 ;
199+ }
200+
201+ size_t n = fread (key , 1 , DLM_AUTH_KEY_LEN , f );
202+ fclose (f );
203+
204+ if (n != DLM_AUTH_KEY_LEN ) {
205+ warnx ("key file must be %d bytes (got %zu)" , DLM_AUTH_KEY_LEN , n );
206+ return -1 ;
207+ }
208+
209+ return 0 ;
210+ }
211+
212+ /*
213+ * Parse authentication key from string
214+ * Format: file:<filename> - read 16-byte binary key from file
215+ * hex:<value> - parse 32-char hex string (with/without 0x)
216+ * Returns: 0 on success, -1 on error
217+ */
218+ static int
219+ parse_auth_key (const char * str , uint8_t * key ) {
220+ if (strncmp (str , "file:" , 5 ) == 0 ) {
221+ return load_key_from_file (str + 5 , key );
222+ } else if (strncmp (str , "hex:" , 4 ) == 0 ) {
223+ return parse_hex_key (str + 4 , key );
224+ } else {
225+ warnx ("invalid key format: %s" , str );
226+ warnx ("use: file:<filename> for binary key file" );
227+ warnx (" hex:<hex_value> for hex string (32 chars)" );
228+ return -1 ;
229+ }
230+ }
231+
232+ /*
233+ * Parse key type from string: accepts numeric (1,2,3) or keywords
234+ * Keywords: secdbg, nonsecdbg, rma (case-insensitive)
235+ * Returns key type on success, 0 on error
236+ */
237+ static uint8_t
238+ parse_key_type (const char * str ) {
239+ if (strcasecmp (str , "secdbg" ) == 0 )
240+ return KYTY_SECDBG ;
241+ if (strcasecmp (str , "nonsecdbg" ) == 0 )
242+ return KYTY_NONSECDBG ;
243+ if (strcasecmp (str , "rma" ) == 0 )
244+ return KYTY_RMA ;
245+
246+ /* Try numeric */
247+ char * endptr ;
248+ unsigned long val = strtoul (str , & endptr , 0 );
249+ if (* endptr != '\0' || val < 1 || val > 3 ) {
250+ warnx ("invalid key type: %s (use secdbg, nonsecdbg, rma, or 1-3)" , str );
251+ return 0 ;
252+ }
253+ return (uint8_t )val ;
254+ }
255+
145256/* Long-only options use values >= 256 */
146257#define OPT_CFS1 256
147258#define OPT_CFS2 257
@@ -185,6 +296,7 @@ main(int argc, char *argv[]) {
185296 uint8_t param_value = 0 ;
186297 uint8_t key_index = 0 ;
187298 const char * key_file = NULL ;
299+ uint8_t auth_key [DLM_AUTH_KEY_LEN ];
188300 ra_boundary_t bnd = { 0 };
189301 bool bnd_cfs1_set = false, bnd_cfs2_set = false, bnd_dfs_set = false;
190302 bool bnd_srs1_set = false, bnd_srs2_set = false;
@@ -304,6 +416,21 @@ main(int argc, char *argv[]) {
304416 dest_dlm = DLM_STATE_LCK_BOOT ;
305417 else
306418 errx (EXIT_FAILURE , "unknown DLM state: %s (use ssd/nsecsd/dpl/lck_dbg/lck_boot)" , state );
419+ } else if (strcmp (command , "dlm-auth" ) == 0 ) {
420+ cmd = CMD_DLM_AUTH ;
421+ if (optind + 1 >= argc )
422+ errx (EXIT_FAILURE , "dlm-auth requires <state> and <key> arguments" );
423+ const char * state = argv [optind ];
424+ if (strcasecmp (state , "ssd" ) == 0 )
425+ dest_dlm = DLM_STATE_SSD ;
426+ else if (strcasecmp (state , "nsecsd" ) == 0 )
427+ dest_dlm = DLM_STATE_NSECSD ;
428+ else if (strcasecmp (state , "rma_req" ) == 0 )
429+ dest_dlm = DLM_STATE_RMA_REQ ;
430+ else
431+ errx (EXIT_FAILURE , "dlm-auth: invalid target state: %s (use ssd/nsecsd/rma_req)" , state );
432+ if (parse_auth_key (argv [optind + 1 ], auth_key ) < 0 )
433+ errx (EXIT_FAILURE , "dlm-auth: invalid key format" );
307434 } else if (strcmp (command , "boundary" ) == 0 ) {
308435 cmd = CMD_BOUNDARY ;
309436 } else if (strcmp (command , "boundary-set" ) == 0 ) {
@@ -330,14 +457,18 @@ main(int argc, char *argv[]) {
330457 } else if (strcmp (command , "key-set" ) == 0 ) {
331458 cmd = CMD_KEY_SET ;
332459 if (optind + 1 >= argc )
333- errx (EXIT_FAILURE , "key-set requires index and file arguments" );
334- key_index = (uint8_t )strtoul (argv [optind ], NULL , 10 );
460+ errx (EXIT_FAILURE , "key-set requires type and file arguments" );
461+ key_index = parse_key_type (argv [optind ]);
462+ if (key_index == 0 )
463+ errx (EXIT_FAILURE , "key-set: invalid key type" );
335464 key_file = argv [optind + 1 ];
336465 } else if (strcmp (command , "key-verify" ) == 0 ) {
337466 cmd = CMD_KEY_VERIFY ;
338467 if (optind >= argc )
339- errx (EXIT_FAILURE , "key-verify requires index argument" );
340- key_index = (uint8_t )strtoul (argv [optind ], NULL , 10 );
468+ errx (EXIT_FAILURE , "key-verify requires type argument" );
469+ key_index = parse_key_type (argv [optind ]);
470+ if (key_index == 0 )
471+ errx (EXIT_FAILURE , "key-verify: invalid key type" );
341472 } else if (strcmp (command , "ukey-set" ) == 0 ) {
342473 cmd = CMD_UKEY_SET ;
343474 if (optind + 1 >= argc )
@@ -451,6 +582,9 @@ main(int argc, char *argv[]) {
451582 case CMD_DLM_TRANSIT :
452583 ret = ra_dlm_transit (& dev , dest_dlm );
453584 break ;
585+ case CMD_DLM_AUTH :
586+ ret = ra_dlm_auth (& dev , dest_dlm , auth_key );
587+ break ;
454588 case CMD_BOUNDARY :
455589 ret = ra_get_boundary (& dev , NULL );
456590 break ;
0 commit comments