@@ -333,3 +333,205 @@ impl Template {
333
333
Ok ( deser_hjson:: from_str ( content) ?)
334
334
}
335
335
}
336
+
337
+ #[ cfg( test) ]
338
+ mod tests {
339
+ use super :: * ;
340
+ use indoc:: indoc;
341
+
342
+ /// Test parsing a typical cdi_owner template.
343
+ #[ test]
344
+ fn cdi_owner ( ) {
345
+ // Input string for a Hjson template.
346
+ let input = indoc ! { r#"
347
+ {
348
+ name: "cdi_owner",
349
+
350
+ variables: {
351
+ owner_pub_key_ec_x: {
352
+ type: "integer",
353
+ size: 32,
354
+ },
355
+ owner_pub_key_ec_y: {
356
+ type: "integer",
357
+ size: 32,
358
+ },
359
+ owner_pub_key_id: {
360
+ type: "byte-array",
361
+ size: 20,
362
+ },
363
+ signing_pub_key_id: {
364
+ type: "byte-array",
365
+ size: 20,
366
+ },
367
+ rom_ext_hash: {
368
+ type: "byte-array",
369
+ size: 20,
370
+ },
371
+ ownership_manifest_hash: {
372
+ type: "byte-array",
373
+ size: 20,
374
+ },
375
+ rom_ext_security_version: {
376
+ type: "integer",
377
+ size: 4,
378
+ }
379
+ layer: {
380
+ type: "integer",
381
+ size: 4,
382
+ }
383
+ cert_signature_r: {
384
+ type: "integer",
385
+ size: 32,
386
+ },
387
+ cert_signature_s: {
388
+ type: "integer",
389
+ size: 32,
390
+ },
391
+ },
392
+
393
+ certificate: {
394
+ serial_number: { var: "owner_pub_key_id", convert: "little-endian" },
395
+ issuer: {
396
+ serial_number: { var: "signing_pub_key_id", convert: "lowercase-hex" },
397
+ },
398
+ subject: {
399
+ serial_number: { var: "owner_pub_key_id", convert: "lowercase-hex" },
400
+ },
401
+ subject_public_key_info: {
402
+ algorithm: "ec-public-key",
403
+ curve: "prime256v1",
404
+ public_key: {
405
+ x: { var: "owner_pub_key_ec_x" },
406
+ y: { var: "owner_pub_key_ec_y" },
407
+ },
408
+ },
409
+ authority_key_identifier: { var: "signing_pub_key_id" },
410
+ subject_key_identifier: { var: "owner_pub_key_id" },
411
+ vendor: "OpenTitan",
412
+ model: "ROM_EXT",
413
+ svn: { var: "rom_ext_security_version" },
414
+ layer: { var: "layer" },
415
+ version: "ES",
416
+ fw_ids: [
417
+ { hash_algorithm: "sha256", digest: { var: "rom_ext_hash" } },
418
+ { hash_algorithm: "sha256", digest: { var: "ownership_manifest_hash" } },
419
+ ],
420
+ flags: {
421
+ not_configured: true,
422
+ not_secure: false,
423
+ recovery: true,
424
+ debug: false,
425
+ }
426
+ signature: {
427
+ algorithm: "ecdsa-with-sha256",
428
+ // The value field is optional: if not present, the signature will be cleared.
429
+ // Otherwise, we can reference the various fields of the signature.
430
+ value: {
431
+ r: { var: "cert_signature_r" },
432
+ s: { var: "cert_signature_s" }
433
+ }
434
+ }
435
+ }
436
+ }
437
+ "# } ;
438
+
439
+ let variables = HashMap :: from ( [
440
+ (
441
+ "owner_pub_key_ec_x" . to_string ( ) ,
442
+ VariableType :: Integer { size : 32 } ,
443
+ ) ,
444
+ (
445
+ "owner_pub_key_ec_y" . to_string ( ) ,
446
+ VariableType :: Integer { size : 32 } ,
447
+ ) ,
448
+ (
449
+ "owner_pub_key_id" . to_string ( ) ,
450
+ VariableType :: ByteArray { size : 20 } ,
451
+ ) ,
452
+ (
453
+ "signing_pub_key_id" . to_string ( ) ,
454
+ VariableType :: ByteArray { size : 20 } ,
455
+ ) ,
456
+ (
457
+ "rom_ext_hash" . to_string ( ) ,
458
+ VariableType :: ByteArray { size : 20 } ,
459
+ ) ,
460
+ (
461
+ "ownership_manifest_hash" . to_string ( ) ,
462
+ VariableType :: ByteArray { size : 20 } ,
463
+ ) ,
464
+ (
465
+ "rom_ext_security_version" . to_string ( ) ,
466
+ VariableType :: Integer { size : 4 } ,
467
+ ) ,
468
+ ( "layer" . to_string ( ) , VariableType :: Integer { size : 4 } ) ,
469
+ (
470
+ "cert_signature_r" . to_string ( ) ,
471
+ VariableType :: Integer { size : 32 } ,
472
+ ) ,
473
+ (
474
+ "cert_signature_s" . to_string ( ) ,
475
+ VariableType :: Integer { size : 32 } ,
476
+ ) ,
477
+ ] ) ;
478
+
479
+ // Certificate template values.
480
+ let certificate = Certificate {
481
+ serial_number : Value :: convert ( "owner_pub_key_id" , Conversion :: LittleEndian ) ,
482
+ issuer : HashMap :: from ( [ (
483
+ AttributeType :: SerialNumber ,
484
+ Value :: convert ( "signing_pub_key_id" , Conversion :: LowercaseHex ) ,
485
+ ) ] ) ,
486
+ subject : HashMap :: from ( [ (
487
+ AttributeType :: SerialNumber ,
488
+ Value :: convert ( "owner_pub_key_id" , Conversion :: LowercaseHex ) ,
489
+ ) ] ) ,
490
+ subject_public_key_info : SubjectPublicKeyInfo :: EcPublicKey ( EcPublicKeyInfo {
491
+ curve : EcCurve :: Prime256v1 ,
492
+ public_key : EcPublicKey {
493
+ x : Value :: variable ( "owner_pub_key_ec_x" ) ,
494
+ y : Value :: variable ( "owner_pub_key_ec_y" ) ,
495
+ } ,
496
+ } ) ,
497
+ authority_key_identifier : Value :: variable ( "signing_pub_key_id" ) ,
498
+ subject_key_identifier : Value :: variable ( "owner_pub_key_id" ) ,
499
+ vendor : Some ( Value :: literal ( "OpenTitan" ) ) ,
500
+ model : Some ( Value :: literal ( "ROM_EXT" ) ) ,
501
+ svn : Some ( Value :: variable ( "rom_ext_security_version" ) ) ,
502
+ layer : Some ( Value :: variable ( "layer" ) ) ,
503
+ version : Some ( Value :: literal ( "ES" ) ) ,
504
+ fw_ids : Some ( Vec :: from ( [
505
+ FirmwareId {
506
+ hash_algorithm : HashAlgorithm :: Sha256 ,
507
+ digest : Value :: variable ( "rom_ext_hash" ) ,
508
+ } ,
509
+ FirmwareId {
510
+ hash_algorithm : HashAlgorithm :: Sha256 ,
511
+ digest : Value :: variable ( "ownership_manifest_hash" ) ,
512
+ } ,
513
+ ] ) ) ,
514
+ flags : Some ( Flags {
515
+ not_configured : true ,
516
+ not_secure : false ,
517
+ recovery : true ,
518
+ debug : false ,
519
+ } ) ,
520
+ signature : Signature :: EcdsaWithSha256 {
521
+ value : Some ( EcdsaSignature {
522
+ r : Value :: variable ( "cert_signature_r" ) ,
523
+ s : Value :: variable ( "cert_signature_s" ) ,
524
+ } ) ,
525
+ } ,
526
+ } ;
527
+
528
+ // Compare expected and actual parsed structs.
529
+ let expected = Template {
530
+ name : "cdi_owner" . to_string ( ) ,
531
+ variables,
532
+ certificate,
533
+ } ;
534
+ let actual = Template :: from_hjson_str ( input) . expect ( "failed to parse template" ) ;
535
+ assert_eq ! ( expected, actual) ;
536
+ }
537
+ }
0 commit comments